volumeexplorer.cpp 23.8 KB
Newer Older
schultezub's avatar
schultezub committed
1
2
3
4
// ================================================================================================
// 
// This file is part of the CAMPVis Software Framework.
// 
5
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
schultezub's avatar
schultezub committed
6
7
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
//      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
12
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
// 
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
schultezub's avatar
schultezub committed
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.
schultezub's avatar
schultezub committed
22
23
24
25
// 
// ================================================================================================

#include "volumeexplorer.h"
26
27
28
#include "cgt/logmanager.h"
#include "cgt/shadermanager.h"
#include "cgt/textureunit.h"
schultezub's avatar
schultezub committed
29

schultezub's avatar
schultezub committed
30
#include "core/datastructures/facegeometry.h"
31
#include "core/datastructures/geometrydatafactory.h"
32
#include "core/datastructures/renderdata.h"
schultezub's avatar
schultezub committed
33
34

#include "core/classification/simpletransferfunction.h"
35
#include "core/pipeline/processordecoratorbackground.h"
schultezub's avatar
schultezub committed
36
#include "core/tools/quadrenderer.h"
schultezub's avatar
schultezub committed
37
38

namespace campvis {
39
40
41
42
43
44
45
    static const GenericOption<VolumeExplorer::Views> largeViewOptions[4] = {
        GenericOption<VolumeExplorer::Views>("z", "XY Plane", VolumeExplorer::XY_PLANE),
        GenericOption<VolumeExplorer::Views>("y", "XZ Plane", VolumeExplorer::XZ_PLANE),
        GenericOption<VolumeExplorer::Views>("x", "YZ Plane", VolumeExplorer::YZ_PLANE),
        GenericOption<VolumeExplorer::Views>("volume", "Volume", VolumeExplorer::VOLUME)
    };

schultezub's avatar
schultezub committed
46
47
    const std::string VolumeExplorer::loggerCat_ = "CAMPVis.modules.vis.VolumeExplorer";

48
    VolumeExplorer::VolumeExplorer(IVec2Property* viewportSizeProp, SliceRenderProcessor* sliceRenderer, RaycastingProcessor* raycaster)
49
        : VisualizationProcessor(viewportSizeProp)
50
        , p_inputVolume("InputVolume", "Input Volume", "", DataNameProperty::READ)
schultezub's avatar
schultezub committed
51
        , p_outputImage("OutputImage", "Output Image", "ve.output", DataNameProperty::WRITE)
52
        , p_largeView("LargeView", "Large View Selection", largeViewOptions, 4)
53
        , p_enableScribbling("EnableScribbling", "Enable Scribbling in Slice Views", false)
54
55
        , p_seProperties("SliceExtractorProperties", "Slice Extractor Properties")
        , p_vrProperties("VolumeRendererProperties", "Volume Renderer Properties")
56
57
        , _shader(nullptr)
        , _quad(nullptr)
58
        , _tcp(viewportSizeProp)
59
        , _raycaster(viewportSizeProp, raycaster)
60
        , _sliceRenderer(sliceRenderer)
61
62
        , p_smallRenderSize("SmallRenderSize", "Small Render Size", cgt::ivec2(32), cgt::ivec2(0), cgt::ivec2(10000), cgt::ivec2(1))
        , p_largeRenderSize("LargeRenderSize", "Large Render Size", cgt::ivec2(32), cgt::ivec2(0), cgt::ivec2(10000), cgt::ivec2(1))
63
64
65
66
        , _xSliceHandler(&_sliceRenderer->p_xSliceNumber)
        , _ySliceHandler(&_sliceRenderer->p_ySliceNumber)
        , _zSliceHandler(&_sliceRenderer->p_zSliceNumber)
        , _windowingHandler(nullptr)
67
        , _mousePressedInRaycaster(false)
68
69
70
        , _viewUnderEvent(VOLUME)
        , _eventPositionOffset(0)
        , _eventViewportSize(0)
71
        , _scribblePointer(nullptr)
72
        , _cachedImageSize(0)
schultezub's avatar
schultezub committed
73
    {
74
75
        cgtAssert(raycaster != nullptr, "Raycasting Processor must not be 0.");
        cgtAssert(_sliceRenderer != nullptr, "Slice Rendering Processor must not be 0.");
76

77
78
        p_largeView.selectByOption(VOLUME);

79
        addProperty(p_inputVolume, INVALID_PROPERTIES | CAMERA_INVALID);
80
        addProperty(p_outputImage);
81
        addProperty(p_largeView, LARGE_VIEW_INVALID | CAMERA_INVALID | SLICES_INVALID | VR_INVALID | INVALID_RESULT);
82
        addProperty(p_enableScribbling, VALID);
schultezub's avatar
schultezub committed
83

84
85
86
        addDecorator(new ProcessorDecoratorBackground());
        decoratePropertyCollection(this);
        
87
88
89
90
91
92
93
94
        p_seProperties.addPropertyCollection(*_sliceRenderer);
        _sliceRenderer->p_lqMode.setVisible(false);
        _sliceRenderer->p_sourceImageID.setVisible(false);
        _sliceRenderer->p_targetImageID.setVisible(false);
        _sliceRenderer->p_sliceOrientation.setVisible(false);
        _sliceRenderer->p_xSliceColor.setVisible(false);
        _sliceRenderer->p_ySliceColor.setVisible(false);
        _sliceRenderer->p_zSliceColor.setVisible(false);
95
        addProperty(p_seProperties, VALID);
96
97
98
99
100

        p_vrProperties.addPropertyCollection(_raycaster);
        _raycaster.p_lqMode.setVisible(false);
        _raycaster.p_inputVolume.setVisible(false);
        _raycaster.p_outputImage.setVisible(false);
101
        addProperty(p_vrProperties, VALID);
schultezub's avatar
schultezub committed
102

103
        p_inputVolume.addSharedProperty(&_tcp.p_image);
schultezub's avatar
schultezub committed
104
        p_inputVolume.addSharedProperty(&_raycaster.p_inputVolume);
105
        p_inputVolume.addSharedProperty(&_sliceRenderer->p_sourceImageID);
schultezub's avatar
schultezub committed
106

Christian Schulte zu Berge's avatar
Christian Schulte zu Berge committed
107
108
        _tcp.p_cameraId.addSharedProperty(&_raycaster.p_camera);

109
        _tcp.setViewportSizeProperty(&p_largeRenderSize);
110
111
        _sliceRenderer->setViewportSizeProperty(&p_smallRenderSize);
        _raycaster.setViewportSizeProperty(&p_largeRenderSize);
112

113
114
        addProperty(p_smallRenderSize, VALID);
        addProperty(p_largeRenderSize, VALID);
115
116

        // Event-Handlers
117
        _tcp.addLqModeProcessor(&_raycaster);
118
119
120
121

        if (TransferFunctionProperty* tester = dynamic_cast<TransferFunctionProperty*>(_sliceRenderer->getProperty("TransferFunction"))) {
        	_windowingHandler.setTransferFunctionProperty(tester);
        }
schultezub's avatar
schultezub committed
122
123
124
125
126
127
128
    }

