[MESA/OPENGL32]
[reactos.git] / reactos / dll / opengl / mesa / 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 "mfeatures.h"
22 #include "mtypes.h"
23 #include "imports.h"
24 #include "pixelstore.h"
25 #include "teximage.h"
26 #include "texpal.h"
27
28 #if FEATURE_ES
29
30
31 static const struct cpal_format_info {
32 GLenum cpal_format;
33 GLenum format;
34 GLenum type;
35 GLuint palette_size;
36 GLuint size;
37 } formats[] = {
38 { GL_PALETTE4_RGB8_OES, GL_RGB, GL_UNSIGNED_BYTE, 16, 3 },
39 { GL_PALETTE4_RGBA8_OES, GL_RGBA, GL_UNSIGNED_BYTE, 16, 4 },
40 { GL_PALETTE4_R5_G6_B5_OES, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 16, 2 },
41 { GL_PALETTE4_RGBA4_OES, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 16, 2 },
42 { GL_PALETTE4_RGB5_A1_OES, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 16, 2 },
43 { GL_PALETTE8_RGB8_OES, GL_RGB, GL_UNSIGNED_BYTE, 256, 3 },
44 { GL_PALETTE8_RGBA8_OES, GL_RGBA, GL_UNSIGNED_BYTE, 256, 4 },
45 { GL_PALETTE8_R5_G6_B5_OES, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 256, 2 },
46 { GL_PALETTE8_RGBA4_OES, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 256, 2 },
47 { GL_PALETTE8_RGB5_A1_OES, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 256, 2 }
48 };
49
50
51 /**
52 * Get a color/entry from the palette.
53 */
54 static GLuint
55 get_palette_entry(const struct cpal_format_info *info, const GLubyte *palette,
56 GLuint index, GLubyte *pixel)
57 {
58 memcpy(pixel, palette + info->size * index, info->size);
59 return info->size;
60 }
61
62
63 /**
64 * Convert paletted texture to color texture.
65 */
66 static void
67 paletted_to_color(const struct cpal_format_info *info, const GLubyte *palette,
68 const void *indices, GLuint num_pixels, GLubyte *image)
69 {
70 GLubyte *pix = image;
71 GLuint remain, i;
72
73 if (info->palette_size == 16) {
74 /* 4 bits per index */
75 const GLubyte *ind = (const GLubyte *) indices;
76
77 /* two pixels per iteration */
78 remain = num_pixels % 2;
79 for (i = 0; i < num_pixels / 2; i++) {
80 pix += get_palette_entry(info, palette, (ind[i] >> 4) & 0xf, pix);
81 pix += get_palette_entry(info, palette, ind[i] & 0xf, pix);
82 }
83 if (remain) {
84 get_palette_entry(info, palette, (ind[i] >> 4) & 0xf, pix);
85 }
86 }
87 else {
88 /* 8 bits per index */
89 const GLubyte *ind = (const GLubyte *) indices;
90 for (i = 0; i < num_pixels; i++)
91 pix += get_palette_entry(info, palette, ind[i], pix);
92 }
93 }
94
95 unsigned
96 _mesa_cpal_compressed_size(int level, GLenum internalFormat,
97 unsigned width, unsigned height)
98 {
99 const struct cpal_format_info *info;
100 const int num_levels = -level + 1;
101 int lvl;
102 unsigned w, h, expect_size;
103
104 if (internalFormat < GL_PALETTE4_RGB8_OES
105 || internalFormat > GL_PALETTE8_RGB5_A1_OES) {
106 return 0;
107 }
108
109 info = &formats[internalFormat - GL_PALETTE4_RGB8_OES];
110 ASSERT(info->cpal_format == internalFormat);
111
112 expect_size = info->palette_size * info->size;
113 for (lvl = 0; lvl < num_levels; lvl++) {
114 w = width >> lvl;
115 if (!w)
116 w = 1;
117 h = height >> lvl;
118 if (!h)
119 h = 1;
120
121 if (info->palette_size == 16)
122 expect_size += (w * h + 1) / 2;
123 else
124 expect_size += w * h;
125 }
126
127 return expect_size;
128 }
129
130 void
131 _mesa_cpal_compressed_format_type(GLenum internalFormat, GLenum *format,
132 GLenum *type)
133 {
134 const struct cpal_format_info *info;
135
136 if (internalFormat < GL_PALETTE4_RGB8_OES
137 || internalFormat > GL_PALETTE8_RGB5_A1_OES) {
138 return;
139 }
140
141 info = &formats[internalFormat - GL_PALETTE4_RGB8_OES];
142 *format = info->format;
143 *type = info->type;
144 }
145
146 /**
147 * Convert a call to glCompressedTexImage2D() where internalFormat is a
148 * compressed palette format into a regular GLubyte/RGBA glTexImage2D() call.
149 */
150 void
151 _mesa_cpal_compressed_teximage2d(GLenum target, GLint level,
152 GLenum internalFormat,
153 GLsizei width, GLsizei height,
154 GLsizei imageSize, const void *palette)
155 {
156 const struct cpal_format_info *info;
157 GLint lvl, num_levels;
158 const GLubyte *indices;
159 GLint saved_align, align;
160 GET_CURRENT_CONTEXT(ctx);
161
162 /* By this point, the internalFormat should have been validated.
163 */
164 assert(internalFormat >= GL_PALETTE4_RGB8_OES
165 && internalFormat <= GL_PALETTE8_RGB5_A1_OES);
166
167 info = &formats[internalFormat - GL_PALETTE4_RGB8_OES];
168
169 num_levels = -level + 1;
170
171 /* first image follows the palette */
172 indices = (const GLubyte *) palette + info->palette_size * info->size;
173
174 saved_align = ctx->Unpack.Alignment;
175 align = saved_align;
176
177 for (lvl = 0; lvl < num_levels; lvl++) {
178 GLsizei w, h;
179 GLuint num_texels;
180 GLubyte *image = NULL;
181
182 w = width >> lvl;
183 if (!w)
184 w = 1;
185 h = height >> lvl;
186 if (!h)
187 h = 1;
188 num_texels = w * h;
189 if (w * info->size % align) {
190 _mesa_PixelStorei(GL_UNPACK_ALIGNMENT, 1);
191 align = 1;
192 }
193
194 /* allocate and fill dest image buffer */
195 if (palette) {
196 image = (GLubyte *) malloc(num_texels * info->size);
197 paletted_to_color(info, palette, indices, num_texels, image);
198 }
199
200 _mesa_TexImage2D(target, lvl, info->format, w, h, 0,
201 info->format, info->type, image);
202 if (image)
203 free(image);
204
205 /* advance index pointer to point to next src mipmap */
206 if (info->palette_size == 16)
207 indices += (num_texels + 1) / 2;
208 else
209 indices += num_texels;
210 }
211
212 if (saved_align != align)
213 _mesa_PixelStorei(GL_UNPACK_ALIGNMENT, saved_align);
214 }
215
216 #endif