genericgeometrytransferfunction.h 10.8 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 25 26 27 28 29
// 
// ================================================================================================

#ifndef GENERICGEOMETRYTRANSFERFUNCTION_H__
#define GENERICGEOMETRYTRANSFERFUNCTION_H__

#include "core/classification/abstracttransferfunction.h"

30 31 32 33 34 35
#include "cgt/assert.h"
#include "cgt/framebufferobject.h"
#include "cgt/logmanager.h"
#include "cgt/shadermanager.h"
#include "cgt/texture.h"
#include "cgt/textureunit.h"
36 37 38

#include <vector>

schultezub's avatar
schultezub committed
39
namespace campvis {
40 41 42 43 44 45

    /**
     * Generic base class for transfer functions built from multiple geometries.
     * \tparam  T   Type of the base geometry class.
     */
    template<class T>
46
    class GenericGeometryTransferFunction : public AbstractTransferFunction, public sigslot::has_slots {
47 48 49 50 51 52 53 54 55
    public:
        /// Typedef for the geometry class this transfer function is built from.
        typedef T GeometryType;

        /**
         * Creates a new GenericGeometryTransferFunction.
         * \param   size            Size of the transfer function texture
         * \param   intensityDomain Intensity Domain where the transfer function is mapped to during classification
         */
56
        GenericGeometryTransferFunction(const cgt::vec3& size, const cgt::vec2& intensityDomain = cgt::vec2(0.f, 1.f));
57 58 59 60 61

        /**
         * Destructor, make sure to delete the OpenGL texture beforehand by calling deinit() with a valid OpenGL context!
         */
        virtual ~GenericGeometryTransferFunction();
62 63 64 65 66 67 68

        /**
         * Returns the intensity domain where this TF has it's non-transparent parts.
         * I.e. the minimum and the maximum intensity being opaque.
         * \return  cgt::vec2(0.f, 1.f)
         */
        virtual cgt::vec2 getVisibilityDomain() const;
69 70 71 72 73
        
        /**
         * Initializes the Shader, hence, this methods has to be called from a thread with a valid OpenGL context!
         */
        virtual void initShader();
74 75

        /**
76
         * Deletes the OpenGL texture and shader, hence, this methods has to be called from a thread with a valid OpenGL context!
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
         */
        virtual void deinit();

        /**
         * Gets the list of transfer function geometries.
         * \return  _geometries
         */
        const std::vector<T*>& getGeometries() const;

        /**
         * Adds the given TF geometry to this transfer function.
         * \note    GenericGeometryTransferFunction takes ownership \a geometry.
         * \param   geometry    TF geometry to add, GenericGeometryTransferFunction takes the ownership.
         */
        void addGeometry(T* geometry);

        /**
         * Removes the given TF geometry from this transfer function.
         * \note    After the call \a geometry will no longer be valid as GenericGeometryTransferFunction deletes the given T.
         * \param   geometry    TF geometry to remove, GenericGeometryTransferFunction will delete it
         */
        void removeGeometry(T* geometry);

        /**
         * Slot to be called by T's s_changed signal.
         */
        void onGeometryChanged();

        /// Signal to be emitted when the vector of T objects (_geometries) changed (The collection, not the actual geometry).
106
        sigslot::signal0 s_geometryCollectionChanged;
107

108 109 110
        /// Signal to be emitted when this TF object is about to be deleted.
        sigslot::signal0 s_aboutToBeDeleted;

111 112 113 114 115 116 117 118
    protected:
        /**
         * Creates the texture and uploads it to OpenGL.
         * Gets called by bind() with the local mutex already acquired.
         */
        virtual void createTexture();

        std::vector<T*> _geometries;        ///< The list of transfer function geometries.
119 120
        cgt::FramebufferObject* _fbo;       ///< The FBO used for render into texture.
        cgt::Shader* _shader;               ///< Shader for rendering the TF into a texture
121 122 123 124 125
    };

// ================================================================================================

    template<class T>
126
    campvis::GenericGeometryTransferFunction<T>::GenericGeometryTransferFunction(const cgt::vec3& size, const cgt::vec2& intensityDomain /*= cgt::vec2(0.f, 1.f)*/)
127 128
        : AbstractTransferFunction(size, intensityDomain)
        , _fbo(0)
129
        , _shader(0)
130 131 132 133 134
    {

    }

    template<class T>
schultezub's avatar
schultezub committed
135
    campvis::GenericGeometryTransferFunction<T>::~GenericGeometryTransferFunction() {
136 137
    }

138 139 140 141 142 143 144 145 146 147 148 149 150 151
    template<class T>
    cgt::vec2 campvis::GenericGeometryTransferFunction<T>::getVisibilityDomain() const {
        if (_geometries.empty())
            return cgt::vec2(-1.f, -1.f);
        else {
            cgt::vec2 minmax(1.f, 0.f);
            for (size_t i = 0; i < _geometries.size(); ++i) {
                minmax.x = std::min(minmax.x, _geometries[i]->getIntensityDomain().x);
                minmax.y = std::max(minmax.y, _geometries[i]->getIntensityDomain().y);
            }
            return minmax;
        }
    }

152 153
    template<class T>
    void campvis::GenericGeometryTransferFunction<T>::initShader() {
154
        _shader = ShdrMgr.load("core/glsl/passthrough.vert", "core/glsl/passthrough.frag", "");
155
        if (_shader == nullptr) {
156
            LERROR("Could not create Shader for Rendering the TF into the lookup texture!");
157 158 159 160
        }
    }