    VolumeExplorer::~VolumeExplorer() {
    }

    void VolumeExplorer::init() {
        VisualizationProcessor::init();
129
        _tcp.init();
schultezub's avatar
schultezub committed
130
        _raycaster.init();
131
        _sliceRenderer->init();
schultezub's avatar
schultezub committed
132

133
        _shader = ShdrMgr.load("core/glsl/passthrough.vert", "modules/vis/glsl/volumeexplorer.frag", "");
schultezub's avatar
schultezub committed
134
135
136
        _shader->setAttributeLocation(0, "in_Position");
        _shader->setAttributeLocation(1, "in_TexCoord");

137
        _tcp.s_invalidated.connect(this, &VolumeExplorer::onProcessorInvalidated);
138
        _sliceRenderer->s_invalidated.connect(this, &VolumeExplorer::onProcessorInvalidated);
schultezub's avatar
schultezub committed
139
140
        _raycaster.s_invalidated.connect(this, &VolumeExplorer::onProcessorInvalidated);

141
        _quad = GeometryDataFactory::createQuad(cgt::vec3(0.f), cgt::vec3(1.f), cgt::vec3(0.f), cgt::vec3(1.f));
142
        
143
        // force recalculation of p_smallRenderSize and p_largeRenderSize
144
        onPropertyChanged(_viewportSizeProperty);
schultezub's avatar
schultezub committed
145
146
147
    }

