TextureData.cc 12 KB
Newer Older
Robert Menzel's avatar
Robert Menzel committed
1
2
3
4
5
6
7
8
9
10
11
12
/***********************************************************************
 * Copyright 2011-2013 Computer Graphics Group RWTH Aachen University. *
 * All rights reserved.                                                *
 * Distributed under the terms of the MIT License (see LICENSE.TXT).   *
 **********************************************************************/

#include <ACGL/OpenGL/Data/TextureData.hh>
#include <ACGL/Utils/Memory.hh>

using namespace ACGL;
using namespace ACGL::OpenGL;

13
14
GLsizei  TextureData::getPackAlignment() const
{
15
16
    size_t dataAlignment = Utils::pointerAlignment( mData );
    size_t rowAlignment  = Utils::pointerAlignment( mData + getBytesPerScanline() );
Robert Menzel's avatar
Robert Menzel committed
17
18
19
20
21
22
23

    return std::min( dataAlignment, rowAlignment ); //minimum of the data and the begining of the second row
}


GLsizei  TextureData::getNumberOfChannels() const
{
24
25
26
27
28
29
30
    return ACGL::OpenGL::getNumberOfChannels( mFormat );
}


GLenum TextureData::getRecommendedInternalFormat() const
{
    return recommendedInternalFormat(mFormat, mColorSpace);
Robert Menzel's avatar
Robert Menzel committed
31
}
32
33


34
void TextureData::flipVertically()
35
36
37
38
{
    size_t scanlineInBytes = getBytesPerScanline();
    GLubyte *tmpScanLine = new GLubyte[ scanlineInBytes ];

39
    for (GLsizei line = 0; line < mHeight/2; ++line) {
40
        size_t topLine    = line;
41
42
43
        size_t bottomLine = mHeight - line - 1;
        void *topLinePtr    = mData + topLine*scanlineInBytes;
        void *bottomLinePtr = mData + bottomLine*scanlineInBytes;
44
45
46
47
48
49
50
51
52
53
54
        memcpy( tmpScanLine,   topLinePtr,    scanlineInBytes ); // top    -> tmp
        memcpy( topLinePtr,    bottomLinePtr, scanlineInBytes ); // bottom -> top
        memcpy( bottomLinePtr, tmpScanLine,   scanlineInBytes ); // tmp    -> bottom
    }

    delete[] tmpScanLine;
}


size_t TextureData::getBytesPerScanline() const
{
55
56
57
58
    // if uncompressed -> texel size is a multiple of 8
    // if compressed   -> mWidth is a multiple of 4
    // so this function will work for bitsizes of 2,4,8,16 etc. -> 1 bit per pixel might fail
    return (mWidth*getTexelSizeInBits())/8 + mPaddingBytesPerRow;
59
60
}

61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
size_t TextureData::getSizeInBytes() const
{
    size_t s = getBytesPerScanline(); // correct even for compressed data
    if (mHeight > 0) s *= mHeight;
    if (mDepth  > 0) s *= mDepth;
    return s;
}

bool TextureData::dataIsCompressed() const
{
    if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || mFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT) {
        // BC 1 aka DXT 1
        return true;
    } else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) {
        // BC 2 aka DXT 3
        return true;
    } else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) {
        // BC 3 aka DXT 5
        return true;
    } else if (mFormat == GL_COMPRESSED_RED_RGTC1 || mFormat == GL_COMPRESSED_SIGNED_RED_RGTC1) {
        // BC 4
        return true;
    //} else if (mFormat == GL_COMPRESSED_RED_GREEN_RGTC2 || mFormat == GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2) {
    //    // BC 5
    //    return true;
    //} else if (mFormat == GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT || mFormat == GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT) {
    //    // BC 6H
    //    return true;
    //} else if (mFormat == GL_COMPRESSED_RGBA_BPTC_UNORM || mFormat == GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM) {
    //    // BC 7
    //    return true;
    } else {
        return false;
    }
}

size_t TextureData::getTexelSizeInBits() const
{
    if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || mFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT) {
        // BC 1 aka DXT 1
        return 4;
    } else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) {
        // BC 2 aka DXT 3
        return 8;
    } else if (mFormat == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) {
        // BC 3 aka DXT 5
        return 8;
    } else if (mFormat == GL_COMPRESSED_RED_RGTC1 || mFormat == GL_COMPRESSED_SIGNED_RED_RGTC1) {
        // BC 4
        return 8;
    //} else if (mFormat == GL_COMPRESSED_RED_GREEN_RGTC2 || mFormat == GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2) {
    //    // BC 5
    //    return 8;
    //} else if (mFormat == GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT || mFormat == GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT) {
    //    // BC 6H
    //    return 8;
    //} else if (mFormat == GL_COMPRESSED_RGBA_BPTC_UNORM || mFormat == GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM) {
    //    // BC 7
    //    return 8;
    } else {
        return ( getNumberOfChannels()*getGLTypeSize(mType) )*8;
    }
}
124
125
126
127
128
129
130
131

