/*
** Copyright 1991,1992, Silicon Graphics, Inc.
** All Rights Reserved.
**
** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
** the contents of this file may not be disclosed to third parties, copied or
** duplicated in any form, in whole or in part, without the prior written
** permission of Silicon Graphics, Inc.
**
** RESTRICTED RIGHTS LEGEND:
** Use, duplication or disclosure by the Government is subject to restrictions
** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
** rights reserved under the Copyright Laws of the United States.
**
*/
#include "precomp.h"
#pragma hdrstop

#ifdef GL_EXT_paletted_texture
GLboolean __glCheckColorTableArgs(__GLcontext *gc, GLenum format, GLenum type)
{
    switch (format)
    {
      case GL_RED:
      case GL_GREEN:		case GL_BLUE:
      case GL_ALPHA:		case GL_RGB:
      case GL_RGBA:
#ifdef GL_EXT_bgra
      case GL_BGRA_EXT:
      case GL_BGR_EXT:
#endif
	break;
    default:
    bad_enum:
        __glSetError(GL_INVALID_ENUM);
        return GL_FALSE;
    }
    
    switch (type) {
      case GL_BYTE:
      case GL_UNSIGNED_BYTE:
      case GL_SHORT:
      case GL_UNSIGNED_SHORT:
      case GL_INT:
      case GL_UNSIGNED_INT:
      case GL_FLOAT:
	break;
      default:
	goto bad_enum;
    }

    return GL_TRUE;
}

void APIPRIVATE __glim_ColorTableEXT(GLenum target,
                                     GLenum internalFormat, GLsizei width,
                                     GLenum format, GLenum type,
                                     const GLvoid *data, GLboolean _IsDlist)
{
    __GLtexture *tex;
    GLint level;
    __GLpixelSpanInfo spanInfo;
    GLenum baseFormat;
    RGBQUAD *newData;

    __GL_SETUP_NOT_IN_BEGIN_VALIDATE();

    switch(internalFormat)
    {
    case GL_RGB:		case 3:
    case GL_R3_G3_B2:		case GL_RGB4:
    case GL_RGB5:		case GL_RGB8:
    case GL_RGB10:	        case GL_RGB12:
    case GL_RGB16:
	baseFormat = GL_RGB;
        break;
    case GL_RGBA:		case 4:
    case GL_RGBA2:	        case GL_RGBA4:
    case GL_RGBA8:              case GL_RGB5_A1:
    case GL_RGBA12:             case GL_RGBA16:
    case GL_RGB10_A2:
	baseFormat = GL_RGBA;
        break;
    default:
        __glSetError(GL_INVALID_ENUM);
        return;
    }

    // width must be a positive power of two greater than zero
    if (width <= 0 || (width & (width-1)) != 0)
    {
        __glSetError(GL_INVALID_VALUE);
        return;
    }

    if (!__glCheckColorTableArgs(gc, format, type))
    {
        return;
    }

    tex = __glLookUpTexture(gc, target);
        
    if (target == GL_PROXY_TEXTURE_1D ||
        target == GL_PROXY_TEXTURE_2D)
    {
        // Consider - How do MCD's indicate their palette support?
        
        // We're only in this case if it's a legal proxy target value
        // so there's no need to do a real check
        ASSERTOPENGL(tex != NULL, "Invalid proxy target");
        
        tex->paletteRequestedFormat = internalFormat;
        tex->paletteTotalSize = width;
        tex->paletteSize = tex->paletteTotalSize;
        
        // Proxies have no data so there's no need to do any more
        return;
    }

    if (data == NULL)
    {
        return;
    }
    
    if (tex == NULL)
    {
        __glSetError(GL_INVALID_ENUM);
        return;
    }

    // Allocate palette storage
    newData = GCREALLOC(gc, tex->paletteTotalData, sizeof(RGBQUAD)*width);
    if (newData == NULL)
    {
        return;
    }

    tex->paletteBaseFormat = baseFormat;
    tex->paletteRequestedFormat = internalFormat;
    tex->paletteTotalSize = width;
    __glSetPaletteSubdivision(tex, tex->paletteTotalSize);
    tex->paletteTotalData = newData;
    tex->paletteData = tex->paletteTotalData;

    // This routine can be called on any kind of texture, not necessarily
    // color-indexed ones.  If it is a color-index texture then we
    // need to set the appropriate baseFormat and extract procs
    // according to the palette data
    if (tex->level[0].internalFormat == GL_COLOR_INDEX8_EXT ||
        tex->level[0].internalFormat == GL_COLOR_INDEX16_EXT)
    {
        for (level = 0; level < gc->constants.maxMipMapLevel; level++)
        {
            tex->level[level].baseFormat = tex->paletteBaseFormat;
            // Pick proper extraction proc
            if (tex->level[0].internalFormat == GL_COLOR_INDEX8_EXT)
            {
                __glSetPaletteLevelExtract8(tex, &tex->level[level],
                                            tex->level[level].border);
            }
            else
            {
                ASSERTOPENGL(tex->level[0].internalFormat ==
                             GL_COLOR_INDEX16_EXT,
                             "Unexpected internalFormat\n");
            
                __glSetPaletteLevelExtract16(tex, &tex->level[level],
                                             tex->level[level].border);
            }
        }
        
        // We need to repick the texture procs because the baseFormat
        // field has changed
        __GL_DELAY_VALIDATE(gc);
    }

    // Copy user palette data into BGRA form
    spanInfo.dstImage = tex->paletteTotalData;
    __glInitTextureUnpack(gc, &spanInfo, width, 1, format, type, data, 
                          GL_BGRA_EXT, _IsDlist);
    __glInitUnpacker(gc, &spanInfo);
    __glInitPacker(gc, &spanInfo);
    (*gc->procs.copyImage)(gc, &spanInfo, GL_TRUE);

    // Don't update the optimized palette unless it would actually
    // get used
    if (tex->level[0].internalFormat == GL_COLOR_INDEX8_EXT ||
        tex->level[0].internalFormat == GL_COLOR_INDEX16_EXT)
    {
        __GLtextureObject *pto;
        
        pto = __glLookUpTextureObject(gc, target);
        __glGenUpdateTexturePalette(gc, tex, pto->loadKey,
                                    0, tex->paletteTotalSize);
    }
}

