glreduction.cpp 9.56 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
    GlReduction::GlReduction(ReductionOperator reductionOperator)
        : _reductionOperator(reductionOperator)
53
54
        , _shader2d(0)
        , _shader3d(0)
55
56
        , _fbo(0)
    {
57
58
59
        _shader2d = ShdrMgr.loadSeparate("core/glsl/passthrough.vert", "core/glsl/tools/glreduction.frag", generateGlslHeader(_reductionOperator) + "#define REDUCTION_2D\n", false);
        _shader3d = ShdrMgr.loadSeparate("core/glsl/passthrough.vert", "core/glsl/tools/glreduction.frag", generateGlslHeader(_reductionOperator) + "#define REDUCTION_3D\n", false);
        if (_shader2d == 0 || _shader3d == 0) {
60
61
62
63
            LERROR("Could not load Shader for OpenGL reduction. Reduction will not work!");
            return;
        }

64
65
66
67
        _shader2d->setAttributeLocation(0, "in_Position");
        _shader2d->setAttributeLocation(1, "in_TexCoord");
        _shader3d->setAttributeLocation(0, "in_Position");
        _shader3d->setAttributeLocation(1, "in_TexCoord");
68
69
70
    }

    GlReduction::~GlReduction() {
71
72
        ShdrMgr.dispose(_shader2d);
        ShdrMgr.dispose(_shader3d);
73
74
    }

75
    std::vector<float> GlReduction::reduce(const ImageData* image) {
76
        tgtAssert(image != 0, "Image must not be 0!");
77
        if (_shader2d == 0 || _shader3d == 0) {
78
            LERROR("Could not load Shader for OpenGL reduction. Reduction will not work!");
79
            return std::vector<float>();
80
81
82
        }
        if (image == 0) {
            LERROR("Empty image received - nothing to reduce!");
83
            return std::vector<float>();
84
85
86
87
88
        }

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

92
93
94
        return reduce(repGl->getTexture());
    }
    
95
96
97
    std::vector<float> GlReduction::reduce(const tgt::Texture* texture) {
        std::vector<float> toReturn;

98
        tgtAssert(texture != 0, "Image must not be 0!");
99
        if (_shader2d == 0 || _shader3d == 0) {
100
            LERROR("Could not load Shader for OpenGL reduction. Reduction will not work!");
101
            return toReturn;
102
103
104
        }
        if (texture == 0) {
            LERROR("Empty texture received - nothing to reduce!");
105
            return toReturn;
106
        }
107

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

        // 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
121
        tgt::Texture* tempTextures[2];
122
        for (size_t i = 0; i < 2; ++i) {
123
124
            tempTextures[i] = new tgt::Texture(0, tgt::ivec3(currentSize, 1), GL_RGBA, GL_RGBA32F, GL_FLOAT, tgt::Texture::NEAREST);
            tempTextures[i]->uploadTexture();
125
            tempTextures[i]->setWrapping(tgt::Texture::CLAMP_TO_EDGE);
126
        }
127
128
        size_t readTex = 0;
        size_t writeTex = 1;
129
130
131
132
133
134
135

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

        // perform first reduction step outside:
136
137
        tgt::Shader* leShader = (texture->getDimensions().z == 1) ? _shader2d : _shader3d;
        leShader->activate();
138
        _fbo->attachTexture(tempTextures[readTex]);
139

140
141
        inputUnit.activate();
        texture->bind();
142
143
144
145
146
        leShader->setUniform("_texture", inputUnit.getUnitNumber());
        leShader->setUniform("_texCoordsShift", texCoordShift);
        if (leShader == _shader3d)
            leShader->setUniform("_textureDepth", texture->getDimensions().z);

147
        glViewport(startSize.x - currentSize.x, startSize.y - currentSize.y, currentSize.x, currentSize.y);
148
        QuadRdr.renderQuad();
149
        leShader->deactivate();
150
151
        LGL_ERROR;

152
153
        _shader2d->activate();
        _shader2d->setUniform("_texture", inputUnit.getUnitNumber());
154
155
156
        reduceSizes(currentSize, texCoordShift);
        glViewport(startSize.x - currentSize.x, startSize.y - currentSize.y, currentSize.x, currentSize.y);

157
158
        // perform reduction until 1x1 texture remains
        while (currentSize.x > 1 || currentSize.y > 1) {
159
160
            _fbo->attachTexture(tempTextures[writeTex]);
            tempTextures[readTex]->bind();
161

162
            _shader2d->setUniform("_texCoordsShift", texCoordShift);
163
164
165
            QuadRdr.renderQuad();
            LGL_ERROR;

166
            reduceSizes(currentSize, texCoordShift);
167
            std::swap(writeTex, readTex);
168
169
        }

170
        _shader2d->deactivate();
171
172
173


        // read back stuff
174
175
        GLenum readBackFormat = tempTextures[readTex]->getFormat();
        size_t channels = tempTextures[readTex]->getNumChannels();
176
        toReturn.resize(currentSize.x * currentSize.y * channels);
177
        glReadBuffer(GL_COLOR_ATTACHMENT0);
178
        glReadPixels(startSize.x - currentSize.x, startSize.y - currentSize.y, currentSize.x, currentSize.y, readBackFormat, GL_FLOAT, &toReturn.front());
179
180
181
182
183
184
185
186
        LGL_ERROR;

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

187
188
        delete tempTextures[0];
        delete tempTextures[1];
189
190
        LGL_ERROR;

191
        return toReturn;
192
193
    }

194
    void GlReduction::reduceSizes(tgt::ivec2& currentSize, tgt::vec2& texCoordShift) {
195
196
        if (currentSize.x > 1) {
            currentSize.x = DIV_CEIL(currentSize.x, 2);
197
198
            if (currentSize.x == 1)
                texCoordShift.x *= -1.f;
199
200
201
        }
        if (currentSize.y > 1) {
            currentSize.y = DIV_CEIL(currentSize.y, 2);
202
203
            if (currentSize.y == 1)
                texCoordShift.y *= -1.f;
204
        }
205

206
207
    }

208
209
    std::string GlReduction::generateGlslHeader(ReductionOperator reductionOperator) {
        switch (reductionOperator) {
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
            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:
                tgtAssert(false, "Should not reach this, wrong enum value?");
                return "";
                break;
239
240
241
        }
    }

242
}