state_teximage.c revision cbfc08f1668b06543c25f6280149198ea948d739
/* Copyright (c) 2001, Stanford University
* All rights reserved
*
* See the file LICENSE.txt for information on redistributing this software.
*/
#include "state.h"
#include "state/cr_statetypes.h"
#include "state/cr_texture.h"
#include "cr_pixeldata.h"
#include "cr_string.h"
#include "cr_mem.h"
#include "cr_version.h"
#include "state_internals.h"
static int
bitcount(int value)
{
int bits = 0;
for (; value > 0; value >>= 1) {
if (value & 0x1)
bits++;
}
return bits;
}
/**
* Return 1 if the target is a proxy target, 0 otherwise.
*/
static GLboolean
IsProxyTarget(GLenum target)
{
return (target == GL_PROXY_TEXTURE_1D ||
target == GL_PROXY_TEXTURE_2D ||
target == GL_PROXY_TEXTURE_3D ||
target == GL_PROXY_TEXTURE_RECTANGLE_NV ||
target == GL_PROXY_TEXTURE_CUBE_MAP);
}
/**
* Test if a texture width, height or depth is legal.
* It must be true that 0 <= size <= max.
* Furthermore, if the ARB_texture_non_power_of_two extension isn't
* present, size must also be a power of two.
*/
static GLboolean
isLegalSize(CRContext *g, GLsizei size, GLsizei max)
{
if (size < 0 || size > max)
return GL_FALSE;
if (!g->extensions.ARB_texture_non_power_of_two) {
/* check for power of two */
if (size > 0 && bitcount(size) != 1)
return GL_FALSE;
}
return GL_TRUE;
}
/**
* Return the max legal texture level parameter for the given target.
*/
static GLint
MaxTextureLevel(CRContext *g, GLenum target)
{
CRTextureState *t = &(g->texture);
switch (target) {
case GL_TEXTURE_1D:
case GL_PROXY_TEXTURE_1D:
case GL_TEXTURE_2D:
case GL_PROXY_TEXTURE_2D:
return t->maxLevel;
case GL_TEXTURE_3D:
case GL_PROXY_TEXTURE_3D:
return t->max3DLevel;
case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
return t->maxCubeMapLevel;
case GL_TEXTURE_RECTANGLE_NV:
case GL_PROXY_TEXTURE_RECTANGLE_NV:
return t->maxRectLevel;
default:
return 0;
}
}
/**
* If GL_GENERATE_MIPMAP_SGIS is true and we modify the base level texture
* image we have to finish the mipmap.
* All we really have to do is fill in the width/height/format/etc for the
* remaining image levels. The image data doesn't matter here - the back-
* end OpenGL library will fill those in.
*/
static void
generate_mipmap(CRTextureObj *tobj, GLenum target)
{
CRTextureLevel *levels;
GLint level, width, height, depth;
if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) {
levels = tobj->level[target - GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB];
}
else {
levels = tobj->level[0];
}
width = levels[tobj->baseLevel].width;
height = levels[tobj->baseLevel].height;
depth = levels[tobj->baseLevel].depth;
for (level = tobj->baseLevel + 1; level <= tobj->maxLevel; level++)
{
if (width > 1)
width /= 2;
if (height > 1)
height /= 2;
if (depth > 1)
depth /= 2;
levels[level].width = width;
levels[level].height = height;
levels[level].depth = depth;
levels[level].internalFormat = levels[tobj->baseLevel].internalFormat;
levels[level].format = levels[tobj->baseLevel].format;
levels[level].type = levels[tobj->baseLevel].type;
#ifdef CR_ARB_texture_compression
levels[level].compressed = levels[tobj->baseLevel].compressed;
#endif
levels[level].texFormat = levels[tobj->baseLevel].texFormat;
if (width == 1 && height == 1 && depth == 1)
break;
}
/* Set this flag so when we do the state diff, we enable GENERATE_MIPMAP
* prior to calling diff.TexImage().
*/
levels[tobj->baseLevel].generateMipmap = GL_TRUE;
}
/**
* Given a texture target and level, return pointers to the corresponding
* texture object and texture image level.
*/
void
crStateGetTextureObjectAndImage(CRContext *g, GLenum texTarget, GLint level,
CRTextureObj **obj, CRTextureLevel **img)
{
CRTextureState *t = &(g->texture);
CRTextureUnit *unit = t->unit + t->curTextureUnit;
switch (texTarget) {
case GL_TEXTURE_1D:
*obj = unit->currentTexture1D;
*img = unit->currentTexture1D->level[0] + level;
return;
case GL_PROXY_TEXTURE_1D:
*obj = &(t->proxy1D);
*img = t->proxy1D.level[0] + level;
return;
case GL_TEXTURE_2D:
*obj = unit->currentTexture2D;
*img = unit->currentTexture2D->level[0] + level;
return;
case GL_PROXY_TEXTURE_2D:
*obj = &(t->proxy2D);
*img = t->proxy2D.level[0] + level;
return;
case GL_TEXTURE_3D:
*obj = unit->currentTexture3D;
*img = unit->currentTexture3D->level[0] + level;
return;
case GL_PROXY_TEXTURE_3D:
*obj = &(t->proxy3D);
*img = t->proxy3D.level[0] + level;
return;
default:
/* fall-through */
;
}
#ifdef CR_NV_texture_rectangle
if (g->extensions.NV_texture_rectangle) {
switch (texTarget) {
case GL_PROXY_TEXTURE_RECTANGLE_NV:
*obj = &(t->proxyRect);
*img = t->proxyRect.level[0] + level;
return;
case GL_TEXTURE_RECTANGLE_NV:
*obj = unit->currentTextureRect;
*img = unit->currentTextureRect->level[0] + level;
return;
default:
/* fall-through */
;
}
}
#endif
#ifdef CR_ARB_texture_cube_map
if (g->extensions.ARB_texture_cube_map) {
switch (texTarget) {
case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
*obj = &(t->proxyCubeMap);
*img = t->proxyCubeMap.level[0] + level;
return;
case GL_TEXTURE_CUBE_MAP_ARB:
*obj = unit->currentTextureCubeMap;
*img = NULL;
return;
case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
*obj = unit->currentTextureCubeMap;
*img = unit->currentTextureCubeMap->level[0] + level;
return;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
*obj = unit->currentTextureCubeMap;
*img = unit->currentTextureCubeMap->level[1] + level;
return;
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
*obj = unit->currentTextureCubeMap;
*img = unit->currentTextureCubeMap->level[2] + level;
return;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
*obj = unit->currentTextureCubeMap;
*img = unit->currentTextureCubeMap->level[3] + level;
return;
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
*obj = unit->currentTextureCubeMap;
*img = unit->currentTextureCubeMap->level[4] + level;
return;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
*obj = unit->currentTextureCubeMap;
*img = unit->currentTextureCubeMap->level[5] + level;
return;
default:
/* fall-through */
;
}
}
#endif
*obj = NULL;
*img = NULL;
}
/**
* Do parameter error checking for glTexImagexD functions.
* We'll call crStateError if we detect any errors, unless it's a proxy target.
* Return GL_TRUE if any errors, GL_FALSE if no errors.
*/
static GLboolean
ErrorCheckTexImage(GLuint dims, GLenum target, GLint level,
GLsizei width, GLsizei height, GLsizei depth, GLint border)
{
CRContext *g = GetCurrentContext();
if (g->current.inBeginEnd)
{
crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
"glTexImage%uD called in Begin/End", dims);
return GL_TRUE;
}
/*
* Test target
*/
switch (target)
{
case GL_TEXTURE_1D:
case GL_PROXY_TEXTURE_1D:
if (dims != 1) {
crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
"glTexImage(invalid target=0x%x)", target);
return GL_TRUE;
}
break;
case GL_TEXTURE_2D:
case GL_PROXY_TEXTURE_2D:
if (dims != 2) {
crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
"glTexImage(invalid target=0x%x)", target);
return GL_TRUE;
}
break;
case GL_TEXTURE_3D:
case GL_PROXY_TEXTURE_3D:
if (dims != 3) {
crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
"glTexImage(invalid target=0x%x)", target);
return GL_TRUE;
}
break;
#ifdef CR_NV_texture_rectangle
case GL_TEXTURE_RECTANGLE_NV:
case GL_PROXY_TEXTURE_RECTANGLE_NV:
if (dims != 2 || !g->extensions.NV_texture_rectangle) {
crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
"glTexImage2D(invalid target=0x%x)", target);
return GL_TRUE;
}
break;
#endif
#ifdef CR_ARB_texture_cube_map
case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
if (dims != 2 || !g->extensions.ARB_texture_cube_map) {
crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
"glTexImage2D(invalid target=0x%x)", target);
return GL_TRUE;
}
break;
#endif
default:
crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
"glTexImage%uD(invalid target=0x%x)", dims, target);
return GL_TRUE;
}
/*
* Test level
*/
if (level < 0 || level > MaxTextureLevel(g, target)) {
if (!IsProxyTarget(target))
crStateError(__LINE__, __FILE__, GL_INVALID_VALUE,
"glTexImage%uD(level=%d)", dims, level);
return GL_TRUE;
}
/*
* Test border
*/
if (border != 0 && border != 1) {
if (!IsProxyTarget(target))
crStateError(__LINE__, __FILE__, GL_INVALID_VALUE,
"glTexImage%uD(border=%d)", dims, border);
return GL_TRUE;
}
if ((target == GL_PROXY_TEXTURE_RECTANGLE_NV ||
target == GL_TEXTURE_RECTANGLE_NV) && border != 0) {
if (!IsProxyTarget(target))
crStateError(__LINE__, __FILE__, GL_INVALID_VALUE,
"glTexImage2D(border=%d)", border);
return GL_TRUE;
}
/*
* Test width, height, depth
*/
if (target == GL_PROXY_TEXTURE_1D || target == GL_TEXTURE_1D) {
if (!isLegalSize(g, width - 2 * border, g->limits.maxTextureSize)) {
if (!IsProxyTarget(target))
crStateError(__LINE__, __FILE__, GL_INVALID_VALUE,
"glTexImage1D(width=%d)", width);
return GL_TRUE;
}
}
else if (target == GL_PROXY_TEXTURE_2D || target == GL_TEXTURE_2D) {
if (!isLegalSize(g, width - 2 * border, g->limits.maxTextureSize) ||
!isLegalSize(g, height - 2 * border, g->limits.maxTextureSize)) {
if (!IsProxyTarget(target))
crStateError(__LINE__, __FILE__, GL_INVALID_VALUE,
"glTexImage2D(width=%d, height=%d)", width, height);
return GL_TRUE;
}
}
else if (target == GL_PROXY_TEXTURE_3D || target == GL_TEXTURE_3D) {
if (!isLegalSize(g, width - 2 * border, g->limits.max3DTextureSize) ||
!isLegalSize(g, height - 2 * border, g->limits.max3DTextureSize) ||
!isLegalSize(g, depth - 2 * border, g->limits.max3DTextureSize)) {
if (!IsProxyTarget(target))
crStateError(__LINE__, __FILE__, GL_INVALID_VALUE,
"glTexImage3D(width=%d, height=%d, depth=%d)",
width, height, depth);
return GL_TRUE;
}
}
else if (target == GL_PROXY_TEXTURE_RECTANGLE_NV ||
target == GL_TEXTURE_RECTANGLE_NV) {
if (width < 0 || width > (int) g->limits.maxRectTextureSize ||
height < 0 || height > (int) g->limits.maxRectTextureSize) {
if (!IsProxyTarget(target))
crStateError(__LINE__, __FILE__, GL_INVALID_VALUE,
"glTexImage2D(width=%d, height=%d)", width, height);
return GL_TRUE;
}
}
else {
/* cube map */
if (!isLegalSize(g, width - 2*border, g->limits.maxCubeMapTextureSize) ||
!isLegalSize(g, height - 2*border, g->limits.maxCubeMapTextureSize) ||
width != height) {
if (!IsProxyTarget(target))
crStateError(__LINE__, __FILE__, GL_INVALID_VALUE,
"glTexImage2D(width=%d, height=%d)", width, height);
return GL_TRUE;
}
}
/* OK, no errors */
return GL_FALSE;
}
/**
* Do error check for glTexSubImage() functions.
* We'll call crStateError if we detect any errors.
* Return GL_TRUE if any errors, GL_FALSE if no errors.
*/
static GLboolean
ErrorCheckTexSubImage(GLuint dims, GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth)
{
CRContext *g = GetCurrentContext();
CRTextureObj *tobj;
CRTextureLevel *tl;
if (g->current.inBeginEnd) {
crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
"glTexSubImage%uD called in Begin/End", dims);
return GL_TRUE;
}
if (dims == 1) {
if (target != GL_TEXTURE_1D) {
crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
"glTexSubImage1D(target=0x%x)", target);
return GL_TRUE;
}
}
else if (dims == 2) {
if (target != GL_TEXTURE_2D &&
target != GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
target != GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB &&
target != GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB &&
target != GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB &&
target != GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB &&
target != GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB &&
target != GL_TEXTURE_RECTANGLE_NV) {
crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
"glTexSubImage2D(target=0x%x)", target);
return GL_TRUE;
}
}
else if (dims == 3) {
if (target != GL_TEXTURE_3D) {
crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
"glTexSubImage3D(target=0x%x)", target);
return GL_TRUE;
}
}
/* test level */
if (level < 0 || level > MaxTextureLevel(g, target)) {
crStateError(__LINE__, __FILE__, GL_INVALID_VALUE,
"glTexSubImage%uD(level=%d)", dims, level);
return GL_TRUE;
}
crStateGetTextureObjectAndImage(g, target, level, &tobj, &tl);
if (!tobj || !tl) {
crStateError(__LINE__, __FILE__, GL_INVALID_VALUE,
"glTexSubImage%uD(target or level)", dims);
return GL_TRUE;
}
/* test x/y/zoffset and size */
if (xoffset < -tl->border || xoffset + width > tl->width) {
crStateError(__LINE__, __FILE__, GL_INVALID_VALUE,
"glTexSubImage%uD(xoffset=%d + width=%d > %d)",
dims, xoffset, width, tl->width);
return GL_TRUE;
}
if (dims > 1 && (yoffset < -tl->border || yoffset + height > tl->height)) {
crStateError(__LINE__, __FILE__, GL_INVALID_VALUE,
"glTexSubImage%uD(yoffset=%d + height=%d > %d)",
dims, yoffset, height, tl->height);
return GL_TRUE;
}
if (dims > 2 && (zoffset < -tl->border || zoffset + depth > tl->depth)) {
crStateError(__LINE__, __FILE__, GL_INVALID_VALUE,
"glTexSubImage%uD(zoffset=%d and/or depth=%d)",
dims, zoffset, depth);
return GL_TRUE;
}
/* OK, no errors */
return GL_FALSE;
}
void STATE_APIENTRY
crStateTexImage1D(GLenum target, GLint level, GLint internalFormat,
GLsizei width, GLint border, GLenum format,
GLenum type, const GLvoid * pixels)
{
CRContext *g = GetCurrentContext();
CRTextureState *t = &(g->texture);
CRClientState *c = &(g->client);
CRTextureObj *tobj;
CRTextureLevel *tl;
CRStateBits *sb = GetCurrentBits();
CRTextureBits *tb = &(sb->texture);
FLUSH();
if (ErrorCheckTexImage(1, target, level, width, 1, 1, border)) {
if (IsProxyTarget(target)) {
/* clear all state, but don't generate error */
crStateTextureInitTextureObj(g, &(t->proxy1D), 0, GL_TEXTURE_1D);
}
else {
/* error was already recorded */
}
return;
}
crStateGetTextureObjectAndImage(g, target, level, &tobj, &tl);
CRASSERT(tobj);
CRASSERT(tl);
if (IsProxyTarget(target))
tl->bytes = 0;
else
tl->bytes = crImageSize(format, type, width, 1);
if (tl->bytes)
{
/* this is not a proxy texture target so alloc storage */
if (tl->img)
crFree(tl->img);
tl->img = (GLubyte *) crAlloc(tl->bytes);
if (!tl->img)
{
crStateError(__LINE__, __FILE__, GL_OUT_OF_MEMORY,
"glTexImage1D out of memory");
return;
}
if (pixels)
crPixelCopy1D((GLvoid *) tl->img, format, type,
pixels, format, type, width, &(c->unpack));
}
tl->width = width;
tl->height = 1;
tl->depth = 1;
tl->format = format;
tl->border = border;
tl->internalFormat = internalFormat;
crStateTextureInitTextureFormat(tl, internalFormat);
tl->type = type;
tl->compressed = GL_FALSE;
if (width)
tl->bytesPerPixel = tl->bytes / width;
else
tl->bytesPerPixel = 0;
#ifdef CR_SGIS_generate_mipmap
if (level == tobj->baseLevel && tobj->generateMipmap) {
generate_mipmap(tobj, target);
}
else {
tl->generateMipmap = GL_FALSE;
}
#endif
/* XXX may need to do some fine-tuning here for proxy textures */
DIRTY(tobj->dirty, g->neg_bitid);
DIRTY(tobj->imageBit, g->neg_bitid);
DIRTY(tl->dirty, g->neg_bitid);
DIRTY(tb->dirty, g->neg_bitid);
}
void STATE_APIENTRY
crStateTexImage2D(GLenum target, GLint level, GLint internalFormat,
GLsizei width, GLsizei height, GLint border,
GLenum format, GLenum type, const GLvoid * pixels)
{
CRContext *g = GetCurrentContext();
CRTextureState *t = &(g->texture);
CRClientState *c = &(g->client);
CRTextureObj *tobj = NULL;
CRTextureLevel *tl = NULL;
CRStateBits *sb = GetCurrentBits();
CRTextureBits *tb = &(sb->texture);
const int is_distrib = ((type == GL_TRUE) || (type == GL_FALSE));
FLUSH();
/* NOTE: we skip parameter error checking if this is a distributed
* texture! The user better provide correct parameters!!!
*/
if (!is_distrib
&& ErrorCheckTexImage(2, target, level, width, height, 1, border)) {
if (IsProxyTarget(target)) {
/* clear all state, but don't generate error */
crStateTextureInitTextureObj(g, &(t->proxy2D), 0, GL_TEXTURE_2D);
}
else {
/* error was already recorded */
}
return;
}
crStateGetTextureObjectAndImage(g, target, level, &tobj, &tl);
CRASSERT(tobj);
CRASSERT(tl);
/* compute size of image buffer */
if (is_distrib) {
tl->bytes = crStrlen((char *) pixels) + 1;
tl->bytes += crImageSize(format, GL_UNSIGNED_BYTE, width, height);
}
else if (IsProxyTarget(target)) {
tl->bytes = 0;
}
else {
tl->bytes = crImageSize(format, type, width, height);
}
/* allocate the image buffer and fill it */
if (tl->bytes)
{
/* this is not a proxy texture target so alloc storage */
if (tl->img)
crFree(tl->img);
tl->img = (GLubyte *) crAlloc(tl->bytes);
if (!tl->img)
{
crStateError(__LINE__, __FILE__, GL_OUT_OF_MEMORY,
"glTexImage2D out of memory");
return;
}
if (pixels)
{
if (is_distrib)
{
crMemcpy((void *) tl->img, (void *) pixels, tl->bytes);
}
else
{
crPixelCopy2D(width, height,
(GLvoid *) tl->img, format, type, NULL, /* dst */
pixels, format, type, &(c->unpack)); /* src */
}
}
}
tl->width = width;
tl->height = height;
tl->depth = 1;
tl->format = format;
tl->internalFormat = internalFormat;
crStateTextureInitTextureFormat(tl, internalFormat);
tl->border = border;
tl->type = type;
tl->compressed = GL_FALSE;
if (width && height)
{
if (is_distrib)
tl->bytesPerPixel = 3; /* only support GL_RGB */
else
tl->bytesPerPixel = tl->bytes / (width * height);
}
else
tl->bytesPerPixel = 0;
#ifdef CR_SGIS_generate_mipmap
if (level == tobj->baseLevel && tobj->generateMipmap) {
generate_mipmap(tobj, target);
}
else {
tl->generateMipmap = GL_FALSE;
}
#endif
/* XXX may need to do some fine-tuning here for proxy textures */
DIRTY(tobj->dirty, g->neg_bitid);
DIRTY(tobj->imageBit, g->neg_bitid);
DIRTY(tl->dirty, g->neg_bitid);
DIRTY(tb->dirty, g->neg_bitid);
}
#if defined( CR_OPENGL_VERSION_1_2 ) || defined( GL_EXT_texture3D )
void STATE_APIENTRY
crStateTexImage3D(GLenum target, GLint level,
GLint internalFormat,
GLsizei width, GLsizei height,
GLsizei depth, GLint border,
GLenum format, GLenum type, const GLvoid * pixels)
{
CRContext *g = GetCurrentContext();
CRTextureState *t = &(g->texture);
CRClientState *c = &(g->client);
CRTextureObj *tobj = NULL;
CRTextureLevel *tl = NULL;
CRStateBits *sb = GetCurrentBits();
CRTextureBits *tb = &(sb->texture);
FLUSH();
if (ErrorCheckTexImage(3, target, level, width, height, depth, border)) {
if (IsProxyTarget(target)) {
/* clear all state, but don't generate error */
crStateTextureInitTextureObj(g, &(t->proxy3D), 0, GL_TEXTURE_3D);
}
else {
/* error was already recorded */
}
return;
}
crStateGetTextureObjectAndImage(g, target, level, &tobj, &tl);
CRASSERT(tobj);
CRASSERT(tl);
if (IsProxyTarget(target))
tl->bytes = 0;
else
tl->bytes = crTextureSize(format, type, width, height, depth);
if (tl->bytes)
{
/* this is not a proxy texture target so alloc storage */
if (tl->img)
crFree(tl->img);
tl->img = (GLubyte *) crAlloc(tl->bytes);
if (!tl->img)
{
crStateError(__LINE__, __FILE__, GL_OUT_OF_MEMORY,
"glTexImage3D out of memory");
return;
}
if (pixels)
crPixelCopy3D(width, height, depth, (GLvoid *) (tl->img), format, type,
NULL, pixels, format, type, &(c->unpack));
}
tl->internalFormat = internalFormat;
tl->border = border;
tl->width = width;
tl->height = height;
tl->depth = depth;
tl->format = format;
tl->type = type;
tl->compressed = GL_FALSE;
#ifdef CR_SGIS_generate_mipmap
if (level == tobj->baseLevel && tobj->generateMipmap) {
generate_mipmap(tobj, target);
}
else {
tl->generateMipmap = GL_FALSE;
}
#endif
/* XXX may need to do some fine-tuning here for proxy textures */
DIRTY(tobj->dirty, g->neg_bitid);
DIRTY(tobj->imageBit, g->neg_bitid);
DIRTY(tl->dirty, g->neg_bitid);
DIRTY(tb->dirty, g->neg_bitid);
}
#endif /* CR_OPENGL_VERSION_1_2 || GL_EXT_texture3D */
#ifdef GL_EXT_texture3D
void STATE_APIENTRY
crStateTexImage3DEXT(GLenum target, GLint level,
GLenum internalFormat,
GLsizei width, GLsizei height, GLsizei depth,
GLint border, GLenum format, GLenum type,
const GLvoid * pixels)
{
crStateTexImage3D(target, level, (GLint) internalFormat, width, height,
depth, border, format, type, pixels);
}
#endif /* GL_EXT_texture3D */
void STATE_APIENTRY
crStateTexSubImage1D(GLenum target, GLint level, GLint xoffset,
GLsizei width, GLenum format,
GLenum type, const GLvoid * pixels)
{
CRContext *g = GetCurrentContext();
CRTextureState *t = &(g->texture);
CRClientState *c = &(g->client);
CRStateBits *sb = GetCurrentBits();
CRTextureBits *tb = &(sb->texture);
CRTextureUnit *unit = t->unit + t->curTextureUnit;
CRTextureObj *tobj = unit->currentTexture1D;
CRTextureLevel *tl = tobj->level[0] + level;
FLUSH();
if (ErrorCheckTexSubImage(1, target, level, xoffset, 0, 0,
width, 1, 1)) {
return; /* GL error state already set */
}
xoffset += tl->border;
crPixelCopy1D((void *) (tl->img + xoffset * tl->bytesPerPixel),
tl->format, tl->type,
pixels, format, type, width, &(c->unpack));
#ifdef CR_SGIS_generate_mipmap
if (level == tobj->baseLevel && tobj->generateMipmap) {
generate_mipmap(tobj, target);
}
else {
tl->generateMipmap = GL_FALSE;
}
#endif
DIRTY(tobj->dirty, g->neg_bitid);
DIRTY(tobj->imageBit, g->neg_bitid);
DIRTY(tl->dirty, g->neg_bitid);
DIRTY(tb->dirty, g->neg_bitid);
}
void STATE_APIENTRY
crStateTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLsizei width, GLsizei height,
GLenum format, GLenum type, const GLvoid * pixels)
{
CRContext *g = GetCurrentContext();
CRClientState *c = &(g->client);
CRStateBits *sb = GetCurrentBits();
CRTextureBits *tb = &(sb->texture);
CRTextureObj *tobj;
CRTextureLevel *tl;
GLubyte *subimg = NULL;
GLubyte *img = NULL;
GLubyte *src;
int i;
FLUSH();
if (ErrorCheckTexSubImage(2, target, level, xoffset, yoffset, 0,
width, height, 1)) {
return; /* GL error state already set */
}
crStateGetTextureObjectAndImage(g, target, level, &tobj, &tl);
CRASSERT(tobj);
CRASSERT(tl);
xoffset += tl->border;
yoffset += tl->border;
subimg =
(GLubyte *) crAlloc(crImageSize(tl->format, tl->type, width, height));
crPixelCopy2D(width, height, subimg, tl->format, tl->type, NULL, /* dst */
pixels, format, type, &(c->unpack)); /* src */
img = tl->img +
xoffset * tl->bytesPerPixel + yoffset * tl->width * tl->bytesPerPixel;
src = subimg;
/* Copy the data into the texture */
for (i = 0; i < height; i++)
{
crMemcpy(img, src, tl->bytesPerPixel * width);
img += tl->width * tl->bytesPerPixel;
src += width * tl->bytesPerPixel;
}
crFree(subimg);
#ifdef CR_SGIS_generate_mipmap
if (level == tobj->baseLevel && tobj->generateMipmap) {
generate_mipmap(tobj, target);
}
else {
tl->generateMipmap = GL_FALSE;
}
#endif
DIRTY(tobj->dirty, g->neg_bitid);
DIRTY(tobj->imageBit, g->neg_bitid);
DIRTY(tl->dirty, g->neg_bitid);
DIRTY(tb->dirty, g->neg_bitid);
}
#if defined( CR_OPENGL_VERSION_1_2 )
void STATE_APIENTRY
crStateTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLint zoffset, GLsizei width, GLsizei height,
GLsizei depth, GLenum format, GLenum type,
const GLvoid * pixels)
{
CRContext *g = GetCurrentContext();
CRTextureState *t = &(g->texture);
CRClientState *c = &(g->client);
CRStateBits *sb = GetCurrentBits();
CRTextureBits *tb = &(sb->texture);
CRTextureUnit *unit = t->unit + t->curTextureUnit;
CRTextureObj *tobj = unit->currentTexture3D;
CRTextureLevel *tl = tobj->level[0] + level;
GLubyte *subimg = NULL;
GLubyte *img = NULL;
GLubyte *src;
int i;
FLUSH();
if (ErrorCheckTexSubImage(3, target, level, xoffset, yoffset, zoffset,
width, height, depth)) {
return; /* GL error state already set */
}
xoffset += tl->border;
yoffset += tl->border;
zoffset += tl->border;
subimg =
(GLubyte *)
crAlloc(crTextureSize(tl->format, tl->type, width, height, depth));
crPixelCopy3D(width, height, depth, subimg, tl->format, tl->type, NULL,
pixels, format, type, &(c->unpack));
img = tl->img + xoffset * tl->bytesPerPixel +
yoffset * tl->width * tl->bytesPerPixel +
zoffset * tl->width * tl->height * tl->bytesPerPixel;
src = subimg;
/* Copy the data into the texture */
for (i = 0; i < depth; i++)
{
crMemcpy(img, src, tl->bytesPerPixel * width * height);
img += tl->width * tl->height * tl->bytesPerPixel;
src += width * height * tl->bytesPerPixel;
}
crFree(subimg);
#ifdef CR_SGIS_generate_mipmap
if (level == tobj->baseLevel && tobj->generateMipmap) {
generate_mipmap(tobj, target);
}
else {
tl->generateMipmap = GL_FALSE;
}
#endif
DIRTY(tobj->dirty, g->neg_bitid);
DIRTY(tobj->imageBit, g->neg_bitid);
DIRTY(tl->dirty, g->neg_bitid);
DIRTY(tb->dirty, g->neg_bitid);
}
#endif /* CR_OPENGL_VERSION_1_2 || GL_EXT_texture3D */
void STATE_APIENTRY
crStateCompressedTexImage1DARB(GLenum target, GLint level,
GLenum internalFormat, GLsizei width,
GLint border, GLsizei imageSize,
const GLvoid * data)
{
CRContext *g = GetCurrentContext();
CRTextureState *t = &(g->texture);
CRTextureObj *tobj;
CRTextureLevel *tl;
CRStateBits *sb = GetCurrentBits();
CRTextureBits *tb = &(sb->texture);
FLUSH();
if (ErrorCheckTexImage(1, target, level, width, 1, 1, border)) {
if (IsProxyTarget(target)) {
/* clear all state, but don't generate error */
crStateTextureInitTextureObj(g, &(t->proxy1D), 0, GL_TEXTURE_1D);
}
else {
/* error was already recorded */
}
return;
}
crStateGetTextureObjectAndImage(g, target, level, &tobj, &tl);
CRASSERT(tobj);
CRASSERT(tl);
if (IsProxyTarget(target))
tl->bytes = 0;
else
tl->bytes = imageSize;
if (tl->bytes)
{
/* this is not a proxy texture target so alloc storage */
if (tl->img)
crFree(tl->img);
tl->img = (GLubyte *) crAlloc(tl->bytes);
if (!tl->img)
{
crStateError(__LINE__, __FILE__, GL_OUT_OF_MEMORY,
"glTexImage1D out of memory");
return;
}
if (data)
crMemcpy(tl->img, data, imageSize);
}
tl->width = width;
tl->height = 1;
tl->depth = 1;
tl->border = border;
tl->format = GL_NONE;
tl->type = GL_NONE;
tl->internalFormat = internalFormat;
crStateTextureInitTextureFormat(tl, internalFormat);
tl->compressed = GL_TRUE;
tl->bytesPerPixel = 0; /* n/a */
#ifdef CR_SGIS_generate_mipmap
if (level == tobj->baseLevel && tobj->generateMipmap) {
generate_mipmap(tobj, target);
}
else {
tl->generateMipmap = GL_FALSE;
}
#endif
DIRTY(tobj->dirty, g->neg_bitid);
DIRTY(tobj->imageBit, g->neg_bitid);
DIRTY(tl->dirty, g->neg_bitid);
DIRTY(tb->dirty, g->neg_bitid);
}
void STATE_APIENTRY
crStateCompressedTexImage2DARB(GLenum target, GLint level,
GLenum internalFormat, GLsizei width,
GLsizei height, GLint border,
GLsizei imageSize, const GLvoid * data)
{
CRContext *g = GetCurrentContext();
CRTextureState *t = &(g->texture);
CRTextureObj *tobj = NULL;
CRTextureLevel *tl = NULL;
CRStateBits *sb = GetCurrentBits();
CRTextureBits *tb = &(sb->texture);
FLUSH();
if (ErrorCheckTexImage(2, target, level, width, height, 1, border)) {
if (IsProxyTarget(target)) {
/* clear all state, but don't generate error */
crStateTextureInitTextureObj(g, &(t->proxy2D), 0, GL_TEXTURE_2D);
}
else {
/* error was already recorded */
}
return;
}
crStateGetTextureObjectAndImage(g, target, level, &tobj, &tl);
CRASSERT(tobj);
CRASSERT(tl);
if (IsProxyTarget(target))
tl->bytes = 0;
else
tl->bytes = imageSize;
if (tl->bytes)
{
/* this is not a proxy texture target so alloc storage */
if (tl->img)
crFree(tl->img);
tl->img = (GLubyte *) crAlloc(tl->bytes);
if (!tl->img)
{
crStateError(__LINE__, __FILE__, GL_OUT_OF_MEMORY,
"glTexImage2D out of memory");
return;
}
if (data)
crMemcpy(tl->img, data, imageSize);
}
tl->width = width;
tl->height = height;
tl->depth = 1;
tl->border = border;
tl->format = GL_NONE;
tl->type = GL_NONE;
tl->internalFormat = internalFormat;
crStateTextureInitTextureFormat(tl, internalFormat);
tl->compressed = GL_TRUE;
tl->bytesPerPixel = 0; /* n/a */
#ifdef CR_SGIS_generate_mipmap
if (level == tobj->baseLevel && tobj->generateMipmap) {
generate_mipmap(tobj, target);
}
else {
tl->generateMipmap = GL_FALSE;
}
#endif
/* XXX may need to do some fine-tuning here for proxy textures */
DIRTY(tobj->dirty, g->neg_bitid);
DIRTY(tobj->imageBit, g->neg_bitid);
DIRTY(tl->dirty, g->neg_bitid);
DIRTY(tb->dirty, g->neg_bitid);
}
void STATE_APIENTRY
crStateCompressedTexImage3DARB(GLenum target, GLint level,
GLenum internalFormat, GLsizei width,
GLsizei height, GLsizei depth, GLint border,
GLsizei imageSize, const GLvoid * data)
{
CRContext *g = GetCurrentContext();
CRTextureState *t = &(g->texture);
CRTextureObj *tobj = NULL;
CRTextureLevel *tl = NULL;
CRStateBits *sb = GetCurrentBits();
CRTextureBits *tb = &(sb->texture);
FLUSH();
if (ErrorCheckTexImage(3, target, level, width, height, depth, border)) {
if (IsProxyTarget(target)) {
/* clear all state, but don't generate error */
crStateTextureInitTextureObj(g, &(t->proxy3D), 0, GL_TEXTURE_3D);
}
else {
/* error was already recorded */
}
return;
}
crStateGetTextureObjectAndImage(g, target, level, &tobj, &tl);
CRASSERT(tobj);
CRASSERT(tl);
if (IsProxyTarget(target))
tl->bytes = 0;
else
tl->bytes = imageSize;
if (tl->bytes)
{
/* this is not a proxy texture target so alloc storage */
if (tl->img)
crFree(tl->img);
tl->img = (GLubyte *) crAlloc(tl->bytes);
if (!tl->img)
{
crStateError(__LINE__, __FILE__, GL_OUT_OF_MEMORY,
"glCompressedTexImage3D out of memory");
return;
}
if (data)
crMemcpy(tl->img, data, imageSize);
}
tl->width = width;
tl->height = height;
tl->depth = depth;
tl->border = border;
tl->format = GL_NONE;
tl->type = GL_NONE;
tl->internalFormat = internalFormat;
crStateTextureInitTextureFormat(tl, internalFormat);
tl->compressed = GL_TRUE;
tl->bytesPerPixel = 0; /* n/a */
#ifdef CR_SGIS_generate_mipmap
if (level == tobj->baseLevel && tobj->generateMipmap) {
generate_mipmap(tobj, target);
}
else {
tl->generateMipmap = GL_FALSE;
}
#endif
/* XXX may need to do some fine-tuning here for proxy textures */
DIRTY(tobj->dirty, g->neg_bitid);
DIRTY(tobj->imageBit, g->neg_bitid);
DIRTY(tl->dirty, g->neg_bitid);
DIRTY(tb->dirty, g->neg_bitid);
}
void STATE_APIENTRY
crStateCompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset,
GLsizei width, GLenum format,
GLsizei imageSize, const GLvoid * data)
{
CRContext *g = GetCurrentContext();
CRTextureState *t = &(g->texture);
CRStateBits *sb = GetCurrentBits();
CRTextureBits *tb = &(sb->texture);
CRTextureUnit *unit = t->unit + t->curTextureUnit;
CRTextureObj *tobj = unit->currentTexture1D;
CRTextureLevel *tl = tobj->level[0] + level;
FLUSH();
if (ErrorCheckTexSubImage(1, target, level, xoffset, 0, 0, width, 1, 1)) {
return; /* GL error state already set */
}
xoffset += tl->border;
if (xoffset == 0 && width == tl->width) {
/* just memcpy */
crMemcpy(tl->img, data, imageSize);
}
else {
/* XXX this depends on the exact compression method */
}
#ifdef CR_SGIS_generate_mipmap
if (level == tobj->baseLevel && tobj->generateMipmap) {
generate_mipmap(tobj, target);
}
else {
tl->generateMipmap = GL_FALSE;
}
#endif
DIRTY(tobj->dirty, g->neg_bitid);
DIRTY(tobj->imageBit, g->neg_bitid);
DIRTY(tl->dirty, g->neg_bitid);
DIRTY(tb->dirty, g->neg_bitid);
}
void STATE_APIENTRY
crStateCompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset,
GLint yoffset, GLsizei width,
GLsizei height, GLenum format,
GLsizei imageSize, const GLvoid * data)
{
CRContext *g = GetCurrentContext();
CRTextureState *t = &(g->texture);
CRStateBits *sb = GetCurrentBits();
CRTextureBits *tb = &(sb->texture);
CRTextureUnit *unit = t->unit + t->curTextureUnit;
CRTextureObj *tobj = unit->currentTexture1D;
CRTextureLevel *tl = tobj->level[0] + level;
FLUSH();
if (ErrorCheckTexSubImage(2, target, level, xoffset, yoffset, 0,
width, height, 1)) {
return; /* GL error state already set */
}
xoffset += tl->border;
yoffset += tl->border;
if (xoffset == 0 && width == tl->width &&
yoffset == 0 && height == tl->height) {
/* just memcpy */
crMemcpy(tl->img, data, imageSize);
}
else {
/* XXX this depends on the exact compression method */
}
#ifdef CR_SGIS_generate_mipmap
if (level == tobj->baseLevel && tobj->generateMipmap) {
generate_mipmap(tobj, target);
}
else {
tl->generateMipmap = GL_FALSE;
}
#endif
DIRTY(tobj->dirty, g->neg_bitid);
DIRTY(tobj->imageBit, g->neg_bitid);
DIRTY(tl->dirty, g->neg_bitid);
DIRTY(tb->dirty, g->neg_bitid);
}
void STATE_APIENTRY
crStateCompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset,
GLint yoffset, GLint zoffset, GLsizei width,
GLsizei height, GLsizei depth,
GLenum format, GLsizei imageSize,
const GLvoid * data)
{
CRContext *g = GetCurrentContext();
CRTextureState *t = &(g->texture);
CRStateBits *sb = GetCurrentBits();
CRTextureBits *tb = &(sb->texture);
CRTextureUnit *unit = t->unit + t->curTextureUnit;
CRTextureObj *tobj = unit->currentTexture1D;
CRTextureLevel *tl = tobj->level[0] + level;
FLUSH();
if (ErrorCheckTexSubImage(3, target, level, xoffset, yoffset, zoffset,
width, height, depth)) {
return; /* GL error state already set */
}
xoffset += tl->border;
yoffset += tl->border;
zoffset += tl->border;
if (xoffset == 0 && width == tl->width &&
yoffset == 0 && height == tl->height &&
zoffset == 0 && depth == tl->depth) {
/* just memcpy */
crMemcpy(tl->img, data, imageSize);
}
else {
/* XXX this depends on the exact compression method */
}
#ifdef CR_SGIS_generate_mipmap
if (level == tobj->baseLevel && tobj->generateMipmap) {
generate_mipmap(tobj, target);
}
else {
tl->generateMipmap = GL_FALSE;
}
#endif
DIRTY(tobj->dirty, g->neg_bitid);
DIRTY(tobj->imageBit, g->neg_bitid);
DIRTY(tl->dirty, g->neg_bitid);
DIRTY(tb->dirty, g->neg_bitid);
}
void STATE_APIENTRY
crStateGetCompressedTexImageARB(GLenum target, GLint level, GLvoid * img)
{
CRContext *g = GetCurrentContext();
CRTextureObj *tobj;
CRTextureLevel *tl;
if (g->current.inBeginEnd)
{
crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
"glGetCompressedTexImage called in begin/end");
return;
}
crStateGetTextureObjectAndImage(g, target, level, &tobj, &tl);
if (!tobj || !tl) {
crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
"glGetCompressedTexImage(invalid target or level)");
return;
}
if (!tl->compressed) {
crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
"glGetCompressedTexImage(not a compressed texture)");
return;
}
crMemcpy(img, tl->img, tl->bytes);
}
void STATE_APIENTRY
crStateGetTexImage(GLenum target, GLint level, GLenum format,
GLenum type, GLvoid * pixels)
{
CRContext *g = GetCurrentContext();
CRClientState *c = &(g->client);
CRTextureObj *tobj;
CRTextureLevel *tl;
if (g->current.inBeginEnd)
{
crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
"glGetTexImage called in begin/end");
return;
}
crStateGetTextureObjectAndImage(g, target, level, &tobj, &tl);
if (!tobj || !tl) {
crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
"glGetTexImage(invalid target or level)");
return;
}
if (tl->compressed) {
crWarning("glGetTexImage cannot decompress a compressed texture!");
return;
}
switch (format)
{
case GL_RED:
case GL_GREEN:
case GL_BLUE:
case GL_ALPHA:
case GL_RGB:
case GL_RGBA:
case GL_LUMINANCE:
case GL_LUMINANCE_ALPHA:
break;
default:
crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
"glGetTexImage called with bogus format: %d", format);
return;
}
switch (type)
{
case GL_UNSIGNED_BYTE:
case GL_BYTE:
case GL_UNSIGNED_SHORT:
case GL_SHORT:
case GL_UNSIGNED_INT:
case GL_INT:
case GL_FLOAT:
break;
default:
crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
"glGetTexImage called with bogus type: %d", type);
return;
}
#ifdef CR_OPENGL_VERSION_1_2
if (target == GL_TEXTURE_3D)
{
crPixelCopy3D(tl->width, tl->height, tl->depth, (GLvoid *) pixels, format,
type, NULL, (tl->img), format, type, &(c->pack));
}
else
#endif
if ((target == GL_TEXTURE_2D) || (target == GL_TEXTURE_1D))
{
crPixelCopy2D(tl->width, tl->height, (GLvoid *) pixels, format, type, NULL, /* dst */
(tl->img), format, type, &(c->pack)); /* src */
}
}