Tizen 2.0 Release
[profile/ivi/osmesa.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 "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