campvisapplication.cpp 13.3 KB
Newer Older
1
2
// ================================================================================================
// 
schultezub's avatar
schultezub committed
3
// This file is part of the CAMPVis Software Framework.
4
// 
5
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
schultezub's avatar
schultezub committed
6
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
7
//      Chair for Computer Aided Medical Procedures
8
9
//      Technische Universitaet Muenchen
//      Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
10
// 
schultezub's avatar
schultezub committed
11
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
12
// 
13
14
15
16
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 
// except in compliance with the License. You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
17
// 
18
19
20
21
// Unless required by applicable law or agreed to in writing, software distributed under the 
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
// either express or implied. See the License for the specific language governing permissions 
// and limitations under the License.
22
23
24
// 
// ================================================================================================

schultezub's avatar
schultezub committed
25
#include "campvisapplication.h"
26

27
28
29
30
31
32
33
34
35
36
#include "cgt/assert.h"
#include "cgt/exception.h"
#include "cgt/glcanvas.h"
#include "cgt/glcontextmanager.h"
#include "cgt/gpucapabilities.h"
#include "cgt/init.h"
#include "cgt/opengljobprocessor.h"
#include "cgt/shadermanager.h"
#include "cgt/texturereadertga.h"
#include "cgt/qt/qtthreadedcanvas.h"
37

schultezub's avatar
schultezub committed
38
#include "application/campvispainter.h"
39
#include "application/gui/properties/propertywidgetfactory.h"
40
#include "application/gui/mainwindow.h"
Jakob Weiss's avatar
Jakob Weiss committed
41
#include "application/gui/mdi/mdidockablewindow.h"
42

43
#include "core/tools/simplejobprocessor.h"
44
#include "core/tools/stringutils.h"
45
#include "core/tools/quadrenderer.h"
46
#include "core/pipeline/abstractpipeline.h"
47
#include "core/datastructures/imagerepresentationconverter.h"
48
#include "core/pipeline/visualizationprocessor.h"
49

50
#include "modules/pipelinefactory.h"
51
#include "qtjobprocessor.h"
52

53
54
#include <QApplication>

55
#ifdef CAMPVIS_HAS_SCRIPTING
56
#include "scripting/gen_pipelineregistration.h"
57
58
#endif