glm::vec4 TextureData::getTexel( glm::uvec2 _texCoord )
{
    // clamp negative to 0:
    _texCoord.x = std::max( 0u, _texCoord.x );
    _texCoord.y = std::max( 0u, _texCoord.y );

    // clamp values larger than the texture size to the maximum:
132
133
    _texCoord.x = std::min( _texCoord.x, (unsigned int) getWidth()  );
    _texCoord.y = std::min( _texCoord.y, (unsigned int) getHeight() );
134
135
136
137
138
139
140
141
142

    // the byte offset into pData of the desired texel:
    size_t texelOffset  = _texCoord.y * getBytesPerScanline();
    texelOffset        += _texCoord.x * getNumberOfChannels()*getGLTypeSize(mType);

    // default values:
    glm::vec4 result = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);

    if ( mType == GL_BYTE ) {
143
        GLbyte *data = (GLbyte *) (mData+texelOffset);
144
145
146
147
148
149
        result.r = data[0]/128.0f; // to -1..1
        if ( getNumberOfChannels() > 1 ) result.g = data[1]/128.0f;
        if ( getNumberOfChannels() > 2 ) result.b = data[2]/128.0f;
        if ( getNumberOfChannels() > 3 ) result.a = data[3]/128.0f;

    } else if ( mType == GL_UNSIGNED_BYTE ) {
150
        GLubyte *data = (GLubyte *) (mData+texelOffset);
151
152
153
154
155
156
        result.r = data[0]/255.0f; // to 0..1
        if ( getNumberOfChannels() > 1 ) result.g = data[1]/255.0f;
        if ( getNumberOfChannels() > 2 ) result.b = data[2]/255.0f;
        if ( getNumberOfChannels() > 3 ) result.a = data[3]/255.0f;

    } else if ( mType == GL_SHORT ) {
157
        GLshort *data = (GLshort *) (mData+texelOffset);
158
159
160
161
162
163
        result.r = data[0]/32768.0f; // to -1..1
        if ( getNumberOfChannels() > 1 ) result.g = data[1]/32768.0f;
        if ( getNumberOfChannels() > 2 ) result.b = data[2]/32768.0f;
        if ( getNumberOfChannels() > 3 ) result.a = data[3]/32768.0f;

    } else if ( mType == GL_UNSIGNED_SHORT ) {
164
        GLushort *data = (GLushort *) (mData+texelOffset);
165
166
167
168
169
170
        result.r = data[0]/65535.0f; // to 0..1
        if ( getNumberOfChannels() > 1 ) result.g = data[1]/65535.0f;
        if ( getNumberOfChannels() > 2 ) result.b = data[2]/65535.0f;
        if ( getNumberOfChannels() > 3 ) result.a = data[3]/65535.0f;

    } else if ( mType == GL_INT ) {
171
        GLint *data = (GLint *) (mData+texelOffset);
172
173
174
175
176
177
        result.r = data[0]/2147483648.0f; // to -1..1
        if ( getNumberOfChannels() > 1 ) result.g = data[1]/2147483648.0f;
        if ( getNumberOfChannels() > 2 ) result.b = data[2]/2147483648.0f;
        if ( getNumberOfChannels() > 3 ) result.a = data[3]/2147483648.0f;

    } else if ( mType == GL_UNSIGNED_INT ) {
178
        GLuint *data = (GLuint *) (mData+texelOffset);
179
180
181
182
183
184
        result.r = data[0]/4294967295.0f; // to 0..1
        if ( getNumberOfChannels() > 1 ) result.g = data[1]/4294967295.0f;
        if ( getNumberOfChannels() > 2 ) result.b = data[2]/4294967295.0f;
        if ( getNumberOfChannels() > 3 ) result.a = data[3]/4294967295.0f;

    } else if ( mType == GL_FLOAT ) {
185
        GLfloat *data = (GLfloat *) (mData+texelOffset);
186
187
188
189
190
191
        result.r = data[0];
        if ( getNumberOfChannels() > 1 ) result.g = data[1];
        if ( getNumberOfChannels() > 2 ) result.b = data[2];
        if ( getNumberOfChannels() > 3 ) result.a = data[3];

    } else if ( mType == GL_DOUBLE ) {
192
        GLdouble *data = (GLdouble *) (mData+texelOffset);
193
194
195
196
197
198
199
200
201
202
203
204
205
206
        result.r = (float) data[0];
        if ( getNumberOfChannels() > 1 ) result.g = (float) data[1];
        if ( getNumberOfChannels() > 2 ) result.b = (float) data[2];
        if ( getNumberOfChannels() > 3 ) result.a = (float) data[3];

    } else {
        ACGL::Utils::error() << "datatype " << mType << " not supported for getTexel! Return (0,0,0,1)." << std::endl;
    }

    return result;
}

