texture.cpp 11.4 KB
Newer Older
1
/**********************************************************************
schultezub's avatar
schultezub committed
2
 *                                                                    *
3
 * cgt - CAMP Graphics Toolbox, Copyright (C) 2012-2015               *
4
5
6
 *     Chair for Computer Aided Medical Procedures                    *
 *     Technische Universitaet Muenchen, Germany.                     *
 *     <http://campar.in.tum.de/>                                     *
schultezub's avatar
schultezub committed
7
 *                                                                    *
8
9
10
11
 * forked from tgt - Tiny Graphics Toolbox, Copyright (C) 2006-2011   *
 *     Visualization and Computer Graphics Group, Department of       *
 *     Computer Science, University of Muenster, Germany.             *
 *     <http://viscg.uni-muenster.de>                                 *
schultezub's avatar
schultezub committed
12
 *                                                                    *
13
 * This file is part of the cgt library. This library is free         *
schultezub's avatar
schultezub committed
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 * software; you can redistribute it and/or modify it under the terms *
 * of the GNU Lesser General Public License version 2.1 as published  *
 * by the Free Software Foundation.                                   *
 *                                                                    *
 * This library is distributed in the hope that it will be useful,    *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the       *
 * GNU Lesser General Public License for more details.                *
 *                                                                    *
 * You should have received a copy of the GNU Lesser General Public   *
 * License in the file "LICENSE.txt" along with this library.         *
 * If not, see <http://www.gnu.org/licenses/>.                        *
 *                                                                    *
 **********************************************************************/

29
30
#include "cgt/texture.h"
#include "cgt/types.h"
schultezub's avatar
schultezub committed
31

32
33
#include "cgt/gpucapabilities.h"
#include "cgt/filesystem.h"
schultezub's avatar
schultezub committed
34

Jakob Weiss's avatar
Jakob Weiss committed
35
36
#include "texturemanager.h"

