volumeexplorer.cpp 13.9 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-2013, 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 Universität München
//      Boltzmannstr. 3, 85748 Garching b. München, 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
26
27
28
29
// 
// ================================================================================================

#include "volumeexplorer.h"
#include "tgt/logmanager.h"
#include "tgt/shadermanager.h"
#include "tgt/textureunit.h"

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
39
40

namespace campvis {
    const std::string VolumeExplorer::loggerCat_ = "CAMPVis.modules.vis.VolumeExplorer";

41
    VolumeExplorer::VolumeExplorer(IVec2Property* viewportSizeProp, RaycastingProcessor* raycaster)
42
        : VisualizationProcessor(viewportSizeProp)
schultezub's avatar
schultezub committed
43
        , p_inputVolume("InputVolume", "Input Volume", "", DataNameProperty::READ, AbstractProcessor::INVALID_PROPERTIES)
schultezub's avatar
schultezub committed
44
        , p_outputImage("OutputImage", "Output Image", "ve.output", DataNameProperty::WRITE)
45
46
        , p_seProperties("SliceExtractorProperties", "Slice Extractor Properties", AbstractProcessor::VALID)
        , p_vrProperties("VolumeRendererProperties", "Volume Renderer Properties", AbstractProcessor::VALID)
47
        , _raycaster(viewportSizeProp, raycaster)
48
        , _sliceExtractor(viewportSizeProp)
49
50
        , p_sliceRenderSize("SliceRenderSize", "Slice Render Size", tgt::ivec2(32), tgt::ivec2(0), tgt::ivec2(10000), tgt::ivec2(1), AbstractProcessor::VALID)
        , p_volumeRenderSize("VolumeRenderSize", "Volume Render Size", tgt::ivec2(32), tgt::ivec2(0), tgt::ivec2(10000), tgt::ivec2(1), AbstractProcessor::VALID)
51
52
53
        , _xSliceHandler(&_sliceExtractor.p_xSliceNumber)
        , _ySliceHandler(&_sliceExtractor.p_ySliceNumber)
        , _zSliceHandler(&_sliceExtractor.p_zSliceNumber)
54
55
        , _windowingHandler(&_sliceExtractor.p_transferFunction)
        , _trackballEH(0)
56
        , _mousePressed(false)
schultezub's avatar
schultezub committed
57
58
59
60
    {
        addProperty(&p_inputVolume);
        addProperty(&p_outputImage);

61
62
63
        addDecorator(new ProcessorDecoratorBackground());
        decoratePropertyCollection(this);
        
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
        p_seProperties.addPropertyCollection(_sliceExtractor);
        _sliceExtractor.p_lqMode.setVisible(false);
        _sliceExtractor.p_sourceImageID.setVisible(false);
        _sliceExtractor.p_targetImageID.setVisible(false);
        _sliceExtractor.p_sliceOrientation.setVisible(false);
        _sliceExtractor.p_xSliceColor.setVisible(false);
        _sliceExtractor.p_ySliceColor.setVisible(false);
        _sliceExtractor.p_zSliceColor.setVisible(false);
        addProperty(&p_seProperties);

        p_vrProperties.addPropertyCollection(_raycaster);
        _raycaster.p_lqMode.setVisible(false);
        _raycaster.p_inputVolume.setVisible(false);
        _raycaster.p_outputImage.setVisible(false);
        addProperty(&p_vrProperties);

80
81
        addProperty(&_sliceExtractor.p_transferFunction);
        addProperty(_raycaster.getProperty("TransferFunction"));
schultezub's avatar
schultezub committed
82

schultezub's avatar
schultezub committed
83
84
        p_inputVolume.addSharedProperty(&_raycaster.p_inputVolume);
        p_inputVolume.addSharedProperty(&_sliceExtractor.p_sourceImageID);
schultezub's avatar
schultezub committed
85

86
87
        _sliceExtractor.setViewportSizeProperty(&p_sliceRenderSize);
        _raycaster.setViewportSizeProperty(&p_volumeRenderSize);
88
89
90
91
92
93

        addProperty(&p_sliceRenderSize);
        addProperty(&p_volumeRenderSize);


        // Event-Handlers
94
        _trackballEH = new TrackballNavigationEventListener(&_raycaster.p_camera, &p_volumeRenderSize);
95
        _trackballEH->addLqModeProcessor(&_raycaster);
schultezub's avatar
schultezub committed
96
97
98
    }

