glreduction.cpp 8.48 KB
Newer Older
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,
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
// 
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
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
// 
// ================================================================================================

#include "glreduction.h"

27 28 29 30 31
#include "cgt/logmanager.h"
#include "cgt/framebufferobject.h"
#include "cgt/shadermanager.h"
#include "cgt/texture.h"
#include "cgt/textureunit.h"
32 33 34 35 36 37 38 39 40 41 42 43 44 45

#include "core/datastructures/facegeometry.h"
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationgl.h"
#include "core/tools/quadrenderer.h"

#include <algorithm>

#define DIV_CEIL(x,y) ((x) > 0) ? (1 + ((x) - 1)/(y)) : ((x) / (y))

namespace campvis {

    const std::string GlReduction::loggerCat_ = "CAMPVis.modules.registration.GlReduction";

Hossain Mahmud's avatar
Hossain Mahmud committed
46
    GlReduction::GlReduction(ReductionOperator reductionOperator)
47
        : _reductionOperator(reductionOperator)
48
        , _shader1d(0)
49 50
        , _shader2d(0)
        , _shader3d(0)
51 52
        , _fbo(0)
    {
Hossain Mahmud's avatar
Hossain Mahmud committed
53 54 55 56
        _shader1d = ShdrMgr.load("core/glsl/passthrough.vert", "core/glsl/tools/glreduction.frag", generateGlslHeader(_reductionOperator) + "#define REDUCTION_1D\n");
        _shader2d = ShdrMgr.load("core/glsl/passthrough.vert", "core/glsl/tools/glreduction.frag", generateGlslHeader(_reductionOperator) + "#define REDUCTION_2D\n");
        _shader3d = ShdrMgr.load("core/glsl/passthrough.vert", "core/glsl/tools/glreduction.frag", generateGlslHeader(_reductionOperator) + "#define REDUCTION_3D\n");

57
        if (_shader1d == 0 || _shader2d == 0 || _shader3d == 0) {
58 59 60 61 62 63
            LERROR("Could not load Shader for OpenGL reduction. Reduction will not work!");
            return;
        }
    }

