/* * $Id$ * * $Date$ * $Revision$ * * (C) 1999 by Hyperion * All rights reserved * * This file is part of the MiniGL library project * See the file Licence.txt for more details * */ #include "sysinc.h" #include #include #include #ifdef MGL_TEXTURE_COMPRESSION #include #endif #include "util.h" #include "mgl_profileitems.h" // TODO - adopt fast W3D for all internal formats, fix conversion routines for performance static char rcsid[] UNUSED = "$Id$"; #if defined __GNUC__ && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) #define bswap32 __builtin_bswap32 #else #warning "GCC too old to use __builtin_bswap32(), so dropping to byte-wise unpack. Upgrade to GCC >= 4.4.2 to use the faster version." static inline unsigned int bswap32(unsigned int x) { return ((x << 24) & 0xff000000 ) | ((x << 8) & 0x00ff0000 ) | ((x >> 8) & 0x0000ff00 ) | ((x >> 24) & 0x000000ff ); } #endif _glTransferFn MGLSelectTransfer(GLenum format, struct GLpixel_state *pixelState); /* The following functions take a span of pixels and pack them into an * appropriate texture format. The input data is always of the form: * GLubyte r; * GLubyte g; * GLubyte b; * GLubyte a; * with a stride of stride. * The function will select the appropriate component(s) and write them into * it's destination tightly packed. */ #define A_COMPONENT 0 #define R_COMPONENT 1 #define G_COMPONENT 2 #define B_COMPONENT 3 // Indicates the write function that is a simple copy (i.e., the source and destination formats match) #define COPY_WRITEFUNC write_argb static void write_single_component(PROFILE_PROTO const GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { PROFILE_ENTRY(FID_TEX_WRITE_SINGLE_COMPONENT); if ((num|(uint32)to) & 3UL) { /* generic case */ while (num--) { *to++ = *from; from += stride; } } else { /* when the destination is 4-byte aligned and the count is a multiple of 4 we can optimise the conversion */ uint32 *to32 = (uint32*)to, out; num >>= 2; while (num--) { out = ((uint32)*from) << 24; from += stride; out |= ((uint32)*from) << 16; from += stride; out |= ((uint32)*from) << 8; from += stride; out |= ((uint32)*from); from += stride; *to32++ = out; } } PROFILE_EXIT(FID_TEX_WRITE_SINGLE_COMPONENT); } void write_a8(PROFILE_PROTO const GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { /* adjust the from pointer to the target component */ from += A_COMPONENT; write_single_component(PROFILE_PARAM from, to, num, stride); } void write_l8(PROFILE_PROTO const GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { /* adjust the from pointer to the target component */ from += R_COMPONENT; write_single_component(PROFILE_PARAM from, to, num, stride); } void write_l8a8(PROFILE_PROTO const GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { PROFILE_ENTRY(FID_TEX_WRITE_L8A8) GLsizei i; for (i = 0; i < num; i++) { *to++ = from[R_COMPONENT]; *to++ = from[A_COMPONENT]; from += stride; } PROFILE_EXIT(FID_TEX_WRITE_L8A8) } /* functionally equivalent */ #define write_i8 write_l8 #if 0 void write_i8(const GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { /* adjust the from pointer to the target component */ from += R_COMPONENT; write_single_component(from, to, num, stride); } #endif void write_rgb(PROFILE_PROTO const GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { PROFILE_ENTRY(FID_TEX_WRITE_RGB) if (((uint32)from|(uint32)to|num|stride) & 3) { while (num--) { *to++ = from[R_COMPONENT]; *to++ = from[G_COMPONENT]; *to++ = from[B_COMPONENT]; from += stride; } } else { /* when source, destination and stride are 4 byte aligned and we have a multiple of 4 count, * we can optimise the conversion by converting 4 32 bit reads into 3 32-bit writes */ uint32 *to32=(uint32*)to, mask=0x00FFFFFF, out1, out2, out3, tmp; num >>= 2; while (num--) { tmp = *(uint32*)from; from += stride; // tmp = xx R[0] G[0] B[0] out1 = tmp << 8; // out1 = R[0] G[0] B[0] 00 tmp = *(uint32*)from; from += stride; // tmp = xx R[1] G[1] B[1] out2 = tmp << 16; // out2 = G[1] B[1] 00 00 out1 |= ((tmp & mask) >> 16); // out1 = R[0] G[0] B[0] R[1] - OK tmp = *(uint32*)from; from += stride; // tmp = xx R[2] G[2] B[2] out2 |= ((tmp & mask) >> 8); // out2 = G[1] B[1] R[2] G[2] - OK out3 = tmp << 24; // out3 = B[2] 00 00 00 tmp = *(uint32*)from; from += stride; // tmp = xx R[3] G[3] B[3] out3 |= (tmp & mask); // out3 = B[2] R[3] G[3] B[3] - OK *to32++ = out1; *to32++ = out2; *to32++ = out3; } } PROFILE_EXIT(FID_TEX_WRITE_RGB) } void write_argb(PROFILE_PROTO const GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { PROFILE_ENTRY(FID_TEX_WRITE_ARGB) if ( ((uint32)from|(uint32)to|stride) & 3) { while (num--) { *to++ = from[A_COMPONENT]; *to++ = from[R_COMPONENT]; *to++ = from[G_COMPONENT]; *to++ = from[B_COMPONENT]; from += stride; } } else { /* source and destination are 4-byte aligned and the count is divisible by 4 */ uint32 *to32=(uint32*)to; const uint32 *from32=(const uint32*)from; while (num--) { *to32++ = *from32++; } } PROFILE_EXIT(FID_TEX_WRITE_ARGB) } void write_rgb5(PROFILE_PROTO const GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { PROFILE_ENTRY(FID_TEX_WRITE_RGB5) while (num--) { * (uint16 *)to = ((from[R_COMPONENT] & 0xf8) << 8) | ((from[G_COMPONENT] & 0xfc) << 3) | ((from[B_COMPONENT] & 0xf8) >> 3); to += 2; from += stride; } PROFILE_EXIT(FID_TEX_WRITE_RGB5) } void write_argb4(PROFILE_PROTO const GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { PROFILE_ENTRY(FID_TEX_WRITE_ARGB4) while (num--) { * (uint16 *)to = ((from[A_COMPONENT] & 0xf0) << 8) | ((from[R_COMPONENT] & 0xf0) << 4) | ((from[G_COMPONENT] & 0xf0) ) | ((from[B_COMPONENT] & 0xf0) >> 4); to += 2; from += stride; } PROFILE_EXIT(FID_TEX_WRITE_ARGB4) } void write_rgb5_a1(PROFILE_PROTO const GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { PROFILE_ENTRY(FID_TEX_WRITE_RGB5_A1) while (num--) { * (uint16 *)to = ((from[A_COMPONENT] & 0x80) << 8) | ((from[R_COMPONENT] & 0xf8) << 7) | ((from[G_COMPONENT] & 0xf8) << 2) | ((from[B_COMPONENT] & 0xf8) >> 3); to += 2; from += stride; } PROFILE_EXIT(FID_TEX_WRITE_RGB5_A1) } #ifdef MGL_TEXTURE_COMPRESSION void write_rgba(PROFILE_PROTO const GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { //PROFILE_ENTRY(FID_TEX_WRITE_ARGB) while (num--) { *to++ = from[R_COMPONENT]; *to++ = from[G_COMPONENT]; *to++ = from[B_COMPONENT]; *to++ = from[A_COMPONENT]; from += stride; } //PROFILE_EXIT(FID_TEX_WRITE_ARGB) } #endif /* Internalformat to Warp3D format mapping table. * For each possible internal format, this table lists an appropriate Warp3D * format. */ struct InternalToW3D i2w3d[] = { /* r g b a l i */ {GL_ALPHA, W3D_A8, 1, write_a8, 0, 0, 0, 8, 0, 0}, {GL_ALPHA8, W3D_A8, 1, write_a8, 0, 0, 0, 8, 0, 0}, {GL_LUMINANCE, W3D_L8, 1, write_l8, 0, 0, 0, 0, 8, 0}, {GL_LUMINANCE8, W3D_L8, 1, write_l8, 0, 0, 0, 0, 8, 0}, {1, W3D_L8, 1, write_l8, 0, 0, 0, 0, 8, 0}, {GL_LUMINANCE_ALPHA, W3D_L8A8, 2, write_l8a8, 0, 0, 0, 8, 8, 0}, {GL_LUMINANCE8_ALPHA8, W3D_L8A8, 2, write_l8a8, 0, 0, 0, 8, 8, 0}, {2, W3D_L8A8, 2, write_l8a8, 0, 0, 0, 8, 8, 0}, {GL_INTENSITY, W3D_I8, 1, write_i8, 0, 0, 0, 0, 0, 8}, {GL_RGB, W3D_R8G8B8, 3, write_rgb, 8, 8, 8, 0, 0, 0}, {3, W3D_R8G8B8, 3, write_rgb, 8, 8, 8, 0, 0, 0}, {GL_RGBA, W3D_A8R8G8B8, 4, write_argb, 8, 8, 8, 8, 0, 0}, {4, W3D_A8R8G8B8, 4, write_argb, 8, 8, 8, 8, 0, 0}, {GL_RGB5, W3D_R5G6B5, 2, write_rgb5, 5, 6, 7, 0, 0, 0}, {GL_RGB4, W3D_R5G6B5, 2, write_rgb5, 5, 6, 5, 0, 0, 0}, {GL_RGBA4, W3D_A4R4G4B4, 2, write_argb4, 4, 4, 4, 4, 0, 0}, {GL_RGB5_A1, W3D_A1R5G5B5, 2, write_rgb5_a1, 5, 5, 5, 1, 0, 0}, {GL_RGB8, W3D_R8G8B8, 3, write_rgb, 8, 8, 8, 0, 0, 0}, {GL_RGBA8, W3D_A8R8G8B8, 4, write_argb, 8, 8, 8, 8, 0, 0}, #ifdef MGL_TEXTURE_COMPRESSION {GL_RGB_S3TC, W3D_COMPRESSED_R5G6B5, 4, write_rgba, 5, 6, 5, 0, 0, 0}, {GL_RGB4_S3TC, W3D_COMPRESSED_R5G6B5, 4, write_rgba, 5, 6, 5, 0, 0, 0}, {GL_COMPRESSED_RGB_ARB, W3D_COMPRESSED_R5G6B5, 4, write_rgba, 5, 6, 5, 0, 0, 0}, {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, W3D_COMPRESSED_R5G6B5, 4, write_rgba, 5, 6, 5, 0, 0, 0}, {GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, W3D_COMPRESSED_R5G6B5, 4, write_rgba, 5, 6, 5, 1, 0, 0}, {GL_RGBA_S3TC, W3D_A4_COMPRESSED_R5G6B5, 4, write_rgba, 5, 6, 5, 4, 0, 0}, {GL_RGBA4_S3TC, W3D_A4_COMPRESSED_R5G6B5, 4, write_rgba, 5, 6, 5, 4, 0, 0}, {GL_COMPRESSED_RGBA_ARB, W3D_A4_COMPRESSED_R5G6B5, 4, write_rgba, 5, 6, 5, 4, 0, 0}, {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, W3D_A4_COMPRESSED_R5G6B5, 4, write_rgba, 5, 6, 5, 4, 0, 0}, {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, W3D_COMPRESSED_A8R5G6B5, 4, write_rgba, 5, 6, 5, 8, 0, 0}, /* the formats below are not compressed, and are only there for standard compliance */ {GL_COMPRESSED_ALPHA_ARB, W3D_A8, 1, write_a8, 0, 0, 0, 8, 0, 0}, {GL_COMPRESSED_LUMINANCE_ARB, W3D_L8, 1, write_l8, 0, 0, 0, 0, 8, 0}, {GL_COMPRESSED_LUMINANCE_ALPHA_ARB, W3D_L8A8, 2, write_l8a8, 0, 0, 0, 8, 8, 0}, {GL_COMPRESSED_INTENSITY_ARB, W3D_I8, 1, write_i8, 0, 0, 0, 0, 0, 8}, #endif {GL_NONE, 0, 0} }; /* Return index of appropriate entry */ int32 SelectInternalFormat(GLcontext context, GLenum internalformat) { int32 i; if (context->ConvertTo16Bit == GL_TRUE) { if (internalformat == GL_RGB || internalformat == 3) { internalformat = GL_RGB5; } else if (internalformat == GL_RGBA || internalformat == 4) { internalformat = GL_RGBA4; } } for (i = 0; i2w3d[i].internalformat != GL_NONE; i++) { if (i2w3d[i].internalformat == internalformat) { return i; } } return -1; } /* Format/Type unpack table. * This table has entries for format and type, and is used to select an unpack * function depending on format and type. Note that not all combinations are * supported */ #define REDBYTE(rgb) (((uint16)rgb & 0xF800) >> 8) #define GREENBYTE(rgb) (((uint16)rgb & 0x07E0) >> 3) #define BLUEBYTE(rgb) (((uint16)rgb & 0x001F) << 3) #define REDBYTEA(rgba) (((uint16)rgba & 0x0f00) >> 4) #define GREENBYTEA(rgba) (((uint16)rgba & 0x00f0)) #define BLUEBYTEA(rgba) (((uint16)rgba & 0x000f) << 4) #define ALPHABYTEA(rgba) (((uint16)rgba & 0xf000) >> 8) #define REDBYTE5551(rgba) (((uint16)rgba & 0x7C00) >> 7) #define GREENBYTE5551(rgba) (((uint16)rgba & 0x03e0) >> 2) #define BLUEBYTE5551(rgba) (((uint16)rgba & 0x001F) << 3) #define ALPHABYTE5551(rgba) (((uint16)rgba & 0x8000) ? 0xff : 0x00) #define UNSIGNED_BYTE(c) ((uint8)(((int32)(c)) + 128)) void unpack_ci_b(GLcontext context, const GLubyte *from, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_CI_B) GLsizei i; uint8 *pal = (uint8 *)context->PaletteData; if (context->PaletteFormat == GL_RGB) { // Palette is RGB for (i = 0; i < num; i++) { uint32 idx = *from++; to[R_COMPONENT] = pal[idx*3]; to[G_COMPONENT] = pal[idx*3+1]; to[B_COMPONENT] = pal[idx*3+2]; to[A_COMPONENT] = 0xff; to += 4; } } else { // Palette is RGBA for (i = 0; i < num; i++) { uint32 idx = *from++; to[R_COMPONENT] = pal[idx*4]; to[G_COMPONENT] = pal[idx*4+1]; to[B_COMPONENT] = pal[idx*4+2]; to[A_COMPONENT] = pal[idx*4+2]; to += 4; } } PROFILE_EXIT(FID_TEX_UNPACK_CI_B) } void unpack_a_b(GLcontext context, const GLubyte *from, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_A_B) GLsizei i; for (i = 0; i < num; i++) { to[A_COMPONENT] = *from++; to[R_COMPONENT] = 0; // FIXME: Really ? to[G_COMPONENT] = 0; // FIXME: Really ? to[B_COMPONENT] = 0; // FIXME: Really ? to += 4; } PROFILE_EXIT(FID_TEX_UNPACK_A_B) } void unpack_a_f(GLcontext context, const GLubyte *src, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_A_F) GLsizei i; const GLfloat *from = (const GLfloat*)src; for (i = 0; i < num; i++) { to[A_COMPONENT] = *from++ * 255; to[R_COMPONENT] = 0; // FIXME: Really ? to[G_COMPONENT] = 0; // FIXME: Really ? to[B_COMPONENT] = 0; // FIXME: Really ? to += 4; } PROFILE_EXIT(FID_TEX_UNPACK_A_F) } void unpack_rgb_b(GLcontext context, const GLubyte *from, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_RGB_B) GLsizei i; for (i = 0; i < num; i++) { to[R_COMPONENT] = *from++; to[G_COMPONENT] = *from++; to[B_COMPONENT] = *from++; to[A_COMPONENT] = 0xff; to += 4; } PROFILE_EXIT(FID_TEX_UNPACK_RGB_B) } void unpack_rgb_us565(GLcontext context, const GLubyte *from, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_RGB_US565) GLsizei i; GLushort *src = (GLushort *)from; for (i = 0; i < num; i++) { GLushort rgb = *src++; to[R_COMPONENT] = REDBYTE(rgb); to[G_COMPONENT] = GREENBYTE(rgb); to[B_COMPONENT] = BLUEBYTE(rgb); to[A_COMPONENT] = 0xff; to += 4; } PROFILE_EXIT(FID_TEX_UNPACK_RGB_US565) } void unpack_rgb_f(GLcontext context, const GLubyte *src, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_RGB_F) GLsizei i; const GLfloat *from = (const GLfloat*)src; for (i = 0; i < num; i++) { to[R_COMPONENT] = *from++ * 255; to[G_COMPONENT] = *from++ * 255; to[B_COMPONENT] = *from++ * 255; to[A_COMPONENT] = 0xff; to += 4; } PROFILE_EXIT(FID_TEX_UNPACK_RGB_F) } void unpack_rgba_b(GLcontext context, const GLubyte *from, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_RGBA_B) GLsizei i; uint32* to32 = (uint32*)to; uint32* from32 = (uint32*)from; for (i = 0; i < num; i++) { uint32 temp = *from32++; *to32++ = temp << 24 | temp >> 8; } PROFILE_EXIT(FID_TEX_UNPACK_RGBA_B) } void unpack_rgba_sb(GLcontext context, const GLbyte *from, GLubyte *to, GLsizei num) { //PROFILE_ENTRY(FID_TEX_UNPACK_RGBA_B) GLsizei i; for (i = 0; i < num; i++) { to[R_COMPONENT] = UNSIGNED_BYTE(*from++); to[G_COMPONENT] = UNSIGNED_BYTE(*from++); to[B_COMPONENT] = UNSIGNED_BYTE(*from++); to[A_COMPONENT] = UNSIGNED_BYTE(*from++); to += 4; } //PROFILE_EXIT(FID_TEX_UNPACK_RGBA_B) } void unpack_abgr_b(GLcontext context, const GLubyte *from, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_ABGR_B) GLsizei i; uint32* to32 = (uint32*)to; uint32* from32 = (uint32*)from; for (i = 0; i < num; i++) { uint32 temp = bswap32(*from32++); *to32++ = temp << 24 | temp >> 8; } PROFILE_EXIT(FID_TEX_UNPACK_ABGR_B) } void unpack_rgba_us4444(GLcontext context, const GLubyte *from, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_RGBA_US4444) GLsizei i; GLushort *src = (GLushort *)from; for (i = 0; i < num; i++) { GLushort rgb = *src++; to[R_COMPONENT] = REDBYTEA(rgb); to[G_COMPONENT] = GREENBYTEA(rgb); to[B_COMPONENT] = BLUEBYTEA(rgb); to[A_COMPONENT] = ALPHABYTEA(rgb); to += 4; } PROFILE_EXIT(FID_TEX_UNPACK_RGBA_US4444) } void unpack_rgba_f(GLcontext context, const GLubyte *src, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_RGBA_F) GLsizei i; const GLfloat *from = (const GLfloat*)src; for (i = 0; i < num; i++) { to[R_COMPONENT] = *from++ * 255; to[G_COMPONENT] = *from++ * 255; to[B_COMPONENT] = *from++ * 255; to[A_COMPONENT] = *from++ * 255; to += 4; } PROFILE_EXIT(FID_TEX_UNPACK_RGBA_F) } void unpack_bgr_b(GLcontext context, const GLubyte *from, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_BGR_B) GLsizei i; for (i = 0; i < num; i++) { to[B_COMPONENT] = *from++; to[G_COMPONENT] = *from++; to[R_COMPONENT] = *from++; to[A_COMPONENT] = 0xff; to += 4; } PROFILE_EXIT(FID_TEX_UNPACK_BGR_B) } void unpack_bgr_f(GLcontext context, const GLubyte *src, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_BGR_F) GLsizei i; const GLfloat *from = (const GLfloat*)src; for (i = 0; i < num; i++) { to[B_COMPONENT] = *from++ * 255; to[G_COMPONENT] = *from++ * 255; to[R_COMPONENT] = *from++ * 255; to[A_COMPONENT] = 0xff; to += 4; } PROFILE_EXIT(FID_TEX_UNPACK_BGR_F) } void unpack_bgra_b(GLcontext context, const GLubyte *from, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_ABGR_B) // ARGB is the native format, so BGRA just needs to be byte-swapped GLsizei i; const GLuint *src = (const GLuint *)from; GLuint *dst = (GLuint *)to; for (i = 0; i < num; i++) { *dst++ = bswap32(*src++); } PROFILE_EXIT(FID_TEX_UNPACK_ABGR_B) } #if 1 void unpack_argb_b(GLcontext context, const GLubyte *from, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_ARGB_B) // ARGB is the native format GLsizei i; const GLuint *src = (const GLuint *)from; GLuint *dst = (GLuint *)to; for (i = 0; i < num; i++) { *dst++ = *src++; } PROFILE_EXIT(FID_TEX_UNPACK_ARGB_B) } #else void unpack_argb_b(GLcontext context, const GLubyte *from, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_ARGB_B) GLsizei i; for (i = 0; i < num; i++) { to[A_COMPONENT] = *from++; to[R_COMPONENT] = *from++; to[G_COMPONENT] = *from++; to[B_COMPONENT] = *from++; to += 4; } PROFILE_EXIT(FID_TEX_UNPACK_ARGB_B) } #endif void unpack_bgra_1555rev(GLcontext context, const GLubyte *from, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_BGRA_1555REV) GLsizei i; GLushort *src = (GLushort *)from; for (i = 0; i < num; i++) { GLushort rgb = *src++; to[R_COMPONENT] = (GLubyte)REDBYTE5551(rgb); to[G_COMPONENT] = (GLubyte)GREENBYTE5551(rgb); to[B_COMPONENT] = (GLubyte)BLUEBYTE5551(rgb); to[A_COMPONENT] = (GLubyte)ALPHABYTE5551(rgb); to += 4; } PROFILE_EXIT(FID_TEX_UNPACK_BGRA_1555REV) } void unpack_bgra_f(GLcontext context, const GLubyte *src, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_BGRA_F) GLsizei i; const GLfloat *from = (const GLfloat*)src; for (i = 0; i < num; i++) { to[B_COMPONENT] = *from++ * 255; to[G_COMPONENT] = *from++ * 255; to[R_COMPONENT] = *from++ * 255; to[A_COMPONENT] = *from++ * 255; to += 4; } PROFILE_EXIT(FID_TEX_UNPACK_BGRA_F) } void unpack_l_b(GLcontext context, const GLubyte *from, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_L_B) GLsizei i; for (i = 0; i < num; i++) { to[R_COMPONENT] = *from++; to[A_COMPONENT] = 0; // FIXME: Really ? to[G_COMPONENT] = 0; // FIXME: Really ? to[B_COMPONENT] = 0; // FIXME: Really ? to += 4; } PROFILE_EXIT(FID_TEX_UNPACK_L_B) } void unpack_l_f(GLcontext context, const GLubyte *src, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_L_F) GLsizei i; const GLfloat *from = (const GLfloat*)src; for (i = 0; i < num; i++) { to[R_COMPONENT] = *from++ * 255; to[A_COMPONENT] = 0; // FIXME: Really ? to[G_COMPONENT] = 0; // FIXME: Really ? to[B_COMPONENT] = 0; // FIXME: Really ? to += 4; } PROFILE_EXIT(FID_TEX_UNPACK_L_F) } void unpack_la_b(GLcontext context, const GLubyte *from, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_LA_B) GLsizei i; for (i = 0; i < num; i++) { to[R_COMPONENT] = *from++; to[A_COMPONENT] = *from++; to[G_COMPONENT] = 0; // FIXME: Really ? to[B_COMPONENT] = 0; // FIXME: Really ? to += 4; } PROFILE_EXIT(FID_TEX_UNPACK_LA_B) } void unpack_la_f(GLcontext context, const GLubyte *src, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_LA_F) GLsizei i; const GLfloat *from = (const GLfloat*)src; for (i = 0; i < num; i++) { to[R_COMPONENT] = *from++ * 255; to[A_COMPONENT] = *from++ * 255; to[G_COMPONENT] = 0; // FIXME: Really ? to[B_COMPONENT] = 0; // FIXME: Really ? to += 4; } PROFILE_EXIT(FID_TEX_UNPACK_LA_F) } void unpack_bitmap(GLcontext context, const GLubyte *from, GLubyte *to, GLsizei num) { PROFILE_ENTRY(FID_TEX_UNPACK_BITMAP) /* FIXME: Honor Unpack skip pixels */ GLsizei i, j; unsigned int mask; GLuint *dst = (GLuint *)to; for (i = 0; i < num/8; i++) { mask = 0x80; GLubyte cur = *from++; for (j = 0; j < 8; j++) { if (cur & mask) { *dst++ = 0xffffffff; } else { *dst++ = 0; } mask >>= 1; } } PROFILE_EXIT(FID_TEX_UNPACK_BITMAP) } struct FormatTypeToUnpack ft2u[] = { {GL_COLOR_INDEX, GL_UNSIGNED_BYTE, unpack_ci_b, 1}, {GL_ALPHA, GL_UNSIGNED_BYTE, unpack_a_b, 1}, /* {GL_ALPHA, GL_UNSIGNED_SHORT_4_4_4_4, 0, 1}, */ {GL_ALPHA, GL_FLOAT, unpack_a_f, 1}, {GL_RGB, GL_UNSIGNED_BYTE, unpack_rgb_b, 3}, {GL_RGB, GL_UNSIGNED_SHORT_5_6_5, unpack_rgb_us565, 2}, {GL_RGB, GL_FLOAT, unpack_rgb_f, 3}, {GL_RGBA, GL_BYTE, (unpack_func)unpack_rgba_sb, 4}, {GL_RGBA, GL_UNSIGNED_BYTE, unpack_rgba_b, 4}, {GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, unpack_rgba_us4444, 2}, {GL_RGBA, GL_FLOAT, unpack_rgba_f, 4}, {GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, unpack_abgr_b, 4}, {GL_BGR, GL_UNSIGNED_BYTE, unpack_bgr_b, 3}, /* {GL_BGR, GL_UNSIGNED_SHORT_5_6_5, 0, 2}, */ {GL_BGR, GL_FLOAT, unpack_bgr_f, 3}, {GL_BGRA, GL_UNSIGNED_BYTE, unpack_bgra_b, 4}, {GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, unpack_bgra_1555rev, 2}, {GL_BGRA, GL_FLOAT, unpack_bgra_f, 4}, /* {GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4, 0, 2}, */ {GL_LUMINANCE, GL_UNSIGNED_BYTE, unpack_l_b, 1}, {GL_LUMINANCE, GL_FLOAT, unpack_l_f, 1}, {GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, unpack_la_b, 2}, /* {GL_LUMINANCE_ALPHA, GL_UNSIGNED_SHORT_4_4_4_4, 0, 2}, */ {GL_LUMINANCE_ALPHA, GL_FLOAT, unpack_la_f, 2}, {GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, unpack_argb_b, 4}, {GL_NONE, GL_NONE, 0, 0} }; int32 SelectUnpacker(GLcontext context, GLenum format, GLenum type) { int32 i; for (i = 0; ft2u[i].format != GL_NONE; i++) { if (format == ft2u[i].format && type == ft2u[i].type) { return i; } } return -1; } BOOL EnsureConvertBuffer(GLcontext context, uint32 dataSize) { if (context->ConvertBufferSize < dataSize) { dprintf("ConvertBuffer too small (%ld), reallocating (%ld)\n", context->ConvertBufferSize, dataSize); if (context->ConvertBuffer) { FreeVecInternal(context->ConvertBuffer); } context->ConvertBuffer = AllocVecInternal(dataSize,MEMF_SHARED); if (!context->ConvertBuffer) { dprintf("Couldn't allocate ConvertBuffer\n"); context->ConvertBufferSize = 0; return FALSE; } context->ConvertBufferSize = dataSize; } return TRUE; } #ifdef MGL_TEXTURE_COMPRESSION BOOL CompressImage(GLcontext context, GLubyte *dest, GLuint width, GLuint height, GLenum internalformat) { int blocks_w = (width + 3) / 4; int blocks_h = (height + 3) / 4; int blocksize; int buffersize; switch (internalformat) { case GL_RGB_S3TC: case GL_RGB4_S3TC: case GL_COMPRESSED_RGB_ARB: internalformat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: blocksize = 8; break; case GL_RGBA_S3TC: case GL_RGBA4_S3TC: case GL_COMPRESSED_RGBA_ARB: internalformat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: blocksize = 16; break; default: case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: blocksize = 16; break; } buffersize = blocks_w * blocks_h * blocksize; if (!EnsureConvertBuffer(context, buffersize)) { return FALSE; } tx_compress_dxtn(4, width, height, dest, internalformat, context->ConvertBuffer, blocks_w * blocksize); memcpy(dest, context->ConvertBuffer, buffersize); return TRUE; } #endif uint32 MGLConvert(GLcontext context, GLenum internalformat, GLuint width, GLuint height, GLenum format, GLenum type, GLubyte *source, GLubyte *dest) { int32 internal; int32 unpack; int h; int srcWidth; int dstWidth; #ifdef MGL_TEXTURE_COMPRESSION GLubyte *dstStart; #endif PROFILE_ENTRY(FID_MGL_CONVERT) _glTransferFn transfer = MGLSelectTransfer(format, &context->pixel); internal = SelectInternalFormat(context, internalformat); unpack = SelectUnpacker(context, format, type); if (unpack == -1) { dprintf("Unknown format/type\n"); PROFILE_EXIT(FID_MGL_CONVERT) return 0; } if (internal == -1) { dprintf("Unknown internal format\n"); PROFILE_EXIT(FID_MGL_CONVERT) return 0; } if (!EnsureConvertBuffer(context, 4*width)) { PROFILE_EXIT(FID_MGL_CONVERT) return 0; } /* Select correct source stride, taking care of the unpack row length */ srcWidth = width * ft2u[unpack].stride; if (context->pixel_store.unpack.row_length > 0) { srcWidth = context->pixel_store.unpack.row_length * ft2u[unpack].stride; } /* Destination stride is the width time the texel size */ dstWidth = i2w3d[internal].w3dBpp * width; /* Compute the address of the first pixel (taking skip pixels/rows into * account) */ source += context->pixel_store.unpack.skip_rows * srcWidth + context->pixel_store.unpack.skip_pixels * ft2u[unpack].stride; #ifdef MGL_TEXTURE_COMPRESSION dstStart = dest; #endif /* Now convert */ // dprintf("Converting from source = %p via convertBuffer = %p to convertBuffer = %p\n", // source, context->ConvertBuffer, dest); // dprintf("Width = %ld, Height = %ld\n", width, height); if(i2w3d[internal].write == COPY_WRITEFUNC) { // The unpack function unpacks pixels to the destination format, so we can skip the write step for (h = 0; h < height; h++) { ft2u[unpack].unpack(context, source, dest, width); if (transfer) { transfer(context, width, dest, &context->pixel); } source += srcWidth; dest += dstWidth; } } else { // The destination format isn't the native unpack format, so need to use the full conversion pipeline for (h = 0; h < height; h++) { ft2u[unpack].unpack(context, source, context->ConvertBuffer, width); if (transfer) { transfer(context, width, context->ConvertBuffer, &context->pixel); } i2w3d[internal].write(PROFILE_PARAM context->ConvertBuffer, dest, width, 4); source += srcWidth; dest += dstWidth; } } #ifdef MGL_TEXTURE_COMPRESSION if (IS_COMPRESSED_FORMAT(i2w3d[internal].w3dFormat)) { if (!CompressImage(context, dstStart, width, height, i2w3d[internal].internalformat)) { PROFILE_EXIT(FID_MGL_CONVERT) return W3D_R8G8B8A8; } } #endif // dprintf("Wrote %ld bytes of data\n", height*dstWidth); PROFILE_EXIT(FID_MGL_CONVERT) return i2w3d[internal].w3dFormat; } BOOL MGLUpdate(GLcontext context, GLenum internalformat, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, const GLubyte *source, GLubyte *dest, GLsizei destWidth, GLenum format, GLenum type) { int32 internal; int32 unpacker; int h; int srcWidth; int dstWidth; #ifdef MGL_TEXTURE_COMPRESSION GLubyte *dstStart; #endif PROFILE_ENTRY(FID_MGL_UPDATE) _glTransferFn transfer = MGLSelectTransfer(format, &context->pixel); internal = SelectInternalFormat(context, internalformat); unpacker = SelectUnpacker(context, format, type); if (unpacker == -1 || internal == -1 || source == 0 || dest == 0) { PROFILE_EXIT(FID_MGL_UPDATE) return FALSE; } if (!EnsureConvertBuffer(context, 4*width)) { PROFILE_EXIT(FID_MGL_UPDATE) return FALSE; } /* Select correct source stride, taking care of the unpack row length */ srcWidth = width * ft2u[unpacker].stride; if (context->pixel_store.unpack.row_length > 0) { srcWidth = context->pixel_store.unpack.row_length * ft2u[unpacker].stride; } /* Destination stride is the width time the texel size */ dstWidth = i2w3d[internal].w3dBpp * destWidth; /* Compute the address of the first pixel (taking skip pixels/rows into * account). * FIXME: Is this really true here ? */ // source += context->CurUnpackSkipRows * srcWidth // + context->CurUnpackSkipPixels * ft2u[unpack].stride; source += context->pixel_store.unpack.skip_rows *srcWidth + context->pixel_store.unpack.skip_pixels *ft2u[unpacker].stride; /* Compute destination pixels address */ dest += dstWidth * yoffset + i2w3d[internal].w3dBpp * xoffset; #ifdef MGL_TEXTURE_COMPRESSION if (IS_COMPRESSED_FORMAT(i2w3d[internal].w3dFormat) && (xoffset % 16 || yoffset % 16 || width % 16 || height % 16)) { dprintf("Compressed textures can only be updated on 16-pixel boundaries. xoffset %d yoffset %d width %d height %d\n", xoffset, yoffset, width, height); PROFILE_EXIT(FID_MGL_UPDATE) return FALSE; } dstStart = dest; #endif /* Now convert */ if(i2w3d[internal].write == COPY_WRITEFUNC) { // The unpack function unpacks pixels to the destination format, so we can skip the write step for (h = 0; h < height; h++) { ft2u[unpacker].unpack(context, source, dest, width); if (transfer) { transfer(context, width, dest, &context->pixel); } source += srcWidth; dest += dstWidth; } } else { // The destination format isn't the native unpack format, so need to use the full conversion pipeline for (h = 0; h < height; h++) { ft2u[unpacker].unpack(context, source, context->ConvertBuffer, width); if (transfer) { transfer(context, width, context->ConvertBuffer, &context->pixel); } i2w3d[internal].write(PROFILE_PARAM context->ConvertBuffer, dest, width, 4); source += srcWidth; dest += dstWidth; } } #ifdef MGL_TEXTURE_COMPRESSION if (IS_COMPRESSED_FORMAT(i2w3d[internal].w3dFormat)) { if (!CompressImage(context, dstStart, width, height, i2w3d[internal].internalformat)) { PROFILE_EXIT(FID_MGL_CONVERT) return FALSE; } } #endif PROFILE_EXIT(FID_MGL_UPDATE) return TRUE; }