void APIPRIVATE __glim_ColorSubTableEXT(GLenum target, GLsizei start,
                                        GLsizei count, GLenum format,
                                        GLenum type, const GLvoid *data,
                                        GLboolean _IsDlist)
{
    __GLtexture *tex;
    __GLpixelSpanInfo spanInfo;

    __GL_SETUP_NOT_IN_BEGIN_VALIDATE();

    if (!__glCheckColorTableArgs(gc, format, type))
    {
        return;
    }

    tex = __glLookUpTexture(gc, target);
    if (tex == NULL ||
        target == GL_PROXY_TEXTURE_1D ||
        target == GL_PROXY_TEXTURE_2D)
    {
        __glSetError(GL_INVALID_ENUM);
        return;
    }

    if (data == NULL)
    {
        return;
    }
    
    // Validate start and count
    if (start > tex->paletteTotalSize ||
        start+count > tex->paletteTotalSize)
    {
        __glSetError(GL_INVALID_VALUE);
        return;
    }

    // Copy user palette data into BGRA form
    spanInfo.dstImage = tex->paletteTotalData;
    __glInitTextureUnpack(gc, &spanInfo, count, 1, format, type, data, 
                          GL_BGRA_EXT, _IsDlist);
    spanInfo.dstSkipPixels += start;
    __glInitUnpacker(gc, &spanInfo);
    __glInitPacker(gc, &spanInfo);
    (*gc->procs.copyImage)(gc, &spanInfo, GL_TRUE);

    // Don't update the optimized palette unless it would actually
    // get used
    if (tex->level[0].internalFormat == GL_COLOR_INDEX8_EXT ||
        tex->level[0].internalFormat == GL_COLOR_INDEX16_EXT)
    {
        __GLtextureObject *pto;
        
        pto = __glLookUpTextureObject(gc, target);
        __glGenUpdateTexturePalette(gc, tex, pto->loadKey, start, count);
    }
}

void APIPRIVATE __glim_GetColorTableEXT(GLenum target, GLenum format,
                                        GLenum type, GLvoid *data)
{
    __GLtexture *tex;
    GLint level;
    __GLpixelSpanInfo spanInfo;
    GLenum baseFormat;

    __GL_SETUP_NOT_IN_BEGIN_VALIDATE();
    
    if (!__glCheckColorTableArgs(gc, format, type))
    {
        return;
    }
    
    tex = __glLookUpTexture(gc, target);
    if (tex == NULL ||
        target == GL_PROXY_TEXTURE_1D ||
        target == GL_PROXY_TEXTURE_2D)
    {
        __glSetError(GL_INVALID_ENUM);
        return;
    }
    
    ASSERTOPENGL(tex->paletteTotalData != NULL,
                 "GetColorTable with no palette data\n");

    // Copy BGRA data into user buffer
    spanInfo.srcImage = tex->paletteTotalData;
    spanInfo.srcFormat = GL_BGRA_EXT;
    spanInfo.srcType = GL_UNSIGNED_BYTE;
    spanInfo.srcAlignment = 4;
    __glInitImagePack(gc, &spanInfo, tex->paletteTotalSize, 1,
                      format, type, data);
    __glInitUnpacker(gc, &spanInfo);
    __glInitPacker(gc, &spanInfo);
    (*gc->procs.copyImage)(gc, &spanInfo, GL_TRUE);
}

