campvisapplication.cpp 13.6 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-2015, 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

38
#include "application/gui/properties/propertywidgetfactory.h"
39
#include "application/gui/mainwindow.h"
CAMP C++ Builder's avatar
CAMP C++ Builder committed
40
#include "application/gui/mdi/mdidockablewindow.h"
41

42
#include "core/init.h"
43
#include "core/tools/stringutils.h"
44
#include "core/tools/quadrenderer.h"
45
#include "core/pipeline/abstractpipeline.h"
46
#include "core/pipeline/abstractworkflow.h"
47
#include "core/pipeline/pipelinefactory.h"
48
#include "core/pipeline/pipelinepainter.h"
49
#include "core/pipeline/visualizationprocessor.h"
50
#include "core/datastructures/imagerepresentationconverter.h"
51
#include "core/pipeline/visualizationprocessor.h"
52

53
#include "tools/qtjobprocessor.h"
54

55
#include <QApplication>
56
#include <QThread>
57
#include <QStyleFactory>
58

59 60 61 62
#ifdef CAMPVIS_HAS_SCRIPTING
#include "scripting/glue/luavmstate.h"
#endif

schultezub's avatar
schultezub committed
63
namespace campvis {
64

65
    const std::string CampVisApplication::loggerCat_ = "CAMPVis.application.CampVisApplication";
66

67
    CampVisApplication::CampVisApplication(int& argc, char** argv) 
68 69
        : QApplication(argc, argv)
        , _localContext(0)
70
        , _mainWindow(0)
71
        , _errorTexture(nullptr)
72
        , _luaVmState(nullptr)
73 74 75 76 77 78
        , _initialized(false)
        , _argc(argc)
        , _argv(argv)
    {
    }

79
    CampVisApplication::~CampVisApplication() {
80
        cgtAssert(_initialized == false, "Destructing initialized CampVisApplication, deinitialize first!");
81 82
    }

83
    void CampVisApplication::init() {
84
        cgtAssert(_initialized == false, "Tried to initialize CampVisApplication twice.");
85

86 87
        QtJobProcessor::init();

88
        std::vector<std::string> searchPaths;
89 90
        if (_argc > 0) {
            // ugly hack
schultezub's avatar
schultezub committed
91
            std::string basePath(_argv[0]);
92 93
            searchPaths.push_back(cgt::FileSystem::parentDir(basePath));
            searchPaths.push_back(cgt::FileSystem::parentDir(cgt::FileSystem::parentDir(basePath)));
94
#ifdef CAMPVIS_SOURCE_DIR
95
            searchPaths.push_back(CAMPVIS_SOURCE_DIR);
schultezub's avatar
schultezub committed
96
#endif
97 98
        }

99
        _localContext = new cgt::QtThreadedCanvas("", cgt::ivec2(16, 16));
100
        campvis::init(_localContext, searchPaths);
101

102
        _mainWindow = new MainWindow(this);
103
        GLJobProc.enqueueJobBlocking([&]() {
104
            _mainWindow->init();
105

106 107 108
            // load textureData from file
            cgt::TextureReaderTga trt;
            _errorTexture = trt.loadTexture(ShdrMgr.completePath("application/data/no_input.tga"), cgt::Texture::LINEAR);
109 110

#ifdef CAMPVIS_HAS_SCRIPTING
111 112 113 114 115 116 117 118 119 120 121
            // create and store Lua VM for this very pipeline
            _luaVmState = new LuaVmState();
            _luaVmState->redirectLuaPrint();

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

            // Load CAMPVis' core Lua module to have SWIG glue for AutoEvaluationPipeline available
122 123
            if (! _luaVmState->execString("require(\"cgt\")"))
                LERROR("Error setting up Lua VM.");
124 125
            if (! _luaVmState->execString("require(\"campvis\")"))
                LERROR("Error setting up Lua VM.");
126
            if (! _luaVmState->execString("require(\"application\")"))
127 128 129 130 131 132 133
                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.");
134 135 136

            if (! _luaVmState->injectGlobalObjectPointer(this, "campvis::CampVisApplication *", "application"))
                LERROR("Could not inject the pipeline into the Lua VM.");
137
#endif
138
        });
139

140 141 142
        // parse argument list and create pipelines
        QStringList pipelinesToAdd = this->arguments();
        for (int i = 1; i < pipelinesToAdd.size(); ++i) {
143 144 145 146 147 148 149 150 151 152 153
            if (pipelinesToAdd[i] == "-w" && i+1 < pipelinesToAdd.size()) {
                // create workflow
                AbstractWorkflow* w = PipelineFactory::getRef().createWorkflow(pipelinesToAdd[i+1].toStdString());

                if (w != nullptr) {
                    // get DataContainers and Pipelines from workflow, take ownership and initialize them where necessary
                    _dataContainers.push_back(w->getDataContainer());
                    s_DataContainersChanged.emitSignal();

                    std::vector<AbstractPipeline*> pipelines = w->getPipelines();
                    for (auto it = pipelines.begin(); it != pipelines.end(); ++it) {
154
                        addPipeline(*it);
155 156 157 158 159 160 161 162 163
                    }

                    _workflows.push_back(w);
                    _mainWindow->setWorkflow(w);
                    w->init();
                }

                ++i;
            }
164 165 166 167
            else if (pipelinesToAdd[i] == "-k") {
                // set kiosk mode
                _mainWindow->enableKioskMode();
            }
168 169
            else {
                DataContainer* dc = createAndAddDataContainer("DataContainer #" + StringUtils::toString(_dataContainers.size() + 1));
170
                AbstractPipeline* p = PipelineFactory::getRef().createPipeline(pipelinesToAdd[i].toStdString(), *dc);
171
                if (p != nullptr)
172
                    addPipeline(p);
173
            }
174
        }
175

Jakob Weiss's avatar
Jakob Weiss committed
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
        // Set Qt color palette to dark - adapted from https://gist.github.com/QuantumCD/6245215
        QApplication::setStyle(QStyleFactory::create("Fusion"));
        QPalette darkPalette;
        darkPalette.setColor(QPalette::Window, QColor(53, 53, 53));
        darkPalette.setColor(QPalette::WindowText, Qt::white);
        darkPalette.setColor(QPalette::Base, QColor(25, 25, 25));
        darkPalette.setColor(QPalette::AlternateBase, QColor(53, 53, 53));
        darkPalette.setColor(QPalette::ToolTipBase, Qt::white);
        darkPalette.setColor(QPalette::ToolTipText, Qt::white);
        darkPalette.setColor(QPalette::Text, Qt::white);
        darkPalette.setColor(QPalette::Button, QColor(53, 53, 53));
        darkPalette.setColor(QPalette::ButtonText, Qt::white);
        darkPalette.setColor(QPalette::BrightText, Qt::red);
        darkPalette.setColor(QPalette::Link, QColor(42, 130, 218));
        darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218));
        darkPalette.setColor(QPalette::HighlightedText, Qt::black);

        setPalette(darkPalette);
        setStyleSheet("QMainWindow * {font: 12pt;} QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
195 196


197 198 199
        _initialized = true;
    }