    VolumeExplorer::~VolumeExplorer() {
99
        delete _trackballEH;
schultezub's avatar
schultezub committed
100
101
102
103
104
105
    }

    void VolumeExplorer::init() {
        VisualizationProcessor::init();
        _raycaster.init();
        _sliceExtractor.init();
schultezub's avatar
schultezub committed
106

107
        _shader = ShdrMgr.load("core/glsl/passthrough.vert", "modules/vis/glsl/volumeexplorer.frag", "");
schultezub's avatar
schultezub committed
108
109
110
        _shader->setAttributeLocation(0, "in_Position");
        _shader->setAttributeLocation(1, "in_TexCoord");

111
        _sliceExtractor.s_invalidated.connect(this, &VolumeExplorer::onProcessorInvalidated);
schultezub's avatar
schultezub committed
112
113
        _raycaster.s_invalidated.connect(this, &VolumeExplorer::onProcessorInvalidated);

114
        _quad = GeometryDataFactory::createQuad(tgt::vec3(0.f), tgt::vec3(1.f), tgt::vec3(0.f), tgt::vec3(1.f));
schultezub's avatar
schultezub committed
115
116
117
118
119
120
    }

    void VolumeExplorer::deinit() {
        _raycaster.deinit();
        _sliceExtractor.deinit();
        VisualizationProcessor::deinit();
schultezub's avatar
schultezub committed
121
122
        ShdrMgr.dispose(_shader);
        delete _quad;
schultezub's avatar
schultezub committed
123
124
    }

125
    void VolumeExplorer::updateResult(DataContainer& data) {
schultezub's avatar
schultezub committed
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
        // launch sub-renderers if necessary
        if (getInvalidationLevel() & VR_INVALID) {
            _raycaster.process(data);
        }
        if (getInvalidationLevel() & SLICES_INVALID) {
            _sliceExtractor.p_sliceOrientation.selectById("x");
            _sliceExtractor.p_targetImageID.setValue(p_outputImage.getValue() + ".xSlice");
            _sliceExtractor.process(data);

            _sliceExtractor.p_sliceOrientation.selectById("y");
            _sliceExtractor.p_targetImageID.setValue(p_outputImage.getValue() + ".ySlice");
            _sliceExtractor.process(data);

            _sliceExtractor.p_sliceOrientation.selectById("z");
            _sliceExtractor.p_targetImageID.setValue(p_outputImage.getValue() + ".zSlice");
            _sliceExtractor.process(data);
        }

        // compose rendering
        composeFinalRendering(data);

        validate(INVALID_RESULT | VR_INVALID | SLICES_INVALID);
    }

    void VolumeExplorer::onPropertyChanged(const AbstractProperty* prop) {
151
152
153
        if (prop == _viewportSizeProperty) {
            p_sliceRenderSize.setValue(tgt::ivec2(_viewportSizeProperty->getValue().y / 3, _viewportSizeProperty->getValue().y / 3));
            p_volumeRenderSize.setValue(tgt::ivec2(_viewportSizeProperty->getValue().x - _viewportSizeProperty->getValue().y / 3, _viewportSizeProperty->getValue().y));
schultezub's avatar
schultezub committed
154
155
156
157
158
        }
        if (prop == &p_outputImage) {
            _raycaster.p_outputImage.setValue(p_outputImage.getValue() + ".raycaster");
        }
        if (prop == &p_inputVolume) {
159
            invalidate(VR_INVALID | SLICES_INVALID);
schultezub's avatar
schultezub committed
160
161
162
163
164
        }
        VisualizationProcessor::onPropertyChanged(prop);
    }