37
namespace cgt {
schultezub's avatar
schultezub committed
38

39
Texture::Texture(GLenum type, const cgt::ivec3& dimensions, GLint internalFormat, Filter filter /*= LINEAR*/) 
schultezub's avatar
schultezub committed
40
    : dimensions_(dimensions)
41
    , internalformat_(internalFormat)
schultezub's avatar
schultezub committed
42
    , filter_(filter)
43
    , wrapping_(CLAMP_TO_EDGE)
44
45
46
    , id_(0)
    , type_(type)
    , bpp_(0)
schultezub's avatar
schultezub committed
47
{
48
    init();
schultezub's avatar
schultezub committed
49
50
}

51
Texture::Texture(GLenum type, const cgt::ivec3& dimensions, GLint internalFormat, GLubyte* data, GLint format, GLenum dataType, Filter filter /*= LINEAR*/) 
schultezub's avatar
schultezub committed
52
    : dimensions_(dimensions)
53
    , internalformat_(internalFormat)
schultezub's avatar
schultezub committed
54
    , filter_(filter)
55
    , wrapping_(CLAMP_TO_EDGE)
56
57
58
    , id_(0)
    , type_(type)
    , bpp_(0)
schultezub's avatar
schultezub committed
59
{
60
61
    init();
    uploadTexture(data, format, dataType);
schultezub's avatar
schultezub committed
62
63
64
}


65
66
Texture::~Texture() {
    if (id_)
Jakob Weiss's avatar
Jakob Weiss committed
67
        TexMgr.releaseId(id_, type_, dimensions_, internalformat_);
68
69
70
}


71
72
void Texture::init() {
    bpp_ = calcBpp(internalformat_);
schultezub's avatar
schultezub committed
73
74
    generateId();
    applyFilter();
Jakob Weiss's avatar
Jakob Weiss committed
75
76
    applyWrapping();
    LGL_ERROR;
schultezub's avatar
schultezub committed
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
}

int Texture::calcBpp(GLint format, GLenum dataType) {

    int numChannels = calcNumChannels(format);

    int typeSize = 0;
    switch (dataType) {
        case GL_BYTE:
        case GL_UNSIGNED_BYTE:
            typeSize = 1;
            break;

        case GL_SHORT:
        case GL_UNSIGNED_SHORT:
            typeSize = 2;
            break;

        case GL_INT:
        case GL_UNSIGNED_INT:
        case GL_FLOAT:
            typeSize = 4;
            break;

        default:
102
            LWARNINGC("cgt.Texture", "unknown dataType");
schultezub's avatar
schultezub committed
103
104
105
106
107
108
    }

    return typeSize * numChannels;
}

int Texture::calcBpp(GLint internalformat) {
109
    auto ft = GLTextureFormatTraits::get(internalformat);
schultezub's avatar
schultezub committed
110

111
112
113
114
115
    if (ft.known())
        return ft.bpp();
    else {
        cgtAssert(false, "Unknown internal format, this should not happen!");
        return 0;
schultezub's avatar
schultezub committed
116
117
118
    }
}

119
int Texture::calcNumChannels(GLint internalFormat) {
120
121
122
123
124
125
126
    auto ft = GLTextureFormatTraits::get(internalFormat);

    if (ft.known())
        return ft.channels();
    else {

        switch (internalFormat) {
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
        case 1:
        case GL_RED:
            return 1;
            break;
        case 2:
        case GL_DEPTH_STENCIL:
        case GL_RG:
            return 2;
            break;

        case 3:
        case GL_RGB:
            return 3;
            break;
        case 4:
        case GL_RGBA:
            return 4;
            break;

        default:
147
            cgtAssert(false, "Unknown internal format, this should not happen!");
148
            return 0;
149
150
        }

schultezub's avatar
schultezub committed
151
152
153
154
155
156
157
158
    }
}

int Texture::getSizeOnGPU() const {
    int bpp = calcBpp(internalformat_);
    return bpp * hmul(dimensions_);
}

Jakob Weiss's avatar
Jakob Weiss committed
159
160
161
162
163
164
165
166
167
168
169
void Texture::bind() const
{
    glBindTexture(type_, id_);
}

GLuint Texture::generateId()
{
    id_ = TexMgr.generateId(type_, dimensions_, internalformat_);
    return id_;
}

schultezub's avatar
schultezub committed
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
void Texture::setFilter(Filter filter) {
    filter_ = filter;
    applyFilter();
}

void Texture::applyFilter() {
    bind();

    switch(filter_) {
        case NEAREST:
            glTexParameteri(type_,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
            glTexParameteri(type_,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
            break;

        case LINEAR:
            glTexParameteri(type_, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameteri(type_, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            break;

        case ANISOTROPIC:
            glTexParameterf(type_, GL_TEXTURE_MAX_ANISOTROPY_EXT, GpuCaps.getMaxTextureAnisotropy());

        case MIPMAP:
193
            glTexParameteri(type_,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
194
            glTexParameteri(type_,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_NEAREST);
schultezub's avatar
schultezub committed
195
196
197
198
199
200
201
202
203
204
205
206
207
            break;
    }
}

void Texture::setWrapping(Wrapping w) {
    wrapping_ = w;
    applyWrapping();
}

void Texture::applyWrapping() {
    bind();
    GLint wrap = wrapping_;

208
    // set wrapping for all diminesions
schultezub's avatar
schultezub committed
209
210
    glTexParameteri(type_, GL_TEXTURE_WRAP_S, wrap);

211
    if (type_ == GL_TEXTURE_2D || type_ == GL_TEXTURE_2D_ARRAY || type_ == GL_TEXTURE_3D )
schultezub's avatar
schultezub committed
212
213
214
215
216
        glTexParameteri(type_, GL_TEXTURE_WRAP_T, wrap);
    if (GL_TEXTURE_3D)
        glTexParameteri(type_, GL_TEXTURE_WRAP_R, wrap);
}

217
void Texture::uploadTexture(const GLubyte* data, GLint format, GLenum dataType) {
schultezub's avatar
schultezub committed
218
219
    bind();

220
    switch (type_) {
schultezub's avatar
schultezub committed
221
        case GL_TEXTURE_1D:
Jakob Weiss's avatar
Jakob Weiss committed
222
            glTexSubImage1D(type_, 0, 0, dimensions_.x, format, dataType, data);
223
224
            if (filter_ == MIPMAP)
                glGenerateMipmap(GL_TEXTURE_1D);
schultezub's avatar
schultezub committed
225
226
            break;

227
        case GL_TEXTURE_1D_ARRAY: // fallthrough
schultezub's avatar
schultezub committed
228
        case GL_TEXTURE_2D:
Jakob Weiss's avatar
Jakob Weiss committed
229
            glTexSubImage2D(type_, 0, 0, 0, dimensions_.x, dimensions_.y, format, dataType, data);
230
231
            if (filter_ == MIPMAP)
                glGenerateMipmap(GL_TEXTURE_2D);
schultezub's avatar
schultezub committed
232
233
            break;

234
        case GL_TEXTURE_2D_ARRAY: // fallthrough
schultezub's avatar
schultezub committed
235
        case GL_TEXTURE_3D:
Jakob Weiss's avatar
Jakob Weiss committed
236
            glTexSubImage3D(type_, 0, 0, 0, 0, dimensions_.x, dimensions_.y, dimensions_.z, format, dataType, data);
237
238
            if (filter_ == MIPMAP)
                glGenerateMipmap(GL_TEXTURE_3D);
schultezub's avatar
schultezub committed
239
240
            break;
    }
241
242

    LGL_ERROR;
schultezub's avatar
schultezub committed
243
244
}

245
246
GLubyte* Texture::downloadTextureToBuffer(GLint format, GLenum dataType) const {
    bind();
247

248
249
250
    int arraySize = hmul(dimensions_) * calcBpp(format, dataType);
    GLubyte* pixels = new GLubyte[arraySize];

Jakob Weiss's avatar
Jakob Weiss committed
251
252
    glFlush(); // better to use a barrier here but too lazy to figure out which one would be correct

253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    glGetTexImage(type_, 0, format, dataType, pixels);
    return pixels;
}

bool Texture::isDepthTexture() const {
    return internalformat_ == GL_DEPTH_COMPONENT
        || internalformat_ == GL_DEPTH_COMPONENT16 
        || internalformat_ == GL_DEPTH_COMPONENT24
        || internalformat_ == GL_DEPTH_COMPONENT32
        || internalformat_ == GL_DEPTH_COMPONENT32F;
}

void Texture::setPriority(GLclampf p) {
    glPrioritizeTextures(1, &id_, &p);
}

bool Texture::isResident() const {
    GLboolean resident;
    return glAreTexturesResident(1, &id_, &resident) == GL_TRUE;
}

GLint Texture::calcInternalFormat(GLint format, GLenum dataType) {
    switch (format) {
        case GL_RED:
            switch (dataType) {
279
                case GL_UNSIGNED_BYTE:
280
281
                case GL_BYTE:
                    return GL_R8;
282
                case GL_UNSIGNED_SHORT:
283
284
                case GL_SHORT:
                    return GL_R16;
285
                case GL_UNSIGNED_INT:
286
287
                case GL_INT:
                    return GL_R32F;
schultezub's avatar
schultezub committed
288
                case GL_FLOAT:
289
                    return GL_R32F;
schultezub's avatar
schultezub committed
290
                default:
291
292
                    cgtAssert(false, "Should not reach this - wrong base data type!");
                    return GL_RED;
schultezub's avatar
schultezub committed
293
            }
294
295
        case GL_RG:
            switch (dataType) {
296
                case GL_UNSIGNED_BYTE:
297
298
                case GL_BYTE:
                    return GL_RG8;
299
                case GL_UNSIGNED_SHORT:
300
301
                case GL_SHORT:
                    return GL_RG16;
302
                case GL_UNSIGNED_INT:
303
304
                case GL_INT:
                    return GL_RG32F;
305
                case GL_FLOAT:
306
                    return GL_RG32F;
schultezub's avatar
schultezub committed
307
                default:
308
309
                    cgtAssert(false, "Should not reach this - wrong base data type!");
                    return GL_RG;
schultezub's avatar
schultezub committed
310
            }
311
312
        case GL_RGB:
            switch (dataType) {
313
                case GL_UNSIGNED_BYTE:
314
315
                case GL_BYTE:
                    return GL_RGB8;
316
                case GL_UNSIGNED_SHORT:
317
318
                case GL_SHORT:
                    return GL_RGB16;
319
                case GL_UNSIGNED_INT:
320
321
                case GL_INT:
                    return GL_RGB32F;
322
                case GL_FLOAT:
323
                    return GL_RGB32F;
schultezub's avatar
schultezub committed
324
                default:
325
326
                    cgtAssert(false, "Should not reach this - wrong base data type!");
                    return GL_RGB;
327
            }
328
329
        case GL_RGBA:
            switch (dataType) {
330
                case GL_UNSIGNED_BYTE:
331
332
                case GL_BYTE:
                    return GL_RGBA8;
333
                case GL_UNSIGNED_SHORT:
334
335
                case GL_SHORT:
                    return GL_RGBA16;
336
                case GL_UNSIGNED_INT:
337
338
                case GL_INT:
                    return GL_RGBA32F;
339
                case GL_FLOAT:
340
                    return GL_RGBA32F;
341
                default:
342
343
                    cgtAssert(false, "Should not reach this - wrong base data type!");
                    return GL_RGBA;
344
            }
schultezub's avatar
schultezub committed
345
        default:
346
347
            cgtAssert(false, "Should not reach this, wrong number of channels!");
            return GL_RED;
schultezub's avatar
schultezub committed
348
349
350
    }
}

351
352
GLint Texture::calcMatchingPixelFormat(GLint internalFormat) {
    auto ft = GLTextureFormatTraits::get(internalFormat);
353

354
355
356
357
358
    if (ft.known())
        return ft.pixelFormat();
    else {
        cgtAssert(false, "Unknown internal format, this should not happen!");
        return 0;
359
360
361
    }
}

362
363
GLenum Texture::calcMatchingPixelDataType(GLint internalFormat) {
    auto ft = GLTextureFormatTraits::get(internalFormat);
schultezub's avatar
schultezub committed
364

365
366
367
368
369
370
371
    if (ft.known())
        return ft.pixelDataType();
    else {
        cgtAssert(false, "Unknown internal format, this should not happen!");
        return 0;
    }
}
schultezub's avatar
schultezub committed
372

373
374
375
376
377
378
379
380
std::string Texture::calcMatchingWriteFormat(GLint internalFormat) {
    auto ft = GLTextureFormatTraits::get(internalFormat);

    if (ft.known())
        return ft.glslFormatQualifier();
    else {
        cgtAssert(false, "Unknown internal format, this should not happen!");
        return "UNKNOWN";
381
    }
382
383
}

Jakob Weiss's avatar
Jakob Weiss committed
384
385
386
387
void Texture::unbind() const
{
    glBindTexture(type_, 0);
}
388

389
} // namespace cgt