    void VolumeExplorer::deinit() {
148
        _tcp.deinit();
schultezub's avatar
schultezub committed
149
        _raycaster.deinit();
150
        _sliceRenderer->deinit();
schultezub's avatar
schultezub committed
151
        VisualizationProcessor::deinit();
schultezub's avatar
schultezub committed
152
153
        ShdrMgr.dispose(_shader);
        delete _quad;
schultezub's avatar
schultezub committed
154
155
    }

156
    void VolumeExplorer::updateResult(DataContainer& data) {
schultezub's avatar
schultezub committed
157
        // launch sub-renderers if necessary
158
159
160
161
162
163
        if (getInvalidationLevel() & LARGE_VIEW_INVALID) {
            switch (p_largeView.getOptionValue()) {
                case XY_PLANE: // fallthrough
                case XZ_PLANE: // fallthrough
                case YZ_PLANE:
                    _raycaster.setViewportSizeProperty(&p_smallRenderSize);
164
                    _tcp.setViewportSizeProperty(&p_smallRenderSize);
165
166
167
                    break;
                case VOLUME:
                    _raycaster.setViewportSizeProperty(&p_largeRenderSize);
168
                    _tcp.setViewportSizeProperty(&p_largeRenderSize);
169
170
                    break;
            }
171
            validate(LARGE_VIEW_INVALID);
172
        }
173
        if (getInvalidationLevel() & SCRIBBLE_INVALID) {
174
175
            std::vector<cgt::vec3> vertices;
            std::vector<cgt::vec4> colors;
176
177

            for (size_t i = 0; i < _yesScribbles.size(); ++i) {
178
179
                vertices.push_back(cgt::vec3(_yesScribbles[i]));
                colors.push_back(cgt::vec4(.2f, .8f, 0.f, 1.f));
180
181
            }
            for (size_t i = 0; i < _noScribbles.size(); ++i) {
182
183
                vertices.push_back(cgt::vec3(_noScribbles[i]));
                colors.push_back(cgt::vec4(.85f, .2f, 0.f, 1.f));
184
185
            }

186
            FaceGeometry* g = new FaceGeometry(vertices, std::vector<cgt::vec3>(), colors);
187
188
189
190
191
192
193
            data.addData(p_outputImage.getValue() + ".scribbles", g);
            validate(SCRIBBLE_INVALID);

            // force update of slice renderer if necessary
            if (! (getInvalidationLevel() & VR_INVALID))
                invalidate(SLICES_INVALID);
        }
194
195
196
197
198
199

        if (getInvalidationLevel() & CAMERA_INVALID) {
            _tcp.process(data);
            _raycaster.process(data);
        }
        else if (getInvalidationLevel() & VR_INVALID) {
schultezub's avatar
schultezub committed
200
201
            _raycaster.process(data);
        }
202

schultezub's avatar
schultezub committed
203
        if (getInvalidationLevel() & SLICES_INVALID) {
204
205
            _sliceRenderer->setViewportSizeProperty(p_largeView.getOptionValue() == YZ_PLANE ? &p_largeRenderSize : &p_smallRenderSize);
            _sliceRenderer->p_sliceOrientation.selectByOption(SliceRenderProcessor::YZ_PLANE);
206
207
            _sliceRenderer->p_targetImageID.setValue(p_outputImage.getValue() + ".xSlice");
            _sliceRenderer->process(data);
schultezub's avatar
schultezub committed
208

209
210
            _sliceRenderer->setViewportSizeProperty(p_largeView.getOptionValue() == XZ_PLANE ? &p_largeRenderSize : &p_smallRenderSize);
            _sliceRenderer->p_sliceOrientation.selectByOption(SliceRenderProcessor::XZ_PLANE);
211
212
            _sliceRenderer->p_targetImageID.setValue(p_outputImage.getValue() + ".ySlice");
            _sliceRenderer->process(data);
schultezub's avatar
schultezub committed
213

214
215
            _sliceRenderer->setViewportSizeProperty(p_largeView.getOptionValue() == XY_PLANE ? &p_largeRenderSize : &p_smallRenderSize);
            _sliceRenderer->p_sliceOrientation.selectByOption(SliceRenderProcessor::XY_PLANE);
216
217
            _sliceRenderer->p_targetImageID.setValue(p_outputImage.getValue() + ".zSlice");
            _sliceRenderer->process(data);
schultezub's avatar
schultezub committed
218
219
220
221
222
        }

        // compose rendering
        composeFinalRendering(data);

223
        validate(INVALID_RESULT | CAMERA_INVALID | VR_INVALID | SLICES_INVALID);
schultezub's avatar
schultezub committed
224
225
226
    }