    void VolumeExplorer::composeFinalRendering(DataContainer& data) {
165
166
167
168
        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
169
170
171
172

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

173
        FramebufferActivationGuard fag(this);
174
175
176
        createAndAttachColorTexture();
        createAndAttachDepthTexture();

schultezub's avatar
schultezub committed
177
178
179
        tgt::TextureUnit colorUnit, depthUnit;
        _shader->activate();

180
        tgt::vec2 rts(_viewportSizeProperty->getValue());
181
182
        tgt::vec2 vrs(p_volumeRenderSize.getValue());
        tgt::vec2 srs(p_sliceRenderSize.getValue());
schultezub's avatar
schultezub committed
183
184
185
186
187

        _shader->setUniform("_projectionMatrix", tgt::mat4::createOrtho(0, rts.x, rts.y, 0, -1, 1));
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        if (vrImage != 0) {
188
189
190
            decorateRenderProlog(data, _shader);
            _shader->setUniform("_renderBackground", true);

schultezub's avatar
schultezub committed
191
            vrImage->bind(_shader, colorUnit, depthUnit);
192
            float ratio = static_cast<float>(vrs.x) / static_cast<float>(rts.x);
schultezub's avatar
schultezub committed
193
194
195
            _shader->setUniform("_modelMatrix", tgt::mat4::createScale(tgt::vec3(vrs.x, vrs.y, .5f)));
            _shader->setUniform("_viewMatrix", tgt::mat4::createTranslation(tgt::vec3(srs.x, 0.f, 0.f)));
            _quad->render(GL_POLYGON);
196
197
198

            _shader->setUniform("_renderBackground", false);
            decorateRenderEpilog(_shader);
schultezub's avatar
schultezub committed
199
        }
200
201
        if (zSliceImage != 0) {
            zSliceImage->bind(_shader, colorUnit, depthUnit);
schultezub's avatar
schultezub committed
202
203
204
205
206
207
208
209
210
211
            _shader->setUniform("_modelMatrix", tgt::mat4::createScale(tgt::vec3(srs.x, srs.y, .5f)));
            _shader->setUniform("_viewMatrix", tgt::mat4::createTranslation(tgt::vec3(0.f, 2.f * srs.y, 0.f)));
            _quad->render(GL_POLYGON);
        }
        if (ySliceImage != 0) {
            ySliceImage->bind(_shader, colorUnit, depthUnit);
            _shader->setUniform("_modelMatrix", tgt::mat4::createScale(tgt::vec3(srs.x, srs.y, .5f)));
            _shader->setUniform("_viewMatrix", tgt::mat4::createTranslation(tgt::vec3(0.f, srs.y, 0.f)));
            _quad->render(GL_POLYGON);
        }
212
213
        if (xSliceImage != 0) {
            xSliceImage->bind(_shader, colorUnit, depthUnit);
schultezub's avatar
schultezub committed
214
215
216
217
218
219
220
221
222
            _shader->setUniform("_modelMatrix", tgt::mat4::createScale(tgt::vec3(srs.x, srs.y, .5f)));
            _shader->setUniform("_viewMatrix", tgt::mat4::createTranslation(tgt::vec3(0.f, 0.f, 0.f)));
            _quad->render(GL_POLYGON);
        }

        _shader->deactivate();
        tgt::TextureUnit::setZeroUnit();
        LGL_ERROR;

223
        data.addData(p_outputImage.getValue(), new RenderData(_fbo));
schultezub's avatar
schultezub committed
224
225
226
    }

