glreduction.cpp 8.41 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// ================================================================================================
// 
// This file is part of the CAMPVis Software Framework.
// 
// If not explicitly stated otherwise: Copyright (C) 2012, all rights reserved,
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
//      Chair for Computer Aided Medical Procedures
//      Technische Universität München
//      Boltzmannstr. 3, 85748 Garching b. München, Germany
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
// 
// The licensing of this softare is not yet resolved. Until then, redistribution in source or
// binary forms outside the CAMP chair is not permitted, unless explicitly stated in legal form.
// However, the names of the original authors and the above copyright notice must retain in its
// original state in any case.
// 
// Legal disclaimer provided by the BSD license:
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// 
// ================================================================================================

#include "glreduction.h"

#include "tgt/logmanager.h"
#include "tgt/framebufferobject.h"
#include "tgt/shadermanager.h"
#include "tgt/texture.h"
#include "tgt/textureunit.h"

#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";

51
52
53
    GlReduction::GlReduction(ReductionOperator reductionOperator)
        : _reductionOperator(reductionOperator)
        , _shader(0)
54
55
        , _fbo(0)
    {
56
        _shader = ShdrMgr.loadSeparate("core/glsl/passthrough.vert", "core/glsl/tools/glreduction.frag", generateGlslHeader(_reductionOperator), false);
57
58
59
60
61
62
63
64
65
66
        if (_shader == 0) {
            LERROR("Could not load Shader for OpenGL reduction. Reduction will not work!");
            return;
        }

        _shader->setAttributeLocation(0, "in_Position");
        _shader->setAttributeLocation(1, "in_TexCoord");
    }

    GlReduction::~GlReduction() {
67
        ShdrMgr.dispose(_shader);
68
69
    }

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

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

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

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

103
104
105
        tgtAssert(texture->getDimensions().z == 1, "Reduction of 3D images not yet implemented! Somebody was too lazy (or stressed - deadline was close) to do that...");

        const tgt::ivec3& size = texture->getDimensions();
106
        tgt::vec2 texCoordShift = tgt::vec2(.5f) / tgt::vec2(size.xy());
107
        tgt::ivec2 currentSize = size.xy();
108
109
        reduceSizes(currentSize, texCoordShift);
        tgt::ivec2 startSize = currentSize;
110
111
112
113
114
115
116
117

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

        // get a free texture unit
        tgt::TextureUnit inputUnit;

        // create temporary textures
118
        tgt::Texture* tempTextures[2];
119
        for (size_t i = 0; i < 2; ++i) {
120
121
            tempTextures[i] = new tgt::Texture(0, tgt::ivec3(currentSize, 1), GL_RGBA, GL_RGBA32F, GL_FLOAT, tgt::Texture::NEAREST);
            tempTextures[i]->uploadTexture();
122
            tempTextures[i]->setWrapping(tgt::Texture::CLAMP_TO_EDGE);
123
        }
124
125
        size_t readTex = 0;
        size_t writeTex = 1;
126
127
128
129
130
131
132
133

        // create and initialize FBO
        _fbo = new tgt::FramebufferObject();
        _fbo->activate();
        LGL_ERROR;

        // perform first reduction step outside:
        _shader->activate();
134
        _fbo->attachTexture(tempTextures[readTex]);
135

136
137
138
        inputUnit.activate();
        texture->bind();
        _shader->setUniform("_texture", inputUnit.getUnitNumber());
139
140
        _shader->setUniform("_texCoordsShift", texCoordShift);
        glViewport(startSize.x - currentSize.x, startSize.y - currentSize.y, currentSize.x, currentSize.y);
141
142
143
        QuadRdr.renderQuad();
        LGL_ERROR;

144
145
146
        reduceSizes(currentSize, texCoordShift);
        glViewport(startSize.x - currentSize.x, startSize.y - currentSize.y, currentSize.x, currentSize.y);

147
148
        // perform reduction until 1x1 texture remains
        while (currentSize.x > 1 || currentSize.y > 1) {
149
150
            _fbo->attachTexture(tempTextures[writeTex]);
            tempTextures[readTex]->bind();
151

152
            _shader->setUniform("_texCoordsShift", texCoordShift);
153
154
155
            QuadRdr.renderQuad();
            LGL_ERROR;

156
            reduceSizes(currentSize, texCoordShift);
157
            std::swap(writeTex, readTex);
158
159
160
161
162
163
        }

        _shader->deactivate();


        // read back stuff
164
165
        GLenum readBackFormat = tempTextures[readTex]->getFormat();
        size_t channels = tempTextures[readTex]->getNumChannels();
166
        toReturn.resize(currentSize.x * currentSize.y * channels);
167
        glReadBuffer(GL_COLOR_ATTACHMENT0);
168
        glReadPixels(startSize.x - currentSize.x, startSize.y - currentSize.y, currentSize.x, currentSize.y, readBackFormat, GL_FLOAT, &toReturn.front());
169
170
171
172
173
174
175
176
        LGL_ERROR;

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

177
178
        delete tempTextures[0];
        delete tempTextures[1];
179
180
        LGL_ERROR;

181
        return toReturn;
182
183
    }

184
    void GlReduction::reduceSizes(tgt::ivec2& currentSize, tgt::vec2& texCoordShift) {
185
186
        if (currentSize.x > 1) {
            currentSize.x = DIV_CEIL(currentSize.x, 2);
187
188
            if (currentSize.x == 1)
                texCoordShift.x *= -1.f;
189
190
191
        }
        if (currentSize.y > 1) {
            currentSize.y = DIV_CEIL(currentSize.y, 2);
192
193
            if (currentSize.y == 1)
                texCoordShift.y *= -1.f;
194
        }
195

196
197
    }

198
199
200
201
202
203
204
205
206
207
208
209
210
211
    std::string GlReduction::generateGlslHeader(ReductionOperator reductionOperator) {
        switch (reductionOperator) {
        case MIN:
            return "#define REDUCTION_OP(a, b, c, d) min(a, min(b, min(c, d)))";
            break;
        case MAX:
            return "#define REDUCTION_OP(a, b, c, d) max(a, max(b, max(c, d)))";
            break;
        case PLUS:
            return "#define REDUCTION_OP(a, b, c, d) a+b+c+d";
            break;
        case MULTIPLICATION:
            return "#define REDUCTION_OP(a, b, c, d) a*b*c*d";
            break;
212
213
214
        case MIN_MAX:
            return "#define REDUCTION_OP(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)";
            break;
215
216
217
218
219
220
221
        default:
            tgtAssert(false, "Should not reach this, wrong enum value?");
            return "";
            break;
        }
    }

222
}