1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright 2008 VMware, Inc. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the "Software"), 8848b8605Smrg * to deal in the Software without restriction, including without limitation 9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 11848b8605Smrg * Software is furnished to do so, subject to the following conditions: 12848b8605Smrg * 13848b8605Smrg * The above copyright notice and this permission notice shall be included 14848b8605Smrg * in all copies or substantial portions of the Software. 15848b8605Smrg * 16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 23848b8605Smrg */ 24848b8605Smrg 25848b8605Smrg/** 26848b8605Smrg * Code to convert compressed/paletted texture images to ordinary images. 27848b8605Smrg * See the GL_OES_compressed_paletted_texture spec at 28848b8605Smrg * http://khronos.org/registry/gles/extensions/OES/OES_compressed_paletted_texture.txt 29848b8605Smrg * 30848b8605Smrg * XXX this makes it impossible to add hardware support... 31848b8605Smrg */ 32848b8605Smrg 33848b8605Smrg 34848b8605Smrg#include "glheader.h" 35848b8605Smrg#include "context.h" 36848b8605Smrg#include "mtypes.h" 37848b8605Smrg#include "imports.h" 38848b8605Smrg#include "pixelstore.h" 39848b8605Smrg#include "texcompress_cpal.h" 40848b8605Smrg#include "teximage.h" 41848b8605Smrg 42848b8605Smrg 43848b8605Smrgstatic const struct cpal_format_info { 44848b8605Smrg GLenum cpal_format; 45848b8605Smrg GLenum format; 46848b8605Smrg GLenum type; 47848b8605Smrg GLuint palette_size; 48848b8605Smrg GLuint size; 49848b8605Smrg} formats[] = { 50848b8605Smrg { GL_PALETTE4_RGB8_OES, GL_RGB, GL_UNSIGNED_BYTE, 16, 3 }, 51848b8605Smrg { GL_PALETTE4_RGBA8_OES, GL_RGBA, GL_UNSIGNED_BYTE, 16, 4 }, 52848b8605Smrg { GL_PALETTE4_R5_G6_B5_OES, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 16, 2 }, 53848b8605Smrg { GL_PALETTE4_RGBA4_OES, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 16, 2 }, 54848b8605Smrg { GL_PALETTE4_RGB5_A1_OES, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 16, 2 }, 55848b8605Smrg { GL_PALETTE8_RGB8_OES, GL_RGB, GL_UNSIGNED_BYTE, 256, 3 }, 56848b8605Smrg { GL_PALETTE8_RGBA8_OES, GL_RGBA, GL_UNSIGNED_BYTE, 256, 4 }, 57848b8605Smrg { GL_PALETTE8_R5_G6_B5_OES, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 256, 2 }, 58848b8605Smrg { GL_PALETTE8_RGBA4_OES, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 256, 2 }, 59848b8605Smrg { GL_PALETTE8_RGB5_A1_OES, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 256, 2 } 60848b8605Smrg}; 61848b8605Smrg 62848b8605Smrg 63848b8605Smrg/** 64848b8605Smrg * Get a color/entry from the palette. 65848b8605Smrg */ 66848b8605Smrgstatic GLuint 67848b8605Smrgget_palette_entry(const struct cpal_format_info *info, const GLubyte *palette, 68848b8605Smrg GLuint index, GLubyte *pixel) 69848b8605Smrg{ 70848b8605Smrg memcpy(pixel, palette + info->size * index, info->size); 71848b8605Smrg return info->size; 72848b8605Smrg} 73848b8605Smrg 74848b8605Smrg 75848b8605Smrg/** 76848b8605Smrg * Convert paletted texture to color texture. 77848b8605Smrg */ 78848b8605Smrgstatic void 79848b8605Smrgpaletted_to_color(const struct cpal_format_info *info, const GLubyte *palette, 80848b8605Smrg const void *indices, GLuint num_pixels, GLubyte *image) 81848b8605Smrg{ 82848b8605Smrg GLubyte *pix = image; 83848b8605Smrg GLuint remain, i; 84848b8605Smrg 85848b8605Smrg if (info->palette_size == 16) { 86848b8605Smrg /* 4 bits per index */ 87848b8605Smrg const GLubyte *ind = (const GLubyte *) indices; 88848b8605Smrg 89848b8605Smrg /* two pixels per iteration */ 90848b8605Smrg remain = num_pixels % 2; 91848b8605Smrg for (i = 0; i < num_pixels / 2; i++) { 92848b8605Smrg pix += get_palette_entry(info, palette, (ind[i] >> 4) & 0xf, pix); 93848b8605Smrg pix += get_palette_entry(info, palette, ind[i] & 0xf, pix); 94848b8605Smrg } 95848b8605Smrg if (remain) { 96848b8605Smrg get_palette_entry(info, palette, (ind[i] >> 4) & 0xf, pix); 97848b8605Smrg } 98848b8605Smrg } 99848b8605Smrg else { 100848b8605Smrg /* 8 bits per index */ 101848b8605Smrg const GLubyte *ind = (const GLubyte *) indices; 102848b8605Smrg for (i = 0; i < num_pixels; i++) 103848b8605Smrg pix += get_palette_entry(info, palette, ind[i], pix); 104848b8605Smrg } 105848b8605Smrg} 106848b8605Smrg 107848b8605Smrgunsigned 108848b8605Smrg_mesa_cpal_compressed_size(int level, GLenum internalFormat, 109848b8605Smrg unsigned width, unsigned height) 110848b8605Smrg{ 111848b8605Smrg const struct cpal_format_info *info; 112848b8605Smrg const int num_levels = -level + 1; 113848b8605Smrg int lvl; 114848b8605Smrg unsigned w, h, expect_size; 115848b8605Smrg 116848b8605Smrg if (internalFormat < GL_PALETTE4_RGB8_OES 117848b8605Smrg || internalFormat > GL_PALETTE8_RGB5_A1_OES) { 118848b8605Smrg return 0; 119848b8605Smrg } 120848b8605Smrg 121848b8605Smrg info = &formats[internalFormat - GL_PALETTE4_RGB8_OES]; 122b8e80941Smrg assert(info->cpal_format == internalFormat); 123848b8605Smrg 124848b8605Smrg expect_size = info->palette_size * info->size; 125848b8605Smrg for (lvl = 0; lvl < num_levels; lvl++) { 126848b8605Smrg w = width >> lvl; 127848b8605Smrg if (!w) 128848b8605Smrg w = 1; 129848b8605Smrg h = height >> lvl; 130848b8605Smrg if (!h) 131848b8605Smrg h = 1; 132848b8605Smrg 133848b8605Smrg if (info->palette_size == 16) 134848b8605Smrg expect_size += (w * h + 1) / 2; 135848b8605Smrg else 136848b8605Smrg expect_size += w * h; 137848b8605Smrg } 138848b8605Smrg 139848b8605Smrg return expect_size; 140848b8605Smrg} 141848b8605Smrg 142848b8605Smrg 143848b8605Smrg/** 144848b8605Smrg * Convert a call to glCompressedTexImage2D() where internalFormat is a 145848b8605Smrg * compressed palette format into a regular GLubyte/RGBA glTexImage2D() call. 146848b8605Smrg */ 147848b8605Smrgvoid 148848b8605Smrg_mesa_cpal_compressed_teximage2d(GLenum target, GLint level, 149848b8605Smrg GLenum internalFormat, 150848b8605Smrg GLsizei width, GLsizei height, 151848b8605Smrg GLsizei imageSize, const void *palette) 152848b8605Smrg{ 153848b8605Smrg const struct cpal_format_info *info; 154848b8605Smrg GLint lvl, num_levels; 155848b8605Smrg const GLubyte *indices; 156848b8605Smrg GLint saved_align, align; 157848b8605Smrg GET_CURRENT_CONTEXT(ctx); 158848b8605Smrg 159848b8605Smrg /* By this point, the internalFormat should have been validated. 160848b8605Smrg */ 161848b8605Smrg assert(internalFormat >= GL_PALETTE4_RGB8_OES 162848b8605Smrg && internalFormat <= GL_PALETTE8_RGB5_A1_OES); 163848b8605Smrg 164848b8605Smrg info = &formats[internalFormat - GL_PALETTE4_RGB8_OES]; 165848b8605Smrg 166848b8605Smrg num_levels = -level + 1; 167848b8605Smrg 168848b8605Smrg /* first image follows the palette */ 169848b8605Smrg indices = (const GLubyte *) palette + info->palette_size * info->size; 170848b8605Smrg 171848b8605Smrg saved_align = ctx->Unpack.Alignment; 172848b8605Smrg align = saved_align; 173848b8605Smrg 174848b8605Smrg for (lvl = 0; lvl < num_levels; lvl++) { 175848b8605Smrg GLsizei w, h; 176848b8605Smrg GLuint num_texels; 177848b8605Smrg GLubyte *image = NULL; 178848b8605Smrg 179848b8605Smrg w = width >> lvl; 180848b8605Smrg if (!w) 181848b8605Smrg w = 1; 182848b8605Smrg h = height >> lvl; 183848b8605Smrg if (!h) 184848b8605Smrg h = 1; 185848b8605Smrg num_texels = w * h; 186848b8605Smrg if (w * info->size % align) { 187848b8605Smrg _mesa_PixelStorei(GL_UNPACK_ALIGNMENT, 1); 188848b8605Smrg align = 1; 189848b8605Smrg } 190848b8605Smrg 191848b8605Smrg /* allocate and fill dest image buffer */ 192848b8605Smrg if (palette) { 193848b8605Smrg image = malloc(num_texels * info->size); 194848b8605Smrg paletted_to_color(info, palette, indices, num_texels, image); 195848b8605Smrg } 196848b8605Smrg 197848b8605Smrg _mesa_TexImage2D(target, lvl, info->format, w, h, 0, 198848b8605Smrg info->format, info->type, image); 199848b8605Smrg free(image); 200848b8605Smrg 201848b8605Smrg /* advance index pointer to point to next src mipmap */ 202848b8605Smrg if (info->palette_size == 16) 203848b8605Smrg indices += (num_texels + 1) / 2; 204848b8605Smrg else 205848b8605Smrg indices += num_texels; 206848b8605Smrg } 207848b8605Smrg 208848b8605Smrg if (saved_align != align) 209848b8605Smrg _mesa_PixelStorei(GL_UNPACK_ALIGNMENT, saved_align); 210848b8605Smrg} 211