/* * $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 static char rcsid[] UNUSED = "$Id$"; /* 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 R_COMPONENT 0 #define G_COMPONENT 1 #define B_COMPONENT 2 #define A_COMPONENT 3 void write_a8(GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { GLsizei i; for (i = 0; i < num; i++) { *to++ = from[A_COMPONENT]; from += stride; } } void write_l8(GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { GLsizei i; for (i = 0; i < num; i++) { *to++ = from[R_COMPONENT]; from += stride; } } void write_l8a8(GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { GLsizei i; for (i = 0; i < num; i++) { *to++ = from[R_COMPONENT]; *to++ = from[A_COMPONENT]; from += stride; } } void write_i8(GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { GLsizei i; for (i = 0; i < num; i++) { *to++ = from[R_COMPONENT]; from += stride; } } void write_rgb(GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { GLsizei i; for (i = 0; i < num; i++) { *to++ = from[R_COMPONENT]; *to++ = from[G_COMPONENT]; *to++ = from[B_COMPONENT]; from += stride; } } void write_rgba(GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { GLsizei i; for (i = 0; i < num; i++) { *to++ = from[A_COMPONENT]; *to++ = from[R_COMPONENT]; *to++ = from[G_COMPONENT]; *to++ = from[B_COMPONENT]; from += stride; } } void write_rgb5(GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { GLsizei i; for (i = 0; i < num; i++) { * (uint16 *)to = ((from[R_COMPONENT] & 0xf8) << 8) | ((from[G_COMPONENT] & 0xfc) << 3) | ((from[B_COMPONENT] & 0xf8) >> 3); to += 2; from += stride; } } void write_rgba4(GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { GLsizei i; for (i = 0; i < num; i++) { * (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; } } void write_rgb5_a1(GLubyte *from, GLubyte *to, GLsizei num, GLsizei stride) { GLsizei i; for (i = 0; i < num; i++) { * (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; } } /* 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_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}, {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_rgba, 8, 8, 8, 8, 0, 0}, {4, W3D_A8R8G8B8, 4, write_rgba, 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_rgba4, 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_rgba, 8, 8, 8, 0, 0, 0}, {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) (((UWORD)rgb & 0xF800) >> 8) #define GREENBYTE(rgb) (((UWORD)rgb & 0x07E0) >> 3) #define BLUEBYTE(rgb) (((UWORD)rgb & 0x001F) << 3) #define REDBYTEA(rgba) (((UWORD)rgba & 0x0f00) >> 4) #define GREENBYTEA(rgba) (((UWORD)rgba & 0x00f0)) #define BLUEBYTEA(rgba) (((UWORD)rgba & 0x000f) << 4) #define ALPHABYTEA(rgba) (((UWORD)rgba & 0xf000) >> 8) #define REDBYTE5551(rgba) (((UWORD)rgba & 0x7C00) >> 7) #define GREENBYTE5551(rgba) (((UWORD)rgba & 0x03e0) >> 2) #define BLUEBYTE5551(rgba) (((UWORD)rgba & 0x001F) << 3) #define ALPHABYTE5551(rgba) (((UWORD)rgba & 0x8000) ? 0xff : 0x00) void unpack_ci_b(void *_context, GLubyte *from, GLubyte *to, GLsizei num) { GLsizei i; GLcontext context = (GLcontext)_context; 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; } } } void unpack_a_b(void *context, GLubyte *from, GLubyte *to, GLsizei num) { 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; } } void unpack_a_f(void *context, GLubyte *src, GLubyte *to, GLsizei num) { GLsizei i; GLfloat *from = (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; } } void unpack_rgb_b(void *context, GLubyte *from, GLubyte *to, GLsizei num) { 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; } } void unpack_rgb_us565(void *context, GLubyte *from, GLubyte *to, GLsizei num) { 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; } } void unpack_rgb_f(void *context, GLubyte *src, GLubyte *to, GLsizei num) { GLsizei i; GLfloat *from = (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; } } #if 1 void unpack_rgba_b(void *context, GLubyte *from, GLubyte *to, GLsizei num) { GLsizei i; GLuint *src = (GLuint *)from; GLuint *dst = (GLuint *)to; for (i = 0; i < num; i++) *dst++ = *src++; } #else void unpack_rgba_b(void *context, GLubyte *from, GLubyte *to, GLsizei num) { 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; } } #endif void unpack_rgba_us4444(void *context, GLubyte *from, GLubyte *to, GLsizei num) { 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; } } void unpack_rgba_f(void *context, GLubyte *src, GLubyte *to, GLsizei num) { GLsizei i; GLfloat *from = (GLfloat*)src; for (i = 0; i < num; i++) { to[A_COMPONENT] = *from++ * 255; to[R_COMPONENT] = *from++ * 255; to[G_COMPONENT] = *from++ * 255; to[B_COMPONENT] = *from++ * 255; to += 4; } } void unpack_bgr_b(void *context, GLubyte *from, GLubyte *to, GLsizei num) { 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; } } void unpack_bgr_f(void *context, GLubyte *src, GLubyte *to, GLsizei num) { GLsizei i; GLfloat *from = (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; } } void unpack_bgra_b(void *context, GLubyte *from, GLubyte *to, GLsizei num) { GLsizei i; for (i = 0; i < num; i++) { to[B_COMPONENT] = *from++; to[G_COMPONENT] = *from++; to[R_COMPONENT] = *from++; to[A_COMPONENT] = *from++; to += 4; } } void unpack_bgra_1555rev(void *context, GLubyte *from, GLubyte *to, GLsizei num) { 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; } } void unpack_bgra_f(void *context, GLubyte *src, GLubyte *to, GLsizei num) { GLsizei i; GLfloat *from = (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; } } void unpack_l_b(void *context, GLubyte *from, GLubyte *to, GLsizei num) { 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; } } void unpack_l_f(void *context, GLubyte *src, GLubyte *to, GLsizei num) { GLsizei i; GLfloat *from = (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; } } void unpack_la_b(void *context, GLubyte *from, GLubyte *to, GLsizei num) { 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; } } void unpack_la_f(void *context, GLubyte *src, GLubyte *to, GLsizei num) { GLsizei i; GLfloat *from = (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; } } void unpack_bitmap(void *context, GLubyte *from, GLubyte *to, GLsizei num) { /* 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; } } } 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_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_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_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; } 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; internal = SelectInternalFormat(context, internalformat); unpack = SelectUnpacker(context, format, type); if (unpack == -1) { dprintf("Unknown format/type\n"); return 0; } if (internal == -1) { dprintf("Unknown internal format\n"); return 0; } if (context->ConvertBufferSize < 4*width || !context->ConvertBuffer) { dprintf("ConvertBuffer too small (%ld), reallocating (%ld)\n", context->ConvertBufferSize, 4*width); if (context->ConvertBuffer) IExec->FreeVec(context->ConvertBuffer); context->ConvertBuffer = IExec->AllocVec(4*width, MEMF_ANY); context->ConvertBufferSize = 4*width; } /* 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; /* 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); for (h = 0; h < height; h++) { ft2u[unpack].unpack((GLcontext)context, source, context->ConvertBuffer, width); i2w3d[internal].write(context->ConvertBuffer, dest, width, 4); source += srcWidth; dest += dstWidth; } // dprintf("Wrote %ld bytes of data\n", height*dstWidth); return i2w3d[internal].w3dFormat; } void MGLUpdate(GLcontext context, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLubyte *source, GLubyte *dest, GLsizei destWidth, GLint internal, GLint unpacker) { int h; int srcWidth; int dstWidth; if (unpacker == -1 || internal == -1 || source == 0 || dest == 0) return; if (context->ConvertBufferSize < 4*width || !context->ConvertBuffer) { if (context->ConvertBuffer) IExec->FreeVec(context->ConvertBuffer); context->ConvertBuffer = IExec->AllocVec(4*width, MEMF_ANY); context->ConvertBufferSize = 4*width; } /* 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; /* Now convert */ for (h = 0; h < height; h++) { ft2u[unpacker].unpack((GLcontext)context, source, context->ConvertBuffer, width); i2w3d[internal].write(context->ConvertBuffer, dest, width, 4); source += srcWidth; dest += dstWidth; } }