    GlReduction::~GlReduction() {
64
        ShdrMgr.dispose(_shader1d);
65 66
        ShdrMgr.dispose(_shader2d);
        ShdrMgr.dispose(_shader3d);
67 68
    }

69
    std::vector<float> GlReduction::reduce(const ImageData* image) {
70
        cgtAssert(image != 0, "Image must not be 0!");
71
        if (_shader1d == 0 || _shader2d == 0 || _shader3d == 0) {
72
            LERROR("Could not load Shader for OpenGL reduction. Reduction will not work!");
73
            return std::vector<float>();
74 75 76
        }
        if (image == 0) {
            LERROR("Empty image received - nothing to reduce!");
77
            return std::vector<float>();
78 79 80 81 82
        }

        const ImageRepresentationGL* repGl = image->getRepresentation<ImageRepresentationGL>();
        if (repGl == 0) {
            LERROR("Could not convert input image to OpenGL texture - no reduction possible!");
83
            return std::vector<float>();
84 85
        }

86 87 88
        return reduce(repGl->getTexture());
    }
    
89
    std::vector<float> GlReduction::reduce(const cgt::Texture* texture) {
90 91
        std::vector<float> toReturn;

92
        cgtAssert(texture != 0, "Image must not be 0!");
93
        if (_shader1d == 0 || _shader2d == 0 || _shader3d == 0) {
94
            LERROR("Could not load Shader for OpenGL reduction. Reduction will not work!");
95
            return toReturn;
96 97 98
        }
        if (texture == 0) {
            LERROR("Empty texture received - nothing to reduce!");
99
            return toReturn;
100
        }
101

102 103
        const cgt::ivec3& size = texture->getDimensions();
        cgt::ivec2 texSize = size.xy();
104 105 106 107 108

        // Set OpenGL pixel alignment to 1 to avoid problems with NPOT textures
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

        // get a free texture unit
109
        cgt::TextureUnit inputUnit;
110
        inputUnit.activate();
111 112

        // create temporary textures
113
        cgt::Texture* tempTextures[2];
114
        for (size_t i = 0; i < 2; ++i) {
115
            tempTextures[i] = new cgt::Texture(GL_TEXTURE_2D, cgt::ivec3(texSize, 1), GL_RGBA32F, cgt::Texture::NEAREST);
116
            tempTextures[i]->setWrapping(cgt::Texture::CLAMP_TO_EDGE);
117
        }
118

119 120
        const cgt::Texture* inputTex = texture;
        cgt::Texture* outputTex = tempTextures[1];
121 122

        // create and initialize FBO
123
        _fbo = new cgt::FramebufferObject();
124 125 126
        _fbo->activate();
        LGL_ERROR;

127 128 129 130
        // perform 3D reduction if needed
        if (texture->getDimensions().z > 1) {
            _shader3d->activate();
            _fbo->attachTexture(outputTex);
131

132 133 134 135 136 137 138
            inputTex->bind();
            _shader3d->setUniform("_texture", inputUnit.getUnitNumber());
            _shader3d->setUniform("_textureSize", size);

            glViewport(0, 0, texSize.x, texSize.y);
            QuadRdr.renderQuad();
            _shader3d->deactivate();
139

140 141 142 143
            inputTex = outputTex;
            outputTex = tempTextures[0];
            LGL_ERROR;
        }
144

145 146 147 148
        // perform 2D reduction if needed
        if (texture->getDimensions().y > 1) {
            _shader2d->activate();
            _fbo->attachTexture(outputTex);
149

150 151 152 153 154
            inputTex->bind();
            _shader2d->setUniform("_texture", inputUnit.getUnitNumber());
            _shader2d->setUniform("_textureSize", size.xy());

            glViewport(0, 0, texSize.x, 1);
155
            QuadRdr.renderQuad();
156
            _shader2d->deactivate();
157

158 159 160
            inputTex = outputTex;
            outputTex = (outputTex == tempTextures[1]) ? tempTextures[0] : tempTextures[1];
            LGL_ERROR;
161 162
        }

163 164 165 166 167 168 169 170
        // finally, perform 1D reduction if needed
        {
            _shader1d->activate();
            _fbo->attachTexture(outputTex);

            inputTex->bind();
            _shader1d->setUniform("_texture", inputUnit.getUnitNumber());
            _shader1d->setUniform("_textureSize", size.xy());
171

172 173 174 175 176
            glViewport(0, 0, 1, 1);
            QuadRdr.renderQuad();
            _shader1d->deactivate();
            LGL_ERROR;
        }
177 178

        // read back stuff
179
        GLenum readBackFormat = cgt::Texture::calcMatchingFormat(outputTex->getInternalFormat());
180 181
        size_t channels = outputTex->getNumChannels();
        toReturn.resize(channels);
182
        glReadBuffer(GL_COLOR_ATTACHMENT0);
183
        glReadPixels(0, 0, 1, 1, readBackFormat, GL_FLOAT, &toReturn.front());
184 185 186 187 188 189 190 191
        LGL_ERROR;

        // clean up...
        _fbo->detachAll();
        _fbo->deactivate();
        delete _fbo;
        _fbo = 0;

192 193
        delete tempTextures[0];
        delete tempTextures[1];
194 195
        LGL_ERROR;

196
        return toReturn;
197 198 199
    }


200 201
    std::string GlReduction::generateGlslHeader(ReductionOperator reductionOperator) {
        switch (reductionOperator) {
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
            case MIN:
                return 
                    "#define REDUCTION_OP_2(a, b) min(a, b)\n"
                    "#define REDUCTION_OP_4(a, b, c, d) min(a, min(b, min(c, d)))\n";
                break;
            case MAX:
                return 
                    "#define REDUCTION_OP_2(a, b) max(a, b)\n"
                    "#define REDUCTION_OP_4(a, b, c, d) max(a, max(b, max(c, d)))\n";
                break;
            case PLUS:
                return 
                    "#define REDUCTION_OP_2(a, b) a+b\n"
                    "#define REDUCTION_OP_4(a, b, c, d) a+b+c+d\n";
                break;
            case MULTIPLICATION:
                return 
                    "#define REDUCTION_OP_2(a, b) a*b\n"
                    "#define REDUCTION_OP_4(a, b, c, d) a*b*c*d\n";
                break;
            case MIN_MAX_DEPTH_ONLY:
                return 
                    "#define REDUCTION_OP_2(a, b) vec4(min(a.r, b.r), max(a.g, b.g), 0.0, 0.0)\n"
                    "#define REDUCTION_OP_4(a, b, c, d) vec4(min(a.r, min(b.r, min(c.r, d.r))), max(a.g, max(b.g, max(c.g, d.g))), 0.0, 0.0)\n";
                break;
            default:
228
                cgtAssert(false, "Should not reach this, wrong enum value?");
229 230
                return "";
                break;
231 232 233
        }
    }

234
}