    void VolumeExplorer::onProcessorInvalidated(AbstractProcessor* processor) {
227
228
229
230
231
232
233
234
235
236
237
        // 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()) {
            if (processor == &_raycaster) {
                invalidate(VR_INVALID);
            }
            if (processor == &_sliceExtractor) {
                invalidate(SLICES_INVALID);
            }

            invalidate(AbstractProcessor::INVALID_RESULT);
schultezub's avatar
schultezub committed
238
239
240
        }
    }

241
    void VolumeExplorer::updateProperties(DataContainer& dc) {
242
        ScopedTypedData<ImageData> img(dc, p_inputVolume.getValue());
243
244
        _sliceExtractor.p_transferFunction.setImageHandle(img.getDataHandle());
        static_cast<TransferFunctionProperty*>(_raycaster.getProperty("TransferFunction"))->setImageHandle(img.getDataHandle());
245

246
247
        if (img != 0) {
            const tgt::svec3& imgSize = img->getSize();
248
            if (_sliceExtractor.p_xSliceNumber.getMaxValue() != static_cast<int>(imgSize.x) - 1){
249
250
                _sliceExtractor.p_xSliceNumber.setMaxValue(static_cast<int>(imgSize.x) - 1);
                _sliceExtractor.p_xSliceNumber.setValue(static_cast<int>(imgSize.x) / 2);
251
            }
252
            if (_sliceExtractor.p_ySliceNumber.getMaxValue() != static_cast<int>(imgSize.y) - 1){
253
254
                _sliceExtractor.p_ySliceNumber.setMaxValue(static_cast<int>(imgSize.y) - 1);
                _sliceExtractor.p_ySliceNumber.setValue(static_cast<int>(imgSize.y) / 2);
255
            }
256
            if (_sliceExtractor.p_zSliceNumber.getMaxValue() != static_cast<int>(imgSize.z) - 1){
257
258
                _sliceExtractor.p_zSliceNumber.setMaxValue(static_cast<int>(imgSize.z) - 1);
                _sliceExtractor.p_zSliceNumber.setValue(static_cast<int>(imgSize.z) / 2);
259
            }
260

261
262
            _trackballEH->reinitializeCamera(img);
        }
263
264

        validate(AbstractProcessor::INVALID_PROPERTIES);
265
266
    }

267
    void VolumeExplorer::onEvent(tgt::Event* e) {
268
        // forward the event to the correspsonding event listeners depending on the mouse position
269
270
271
272
        if (typeid(*e) == typeid(tgt::MouseEvent)) {
            tgt::MouseEvent* me = static_cast<tgt::MouseEvent*>(e);

            if (!_mousePressed && me->x() <= p_sliceRenderSize.getValue().x) {
273
                // cycle slices
274
275
                if (me->action() == tgt::MouseEvent::WHEEL) {
                    if (me->y() <= p_sliceRenderSize.getValue().y)
276
                        _xSliceHandler.onEvent(e);
277
                    else if (me->y() <= 2*p_sliceRenderSize.getValue().y)
278
                        _ySliceHandler.onEvent(e);
279
                    else
280
                        _zSliceHandler.onEvent(e);
281
                }
282
283

                // adjust slice TF windowing
284
                else {
285
                    _windowingHandler.onEvent(e);
286
287
288
                }
            }
            else {
289
                // raycasting trackball navigation
290
291
292
293
294
295
296
297
298
299
300
301
302
                if (me->action() == tgt::MouseEvent::PRESSED)
                    _mousePressed = true;
                else if (me->action() == tgt::MouseEvent::RELEASED)
                    _mousePressed = false;

                tgt::MouseEvent adjustedMe(
                    me->x() - p_sliceRenderSize.getValue().x,
                    me->y(),
                    me->action(),
                    me->modifiers(),
                    me->button(),
                    me->viewport() - tgt::ivec2(p_sliceRenderSize.getValue().x, 0)
                    );
303
                _trackballEH->onEvent(&adjustedMe);
304
305
            }
        }
schultezub's avatar
schultezub committed
306
307
308
309
    }

}