void TextureData::setTexel( glm::uvec2 _texCoord, glm::vec4 _color )
{
207
    assert( mData && "can't set texels if there is no data store, define data using setData()" );
208
209
210
211
212
    // clamp negative to 0:
    _texCoord.x = std::max( 0u, _texCoord.x );
    _texCoord.y = std::max( 0u, _texCoord.y );

    // clamp values larger than the texture size to the maximum:
213
214
    _texCoord.x = std::min( _texCoord.x, (unsigned int) getWidth()  );
    _texCoord.y = std::min( _texCoord.y, (unsigned int) getHeight() );
215
216
217
218
219
220

    // the byte offset into pData of the desired texel:
    size_t texelOffset  = _texCoord.y * getBytesPerScanline();
    texelOffset        += _texCoord.x * getNumberOfChannels()*getGLTypeSize(mType);

    if ( mType == GL_BYTE ) {
221
        GLbyte *data = (GLbyte *) (mData+texelOffset);
222
223
224
225
226
227
228
229
230
231

        glm::ivec4 color = glm::ivec4( _color * glm::vec4(128.0f) );
        color = glm::clamp( color, glm::ivec4(-128), glm::ivec4(127) );

        data[0] = color.r;
        if ( getNumberOfChannels() > 1 ) data[1] = color.g;
        if ( getNumberOfChannels() > 2 ) data[2] = color.b;
        if ( getNumberOfChannels() > 3 ) data[3] = color.a;

    } else if ( mType == GL_UNSIGNED_BYTE ) {
232
        GLubyte *data = (GLubyte *) (mData+texelOffset);
233
234
235
236
237
238
239
240
241
242

        glm::ivec4 color = glm::ivec4( _color * glm::vec4(255.0f) );
        color = glm::clamp( color, glm::ivec4(0), glm::ivec4(255) );

        data[0] = color.r;
        if ( getNumberOfChannels() > 1 ) data[1] = color.g;
        if ( getNumberOfChannels() > 2 ) data[2] = color.b;
        if ( getNumberOfChannels() > 3 ) data[3] = color.a;

    } else if ( mType == GL_SHORT ) {
243
        GLshort *data = (GLshort *) (mData+texelOffset);
244
245
246
247
248
249
250
251
252
253

        glm::ivec4 color = glm::ivec4( _color * glm::vec4(32768.0f) );
        color = glm::clamp( color, glm::ivec4(-32768), glm::ivec4(32767) );

        data[0] = color.r;
        if ( getNumberOfChannels() > 1 ) data[1] = color.g;
        if ( getNumberOfChannels() > 2 ) data[2] = color.b;
        if ( getNumberOfChannels() > 3 ) data[3] = color.a;

    } else if ( mType == GL_UNSIGNED_SHORT ) {
254
        GLushort *data = (GLushort *) (mData+texelOffset);
255
256
257
258
259
260
261
262
263
264

        glm::ivec4 color = glm::ivec4( _color * glm::vec4(65535.0f) );
        color = glm::clamp( color, glm::ivec4(0), glm::ivec4(65535) );

        data[0] = color.r;
        if ( getNumberOfChannels() > 1 ) data[1] = color.g;
        if ( getNumberOfChannels() > 2 ) data[2] = color.b;
        if ( getNumberOfChannels() > 3 ) data[3] = color.a;

    } else if ( mType == GL_INT ) {
265
        GLint *data = (GLint *) (mData+texelOffset);
266
267

        glm::ivec4 color = glm::ivec4( _color * glm::vec4(2147483648.0f) );
268
        color = glm::clamp( color, glm::ivec4(std::numeric_limits<int>::min()), glm::ivec4(2147483647) );
269
270
271
272
273
274
275

        data[0] = color.r;
        if ( getNumberOfChannels() > 1 ) data[1] = color.g;
        if ( getNumberOfChannels() > 2 ) data[2] = color.b;
        if ( getNumberOfChannels() > 3 ) data[3] = color.a;

    } else if ( mType == GL_UNSIGNED_INT ) {
276
        GLuint *data = (GLuint *) (mData+texelOffset);
277
278
279
280
281
282
283
284
285
286

        glm::ivec4 color = glm::ivec4( _color * glm::vec4(4294967295.0f) );
        color = glm::clamp( color, glm::ivec4(0), glm::ivec4(4294967295) );

        data[0] = color.r;
        if ( getNumberOfChannels() > 1 ) data[1] = color.g;
        if ( getNumberOfChannels() > 2 ) data[2] = color.b;
        if ( getNumberOfChannels() > 3 ) data[3] = color.a;

    } else if ( mType == GL_FLOAT ) {
287
        GLfloat *data = (GLfloat *) (mData+texelOffset);
288
289
290
291
292
293
294

        data[0] = _color.r;
        if ( getNumberOfChannels() > 1 ) data[1] = _color.g;
        if ( getNumberOfChannels() > 2 ) data[2] = _color.b;
        if ( getNumberOfChannels() > 3 ) data[3] = _color.a;

    } else if ( mType == GL_DOUBLE ) {
295
        GLdouble *data = (GLdouble *) (mData+texelOffset);
296
297
298
299
300
301
302
303
304

        data[0] = (float) _color.r;
        if ( getNumberOfChannels() > 1 ) data[1] = (float) _color.g;
        if ( getNumberOfChannels() > 2 ) data[2] = (float) _color.b;
        if ( getNumberOfChannels() > 3 ) data[3] = (float) _color.a;

    } else {
        ACGL::Utils::error() << "datatype " << mType << " not supported for setTexel!" << std::endl;
    }
305
306
}