schultezub's avatar
schultezub committed
59
namespace campvis {
60

61
    const std::string CampVisApplication::loggerCat_ = "CAMPVis.application.CampVisApplication";
62

63
    CampVisApplication::CampVisApplication(int& argc, char** argv) 
64
65
        : QApplication(argc, argv)
        , _localContext(0)
66
        , _mainWindow(0)
67
        , _errorTexture(nullptr)
68
        , _luaVmState(nullptr)
69
70
71
72
        , _initialized(false)
        , _argc(argc)
        , _argv(argv)
    {
73
74
        // Make Xlib and GLX thread safe under X11
        QApplication::setAttribute(Qt::AA_X11InitThreads);
75

76
77
        sigslot::signal_manager::init();
        sigslot::signal_manager::getRef().start();
78
        cgt::GlContextManager::init();
79
        OpenGLJobProcessor::init();
80
        SimpleJobProcessor::init();
81
        QtJobProcessor::init();
82
83
    }

84
    CampVisApplication::~CampVisApplication() {
85
        cgtAssert(_initialized == false, "Destructing initialized CampVisApplication, deinitialize first!");
86

87
88
        sigslot::signal_manager::getRef().stop();
        sigslot::signal_manager::deinit();
89
90
    }

91
    void CampVisApplication::init() {
92
        cgtAssert(_initialized == false, "Tried to initialize CampVisApplication twice.");
93

94
95
96
        // Init CGT
        cgt::InitFeature::Features featureset = cgt::InitFeature::ALL;
        cgt::init(featureset);
97
98
        LogMgr.getConsoleLog()->addCat("", true);

99
100
        _mainWindow = new MainWindow(this);

101
        // create a local OpenGL context and init GL
102
103
        _localContext = new QtThreadedCanvas("", cgt::ivec2(16, 16));
        cgt::GlContextManager::getRef().registerContextAndInitGlew(_localContext, "Local Context");
104

105
        cgt::initGL(featureset);
106
        ShdrMgr.setDefaultGlslVersion("330");
107
108
        LGL_ERROR;

109
        QuadRenderer::init();
110
        
111
112
        if (_argc > 0) {
            // ugly hack
schultezub's avatar
schultezub committed
113
            std::string basePath(_argv[0]);
114
            basePath = cgt::FileSystem::parentDir(basePath);
115
116
117
            ShdrMgr.addPath(basePath);
            ShdrMgr.addPath(basePath + "/core/glsl");

118
            basePath = cgt::FileSystem::parentDir(cgt::FileSystem::parentDir(basePath));
schultezub's avatar
schultezub committed
119
120
121
            ShdrMgr.addPath(basePath);
            ShdrMgr.addPath(basePath + "/core/glsl");

122
123
124
125
126
127
#ifdef CAMPVIS_SOURCE_DIR
            {
                std::string sourcePath = CAMPVIS_SOURCE_DIR;
                ShdrMgr.addPath(sourcePath);
                ShdrMgr.addPath(sourcePath + "/core/glsl");
            }
schultezub's avatar
schultezub committed
128
#endif
129
130
        }

131
132
        _mainWindow->init();

133
134
135
        // ensure matching OpenGL specs
        LINFO("Using Graphics Hardware " << GpuCaps.getVendorAsString() << " " << GpuCaps.getGlRendererString() << " on " << GpuCaps.getOSVersionString());
        LINFO("Supported OpenGL " << GpuCaps.getGlVersion() << ", GLSL " << GpuCaps.getShaderVersion());
136
        if (GpuCaps.getGlVersion() < cgt::GpuCapabilities::GlVersion::CGT_GL_VERSION_3_3) {
137
138
            LERROR("Your system does not support OpenGL 3.3, which is mandatory. CAMPVis will probably not work as intended.");
        }
139
        if (GpuCaps.getShaderVersion() < cgt::GpuCapabilities::GlVersion::SHADER_VERSION_330) {
140
141
142
            LERROR("Your system does not support GLSL Shader Version 3.30, which is mandatory. CAMPVis will probably not work as intended.");
        }

143

144
        // load textureData from file
145
146
        cgt::TextureReaderTga trt;
        _errorTexture = trt.loadTexture(ShdrMgr.completePath("application/data/no_input.tga"), cgt::Texture::LINEAR);
147

148
149
150
151

#ifdef CAMPVIS_HAS_SCRIPTING
        // create and store Lua VM for this very pipeline
        _luaVmState = new LuaVmState();
152
        _luaVmState->redirectLuaPrint();
153
154
155
156

        // Let Lua know where CAMPVis modules are located
        if (! _luaVmState->execString("package.cpath = '" CAMPVIS_LUA_MODS_PATH "'"))
            LERROR("Error setting up Lua VM.");
157
158
        if (! _luaVmState->execString("package.path = package.path .. ';" CAMPVIS_LUA_SCRIPTS_PATH "'"))
            LERROR("Error setting up Lua VM.");
159
160
161
162

        // Load CAMPVis' core Lua module to have SWIG glue for AutoEvaluationPipeline available
        if (! _luaVmState->execString("require(\"campvis\")"))
            LERROR("Error setting up Lua VM.");
163
        if (! _luaVmState->execString("require(\"cgt\")"))
164
165
166
167
168
169
170
171
            LERROR("Error setting up Lua VM.");

        if (! _luaVmState->execString("pipelines = {}"))
            LERROR("Error setting up Lua VM.");

        if (! _luaVmState->execString("inspect = require 'inspect'"))
            LERROR("Error setting up Lua VM.");
#endif
172
        GLCtxtMgr.releaseContext(_localContext, false);
173

174
175
176
177
178
179
180
        // parse argument list and create pipelines
        QStringList pipelinesToAdd = this->arguments();
        for (int i = 1; i < pipelinesToAdd.size(); ++i) {
            DataContainer* dc = createAndAddDataContainer("DataContainer #" + StringUtils::toString(_dataContainers.size() + 1));
            AbstractPipeline* p = PipelineFactory::getRef().createPipeline(pipelinesToAdd[i].toStdString(), dc);
            if (p != 0)
                addPipeline(pipelinesToAdd[i].toStdString(), p);
181
182
        }

183
184
185
        GLJobProc.setContext(_localContext);
        GLJobProc.start();

186
187
188
        _initialized = true;
    }

189
    void CampVisApplication::deinit() {
190
        cgtAssert(_initialized, "Tried to deinitialize uninitialized CampVisApplication.");
191

192
193
194
195
        // Stop all pipeline threads.
        for (std::vector<PipelineRecord>::iterator it = _pipelines.begin(); it != _pipelines.end(); ++it) {
            it->_pipeline->stop();
        }
196

197
198
        {
            // Deinit everything OpenGL related using the local context.
199
            cgt::GLContextScopedLock lock(_localContext);
200

201
202
            delete _errorTexture;

203
204
205
206
            // Deinit pipeline and painter first
            for (std::vector<PipelineRecord>::iterator it = _pipelines.begin(); it != _pipelines.end(); ++it) {
                it->_pipeline->deinit();
                it->_painter->deinit();
207
208
            }

209
            _mainWindow->deinit();
210
211
            QuadRenderer::deinit();

212
213
            // deinit OpenGL and cgt
            cgt::deinitGL();
214
215
        }

216
217
        // MainWindow dtor needs a valid CampVisApplication, so we need to call it here instead of during destruction.
        delete _mainWindow;
218

219
220
221
222
223
224
225
226
227
        // now delete everything in the right order:
        for (std::vector<PipelineRecord>::iterator it = _pipelines.begin(); it != _pipelines.end(); ++it) {
            delete it->_painter;
            delete it->_pipeline;
        }
        for (std::vector<DataContainer*>::iterator it = _dataContainers.begin(); it != _dataContainers.end(); ++it) {
            delete *it;
        }

228
        GLJobProc.stop();
229
230
231
        OpenGLJobProcessor::deinit();
        SimpleJobProcessor::deinit();

232
233
        cgt::GlContextManager::deinit();
        cgt::deinit();
234

235
236
237
238
        PropertyWidgetFactory::deinit();
        ImageRepresentationConverter::deinit();
        PipelineFactory::deinit();

239
240
241
        _initialized = false;
    }

242
    int CampVisApplication::run() {
243
        cgtAssert(_initialized, "Tried to run uninitialized CampVisApplication.");
244
245

        // disconnect OpenGL context from this thread so that the other threads can acquire an OpenGL context.
246
        //cgt::GlContextManager::getRef().releaseCurrentContext();
247

248
249
        _mainWindow->show();

250
251
252
253
254
255
        // Start QApplication
        int toReturn = QApplication::exec();

        return toReturn;
    }

256
    void CampVisApplication::addPipeline(const std::string& name, AbstractPipeline* pipeline) {
257
        cgtAssert(pipeline != 0, "Pipeline must not be 0.");
258

259
        // create canvas and painter for the pipeline and connect all together
260
        cgt::QtThreadedCanvas* canvas = new cgt::QtThreadedCanvas("CAMPVis", cgt::ivec2(512, 512));
261
262
        canvas->init();

263
        CampVisPainter* painter = new CampVisPainter(canvas, pipeline);
264
        canvas->setPainter(painter, false);
265
        pipeline->setCanvas(canvas);
266
        painter->setErrorTexture(_errorTexture);
267

268
        PipelineRecord pr = { pipeline, painter };
269
        _pipelines.push_back(pr);
270

Jakob Weiss's avatar
Jakob Weiss committed
271
        _pipelineWindows[pipeline] = _mainWindow->addVisualizationPipelineWidget(name, canvas);
272

273
        // initialize context (GLEW) and pipeline in OpenGL thread)
274
        initGlContextAndPipeline(canvas, pipeline);
275

276
#ifdef CAMPVIS_HAS_SCRIPTING
277
278
        if (! _luaVmState->injectObjectPointerToTable(pipeline, "campvis::AutoEvaluationPipeline *", "pipelines", static_cast<int>(_pipelines.size())))
        //if (! _luaVmState->injectObjectPointerToTableField(pipeline, "campvis::AutoEvaluationPipeline *", "pipelines", name))
279
280
            LERROR("Could not inject the pipeline into the Lua VM.");

281
        _luaVmState->execString("inspect(pipelines)");
282
283
#endif

284
        GLCtxtMgr.releaseContext(canvas, false);
285
        s_PipelinesChanged.emitSignal();
286
        pipeline->start();
287
288
    }

289
290
    void CampVisApplication::initGlContextAndPipeline(cgt::GLCanvas* canvas, AbstractPipeline* pipeline) {
        cgt::GlContextManager::getRef().registerContextAndInitGlew(canvas, pipeline->getName());
291
292
293
294
295
296

        pipeline->init();
        LGL_ERROR;
        canvas->getPainter()->init();
        LGL_ERROR;

297
298
299
300
301
        // enable pipeline and invalidate all processors
        pipeline->setEnabled(true);
        for (std::vector<AbstractProcessor*>::const_iterator it = pipeline->getProcessors().begin(); it != pipeline->getProcessors().end(); ++it) {
            (*it)->invalidate(AbstractProcessor::INVALID_RESULT);
        }
302
303
    }

304
    void CampVisApplication::registerDockWidget(Qt::DockWidgetArea area, QDockWidget* dock) {
305
        cgtAssert(dock != 0, "Dock widget must not be 0.");
306
307
308
309

        _mainWindow->addDockWidget(area, dock);
    }

310
311
312
    DataContainer* CampVisApplication::createAndAddDataContainer(const std::string& name) {
        DataContainer* dc = new DataContainer(name);
        _dataContainers.push_back(dc);
313
        s_DataContainersChanged.emitSignal();
314
        return dc;
315
316
    }

317
318
    void CampVisApplication::rebuildAllShadersFromFiles() {
        // rebuilding all shaders has to be done from OpenGL context, use the local one.
319
        GLJobProc.enqueueJob(makeJobOnHeap(this, &CampVisApplication::triggerShaderRebuild));
320
321
322
323
324
325
326
    }

    void CampVisApplication::triggerShaderRebuild() {
        if (! ShdrMgr.rebuildAllShadersFromFile()) {
            LERROR("Could not rebuild all shaders from file.");
            return;
        }
327
328
329
        else {
            LINFO("Rebuilding shaders from file successful.");
        }
330

331
332
        for (std::vector<PipelineRecord>::iterator it = _pipelines.begin(); it != _pipelines.end(); ++it) {
            for (std::vector<AbstractProcessor*>::const_iterator pit = it->_pipeline->getProcessors().begin(); pit != it->_pipeline->getProcessors().end(); ++pit) {
333
334
335
336
337
338
339
                if (VisualizationProcessor* tester = dynamic_cast<VisualizationProcessor*>(*pit)) {
                	tester->invalidate(AbstractProcessor::INVALID_RESULT);
                }
            }
        }
    }

340
341
342
343
#ifdef CAMPVIS_HAS_SCRIPTING
    LuaVmState* CampVisApplication::getLuaVmState() {
        return _luaVmState;
    }
344

345
#endif
346

347
}