    void VolumeExplorer::onPropertyChanged(const AbstractProperty* prop) {
227
        if (prop == _viewportSizeProperty) {
228
229
            p_smallRenderSize.setValue(cgt::ivec2(_viewportSizeProperty->getValue().y / 3, _viewportSizeProperty->getValue().y / 3));
            p_largeRenderSize.setValue(cgt::ivec2(_viewportSizeProperty->getValue().x - _viewportSizeProperty->getValue().y / 3, _viewportSizeProperty->getValue().y));
schultezub's avatar
schultezub committed
230
231
        }
        if (prop == &p_outputImage) {
Christian Schulte zu Berge's avatar
Christian Schulte zu Berge committed
232
            _tcp.p_cameraId.setValue(p_outputImage.getValue() + ".camera");
schultezub's avatar
schultezub committed
233
            _raycaster.p_outputImage.setValue(p_outputImage.getValue() + ".raycaster");
234
            _sliceRenderer->p_geometryID.setValue(p_outputImage.getValue() + ".scribbles");
schultezub's avatar
schultezub committed
235
236
        }
        if (prop == &p_inputVolume) {
237
            invalidate(VR_INVALID | SLICES_INVALID);
schultezub's avatar
schultezub committed
238
        }
239
240
        if (prop == &p_enableScribbling) {
            if (p_enableScribbling.getValue() == true) {
241
242
                _sliceRenderer->s_scribblePainted.connect(this, &VolumeExplorer::onSliceExtractorScribblePainted);
                _sliceRenderer->p_geometryID.setValue(p_outputImage.getValue() + ".scribbles");
243
244
            }
            else {
245
246
                _sliceRenderer->s_scribblePainted.disconnect(this);
                _sliceRenderer->p_geometryID.setValue("");
247
248
249
            }
        }

schultezub's avatar
schultezub committed
250
251
252
253
        VisualizationProcessor::onPropertyChanged(prop);
    }