    template<class T>
schultezub's avatar
schultezub committed
161
    void campvis::GenericGeometryTransferFunction<T>::deinit() {
162 163
        s_aboutToBeDeleted.triggerSignal(); // use trigger to force blocking signal handling in same thread

164 165 166 167 168 169
        for (typename std::vector<T*>::iterator it = _geometries.begin(); it != _geometries.end(); ++it) {
            (*it)->s_changed.disconnect(this);
            delete *it;
        }
        _geometries.clear();

170 171
        if (_fbo != 0) {
            delete _fbo;
172
            _fbo = 0;
173 174
        }

175 176
        ShdrMgr.dispose(_shader);
        _shader = 0;
177 178 179 180
        AbstractTransferFunction::deinit();
    }

    template<class T>
schultezub's avatar
schultezub committed
181
    const std::vector<T*>& campvis::GenericGeometryTransferFunction<T>::getGeometries() const {
182 183 184 185
        return  _geometries;
    }

    template<class T>
schultezub's avatar
schultezub committed
186
    void campvis::GenericGeometryTransferFunction<T>::addGeometry(T* geometry) {
187 188 189 190 191 192
        {
            tbb::mutex::scoped_lock lock(_localMutex);
            _geometries.push_back(geometry);
        }
        geometry->s_changed.connect(this, &GenericGeometryTransferFunction<T>::onGeometryChanged);
        _dirtyTexture = true;
193 194
        s_geometryCollectionChanged.emitSignal();
        s_changed.emitSignal();
195 196 197
    }

    template<class T>
schultezub's avatar
schultezub committed
198
    void campvis::GenericGeometryTransferFunction<T>::removeGeometry(T* geometry) {
199 200
        {
            tbb::mutex::scoped_lock lock(_localMutex);
schultezub's avatar
schultezub committed
201
            for (typename std::vector<T*>::iterator it = _geometries.begin(); it != _geometries.end(); ++it) {
202 203 204 205 206 207 208 209 210
                if (*it == geometry) {
                    _geometries.erase(it);
                    break;
                }
            }
        }
        geometry->s_changed.disconnect(this);
        delete geometry;
        _dirtyTexture = true;
211 212
        s_geometryCollectionChanged.emitSignal();
        s_changed.emitSignal();
213 214 215
    }

    template<class T>
schultezub's avatar
schultezub committed
216
    void campvis::GenericGeometryTransferFunction<T>::onGeometryChanged() {
217
        _dirtyTexture = true;
218
        s_changed.emitSignal();
219 220 221
    }

    template<class T>
schultezub's avatar
schultezub committed
222
    void campvis::GenericGeometryTransferFunction<T>::createTexture() {
223 224 225 226
        if (_shader == 0) {
            initShader();
        }

227
        // acqiure a new TextureUnit, so that we don't mess with other currently bound textures during texture upload...
228
        cgt::TextureUnit tfUnit;
229 230 231 232 233 234 235 236 237 238 239 240
        tfUnit.activate();

        // detach old texture from FBO and delete it
        if (_texture != 0 && _fbo != 0) {
            _fbo->activate();
            _fbo->detachAll();
            _fbo->deactivate();
        }
        delete _texture;

        // create FBO if needed
        if (_fbo == 0) 
241
            _fbo = new cgt::FramebufferObject();
242 243 244 245 246
        _fbo->activate();
        LGL_ERROR;

        // create texture
        GLenum dataType = GL_UNSIGNED_BYTE;
247 248 249 250 251 252 253 254 255 256 257 258 259 260
        GLenum type = GL_TEXTURE_1D;
        switch (getDimensionality()) {
            case 1:
                type = GL_TEXTURE_1D;
                break;
            case 2:
                type = GL_TEXTURE_2D;
                break;
            default:
                cgtAssert(false, "This TF dimensionality is currently not supported - you have to implement it yourself!");
                break;
        }

        _texture = new cgt::Texture(type, _size, GL_RGBA8, cgt::Texture::LINEAR);
261
        _texture->setWrapping(cgt::Texture::CLAMP_TO_EDGE);
262 263 264 265 266 267 268 269 270 271 272 273 274
        LGL_ERROR;

        // attach texture to FBO
        _fbo->attachTexture(_texture);
        if (! _fbo->isComplete()) {
            LERROR("Incomplete FBO.");
            _fbo->deactivate();
            return;
        }
        LGL_ERROR;

        // render TF geometries into texture
        glViewport(0, 0, _texture->getWidth(), _texture->getHeight());
275
        glClearColor(0, 0, 0, 0);
276
        glClear(GL_COLOR_BUFFER_BIT);
277

278
        _shader->activate();
279
        _shader->setUniform("_projectionMatrix", cgt::mat4::createOrtho(0, 1, 0, 1, -1, 1));
280
        LGL_ERROR;
281

schultezub's avatar
schultezub committed
282
        for (typename std::vector<T*>::const_iterator it = _geometries.begin(); it != _geometries.end(); ++it) {
283 284 285 286
            (*it)->render();
        }
        LGL_ERROR;

287 288
        // deactivate Shader and FBO
        _shader->deactivate();
289
        _fbo->detachTexture(GL_COLOR_ATTACHMENT0);
290
        _fbo->detachAll();
291 292 293
        _fbo->deactivate();
        LGL_ERROR;

294
        cgt::TextureUnit::setZeroUnit();
295 296 297 298 299
        _dirtyTexture = false;
    }
}

#endif // GENERICGEOMETRYTRANSFERFUNCTION_H__