Home | History | Annotate | Download | only in main
      1 /*
      2  * Mesa 3-D graphics library
      3  *
      4  * Copyright 2008 VMware, Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included
     14  * in all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  */
     24 
     25 /**
     26  * Code to convert compressed/paletted texture images to ordinary images.
     27  * See the GL_OES_compressed_paletted_texture spec at
     28  * http://khronos.org/registry/gles/extensions/OES/OES_compressed_paletted_texture.txt
     29  *
     30  * XXX this makes it impossible to add hardware support...
     31  */
     32 
     33 
     34 #include "glheader.h"
     35 #include "context.h"
     36 #include "mtypes.h"
     37 #include "imports.h"
     38 #include "pixelstore.h"
     39 #include "texcompress_cpal.h"
     40 #include "teximage.h"
     41 
     42 
     43 static const struct cpal_format_info {
     44    GLenum cpal_format;
     45    GLenum format;
     46    GLenum type;
     47    GLuint palette_size;
     48    GLuint size;
     49 } formats[] = {
     50    { GL_PALETTE4_RGB8_OES,     GL_RGB,  GL_UNSIGNED_BYTE,           16, 3 },
     51    { GL_PALETTE4_RGBA8_OES,    GL_RGBA, GL_UNSIGNED_BYTE,           16, 4 },
     52    { GL_PALETTE4_R5_G6_B5_OES, GL_RGB,  GL_UNSIGNED_SHORT_5_6_5,    16, 2 },
     53    { GL_PALETTE4_RGBA4_OES,    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,  16, 2 },
     54    { GL_PALETTE4_RGB5_A1_OES,  GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1,  16, 2 },
     55    { GL_PALETTE8_RGB8_OES,     GL_RGB,  GL_UNSIGNED_BYTE,          256, 3 },
     56    { GL_PALETTE8_RGBA8_OES,    GL_RGBA, GL_UNSIGNED_BYTE,          256, 4 },
     57    { GL_PALETTE8_R5_G6_B5_OES, GL_RGB,  GL_UNSIGNED_SHORT_5_6_5,   256, 2 },
     58    { GL_PALETTE8_RGBA4_OES,    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 256, 2 },
     59    { GL_PALETTE8_RGB5_A1_OES,  GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 256, 2 }
     60 };
     61 
     62 
     63 /**
     64  * Get a color/entry from the palette.
     65  */
     66 static GLuint
     67 get_palette_entry(const struct cpal_format_info *info, const GLubyte *palette,
     68                   GLuint index, GLubyte *pixel)
     69 {
     70    memcpy(pixel, palette + info->size * index, info->size);
     71    return info->size;
     72 }
     73 
     74 
     75 /**
     76  * Convert paletted texture to color texture.
     77  */
     78 static void
     79 paletted_to_color(const struct cpal_format_info *info, const GLubyte *palette,
     80                   const void *indices, GLuint num_pixels, GLubyte *image)
     81 {
     82    GLubyte *pix = image;
     83    GLuint remain, i;
     84 
     85    if (info->palette_size == 16) {
     86       /* 4 bits per index */
     87       const GLubyte *ind = (const GLubyte *) indices;
     88 
     89       /* two pixels per iteration */
     90       remain = num_pixels % 2;
     91       for (i = 0; i < num_pixels / 2; i++) {
     92          pix += get_palette_entry(info, palette, (ind[i] >> 4) & 0xf, pix);
     93          pix += get_palette_entry(info, palette, ind[i] & 0xf, pix);
     94       }
     95       if (remain) {
     96          get_palette_entry(info, palette, (ind[i] >> 4) & 0xf, pix);
     97       }
     98    }
     99    else {
    100       /* 8 bits per index */
    101       const GLubyte *ind = (const GLubyte *) indices;
    102       for (i = 0; i < num_pixels; i++)
    103          pix += get_palette_entry(info, palette, ind[i], pix);
    104    }
    105 }
    106 
    107 unsigned
    108 _mesa_cpal_compressed_size(int level, GLenum internalFormat,
    109 			   unsigned width, unsigned height)
    110 {
    111    const struct cpal_format_info *info;
    112    const int num_levels = -level + 1;
    113    int lvl;
    114    unsigned w, h, expect_size;
    115 
    116    if (internalFormat < GL_PALETTE4_RGB8_OES
    117        || internalFormat > GL_PALETTE8_RGB5_A1_OES) {
    118       return 0;
    119    }
    120 
    121    info = &formats[internalFormat - GL_PALETTE4_RGB8_OES];
    122    assert(info->cpal_format == internalFormat);
    123 
    124    expect_size = info->palette_size * info->size;
    125    for (lvl = 0; lvl < num_levels; lvl++) {
    126       w = width >> lvl;
    127       if (!w)
    128          w = 1;
    129       h = height >> lvl;
    130       if (!h)
    131          h = 1;
    132 
    133       if (info->palette_size == 16)
    134          expect_size += (w * h  + 1) / 2;
    135       else
    136          expect_size += w * h;
    137    }
    138 
    139    return expect_size;
    140 }
    141 
    142 
    143 /**
    144  * Convert a call to glCompressedTexImage2D() where internalFormat is a
    145  *  compressed palette format into a regular GLubyte/RGBA glTexImage2D() call.
    146  */
    147 void
    148 _mesa_cpal_compressed_teximage2d(GLenum target, GLint level,
    149 				 GLenum internalFormat,
    150 				 GLsizei width, GLsizei height,
    151 				 GLsizei imageSize, const void *palette)
    152 {
    153    const struct cpal_format_info *info;
    154    GLint lvl, num_levels;
    155    const GLubyte *indices;
    156    GLint saved_align, align;
    157    GET_CURRENT_CONTEXT(ctx);
    158 
    159    /* By this point, the internalFormat should have been validated.
    160     */
    161    assert(internalFormat >= GL_PALETTE4_RGB8_OES
    162 	  && internalFormat <= GL_PALETTE8_RGB5_A1_OES);
    163 
    164    info = &formats[internalFormat - GL_PALETTE4_RGB8_OES];
    165 
    166    num_levels = -level + 1;
    167 
    168    /* first image follows the palette */
    169    indices = (const GLubyte *) palette + info->palette_size * info->size;
    170 
    171    saved_align = ctx->Unpack.Alignment;
    172    align = saved_align;
    173 
    174    for (lvl = 0; lvl < num_levels; lvl++) {
    175       GLsizei w, h;
    176       GLuint num_texels;
    177       GLubyte *image = NULL;
    178 
    179       w = width >> lvl;
    180       if (!w)
    181          w = 1;
    182       h = height >> lvl;
    183       if (!h)
    184          h = 1;
    185       num_texels = w * h;
    186       if (w * info->size % align) {
    187          _mesa_PixelStorei(GL_UNPACK_ALIGNMENT, 1);
    188          align = 1;
    189       }
    190 
    191       /* allocate and fill dest image buffer */
    192       if (palette) {
    193          image = malloc(num_texels * info->size);
    194          paletted_to_color(info, palette, indices, num_texels, image);
    195       }
    196 
    197       _mesa_TexImage2D(target, lvl, info->format, w, h, 0,
    198                        info->format, info->type, image);
    199       free(image);
    200 
    201       /* advance index pointer to point to next src mipmap */
    202       if (info->palette_size == 16)
    203          indices += (num_texels + 1) / 2;
    204       else
    205          indices += num_texels;
    206    }
    207 
    208    if (saved_align != align)
    209       _mesa_PixelStorei(GL_UNPACK_ALIGNMENT, saved_align);
    210 }
    211