200
    void CampVisApplication::deinit() {
201
        cgtAssert(_initialized, "Tried to deinitialize uninitialized CampVisApplication.");
202

203
        // Stop all pipeline threads.
204 205
        for (auto it = _pipelines.begin(); it != _pipelines.end(); ++it) {
            (*it)->stop();
206
        }
207

208 209 210
        for (auto it = _workflows.begin(); it != _workflows.end(); ++it)
            (*it)->deinit();

211
        GLJobProc.enqueueJobBlocking([&]() {
212 213
            delete _errorTexture;

214
            // Deinit pipeline and painter first
215 216
            for (auto it = _pipelines.begin(); it != _pipelines.end(); ++it) {
                (*it)->deinit();
217 218
            }

219
            _mainWindow->deinit();
220 221 222
        });

        delete _mainWindow;
223

224
        // now delete everything in the right order:
225 226
        for (auto it = _pipelines.begin(); it != _pipelines.end(); ++it) {
            delete *it;
227
        }
228
        for (auto it = _dataContainers.begin(); it != _dataContainers.end(); ++it) {
229 230 231
            delete *it;
        }

232
        campvis::deinit();
233
        PropertyWidgetFactory::deinit();
234
        QtJobProcessor::deinit();
235

236 237 238
        _initialized = false;
    }