    void VolumeExplorer::composeFinalRendering(DataContainer& data) {
254
255
256
257
        ScopedTypedData<RenderData> vrImage(data, p_outputImage.getValue() + ".raycaster");
        ScopedTypedData<RenderData> xSliceImage(data, p_outputImage.getValue() + ".xSlice");
        ScopedTypedData<RenderData> ySliceImage(data, p_outputImage.getValue() + ".ySlice");
        ScopedTypedData<RenderData> zSliceImage(data, p_outputImage.getValue() + ".zSlice");
schultezub's avatar
schultezub committed
258
259
260
261

        if (vrImage == 0 && xSliceImage == 0 && ySliceImage == 0 && zSliceImage == 0)
            return;

262
        FramebufferActivationGuard fag(this);
263
264
265
        createAndAttachColorTexture();
        createAndAttachDepthTexture();

266
        cgt::TextureUnit colorUnit, depthUnit;
schultezub's avatar
schultezub committed
267
268
        _shader->activate();

269
270
271
        cgt::vec2 rts(_viewportSizeProperty->getValue());
        cgt::vec2 vrs(p_largeRenderSize.getValue());
        cgt::vec2 srs(p_smallRenderSize.getValue());
schultezub's avatar
schultezub committed
272

273
        _shader->setUniform("_projectionMatrix", cgt::mat4::createOrtho(0, rts.x, rts.y, 0, -1, 1));
schultezub's avatar
schultezub committed
274
275
276
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        if (vrImage != 0) {
277
278
279
            decorateRenderProlog(data, _shader);
            _shader->setUniform("_renderBackground", true);

schultezub's avatar
schultezub committed
280
            vrImage->bind(_shader, colorUnit, depthUnit);
281
282
            switch (p_largeView.getOptionValue()) {
                case XY_PLANE:
283
284
                    _shader->setUniform("_modelMatrix", cgt::mat4::createScale(cgt::vec3(srs.x, srs.y, .5f)));
                    _shader->setUniform("_viewMatrix", cgt::mat4::createTranslation(cgt::vec3(0.f, 2.f * srs.y, 0.f)));
285
286
                    break;
                case XZ_PLANE:
287
288
                    _shader->setUniform("_modelMatrix", cgt::mat4::createScale(cgt::vec3(srs.x, srs.y, .5f)));
                    _shader->setUniform("_viewMatrix", cgt::mat4::createTranslation(cgt::vec3(0.f, srs.y, 0.f)));
289
290
                    break;
                case YZ_PLANE:
291
292
                    _shader->setUniform("_modelMatrix", cgt::mat4::createScale(cgt::vec3(srs.x, srs.y, .5f)));
                    _shader->setUniform("_viewMatrix", cgt::mat4::createTranslation(cgt::vec3(0.f, 0.f, 0.f)));
293
294
                    break;
                case VOLUME:
295
296
                    _shader->setUniform("_modelMatrix", cgt::mat4::createScale(cgt::vec3(vrs.x, vrs.y, .5f)));
                    _shader->setUniform("_viewMatrix", cgt::mat4::createTranslation(cgt::vec3(srs.x, 0.f, 0.f)));
297
298
                    break;
            }
299
            _quad->render(GL_TRIANGLE_FAN);
300
301
302

            _shader->setUniform("_renderBackground", false);
            decorateRenderEpilog(_shader);
schultezub's avatar
schultezub committed
303
        }
304
305
        if (zSliceImage != 0) {
            zSliceImage->bind(_shader, colorUnit, depthUnit);
306
            if (p_largeView.getOptionValue() == XY_PLANE) {
307
308
                _shader->setUniform("_modelMatrix", cgt::mat4::createScale(cgt::vec3(vrs.x, vrs.y, .5f)));
                _shader->setUniform("_viewMatrix", cgt::mat4::createTranslation(cgt::vec3(srs.x, 0.f, 0.f)));
309
310
            }
            else {
311
312
                _shader->setUniform("_modelMatrix", cgt::mat4::createScale(cgt::vec3(srs.x, srs.y, .5f)));
                _shader->setUniform("_viewMatrix", cgt::mat4::createTranslation(cgt::vec3(0.f, 2.f * srs.y, 0.f)));
313
            }
314
            _quad->render(GL_TRIANGLE_FAN);
schultezub's avatar
schultezub committed
315
316
317
        }
        if (ySliceImage != 0) {
            ySliceImage->bind(_shader, colorUnit, depthUnit);
318
            if (p_largeView.getOptionValue() == XZ_PLANE) {
319
320
                _shader->setUniform("_modelMatrix", cgt::mat4::createScale(cgt::vec3(vrs.x, vrs.y, .5f)));
                _shader->setUniform("_viewMatrix", cgt::mat4::createTranslation(cgt::vec3(srs.x, 0.f, 0.f)));
321
322
            }
            else {
323
324
                _shader->setUniform("_modelMatrix", cgt::mat4::createScale(cgt::vec3(srs.x, srs.y, .5f)));
                _shader->setUniform("_viewMatrix", cgt::mat4::createTranslation(cgt::vec3(0.f, srs.y, 0.f)));
325
            }
326
            _quad->render(GL_TRIANGLE_FAN);
schultezub's avatar
schultezub committed
327
        }
328
329
        if (xSliceImage != 0) {
            xSliceImage->bind(_shader, colorUnit, depthUnit);
330
            if (p_largeView.getOptionValue() == YZ_PLANE) {
331
332
                _shader->setUniform("_modelMatrix", cgt::mat4::createScale(cgt::vec3(vrs.x, vrs.y, .5f)));
                _shader->setUniform("_viewMatrix", cgt::mat4::createTranslation(cgt::vec3(srs.x, 0.f, 0.f)));
333
334
            }
            else {
335
336
                _shader->setUniform("_modelMatrix", cgt::mat4::createScale(cgt::vec3(srs.x, srs.y, .5f)));
                _shader->setUniform("_viewMatrix", cgt::mat4::createTranslation(cgt::vec3(0.f, 0.f, 0.f)));
337
            }
338
            _quad->render(GL_TRIANGLE_FAN);
schultezub's avatar
schultezub committed
339
340
341
        }

        _shader->deactivate();
342
        cgt::TextureUnit::setZeroUnit();
schultezub's avatar
schultezub committed
343
344
        LGL_ERROR;

345
        data.addData(p_outputImage.getValue(), new RenderData(_fbo));
schultezub's avatar
schultezub committed
346
347
348
    }