void APIPRIVATE __glim_GetColorTableParameterivEXT(GLenum target,
                                                   GLenum pname,
                                                   GLint *params)
{
    __GLtexture *tex;

    __GL_SETUP_NOT_IN_BEGIN();

    tex = __glLookUpTexture(gc, target);
    if (tex == NULL)
    {
        __glSetError(GL_INVALID_ENUM);
        return;
    }

    switch(pname)
    {
    case GL_COLOR_TABLE_FORMAT_EXT:
        *params = tex->paletteRequestedFormat;
        break;
    case GL_COLOR_TABLE_WIDTH_EXT:
        *params = tex->paletteTotalSize;
        break;
    case GL_COLOR_TABLE_RED_SIZE_EXT:
    case GL_COLOR_TABLE_GREEN_SIZE_EXT:
    case GL_COLOR_TABLE_BLUE_SIZE_EXT:
    case GL_COLOR_TABLE_ALPHA_SIZE_EXT:
        *params = 8;
        break;
#ifdef GL_EXT_flat_paletted_lighting
    case GL_COLOR_TABLE_SUBDIVISION_EXT:
        *params = tex->paletteSize;
        break;
#endif

    default:
        __glSetError(GL_INVALID_ENUM);
        return;
    }
}

void APIPRIVATE __glim_GetColorTableParameterfvEXT(GLenum target,
                                                   GLenum pname,
                                                   GLfloat *params)
{
    __GLtexture *tex;

    __GL_SETUP_NOT_IN_BEGIN();

    tex = __glLookUpTexture(gc, target);
    if (tex == NULL)
    {
        __glSetError(GL_INVALID_ENUM);
        return;
    }

    switch(pname)
    {
    case GL_COLOR_TABLE_FORMAT_EXT:
        *params = (GLfloat)tex->paletteRequestedFormat;
        break;
    case GL_COLOR_TABLE_WIDTH_EXT:
        *params = (GLfloat)tex->paletteTotalSize;
        break;
    case GL_COLOR_TABLE_RED_SIZE_EXT:
    case GL_COLOR_TABLE_GREEN_SIZE_EXT:
    case GL_COLOR_TABLE_BLUE_SIZE_EXT:
    case GL_COLOR_TABLE_ALPHA_SIZE_EXT:
        *params = (GLfloat)8;
        break;
#ifdef GL_EXT_flat_paletted_lighting
    case GL_COLOR_TABLE_SUBDIVISION_EXT:
        *params = (GLfloat)tex->paletteSize;
        break;
#endif

    default:
        __glSetError(GL_INVALID_ENUM);
        return;
    }
}
#endif // GL_EXT_paletted_texture

#ifdef GL_EXT_flat_paletted_lighting
void APIPRIVATE __glim_ColorTableParameterivEXT(GLenum target,
                                                GLenum pname,
                                                const GLint *params)
{
    __GLtexture *tex;
    GLint ival;

    __GL_SETUP_NOT_IN_BEGIN();

    tex = __glLookUpTexture(gc, target);
    if (tex == NULL)
    {
        __glSetError(GL_INVALID_ENUM);
        return;
    }

    switch(pname)
    {
    case GL_COLOR_TABLE_SUBDIVISION_EXT:
        ival = *params;
        
        // Value must be an integer power of two between one and the total
        // palette size
        if ((ival & (ival-1)) != 0 ||
            ival < 1 ||
            ival > tex->paletteTotalSize)
        {
            __glSetError(GL_INVALID_VALUE);
            return;
        }
        
        __glSetPaletteSubdivision(tex, ival);
        break;

    default:
        __glSetError(GL_INVALID_ENUM);
        return;
    }
}

void APIPRIVATE __glim_ColorTableParameterfvEXT(GLenum target,
                                                GLenum pname,
                                                const GLfloat *params)
{
    __GLtexture *tex;
    GLfloat fval;
    GLint ival;

    __GL_SETUP_NOT_IN_BEGIN();

    tex = __glLookUpTexture(gc, target);
    if (tex == NULL)
    {
        __glSetError(GL_INVALID_ENUM);
        return;
    }

    switch(pname)
    {
    case GL_COLOR_TABLE_SUBDIVISION_EXT:
        fval = *params;
        ival = (int)fval;
        
        // Value must be an integer power of two between one and the total
        // palette size
        if (fval != (GLfloat)ival ||
            (ival & (ival-1)) != 0 ||
            ival < 1 ||
            ival > tex->paletteTotalSize)
        {
            __glSetError(GL_INVALID_VALUE);
            return;
        }
        
        __glSetPaletteSubdivision(tex, ival);
        break;

    default:
        __glSetError(GL_INVALID_ENUM);
        return;
    }
}
#endif // GL_EXT_flat_paletted_lighting