Merge branch 'shader-file-reorg'
[mesa.git] / src / mesa / main / texpal.c
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
30 static 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 */
53 static GLuint
54 get_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 */
65 static void
66 paletted_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
95 static const struct cpal_format_info *
96 cpal_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 */
139 void
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