texcompress_cpal.c revision 7179a822628963d8cfa0817cf072c5acb70638a7
1/************************************************************************** 2 * 3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * All Rights Reserved. 5 * 6 **************************************************************************/ 7 8 9/** 10 * Code to convert compressed/paletted texture images to ordinary images. 11 * See the GL_OES_compressed_paletted_texture spec at 12 * http://khronos.org/registry/gles/extensions/OES/OES_compressed_paletted_texture.txt 13 * 14 * XXX this makes it impossible to add hardware support... 15 */ 16 17 18#include "glheader.h" 19#include "compiler.h" /* for ASSERT */ 20#include "context.h" 21#include "mtypes.h" 22#include "imports.h" 23#include "pixelstore.h" 24#include "teximage.h" 25#include "texpal.h" 26 27#if FEATURE_ES 28 29 30static const struct cpal_format_info { 31 GLenum cpal_format; 32 GLenum format; 33 GLenum type; 34 GLuint palette_size; 35 GLuint size; 36} formats[] = { 37 { GL_PALETTE4_RGB8_OES, GL_RGB, GL_UNSIGNED_BYTE, 16, 3 }, 38 { GL_PALETTE4_RGBA8_OES, GL_RGBA, GL_UNSIGNED_BYTE, 16, 4 }, 39 { GL_PALETTE4_R5_G6_B5_OES, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 16, 2 }, 40 { GL_PALETTE4_RGBA4_OES, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 16, 2 }, 41 { GL_PALETTE4_RGB5_A1_OES, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 16, 2 }, 42 { GL_PALETTE8_RGB8_OES, GL_RGB, GL_UNSIGNED_BYTE, 256, 3 }, 43 { GL_PALETTE8_RGBA8_OES, GL_RGBA, GL_UNSIGNED_BYTE, 256, 4 }, 44 { GL_PALETTE8_R5_G6_B5_OES, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 256, 2 }, 45 { GL_PALETTE8_RGBA4_OES, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 256, 2 }, 46 { GL_PALETTE8_RGB5_A1_OES, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 256, 2 } 47}; 48 49 50/** 51 * Get a color/entry from the palette. 52 */ 53static GLuint 54get_palette_entry(const struct cpal_format_info *info, const GLubyte *palette, 55 GLuint index, GLubyte *pixel) 56{ 57 memcpy(pixel, palette + info->size * index, info->size); 58 return info->size; 59} 60 61 62/** 63 * Convert paletted texture to color texture. 64 */ 65static void 66paletted_to_color(const struct cpal_format_info *info, const GLubyte *palette, 67 const void *indices, GLuint num_pixels, GLubyte *image) 68{ 69 GLubyte *pix = image; 70 GLuint remain, i; 71 72 if (info->palette_size == 16) { 73 /* 4 bits per index */ 74 const GLubyte *ind = (const GLubyte *) indices; 75 76 /* two pixels per iteration */ 77 remain = num_pixels % 2; 78 for (i = 0; i < num_pixels / 2; i++) { 79 pix += get_palette_entry(info, palette, (ind[i] >> 4) & 0xf, pix); 80 pix += get_palette_entry(info, palette, ind[i] & 0xf, pix); 81 } 82 if (remain) { 83 get_palette_entry(info, palette, (ind[i] >> 4) & 0xf, pix); 84 } 85 } 86 else { 87 /* 8 bits per index */ 88 const GLubyte *ind = (const GLubyte *) indices; 89 for (i = 0; i < num_pixels; i++) 90 pix += get_palette_entry(info, palette, ind[i], pix); 91 } 92} 93 94 95static const struct cpal_format_info * 96cpal_get_info(GLint level, GLenum internalFormat, 97 GLsizei width, GLsizei height, GLsizei imageSize) 98{ 99 const struct cpal_format_info *info; 100 GLint lvl, num_levels; 101 GLsizei w, h, expect_size; 102 103 info = &formats[internalFormat - GL_PALETTE4_RGB8_OES]; 104 ASSERT(info->cpal_format == internalFormat); 105 106 if (level > 0) { 107 _mesa_error(_mesa_get_current_context(), GL_INVALID_VALUE, 108 "glCompressedTexImage2D(level=%d)", level); 109 return NULL; 110 } 111 112 num_levels = -level + 1; 113 expect_size = info->palette_size * info->size; 114 for (lvl = 0; lvl < num_levels; lvl++) { 115 w = width >> lvl; 116 if (!w) 117 w = 1; 118 h = height >> lvl; 119 if (!h) 120 h = 1; 121 122 if (info->palette_size == 16) 123 expect_size += (w * h + 1) / 2; 124 else 125 expect_size += w * h; 126 } 127 if (expect_size > imageSize) { 128 _mesa_error(_mesa_get_current_context(), GL_INVALID_VALUE, 129 "glCompressedTexImage2D(imageSize=%d)", imageSize); 130 return NULL; 131 } 132 return info; 133} 134 135/** 136 * Convert a call to glCompressedTexImage2D() where internalFormat is a 137 * compressed palette format into a regular GLubyte/RGBA glTexImage2D() call. 138 */ 139void 140_mesa_cpal_compressed_teximage2d(GLenum target, GLint level, 141 GLenum internalFormat, 142 GLsizei width, GLsizei height, 143 GLsizei imageSize, const void *palette) 144{ 145 const struct cpal_format_info *info; 146 GLint lvl, num_levels; 147 const GLubyte *indices; 148 GLint saved_align, align; 149 GET_CURRENT_CONTEXT(ctx); 150 151 info = cpal_get_info(level, internalFormat, width, height, imageSize); 152 if (!info) 153 return; 154 155 info = &formats[internalFormat - GL_PALETTE4_RGB8_OES]; 156 ASSERT(info->cpal_format == internalFormat); 157 num_levels = -level + 1; 158 159 /* first image follows the palette */ 160 indices = (const GLubyte *) palette + info->palette_size * info->size; 161 162 saved_align = ctx->Unpack.Alignment; 163 align = saved_align; 164 165 for (lvl = 0; lvl < num_levels; lvl++) { 166 GLsizei w, h; 167 GLuint num_texels; 168 GLubyte *image = NULL; 169 170 w = width >> lvl; 171 if (!w) 172 w = 1; 173 h = height >> lvl; 174 if (!h) 175 h = 1; 176 num_texels = w * h; 177 if (w * info->size % align) { 178 _mesa_PixelStorei(GL_UNPACK_ALIGNMENT, 1); 179 align = 1; 180 } 181 182 /* allocate and fill dest image buffer */ 183 if (palette) { 184 image = (GLubyte *) malloc(num_texels * info->size); 185 paletted_to_color(info, palette, indices, num_texels, image); 186 } 187 188 _mesa_TexImage2D(target, lvl, info->format, w, h, 0, 189 info->format, info->type, image); 190 if (image) 191 free(image); 192 193 /* advance index pointer to point to next src mipmap */ 194 if (info->palette_size == 16) 195 indices += (num_texels + 1) / 2; 196 else 197 indices += num_texels; 198 } 199 200 if (saved_align != align) 201 _mesa_PixelStorei(GL_UNPACK_ALIGNMENT, saved_align); 202} 203 204#endif 205