/* Cop(c) 2001, Stanford University * All rights reserved * * See the file LICENSE.txt for information on redistributing this software. */ #include "cr_pixeldata.h" #include "cr_error.h" #include "cr_mem.h" #include "cr_version.h" #include #include #include #if defined(WINDOWS) # include # undef isnan /* _MSC_VER 12.0+ defines this is a complicated macro */ # define isnan(x) _isnan(x) #endif /** * Maybe export this someday. */ static int crSizeOfType( GLenum type ) { switch (type) { #ifdef CR_OPENGL_VERSION_1_2 case GL_UNSIGNED_BYTE_3_3_2: case GL_UNSIGNED_BYTE_2_3_3_REV: #endif case GL_UNSIGNED_BYTE: case GL_BYTE: return 1; case GL_BITMAP: return 0; /* special case */ #ifdef CR_OPENGL_VERSION_1_2 case GL_UNSIGNED_SHORT_5_6_5: case GL_UNSIGNED_SHORT_5_6_5_REV: case GL_UNSIGNED_SHORT_5_5_5_1: case GL_UNSIGNED_SHORT_1_5_5_5_REV: case GL_UNSIGNED_SHORT_4_4_4_4: case GL_UNSIGNED_SHORT_4_4_4_4_REV: #endif case GL_UNSIGNED_SHORT: case GL_SHORT: return 2; #ifdef CR_OPENGL_VERSION_1_2 case GL_UNSIGNED_INT_8_8_8_8: case GL_UNSIGNED_INT_8_8_8_8_REV: case GL_UNSIGNED_INT_10_10_10_2: case GL_UNSIGNED_INT_2_10_10_10_REV: #endif #ifdef CR_EXT_framebuffer_object case GL_UNSIGNED_INT_24_8: #endif case GL_UNSIGNED_INT: case GL_INT: case GL_FLOAT: return 4; case GL_DOUBLE: return 8; default: crError( "Unknown pixel type in crSizeOfType: 0x%x", (unsigned int) type ); return 0; } } /** * Compute bytes per pixel for the given format/type combination. * \return bytes per pixel or -1 for invalid format or type, 0 for bitmap data. */ int crPixelSize( GLenum format, GLenum type ) { int bytes = 1; /* picky Windows compiler, we override later */ switch (type) { #ifdef CR_OPENGL_VERSION_1_2 case GL_UNSIGNED_BYTE_3_3_2: case GL_UNSIGNED_BYTE_2_3_3_REV: return 1; #endif case GL_UNSIGNED_BYTE: case GL_BYTE: bytes = 1; break; case GL_BITMAP: return 0; /* special case */ #ifdef CR_OPENGL_VERSION_1_2 case GL_UNSIGNED_SHORT_5_6_5: case GL_UNSIGNED_SHORT_5_6_5_REV: case GL_UNSIGNED_SHORT_5_5_5_1: case GL_UNSIGNED_SHORT_1_5_5_5_REV: case GL_UNSIGNED_SHORT_4_4_4_4: case GL_UNSIGNED_SHORT_4_4_4_4_REV: return 2; #endif case GL_UNSIGNED_SHORT: case GL_SHORT: bytes = 2; break; #ifdef CR_OPENGL_VERSION_1_2 case GL_UNSIGNED_INT_8_8_8_8: case GL_UNSIGNED_INT_8_8_8_8_REV: case GL_UNSIGNED_INT_10_10_10_2: case GL_UNSIGNED_INT_2_10_10_10_REV: return 4; #endif #ifdef CR_EXT_framebuffer_object case GL_UNSIGNED_INT_24_8: return 4; #endif case GL_UNSIGNED_INT: case GL_INT: case GL_FLOAT: bytes = 4; break; default: crWarning( "Unknown pixel type in crPixelSize: type:0x%x(fmt:0x%x)", (unsigned int) type, (unsigned int) format); return 0; } switch (format) { case GL_COLOR_INDEX: case GL_STENCIL_INDEX: case GL_DEPTH_COMPONENT: case GL_RED: case GL_GREEN: case GL_BLUE: case GL_ALPHA: case GL_LUMINANCE: case GL_INTENSITY: #ifdef CR_EXT_texture_sRGB case GL_SLUMINANCE_EXT: case GL_SLUMINANCE8_EXT: #endif break; case GL_LUMINANCE_ALPHA: #ifdef CR_EXT_texture_sRGB case GL_SLUMINANCE_ALPHA_EXT: case GL_SLUMINANCE8_ALPHA8_EXT: #endif bytes *= 2; break; case GL_RGB: #ifdef CR_OPENGL_VERSION_1_2 case GL_BGR: #endif #ifdef CR_EXT_texture_sRGB case GL_SRGB_EXT: case GL_SRGB8_EXT: #endif bytes *= 3; break; case GL_RGBA: #ifdef GL_ABGR_EXT case GL_ABGR_EXT: #endif #ifdef CR_OPENGL_VERSION_1_2 case GL_BGRA: #endif #ifdef CR_EXT_texture_sRGB case GL_SRGB_ALPHA_EXT: case GL_SRGB8_ALPHA8_EXT: #endif bytes *= 4; break; default: crWarning( "Unknown pixel format in crPixelSize: type:0x%x(fmt:0x%x)", (unsigned int) type, (unsigned int) format); return 0; } return bytes; } #define BYTE_TO_FLOAT(b) ((b) * (1.0/127.0)) #define FLOAT_TO_BYTE(f) ((GLbyte) ((f) * 127.0)) #define UBYTE_TO_FLOAT(b) ((b) * (1.0/255.0)) #define FLOAT_TO_UBYTE(f) ((GLbyte) ((f) * 255.0)) #define SHORT_TO_FLOAT(s) ((s) * (1.0/32768.0)) #define FLOAT_TO_SHORT(f) ((GLshort) ((f) * 32768.0)) #define USHORT_TO_FLOAT(s) ((s) * (1.0/65535.0)) #define FLOAT_TO_USHORT(f) ((GLushort) ((f) * 65535.0)) #define INT_TO_FLOAT(i) ((i) * (1.0F/2147483647.0)) #define FLOAT_TO_INT(f) ((GLint) ((f) * 2147483647.0)) #define UINT_TO_FLOAT(i) ((i) * (1.0F / 4294967295.0F)) #define FLOAT_TO_UINT(f) ((GLuint) ((f) * 4294967295.0)) static float SRGBF_TO_RGBF(float f) { if (isnan(f)) return 0.f; if (f<=0.04045f) { return f/12.92f; } else { return pow((f+0.055f)/1.055f, 2.4f); } } static float RGBF_TO_SRGBF(float f) { if (isnan(f)) return 0.f; if (f>1.f) return 1.f; if (f<0.f) return 0.f; if (f<0.0031308f) { return f*12.92f; } else { return 1.055f*pow(f, 0.41666f) - 0.055f; } } #ifdef _MSC_VER /** @todo bird: MSC takes 5..20 mins to compile get_row and/or put_row with global * optimizations enabled. It varies a bit between 8.0/64 and 7.1/32 - the latter seems * to be fine with just disabling opts for get_row, while the former needs both to be * disabled to compile it a decent time. It seems this isn't important code after all, * so we're not overly worried about the performance degration. Even so, we might want * to look into it before long, perhaps checking with Visual C++ 9.0 (aka 2008). */ # pragma optimize("g", off) #endif /* * Pack src pixel data into tmpRow array as either GLfloat[][1] or * GLfloat[][4] depending on whether the format is for colors. */ static void get_row(const char *src, GLenum srcFormat, GLenum srcType, GLsizei width, GLfloat *tmpRow) { const GLbyte *bSrc = (GLbyte *) src; const GLubyte *ubSrc = (GLubyte *) src; const GLshort *sSrc = (GLshort *) src; const GLushort *usSrc = (GLushort *) src; const GLint *iSrc = (GLint *) src; const GLuint *uiSrc = (GLuint *) src; const GLfloat *fSrc = (GLfloat *) src; const GLdouble *dSrc = (GLdouble *) src; int i; if (srcFormat == GL_COLOR_INDEX || srcFormat == GL_STENCIL_INDEX) { switch (srcType) { case GL_BYTE: for (i = 0; i < width; i++) tmpRow[i] = (GLfloat) bSrc[i]; break; case GL_UNSIGNED_BYTE: for (i = 0; i < width; i++) tmpRow[i] = (GLfloat) ubSrc[i]; break; case GL_SHORT: for (i = 0; i < width; i++) tmpRow[i] = (GLfloat) sSrc[i]; break; case GL_UNSIGNED_SHORT: for (i = 0; i < width; i++) tmpRow[i] = (GLfloat) usSrc[i]; break; case GL_INT: for (i = 0; i < width; i++) tmpRow[i] = (GLfloat) iSrc[i]; break; case GL_UNSIGNED_INT: for (i = 0; i < width; i++) tmpRow[i] = (GLfloat) uiSrc[i]; break; case GL_FLOAT: for (i = 0; i < width; i++) tmpRow[i] = fSrc[i]; break; case GL_DOUBLE: for (i = 0; i < width; i++) tmpRow[i] = (GLfloat) dSrc[i]; break; default: crError("unexpected type in get_row in pixel.c"); } } else if (srcFormat == GL_DEPTH_COMPONENT) { switch (srcType) { case GL_BYTE: for (i = 0; i < width; i++) tmpRow[i] = (GLfloat) BYTE_TO_FLOAT(bSrc[i]); break; case GL_UNSIGNED_BYTE: for (i = 0; i < width; i++) tmpRow[i] = (GLfloat) UBYTE_TO_FLOAT(ubSrc[i]); break; case GL_SHORT: for (i = 0; i < width; i++) tmpRow[i] = (GLfloat) SHORT_TO_FLOAT(sSrc[i]); break; case GL_UNSIGNED_SHORT: for (i = 0; i < width; i++) tmpRow[i] = (GLfloat) USHORT_TO_FLOAT(usSrc[i]); break; case GL_INT: for (i = 0; i < width; i++) tmpRow[i] = (GLfloat) INT_TO_FLOAT(bSrc[i]); break; case GL_UNSIGNED_INT: for (i = 0; i < width; i++) tmpRow[i] = (GLfloat) UINT_TO_FLOAT(bSrc[i]); break; case GL_FLOAT: for (i = 0; i < width; i++) tmpRow[i] = fSrc[i]; break; case GL_DOUBLE: for (i = 0; i < width; i++) tmpRow[i] = (GLfloat) dSrc[i]; break; default: crError("unexpected type in get_row in pixel.c"); } } else if (srcFormat == GL_RED || srcFormat == GL_GREEN || srcFormat == GL_BLUE || srcFormat == GL_ALPHA) { int dst; if (srcFormat == GL_RED) dst = 0; else if (srcFormat == GL_GREEN) dst = 1; else if (srcFormat == GL_BLUE) dst = 2; else dst = 3; for (i = 0; i < width; i++) { tmpRow[i*4+0] = 0.0; tmpRow[i*4+1] = 0.0; tmpRow[i*4+2] = 0.0; tmpRow[i*4+3] = 1.0; } switch (srcType) { case GL_BYTE: for (i = 0; i < width; i++, dst += 4) tmpRow[dst] = (GLfloat) BYTE_TO_FLOAT(bSrc[i]); break; case GL_UNSIGNED_BYTE: for (i = 0; i < width; i++, dst += 4) tmpRow[dst] = (GLfloat) UBYTE_TO_FLOAT(ubSrc[i]); break; case GL_SHORT: for (i = 0; i < width; i++, dst += 4) tmpRow[dst] = (GLfloat) SHORT_TO_FLOAT(sSrc[i]); break; case GL_UNSIGNED_SHORT: for (i = 0; i < width; i++, dst += 4) tmpRow[dst] = (GLfloat) USHORT_TO_FLOAT(usSrc[i]); break; case GL_INT: for (i = 0; i < width; i++, dst += 4) tmpRow[dst] = (GLfloat) INT_TO_FLOAT(iSrc[i]); break; case GL_UNSIGNED_INT: for (i = 0; i < width; i++, dst += 4) tmpRow[dst] = (GLfloat) UINT_TO_FLOAT(uiSrc[i]); break; case GL_FLOAT: for (i = 0; i < width; i++, dst += 4) tmpRow[dst] = fSrc[i]; break; case GL_DOUBLE: for (i = 0; i < width; i++, dst += 4) tmpRow[dst] = (GLfloat) fSrc[i]; break; default: crError("unexpected type in get_row in pixel.c"); } } else if (srcFormat == GL_LUMINANCE #ifdef CR_EXT_texture_sRGB || srcFormat == GL_SLUMINANCE_EXT || srcFormat == GL_SLUMINANCE8_EXT #endif ) { switch (srcType) { case GL_BYTE: for (i = 0; i < width; i++) { tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = (GLfloat) BYTE_TO_FLOAT(bSrc[i]); tmpRow[i*4+3] = 1.0; } break; case GL_UNSIGNED_BYTE: for (i = 0; i < width; i++) { tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = (GLfloat) UBYTE_TO_FLOAT(ubSrc[i]); tmpRow[i*4+3] = 1.0; } break; case GL_SHORT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = (GLfloat) SHORT_TO_FLOAT(sSrc[i]); tmpRow[i*4+3] = 1.0; } break; case GL_UNSIGNED_SHORT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = (GLfloat) USHORT_TO_FLOAT(usSrc[i]); tmpRow[i*4+3] = 1.0; } break; case GL_INT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = (GLfloat) INT_TO_FLOAT(iSrc[i]); tmpRow[i*4+3] = 1.0; } break; case GL_UNSIGNED_INT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = (GLfloat) UINT_TO_FLOAT(uiSrc[i]); tmpRow[i*4+3] = 1.0; } break; case GL_FLOAT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = fSrc[i]; tmpRow[i*4+3] = 1.0; } break; case GL_DOUBLE: for (i = 0; i < width; i++) { tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = (GLfloat) dSrc[i]; tmpRow[i*4+3] = 1.0; } break; default: crError("unexpected type in get_row in pixel.c"); } } else if (srcFormat == GL_INTENSITY) { switch (srcType) { case GL_BYTE: for (i = 0; i < width; i++) tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = tmpRow[i*4+3] = (GLfloat) BYTE_TO_FLOAT(bSrc[i]); break; case GL_UNSIGNED_BYTE: for (i = 0; i < width; i++) tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = tmpRow[i*4+3] = (GLfloat) UBYTE_TO_FLOAT(ubSrc[i]); break; case GL_SHORT: for (i = 0; i < width; i++) tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = tmpRow[i*4+3] = (GLfloat) SHORT_TO_FLOAT(sSrc[i]); break; case GL_UNSIGNED_SHORT: for (i = 0; i < width; i++) tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = tmpRow[i*4+3] = (GLfloat) USHORT_TO_FLOAT(usSrc[i]); break; case GL_INT: for (i = 0; i < width; i++) tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = tmpRow[i*4+3] = (GLfloat) INT_TO_FLOAT(iSrc[i]); break; case GL_UNSIGNED_INT: for (i = 0; i < width; i++) tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = tmpRow[i*4+3] = UINT_TO_FLOAT(uiSrc[i]); break; case GL_FLOAT: for (i = 0; i < width; i++) tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = tmpRow[i*4+3] = fSrc[i]; break; case GL_DOUBLE: for (i = 0; i < width; i++) tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = tmpRow[i*4+3] = (GLfloat) dSrc[i]; break; default: crError("unexpected type in get_row in pixel.c"); } } else if (srcFormat == GL_LUMINANCE_ALPHA #ifdef CR_EXT_texture_sRGB || srcFormat == GL_SLUMINANCE_ALPHA_EXT || srcFormat == GL_SLUMINANCE8_ALPHA8_EXT #endif ) { switch (srcType) { case GL_BYTE: for (i = 0; i < width; i++) { tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = (GLfloat) BYTE_TO_FLOAT(bSrc[i*2+0]); tmpRow[i*4+3] = (GLfloat) BYTE_TO_FLOAT(bSrc[i*2+1]); } break; case GL_UNSIGNED_BYTE: for (i = 0; i < width; i++) { tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = (GLfloat) UBYTE_TO_FLOAT(ubSrc[i*2+0]); tmpRow[i*4+3] = (GLfloat) UBYTE_TO_FLOAT(ubSrc[i*2+1]); } break; case GL_SHORT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = (GLfloat) SHORT_TO_FLOAT(sSrc[i*2+0]); tmpRow[i*4+3] = (GLfloat) SHORT_TO_FLOAT(sSrc[i*2+1]); } break; case GL_UNSIGNED_SHORT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = (GLfloat) USHORT_TO_FLOAT(usSrc[i*2+0]); tmpRow[i*4+3] = (GLfloat) USHORT_TO_FLOAT(usSrc[i*2+1]); } break; case GL_INT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = (GLfloat) INT_TO_FLOAT(iSrc[i*2+0]); tmpRow[i*4+3] = (GLfloat) INT_TO_FLOAT(iSrc[i*2+1]); } break; case GL_UNSIGNED_INT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = (GLfloat) UINT_TO_FLOAT(uiSrc[i*2+0]); tmpRow[i*4+3] = (GLfloat) UINT_TO_FLOAT(uiSrc[i*2+1]); } break; case GL_FLOAT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = fSrc[i*2+0]; tmpRow[i*4+3] = fSrc[i*2+1]; } break; case GL_DOUBLE: for (i = 0; i < width; i++) { tmpRow[i*4+0] = tmpRow[i*4+1] = tmpRow[i*4+2] = (GLfloat) dSrc[i*2+0]; tmpRow[i*4+3] = (GLfloat) dSrc[i*2+1]; } break; default: crError("unexpected type in get_row in pixel.c"); } } else if (srcFormat == GL_RGB #ifdef CR_OPENGL_VERSION_1_2 || srcFormat == GL_BGR #endif #ifdef CR_EXT_texture_sRGB || srcFormat == GL_SRGB_EXT || srcFormat == GL_SRGB8_EXT #endif ) { int r, b; if (srcFormat == GL_RGB #ifdef CR_EXT_texture_sRGB || srcFormat == GL_SRGB_EXT || srcFormat == GL_SRGB8_EXT #endif ) { r = 0; b = 2; } else { r = 2; b = 0; } switch (srcType) { case GL_BYTE: for (i = 0; i < width; i++) { tmpRow[i*4+0] = (GLfloat) BYTE_TO_FLOAT(bSrc[i*3+r]); tmpRow[i*4+1] = (GLfloat) BYTE_TO_FLOAT(bSrc[i*3+1]); tmpRow[i*4+2] = (GLfloat) BYTE_TO_FLOAT(bSrc[i*3+b]); tmpRow[i*4+3] = 1.0; } break; case GL_UNSIGNED_BYTE: for (i = 0; i < width; i++) { tmpRow[i*4+0] = (GLfloat) UBYTE_TO_FLOAT(ubSrc[i*3+r]); tmpRow[i*4+1] = (GLfloat) UBYTE_TO_FLOAT(ubSrc[i*3+1]); tmpRow[i*4+2] = (GLfloat) UBYTE_TO_FLOAT(ubSrc[i*3+b]); tmpRow[i*4+3] = 1.0; } break; case GL_SHORT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = (GLfloat) SHORT_TO_FLOAT(sSrc[i*3+r]); tmpRow[i*4+1] = (GLfloat) SHORT_TO_FLOAT(sSrc[i*3+1]); tmpRow[i*4+2] = (GLfloat) SHORT_TO_FLOAT(sSrc[i*3+b]); tmpRow[i*4+3] = 1.0; } break; case GL_UNSIGNED_SHORT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = (GLfloat) USHORT_TO_FLOAT(usSrc[i*3+r]); tmpRow[i*4+1] = (GLfloat) USHORT_TO_FLOAT(usSrc[i*3+1]); tmpRow[i*4+2] = (GLfloat) USHORT_TO_FLOAT(usSrc[i*3+b]); tmpRow[i*4+3] = 1.0; } break; case GL_INT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = (GLfloat) INT_TO_FLOAT(iSrc[i*3+r]); tmpRow[i*4+1] = (GLfloat) INT_TO_FLOAT(iSrc[i*3+1]); tmpRow[i*4+2] = (GLfloat) INT_TO_FLOAT(iSrc[i*3+b]); tmpRow[i*4+3] = 1.0; } break; case GL_UNSIGNED_INT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = (GLfloat) UINT_TO_FLOAT(uiSrc[i*3+r]); tmpRow[i*4+1] = (GLfloat) UINT_TO_FLOAT(uiSrc[i*3+1]); tmpRow[i*4+2] = (GLfloat) UINT_TO_FLOAT(uiSrc[i*3+b]); tmpRow[i*4+3] = 1.0; } break; case GL_FLOAT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = fSrc[i*3+r]; tmpRow[i*4+1] = fSrc[i*3+1]; tmpRow[i*4+2] = fSrc[i*3+b]; tmpRow[i*4+3] = 1.0; } break; case GL_DOUBLE: for (i = 0; i < width; i++) { tmpRow[i*4+0] = (GLfloat) dSrc[i*3+r]; tmpRow[i*4+1] = (GLfloat) dSrc[i*3+1]; tmpRow[i*4+2] = (GLfloat) dSrc[i*3+b]; tmpRow[i*4+3] = 1.0; } break; #ifdef CR_OPENGL_VERSION_1_2 case GL_UNSIGNED_BYTE_3_3_2: for (i = 0; i < width; i++) { tmpRow[i*4+r] = (GLfloat) ((ubSrc[i] >> 5) ) / 7.0f; tmpRow[i*4+1] = (GLfloat) ((ubSrc[i] >> 2) & 0x7) / 7.0f; tmpRow[i*4+b] = (GLfloat) ((ubSrc[i] ) & 0x3) / 3.0f; tmpRow[i*4+3] = 1.0; } break; case GL_UNSIGNED_BYTE_2_3_3_REV: for (i = 0; i < width; i++) { tmpRow[i*4+r] = (GLfloat) ((ubSrc[i] ) & 0x7) / 7.0f; tmpRow[i*4+1] = (GLfloat) ((ubSrc[i] >> 3) & 0x7) / 7.0f; tmpRow[i*4+b] = (GLfloat) ((ubSrc[i] >> 6) ) / 3.0f; tmpRow[i*4+3] = 1.0; } break; case GL_UNSIGNED_SHORT_5_6_5: for (i = 0; i < width; i++) { tmpRow[i*4+r] = (GLfloat) ((usSrc[i] >> 11) & 0x1f) / 31.0f; tmpRow[i*4+1] = (GLfloat) ((usSrc[i] >> 5) & 0x3f) / 63.0f; tmpRow[i*4+b] = (GLfloat) ((usSrc[i] ) & 0x1f) / 31.0f; tmpRow[i*4+3] = 1.0; } break; case GL_UNSIGNED_SHORT_5_6_5_REV: for (i = 0; i < width; i++) { tmpRow[i*4+r] = (GLfloat) ((usSrc[i] ) & 0x1f) / 31.0f; tmpRow[i*4+1] = (GLfloat) ((usSrc[i] >> 5) & 0x3f) / 63.0f; tmpRow[i*4+b] = (GLfloat) ((usSrc[i] >> 11) & 0x1f) / 31.0f; tmpRow[i*4+3] = 1.0; } break; #endif default: crError("unexpected type in get_row in pixel.c"); } } else if (srcFormat == GL_RGBA #ifdef CR_OPENGL_VERSION_1_2 || srcFormat == GL_BGRA #endif #ifdef CR_EXT_texture_sRGB || srcFormat == GL_SRGB_ALPHA_EXT || srcFormat == GL_SRGB8_ALPHA8_EXT #endif ) { int r, b; if (srcFormat == GL_RGBA #ifdef CR_EXT_texture_sRGB || srcFormat == GL_SRGB_ALPHA_EXT || srcFormat == GL_SRGB8_ALPHA8_EXT #endif ) { r = 0; b = 2; } else { r = 2; b = 0; } switch (srcType) { case GL_BYTE: for (i = 0; i < width; i++) { tmpRow[i*4+0] = (GLfloat) BYTE_TO_FLOAT(bSrc[i*4+r]); tmpRow[i*4+1] = (GLfloat) BYTE_TO_FLOAT(bSrc[i*4+1]); tmpRow[i*4+2] = (GLfloat) BYTE_TO_FLOAT(bSrc[i*4+b]); tmpRow[i*4+3] = (GLfloat) BYTE_TO_FLOAT(bSrc[i*4+3]); } break; case GL_UNSIGNED_BYTE: for (i = 0; i < width; i++) { tmpRow[i*4+0] = (GLfloat) UBYTE_TO_FLOAT(ubSrc[i*4+r]); tmpRow[i*4+1] = (GLfloat) UBYTE_TO_FLOAT(ubSrc[i*4+1]); tmpRow[i*4+2] = (GLfloat) UBYTE_TO_FLOAT(ubSrc[i*4+b]); tmpRow[i*4+3] = (GLfloat) UBYTE_TO_FLOAT(ubSrc[i*4+3]); } break; case GL_SHORT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = (GLfloat) SHORT_TO_FLOAT(sSrc[i*4+r]); tmpRow[i*4+1] = (GLfloat) SHORT_TO_FLOAT(sSrc[i*4+1]); tmpRow[i*4+2] = (GLfloat) SHORT_TO_FLOAT(sSrc[i*4+b]); tmpRow[i*4+3] = (GLfloat) SHORT_TO_FLOAT(sSrc[i*4+3]); } break; case GL_UNSIGNED_SHORT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = (GLfloat) USHORT_TO_FLOAT(usSrc[i*4+r]); tmpRow[i*4+1] = (GLfloat) USHORT_TO_FLOAT(usSrc[i*4+1]); tmpRow[i*4+2] = (GLfloat) USHORT_TO_FLOAT(usSrc[i*4+b]); tmpRow[i*4+3] = (GLfloat) USHORT_TO_FLOAT(usSrc[i*4+3]); } break; case GL_INT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = (GLfloat) INT_TO_FLOAT(iSrc[i*4+r]); tmpRow[i*4+1] = (GLfloat) INT_TO_FLOAT(iSrc[i*4+1]); tmpRow[i*4+2] = (GLfloat) INT_TO_FLOAT(iSrc[i*4+b]); tmpRow[i*4+3] = (GLfloat) INT_TO_FLOAT(iSrc[i*4+3]); } break; case GL_UNSIGNED_INT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = (GLfloat) UINT_TO_FLOAT(uiSrc[i*4+r]); tmpRow[i*4+1] = (GLfloat) UINT_TO_FLOAT(uiSrc[i*4+1]); tmpRow[i*4+2] = (GLfloat) UINT_TO_FLOAT(uiSrc[i*4+b]); tmpRow[i*4+3] = (GLfloat) UINT_TO_FLOAT(uiSrc[i*4+3]); } break; case GL_FLOAT: for (i = 0; i < width; i++) { tmpRow[i*4+0] = fSrc[i*4+r]; tmpRow[i*4+1] = fSrc[i*4+1]; tmpRow[i*4+2] = fSrc[i*4+b]; tmpRow[i*4+3] = fSrc[i*4+3]; } break; case GL_DOUBLE: for (i = 0; i < width; i++) { tmpRow[i*4+0] = (GLfloat) dSrc[i*4+r]; tmpRow[i*4+1] = (GLfloat) dSrc[i*4+1]; tmpRow[i*4+2] = (GLfloat) dSrc[i*4+b]; tmpRow[i*4+3] = (GLfloat) dSrc[i*4+3]; } break; #ifdef CR_OPENGL_VERSION_1_2 case GL_UNSIGNED_SHORT_5_5_5_1: for (i = 0; i < width; i++) { tmpRow[i*4+r] = (GLfloat) ((usSrc[i] >> 11) ) / 31.0f; tmpRow[i*4+1] = (GLfloat) ((usSrc[i] >> 6) & 0x1f) / 31.0f; tmpRow[i*4+b] = (GLfloat) ((usSrc[i] >> 1) & 0x1f) / 31.0f; tmpRow[i*4+3] = (GLfloat) ((usSrc[i] ) & 0x01); } break; case GL_UNSIGNED_SHORT_1_5_5_5_REV: for (i = 0; i < width; i++) { tmpRow[i*4+r] = (GLfloat) ((usSrc[i] ) & 0x1f) / 31.0f; tmpRow[i*4+1] = (GLfloat) ((usSrc[i] >> 5) & 0x1f) / 31.0f; tmpRow[i*4+b] = (GLfloat) ((usSrc[i] >> 10) & 0x1f) / 31.0f; tmpRow[i*4+3] = (GLfloat) ((usSrc[i] >> 15) ); } break; case GL_UNSIGNED_SHORT_4_4_4_4: for (i = 0; i < width; i++) { tmpRow[i*4+r] = (GLfloat) ((usSrc[i] >> 12) & 0xf) / 15.0f; tmpRow[i*4+1] = (GLfloat) ((usSrc[i] >> 8) & 0xf) / 15.0f; tmpRow[i*4+b] = (GLfloat) ((usSrc[i] >> 4) & 0xf) / 15.0f; tmpRow[i*4+3] = (GLfloat) ((usSrc[i] ) & 0xf) / 15.0f; } break; case GL_UNSIGNED_SHORT_4_4_4_4_REV: for (i = 0; i < width; i++) { tmpRow[i*4+r] = (GLfloat) ((usSrc[i] ) & 0xf) / 15.0f; tmpRow[i*4+1] = (GLfloat) ((usSrc[i] >> 4) & 0xf) / 15.0f; tmpRow[i*4+b] = (GLfloat) ((usSrc[i] >> 8) & 0xf) / 15.0f; tmpRow[i*4+3] = (GLfloat) ((usSrc[i] >> 12) & 0xf) / 15.0f; } break; case GL_UNSIGNED_INT_8_8_8_8: for (i = 0; i < width; i++) { tmpRow[i*4+r] = (GLfloat) ((uiSrc[i] >> 24) & 0xff) / 255.0f; tmpRow[i*4+1] = (GLfloat) ((uiSrc[i] >> 16) & 0xff) / 255.0f; tmpRow[i*4+b] = (GLfloat) ((uiSrc[i] >> 8) & 0xff) / 255.0f; tmpRow[i*4+3] = (GLfloat) ((uiSrc[i] ) & 0xff) / 255.0f; } break; case GL_UNSIGNED_INT_8_8_8_8_REV: for (i = 0; i < width; i++) { tmpRow[i*4+r] = (GLfloat) ((uiSrc[i] ) & 0xff) / 255.0f; tmpRow[i*4+1] = (GLfloat) ((uiSrc[i] >> 8) & 0xff) / 255.0f; tmpRow[i*4+b] = (GLfloat) ((uiSrc[i] >> 16) & 0xff) / 255.0f; tmpRow[i*4+3] = (GLfloat) ((uiSrc[i] >> 24) & 0xff) / 255.0f; } break; case GL_UNSIGNED_INT_10_10_10_2: for (i = 0; i < width; i++) { tmpRow[i*4+r] = (GLfloat) ((uiSrc[i] >> 22) & 0x3ff) / 1023.0f; tmpRow[i*4+1] = (GLfloat) ((uiSrc[i] >> 12) & 0x3ff) / 1023.0f; tmpRow[i*4+b] = (GLfloat) ((uiSrc[i] >> 2) & 0x3ff) / 1023.0f; tmpRow[i*4+3] = (GLfloat) ((uiSrc[i] ) & 0x003) / 3.0f; } break; case GL_UNSIGNED_INT_2_10_10_10_REV: for (i = 0; i < width; i++) { tmpRow[i*4+r] = (GLfloat) ((uiSrc[i] ) & 0x3ff) / 1023.0f; tmpRow[i*4+1] = (GLfloat) ((uiSrc[i] >> 10) & 0x3ff) / 1023.0f; tmpRow[i*4+b] = (GLfloat) ((uiSrc[i] >> 20) & 0x3ff) / 1023.0f; tmpRow[i*4+3] = (GLfloat) ((uiSrc[i] >> 30) & 0x003) / 3.0f; } break; #endif default: crError("unexpected type in get_row in pixel.c"); } } else{ crError("unexpected source format in get_row in pixel.c"); } #ifdef CR_EXT_texture_sRGB if (srcFormat == GL_SRGB_EXT || srcFormat == GL_SRGB8_EXT || srcFormat == GL_SRGB_ALPHA_EXT || srcFormat == GL_SRGB8_ALPHA8_EXT || srcFormat == GL_SLUMINANCE_ALPHA_EXT || srcFormat == GL_SLUMINANCE8_ALPHA8_EXT || srcFormat == GL_SLUMINANCE_EXT || srcFormat == GL_SLUMINANCE8_EXT ) { for (i=0; i> 8) | (us[i] << 8); } } /** * Byte-swap an array of GLuints */ static void swap4(GLuint *ui, GLuint n) { GLuint i; for (i = 0; i < n; i++) { GLuint b = ui[i]; ui[i] = (b >> 24) | ((b >> 8) & 0xff00) | ((b << 8) & 0xff0000) | ((b << 24) & 0xff000000); } } /** * Return number of bytes of storage needed to accommodate an * image with the given format, type, and size. * \return size in bytes or -1 if bad format or type */ unsigned int crImageSize( GLenum format, GLenum type, GLsizei width, GLsizei height ) { unsigned int bytes = width * height; if (type == GL_BITMAP) { /* This was wrong in the old code! */ bytes = ((width + 7) / 8) * height; } else if (GL_DEPTH_COMPONENT==format && type!=GL_FLOAT) { /*GL_DEPTH_COMPONENT with GL_UNSIGNED_BYTE seems to be more than 1 byte per pixel*/ bytes = 4 * width * height * crPixelSize( format, type ); } else { bytes = width * height * crPixelSize( format, type ); } return bytes; } /** * Return number of bytes of storage needed to accommodate a * 3D texture with the give format, type, and size. * \return size in bytes or -1 if bad format or type */ unsigned int crTextureSize( GLenum format, GLenum type, GLsizei width, GLsizei height, GLsizei depth ) { unsigned int bytes = width * height; if (type == GL_BITMAP) { /* * Not sure about this one, so just multiply * by the depth? */ bytes = ((width + 7) / 8) * height * depth; } else { bytes = width * height * depth * crPixelSize( format, type ); } return bytes; } static const CRPixelPackState defaultPacking = { 0, /* rowLength */ 0, /* skipRows */ 0, /* skipPixels */ 1, /* alignment */ 0, /* imageHeight */ 0, /* skipImages */ GL_FALSE, /* swapBytes */ GL_FALSE /* psLSBFirst */ }; void crPixelCopy1D( GLvoid *dstPtr, GLenum dstFormat, GLenum dstType, const GLvoid *srcPtr, GLenum srcFormat, GLenum srcType, GLsizei width, const CRPixelPackState *srcPacking ) { crPixelCopy2D( width, 1, dstPtr, dstFormat, dstType, NULL, /* dst */ srcPtr, srcFormat, srcType, srcPacking ); /* src */ } void crPixelCopy2D( GLsizei width, GLsizei height, GLvoid *dstPtr, GLenum dstFormat, GLenum dstType, const CRPixelPackState *dstPacking, const GLvoid *srcPtr, GLenum srcFormat, GLenum srcType, const CRPixelPackState *srcPacking ) { const char *src = (const char *) srcPtr; char *dst = (char *) dstPtr; int srcBytesPerPixel; int dstBytesPerPixel; int srcBytesPerRow; int dstBytesPerRow; int srcRowStrideBytes; int dstRowStrideBytes; int bytesPerRow; int i; if (!dstPacking) dstPacking = &defaultPacking; if (!srcPacking) srcPacking = &defaultPacking; if (srcType == GL_BITMAP) { CRASSERT(dstType == GL_BITMAP); bytesPerRow = (width + 7) / 8; if (srcPacking->rowLength > 0) srcRowStrideBytes = (srcPacking->rowLength + 7) / 8; else srcRowStrideBytes = bytesPerRow; dstRowStrideBytes = bytesPerRow; for (i=0; irowLength > 0) srcRowStrideBytes = srcPacking->rowLength * srcBytesPerPixel; else srcRowStrideBytes = width * srcBytesPerPixel; if (dstPacking->rowLength > 0) dstRowStrideBytes = dstPacking->rowLength * dstBytesPerPixel; else dstRowStrideBytes = width * dstBytesPerPixel; /* bytes per row */ srcBytesPerRow = width * srcBytesPerPixel; dstBytesPerRow = width * dstBytesPerPixel; /* handle the alignment */ if (srcPacking->alignment != 1) { i = ((intptr_t) src) % srcPacking->alignment; if (i) src += srcPacking->alignment - i; i = (long) srcRowStrideBytes % srcPacking->alignment; if (i) srcRowStrideBytes += srcPacking->alignment - i; } if (dstPacking->alignment != 1) { i = ((intptr_t) dst) % dstPacking->alignment; if (i) dst += dstPacking->alignment - i; i = (long) dstRowStrideBytes % dstPacking->alignment; if (i) dstRowStrideBytes += dstPacking->alignment - i; } /* handle skip rows */ src += srcPacking->skipRows * srcRowStrideBytes; dst += dstPacking->skipRows * dstRowStrideBytes; /* handle skip pixels */ src += srcPacking->skipPixels * srcBytesPerPixel; dst += dstPacking->skipPixels * dstBytesPerPixel; /* we don't do LSBFirst yet */ if (srcPacking->psLSBFirst) crError( "Sorry, no lsbfirst for you" ); if (dstPacking->psLSBFirst) crError( "Sorry, no lsbfirst for you" ); if (srcFormat == dstFormat && srcType == dstType) { CRASSERT(srcBytesPerRow == dstBytesPerRow); if (srcBytesPerRow==srcRowStrideBytes && srcRowStrideBytes==dstRowStrideBytes) { crMemcpy( (void *) dst, (const void *) src, height * srcBytesPerRow ); } else /*crDebug("Sending texture, BytesPerRow!=RowStrideBytes");*/ for (i = 0; i < height; i++) { crMemcpy( (void *) dst, (const void *) src, srcBytesPerRow ); #if 0 /* check if src XOR dst swapping */ if (srcPacking->swapBytes ^ dstPacking->swapBytes) { const GLint size = crSizeOfType(srcType); CRASSERT(srcType == dstType); if (size == 2) { swap2((GLushort *) dst, srcBytesPerRow / size); } else if (size == 4) { swap4((GLuint *) dst, srcBytesPerRow / size); } } #endif dst += dstRowStrideBytes; src += srcRowStrideBytes; } } else { /* need to do format and/or type conversion */ char *swapRow = NULL; GLfloat *tmpRow = crAlloc( 4 * width * sizeof(GLfloat) ); crDebug("Converting texture format"); if (!tmpRow) crError("Out of memory in crPixelCopy2D"); if (srcPacking->swapBytes) { swapRow = (char *) crAlloc(width * srcBytesPerPixel); if (!swapRow) { crError("Out of memory in crPixelCopy2D"); } } for (i = 0; i < height; i++) { /* get src row as floats */ if (srcPacking->swapBytes) { const GLint size = crSizeOfType(srcType); const GLint bytes = width * srcBytesPerPixel; crMemcpy(swapRow, src, bytes); if (size == 2) swap2((GLushort *) swapRow, bytes / 2); else if (size == 4) swap4((GLuint *) swapRow, bytes / 4); get_row(swapRow, srcFormat, srcType, width, tmpRow); } else { get_row(src, srcFormat, srcType, width, tmpRow); } /* store floats in dest row */ if (dstPacking->swapBytes) { const GLint size = crSizeOfType(dstType); const GLint bytes = dstBytesPerPixel * width; put_row(dst, dstFormat, dstType, width, tmpRow); if (size == 2) swap2((GLushort *) dst, bytes / 2); else if (size == 4) swap4((GLuint *) dst, bytes / 4); } else { put_row(dst, dstFormat, dstType, width, tmpRow); } /* increment pointers for next row */ dst += dstRowStrideBytes; src += srcRowStrideBytes; } crFree(tmpRow); if (swapRow) crFree(swapRow); } } } void crPixelCopy3D( GLsizei width, GLsizei height, GLsizei depth, GLvoid *dstPtr, GLenum dstFormat, GLenum dstType, const CRPixelPackState *dstPacking, const GLvoid *srcPtr, GLenum srcFormat, GLenum srcType, const CRPixelPackState *srcPacking ) { int tex_size = 0; (void)srcPacking; (void)srcType; (void)srcFormat; (void)dstPacking; /** @todo this should be implemented properly*/ #ifndef DEBUG_misha crWarning( "crPixelCopy3D: simply crMemcpy'ing from srcPtr to dstPtr" ); #endif if (dstFormat != srcFormat) crWarning( "crPixelCopy3D: formats don't match!" ); if (dstType != srcType) crWarning( "crPixelCopy3D: formats don't match!" ); tex_size = RT_MIN (crTextureSize( dstFormat, dstType, width, height, depth ), crTextureSize( srcFormat, srcType, width, height, depth )); crMemcpy( (void *) dstPtr, (void *) srcPtr, tex_size ); } /* Round N up to the next multiple of 8 */ #define CEIL8(N) (((N) + 7) & ~0x7) void crBitmapCopy( GLsizei width, GLsizei height, GLubyte *dstPtr, const GLubyte *srcPtr, const CRPixelPackState *srcPacking ) { if (srcPacking->psLSBFirst == GL_FALSE && (srcPacking->rowLength == 0 || srcPacking->rowLength == width) && srcPacking->skipRows == 0 && srcPacking->skipPixels == 0 && srcPacking->alignment == 1) { /* simple case */ crMemcpy(dstPtr, srcPtr, CEIL8(width) * height / 8); } else { /* general case */ const GLubyte *srcRow; const GLint dst_row_length = CEIL8(width) / 8; GLubyte *dstRow; GLint src_row_length; GLint i, j; if (srcPacking->rowLength > 0) src_row_length = srcPacking->rowLength; else src_row_length = width; switch (srcPacking->alignment) { case 1: src_row_length = ( ( src_row_length + 7 ) & ~7 ) >> 3; break; case 2: src_row_length = ( ( src_row_length + 15 ) & ~15 ) >> 3; break; case 4: src_row_length = ( ( src_row_length + 31 ) & ~31 ) >> 3; break; case 8: src_row_length = ( ( src_row_length + 63 ) & ~63 ) >> 3; break; default: crError( "Invalid unpack alignment in crBitmapCopy"); return; } /* src_row_length and dst_row_length are in bytes */ srcRow = srcPtr + src_row_length * srcPacking->skipRows; dstRow = dstPtr; if (srcPacking->psLSBFirst) { for (j = 0; j < height; j++) { crMemZero(dstRow, dst_row_length); for (i = 0; i < width; i++) { const GLint iByte = (i + srcPacking->skipPixels) / 8; const GLint iBit = (i + srcPacking->skipPixels) % 8; const GLubyte b = srcRow[iByte]; if (b & (1 << iBit)) dstRow[i / 8] |= (128 >> (i % 8)); } srcRow += src_row_length; dstRow += dst_row_length; } } else { /* unpack MSB first */ for (j = 0; j < height; j++) { crMemZero(dstRow, dst_row_length); for (i = 0; i < width; i++) { const GLint iByte = (i + srcPacking->skipPixels) / 8; const GLint iBit = (i + srcPacking->skipPixels) % 8; const GLubyte b = srcRow[iByte]; if (b & (128 >> iBit)) dstRow[i / 8] |= (128 >> (i % 8)); } srcRow += src_row_length; dstRow += dst_row_length; } } } } static int _tnum = 0; #pragma pack(1) typedef struct tgaheader_tag { char idlen; char colormap; char imagetype; short cm_index; short cm_len; char cm_entrysize; short x, y, w, h; char depth; char imagedesc; } tgaheader_t; #pragma pack() void crDumpTGA(GLint w, GLint h, GLvoid *data) { char fname[200]; if (!w || !h) return; sprintf(fname, "tex%i.tga", _tnum++); crDumpNamedTGA(fname, w, h, data); } void crDumpNamedTGA(const char* fname, GLint w, GLint h, GLvoid *data) { tgaheader_t header; FILE *out; out = fopen(fname, "w"); if (!out) crError("can't create %s!", fname); header.idlen = 0; header.colormap = 0; header.imagetype = 2; header.cm_index = 0; header.cm_len = 0; header.cm_entrysize = 0; header.x = 0; header.y = 0; header.w = w; header.h = h; header.depth = 32; header.imagedesc = 0x08; fwrite(&header, sizeof(header), 1, out); fwrite(data, w*h*4, 1, out); fclose(out); } void crDumpNamedTGAV(GLint w, GLint h, GLvoid *data, const char* fname, va_list va) { char szName[4096]; RTStrPrintfV(szName, sizeof(szName), fname, va); crDumpNamedTGA(szName, w, h, data); } void crDumpNamedTGAF(GLint w, GLint h, GLvoid *data, const char* fname, ...) { va_list va; va_start(va, fname); crDumpNamedTGAV(w, h, data, fname, va); va_end(va); }