239
    int CampVisApplication::run() {
240
        cgtAssert(_initialized, "Tried to run uninitialized CampVisApplication.");
241 242

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

245 246
        _mainWindow->show();

247 248 249 250 251 252
        // Start QApplication
        int toReturn = QApplication::exec();

        return toReturn;
    }

253

254
    void CampVisApplication::addPipeline(AbstractPipeline* pipeline) {
255
        cgtAssert(pipeline != 0, "Pipeline must not be 0.");
256

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

261
        pipeline->setCanvas(canvas);
262
        pipeline->getPipelinePainter()->setErrorTexture(_errorTexture);
263

264
        _pipelines.push_back(pipeline);
265
        _pipelineWindows[pipeline] = _mainWindow->addVisualizationPipelineWidget(pipeline->getName(), canvas);
266

267
        // initialize context (GLEW) and pipeline in OpenGL thread)
268
        initGlContextAndPipeline(canvas, pipeline);
269

270
#ifdef CAMPVIS_HAS_SCRIPTING
271
        if (! _luaVmState->injectObjectPointerToTable(pipeline, "campvis::AutoEvaluationPipeline *", "pipelines", static_cast<int>(_pipelines.size())))
272 273
            LERROR("Could not inject the pipeline into the Lua VM.");

Hossain Mahmud's avatar
stuck!  
Hossain Mahmud committed
274 275
        if (! _luaVmState->injectObjectPointerToTableField(pipeline, "campvis::AutoEvaluationPipeline *", "pipelines", pipeline->getName()))
            LERROR("Could not inject the pipeline into the Lua VM.");
276 277
#endif

278
        GLCtxtMgr.releaseContext(canvas, false);
279

280
        s_PipelinesChanged.emitSignal();
281 282

        startOpenGlThreadAndMoveQtThreadAffinity(pipeline, canvas);
283 284
    }

285 286
    void CampVisApplication::initGlContextAndPipeline(cgt::GLCanvas* canvas, AbstractPipeline* pipeline) {
        cgt::GlContextManager::getRef().registerContextAndInitGlew(canvas, pipeline->getName());
287 288 289 290

        pipeline->init();
        LGL_ERROR;

291 292 293 294 295
        // 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);
        }
296 297
    }

298
    void CampVisApplication::registerDockWidget(Qt::DockWidgetArea area, QDockWidget* dock) {
299
        cgtAssert(dock != 0, "Dock widget must not be 0.");
300 301 302 303

        _mainWindow->addDockWidget(area, dock);
    }

304 305 306
    DataContainer* CampVisApplication::createAndAddDataContainer(const std::string& name) {
        DataContainer* dc = new DataContainer(name);
        _dataContainers.push_back(dc);
307
        s_DataContainersChanged.emitSignal();
308
        return dc;
309 310
    }

311 312
    void CampVisApplication::rebuildAllShadersFromFiles() {
        // rebuilding all shaders has to be done from OpenGL context, use the local one.
313
        GLJobProc.enqueueJob(cgt::makeJobOnHeap(this, &CampVisApplication::triggerShaderRebuild));
314 315 316 317 318 319 320
    }

    void CampVisApplication::triggerShaderRebuild() {
        if (! ShdrMgr.rebuildAllShadersFromFile()) {
            LERROR("Could not rebuild all shaders from file.");
            return;
        }
321 322 323
        else {
            LINFO("Rebuilding shaders from file successful.");
        }
324

325 326
        for (auto it = _pipelines.begin(); it != _pipelines.end(); ++it) {
            for (auto pit = (*it)->getProcessors().cbegin(); pit != (*it)->getProcessors().cend(); ++pit) {
327
                if (VisualizationProcessor* tester = dynamic_cast<VisualizationProcessor*>(*pit)) {
328
                    tester->invalidate(AbstractProcessor::INVALID_RESULT);
329 330 331 332 333
                }
            }
        }
    }

334 335 336 337 338
#ifdef CAMPVIS_HAS_SCRIPTING
    LuaVmState* CampVisApplication::getLuaVmState() {
        return _luaVmState;
    }
#endif
339

340 341 342 343 344 345 346
    void CampVisApplication::setPipelineVisibility(AbstractPipeline* pipeline, bool visibility) {
        auto it = _pipelineWindows.find(pipeline);
        if (it != _pipelineWindows.end()) {
            it->second->setVisible(visibility);
        }
    }

347
}
348