    void VolumeExplorer::onProcessorInvalidated(AbstractProcessor* processor) {
349
350
351
        // make sure to only invalidate ourself if the invalidation is not triggered by us
        // => the _locked state is a trustworthy source for this information :)
        if (! isLocked()) {
352
353
354
            if (processor == &_tcp) {
                invalidate(CAMERA_INVALID);
            }
355
356
357
            if (processor == &_raycaster) {
                invalidate(VR_INVALID);
            }
358
            if (processor == _sliceRenderer) {
359
360
361
362
                invalidate(SLICES_INVALID);
            }

            invalidate(AbstractProcessor::INVALID_RESULT);
schultezub's avatar
schultezub committed
363
364
365
        }
    }

366
    void VolumeExplorer::updateProperties(DataContainer& dc) {
367
        ScopedTypedData<ImageData> img(dc, p_inputVolume.getValue());
368
        static_cast<TransferFunctionProperty*>(_raycaster.getNestedProperty("RaycasterProps::TransferFunction"))->setImageHandle(img.getDataHandle());
369

370
        if (img != 0 && _cachedImageSize != cgt::ivec3(img->getSize())) {
371
372
373
374
            _cachedImageSize = img->getSize();
            if (_sliceRenderer->p_xSliceNumber.getMaxValue() != _cachedImageSize.x - 1){
                _sliceRenderer->p_xSliceNumber.setMaxValue(_cachedImageSize.x - 1);
                _sliceRenderer->p_xSliceNumber.setValue(_cachedImageSize.x / 2);
375
            }
376
377
378
            if (_sliceRenderer->p_ySliceNumber.getMaxValue() != _cachedImageSize.y - 1){
                _sliceRenderer->p_ySliceNumber.setMaxValue(_cachedImageSize.y - 1);
                _sliceRenderer->p_ySliceNumber.setValue(_cachedImageSize.y / 2);
379
            }
380
381
382
            if (_sliceRenderer->p_zSliceNumber.getMaxValue() != _cachedImageSize.z - 1){
                _sliceRenderer->p_zSliceNumber.setMaxValue(_cachedImageSize.z - 1);
                _sliceRenderer->p_zSliceNumber.setValue(_cachedImageSize.z / 2);
383
384
            }
        }
385
386
    }

387
    void VolumeExplorer::onEvent(cgt::Event* e) {
Hossain Mahmud's avatar
Hossain Mahmud committed
388
        // forward the event to the corresponding event listeners depending on the mouse position
389
390
        if (typeid(*e) == typeid(cgt::MouseEvent)) {
            cgt::MouseEvent* me = static_cast<cgt::MouseEvent*>(e);
391

392
393
            // if the mouse was pressed, we need to cache the view parameters of the view underneath
            // the pointer, so that we can adjust the MouseEvents to the corresponding subviews.
394
            if (me->action() == cgt::MouseEvent::PRESSED || (!_mousePressedInRaycaster && me->action() == cgt::MouseEvent::WHEEL)) {
395
396
                if (me->x() <= p_smallRenderSize.getValue().x) {
                    if (me->y() <= p_smallRenderSize.getValue().y) {
397
                        _eventPositionOffset = cgt::ivec2(0, 0);
398
399
                        _eventViewportSize = p_smallRenderSize.getValue();
                        _viewUnderEvent = (p_largeView.getOptionValue() == XY_PLANE) ? VOLUME : XY_PLANE;
400
                    }
401
                    else if (me->y() <= 2*p_smallRenderSize.getValue().y) {
402
                        _eventPositionOffset = cgt::ivec2(0, -p_smallRenderSize.getValue().y);
403
404
                        _eventViewportSize = p_smallRenderSize.getValue();
                        _viewUnderEvent = (p_largeView.getOptionValue() == XZ_PLANE) ? VOLUME : XZ_PLANE;
405
406
                    }
                    else {
407
                        _eventPositionOffset = cgt::ivec2(0, -2 * p_smallRenderSize.getValue().y);
408
409
                        _eventViewportSize = p_smallRenderSize.getValue();
                        _viewUnderEvent = (p_largeView.getOptionValue() == YZ_PLANE) ? VOLUME : YZ_PLANE;
410
411
                    }
                }
412
                else {
413
                    _eventPositionOffset = cgt::ivec2(- p_smallRenderSize.getValue().x, 0);
414
415
                    _eventViewportSize = p_largeRenderSize.getValue();
                    _viewUnderEvent = p_largeView.getOptionValue();
416
417
                }
            }
418
419

            // create a new MouseEvent for the corresponding subview
420
            cgt::MouseEvent adjustedMe(me->x() + _eventPositionOffset.x, me->y() + _eventPositionOffset.y,
421
422
423
424
                me->action(), me->modifiers(), me->button(),
                _eventViewportSize);

            // now divert the new MouseEvent to the corresponding handler
425
            if (me->action() == cgt::MouseEvent::DOUBLECLICK) {
426
427
428
                p_largeView.selectByOption(_viewUnderEvent);
            }
            else if (_mousePressedInRaycaster || _viewUnderEvent == VOLUME) {
429
                // raycasting trackball navigation
430
                if (me->action() == cgt::MouseEvent::PRESSED)
431
                    _mousePressedInRaycaster = true;
432
                else if (me->action() == cgt::MouseEvent::RELEASED)
433
                    _mousePressedInRaycaster = false;
434
                _tcp.onEvent(&adjustedMe);
435
            }
436
            else if (me->action() == cgt::MouseEvent::WHEEL) {
437
438
439
440
441
442
443
444
445
446
447
                // Mouse wheel has changed -> cycle slices
                if (_viewUnderEvent == XY_PLANE) {
                    _zSliceHandler.onEvent(e);
                }
                else if (_viewUnderEvent == XZ_PLANE) {
                    _ySliceHandler.onEvent(e);
                }
                else {
                    _xSliceHandler.onEvent(e);
                }
            }
448
            else if (p_enableScribbling.getValue() && (me->modifiers() & cgt::Event::CTRL || me->modifiers() & cgt::Event::ALT)) {
449
                // CTRL pressed -> forward to SliceExtractor's scribbling
450
451
452
                if (me->action() == cgt::MouseEvent::PRESSED) {
                    _scribblePointer = (me->modifiers() & cgt::Event::CTRL) ? &_yesScribbles : &_noScribbles;
                    if (! (me->modifiers() & cgt::Event::SHIFT))
453
454
                        _scribblePointer->clear();
                }
455
                else if (_scribblePointer != nullptr && me->action() == cgt::MouseEvent::RELEASED) {
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
                    _scribblePointer = nullptr;
                }

                // lock this processor, so that the slice orientation's setting does not change
                AbstractProcessor::ScopedLock lock(this);

                if (_viewUnderEvent == XY_PLANE) {
                    _sliceRenderer->p_sliceOrientation.selectByOption(SliceExtractor::XY_PLANE);
                }
                else if (_viewUnderEvent == XZ_PLANE) {
                    _sliceRenderer->p_sliceOrientation.selectByOption(SliceExtractor::XZ_PLANE);
                }
                else {
                    _sliceRenderer->p_sliceOrientation.selectByOption(SliceExtractor::YZ_PLANE);
                }
                _sliceRenderer->onEvent(&adjustedMe);
            }
            else {
                // adjust slice TF windowing
                _windowingHandler.onEvent(&adjustedMe);
            }
477
        }
schultezub's avatar
schultezub committed
478
479
    }

480
    void VolumeExplorer::onSliceExtractorScribblePainted(cgt::vec3 voxel) {
481
482
483
484
485
        if (_scribblePointer != nullptr) {
            _scribblePointer->push_back(voxel);
            invalidate(INVALID_RESULT | SCRIBBLE_INVALID);
        }
    }
schultezub's avatar
schultezub committed
486

487
488
489
490
491
492
493
494
    VolumeRenderer* VolumeExplorer::getVolumeRenderer() {
        return &_raycaster;
    }

    SliceRenderProcessor* VolumeExplorer::getSliceRenderer() {
        return _sliceRenderer;
    }

495
}