This is teximage.c in view mode; [Download] [Up]
/* $Id: teximage.c,v 1.5 1996/09/27 01:29:57 brianp Exp $ */
/*
* Mesa 3-D graphics library
* Version: 2.0
* Copyright (C) 1995-1996 Brian Paul
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* $Log: teximage.c,v $
* Revision 1.5 1996/09/27 01:29:57 brianp
* removed unused variables, fixed cut&paste bug in color scaling
*
* Revision 1.4 1996/09/26 22:35:10 brianp
* fixed a few compiler warnings from IRIX 6 -n32 and -64 compiler
*
* Revision 1.3 1996/09/15 14:18:55 brianp
* now use GLframebuffer and GLvisual
*
* Revision 1.2 1996/09/15 01:48:58 brianp
* removed #define NULL 0
*
* Revision 1.1 1996/09/13 01:38:16 brianp
* Initial revision
*
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "context.h"
#include "image.h"
#include "macros.h"
#include "pixel.h"
#include "span.h"
#include "teximage.h"
#include "types.h"
/*
* NOTES:
*
* The internal texture storage convension is an array of N GLubytes
* where N = width * height * components. There is no padding.
*/
/*
* Compute log base 2 of n.
* If n isn't an exact power of two return -1.
* If n<0 return -1.
*/
static int logbase2( int n )
{
GLint m = n;
GLint i = 1;
GLint log2 = 0;
if (n<0) {
return -1;
}
while ( m > i ) {
i *= 2;
log2++;
}
if (m != n) {
return -1;
}
else {
return log2;
}
}
/*
* Given an internal texture format enum or 1, 2, 3, 4 return the
* corresponding _base_ internal format: GL_ALPHA, GL_LUMINANCE,
* GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, or GL_RGBA. Return -1 if
* invalid enum.
*/
GLint decode_internal_format( GLint format )
{
switch (format) {
case GL_ALPHA:
case GL_ALPHA4:
case GL_ALPHA8:
case GL_ALPHA12:
case GL_ALPHA16:
return GL_ALPHA;
case 1:
case GL_LUMINANCE:
case GL_LUMINANCE4:
case GL_LUMINANCE8:
case GL_LUMINANCE12:
case GL_LUMINANCE16:
return GL_LUMINANCE;
case 2:
case GL_LUMINANCE_ALPHA:
case GL_LUMINANCE4_ALPHA4:
case GL_LUMINANCE6_ALPHA2:
case GL_LUMINANCE8_ALPHA8:
case GL_LUMINANCE12_ALPHA4:
case GL_LUMINANCE12_ALPHA12:
case GL_LUMINANCE16_ALPHA16:
return GL_LUMINANCE_ALPHA;
case GL_INTENSITY:
case GL_INTENSITY4:
case GL_INTENSITY8:
case GL_INTENSITY12:
case GL_INTENSITY16:
return GL_INTENSITY;
case 3:
case GL_RGB:
case GL_R3_G3_B2:
case GL_RGB4:
case GL_RGB5:
case GL_RGB8:
case GL_RGB10:
case GL_RGB12:
case GL_RGB16:
return GL_RGB;
case 4:
case GL_RGBA:
case GL_RGBA2:
case GL_RGBA4:
case GL_RGB5_A1:
case GL_RGBA8:
case GL_RGB10_A2:
case GL_RGBA12:
case GL_RGBA16:
return GL_RGBA;
default:
return -1; /* error */
}
}
/*
* Given an internal texture format enum or 1, 2, 3, 4 return the
* corresponding _base_ internal format: GL_ALPHA, GL_LUMINANCE,
* GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, or GL_RGBA. Return the
* number of components for the format. Return -1 if invalid enum.
*/
GLint components_in_intformat( GLint format )
{
switch (format) {
case GL_ALPHA:
case GL_ALPHA4:
case GL_ALPHA8:
case GL_ALPHA12:
case GL_ALPHA16:
return 1;
case 1:
case GL_LUMINANCE:
case GL_LUMINANCE4:
case GL_LUMINANCE8:
case GL_LUMINANCE12:
case GL_LUMINANCE16:
return 1;
case 2:
case GL_LUMINANCE_ALPHA:
case GL_LUMINANCE4_ALPHA4:
case GL_LUMINANCE6_ALPHA2:
case GL_LUMINANCE8_ALPHA8:
case GL_LUMINANCE12_ALPHA4:
case GL_LUMINANCE12_ALPHA12:
case GL_LUMINANCE16_ALPHA16:
return 2;
case GL_INTENSITY:
case GL_INTENSITY4:
case GL_INTENSITY8:
case GL_INTENSITY12:
case GL_INTENSITY16:
return 1;
case 3:
case GL_RGB:
case GL_R3_G3_B2:
case GL_RGB4:
case GL_RGB5:
case GL_RGB8:
case GL_RGB10:
case GL_RGB12:
case GL_RGB16:
return 3;
case 4:
case GL_RGBA:
case GL_RGBA2:
case GL_RGBA4:
case GL_RGB5_A1:
case GL_RGBA8:
case GL_RGB10_A2:
case GL_RGBA12:
case GL_RGBA16:
return 4;
default:
return -1; /* error */
}
}
struct gl_texture_image *gl_alloc_texture_image( void )
{
return calloc( 1, sizeof(struct gl_texture_image) );
}
void gl_free_texture_image( struct gl_texture_image *teximage )
{
if (teximage->DeleteFlag) {
if (teximage->Data) {
free( teximage->Data );
}
free( teximage );
}
}
/*
* Convert the texture image given to glTexImage1D or glTexImage2D into
* the internal texture format which is an array of GLubytes.
* Error checking is performed on all parameters.
* Return: pointer to a gl_texture_image struct or NULL if error.
*/
struct gl_texture_image *gl_unpack_texture( GLcontext *ctx,
GLint dimensions,
GLenum target,
GLint level,
GLint internalformat,
GLsizei width, GLsizei height,
GLint border,
GLenum format, GLenum type,
const GLvoid *pixels )
{
GLboolean rflag, gflag, bflag, aflag, lflag;
GLuint elements;
GLuint i, row;
GLubyte *texture, *texptr;
GLboolean scale_or_bias;
struct gl_texture_image *teximage;
GLint iformat;
GLint components;
/* Error checking */
if (level<0 || level>=MAX_TEXTURE_LEVELS) {
return NULL;
}
iformat = decode_internal_format( internalformat );
components = components_in_intformat( internalformat );
if (iformat==-1) {
return NULL;
}
if (border!=0 && border!=1) {
return NULL;
}
switch (type) {
case GL_UNSIGNED_BYTE:
case GL_BYTE:
case GL_UNSIGNED_SHORT:
case GL_SHORT:
case GL_FLOAT:
/* OK */
break;
default:
return NULL;
}
if (dimensions==1) {
if (target!=GL_TEXTURE_1D && target!=GL_PROXY_TEXTURE_1D) {
return NULL;
}
if (width<2*border || width>2+MAX_TEXTURE_SIZE) {
return NULL;
}
if (logbase2( width-2*border )<0) {
return NULL;
}
width -= 2*border;
assert( height==1 );
}
else if (dimensions==2) {
if (target!=GL_TEXTURE_2D && target!=GL_PROXY_TEXTURE_2D) {
return NULL;
}
if (height<2*border || height>2+MAX_TEXTURE_SIZE) {
return NULL;
}
if (logbase2( height-2*border )<0) {
return NULL;
}
width -= 2*border;
height -= 2*border;
}
else {
abort();
}
scale_or_bias = ctx->Pixel.RedScale !=1.0F || ctx->Pixel.RedBias !=0.0F
|| ctx->Pixel.GreenScale!=1.0F || ctx->Pixel.GreenBias!=0.0F
|| ctx->Pixel.BlueScale !=1.0F || ctx->Pixel.BlueBias !=0.0F
|| ctx->Pixel.AlphaScale!=1.0F || ctx->Pixel.AlphaBias!=0.0F;
switch (format) {
case GL_COLOR_INDEX:
elements = 1;
rflag = gflag = bflag = aflag = lflag = GL_FALSE;
break;
case GL_RED:
elements = 1;
rflag = GL_TRUE;
gflag = bflag = aflag = lflag = GL_FALSE;
break;
case GL_GREEN:
elements = 1;
gflag = GL_TRUE;
rflag = bflag = aflag = lflag = GL_FALSE;
break;
case GL_BLUE:
elements = 1;
bflag = GL_TRUE;
rflag = gflag = aflag = lflag = GL_FALSE;
break;
case GL_ALPHA:
elements = 1;
aflag = GL_TRUE;
rflag = gflag = bflag = lflag = GL_FALSE;
break;
case GL_RGB:
elements = 3;
rflag = gflag = bflag = GL_TRUE;
aflag = lflag = GL_FALSE;
break;
case GL_RGBA:
elements = 4;
rflag = gflag = bflag = aflag = GL_TRUE;
lflag = GL_FALSE;
break;
case GL_LUMINANCE:
elements = 1;
rflag = gflag = bflag = aflag = GL_FALSE;
lflag = GL_TRUE;
break;
case GL_LUMINANCE_ALPHA:
elements = 2;
lflag = aflag = GL_TRUE;
rflag = gflag = bflag = GL_FALSE;
break;
default:
return NULL;
}
if (target==GL_PROXY_TEXTURE_1D || target==GL_PROXY_TEXTURE_2D) {
texture = NULL;
}
else {
/* Allocate texture memory */
texture = (GLubyte *) malloc( width * height * components );
if (!texture) {
gl_error( ctx, GL_OUT_OF_MEMORY, "glTexImage1/2D" );
return NULL;
}
texptr = texture;
/* TODO: obey glPixelStore parameters! */
/* Build texture map image row by row */
for (row=0;row<height;row++) {
if (type==GL_UNSIGNED_BYTE && format==GL_RGB && iformat==GL_RGB
&& !scale_or_bias) {
/*
* A frequent and simple case
*/
GLubyte *src = (GLubyte *) pixels + row * width * 3;
MEMCPY( texptr, src, 3*width );
texptr += 3*width;
}
else if (type==GL_UNSIGNED_BYTE && format==GL_RGBA && iformat==GL_RGBA
&& !scale_or_bias) {
/*
* Another frequent and simple case
*/
GLubyte *src = (GLubyte *) pixels + row * width * 4;
MEMCPY( texptr, src, 4*width );
texptr += 4*width;
}
else {
/*
* General solution
*/
GLfloat red[MAX_TEXTURE_SIZE], green[MAX_TEXTURE_SIZE];
GLfloat blue[MAX_TEXTURE_SIZE], alpha[MAX_TEXTURE_SIZE];
switch (type) {
case GL_UNSIGNED_BYTE:
{
GLubyte *src = (GLubyte*) pixels + row * width * elements;
for (i=0;i<width;i++) {
if (lflag) {
red[i] = green[i] = blue[i] = UBYTE_TO_FLOAT(*src++);
}
else {
red[i] = rflag ? UBYTE_TO_FLOAT(*src++) : 0.0F;
green[i] = gflag ? UBYTE_TO_FLOAT(*src++) : 0.0F;
blue[i] = bflag ? UBYTE_TO_FLOAT(*src++) : 0.0F;
}
alpha[i] = aflag ? UBYTE_TO_FLOAT(*src++) : 1.0F;
}
}
break;
case GL_BYTE:
{
GLbyte *src = (GLbyte *) pixels + row * width * elements;
for (i=0;i<width;i++) {
if (lflag) {
red[i] = green[i] = blue[i] = BYTE_TO_FLOAT(*src++);
}
else {
red[i] = rflag ? BYTE_TO_FLOAT(*src++) : 0.0F;
green[i] = gflag ? BYTE_TO_FLOAT(*src++) : 0.0F;
blue[i] = bflag ? BYTE_TO_FLOAT(*src++) : 0.0F;
}
alpha[i] = aflag ? BYTE_TO_FLOAT(*src++) : 1.0F;
}
}
break;
case GL_UNSIGNED_SHORT:
{
GLushort *src = (GLushort *) pixels + row *width*elements;
for (i=0;i<width;i++) {
if (lflag) {
red[i] = green[i] = blue[i]=USHORT_TO_FLOAT(*src++);
}
else {
red[i] = rflag ? USHORT_TO_FLOAT(*src++) : 0.0F;
green[i] = gflag ? USHORT_TO_FLOAT(*src++) : 0.0F;
blue[i] = bflag ? USHORT_TO_FLOAT(*src++) : 0.0F;
}
alpha[i] = aflag ? USHORT_TO_FLOAT(*src++) : 1.0F;
}
}
break;
case GL_SHORT:
{
GLshort *src = (GLshort *) pixels + row * width *elements;
for (i=0;i<width;i++) {
if (lflag) {
red[i] = green[i] = blue[i] =SHORT_TO_FLOAT(*src++);
}
else {
red[i] = rflag ? SHORT_TO_FLOAT(*src++) : 0.0F;
green[i] = gflag ? SHORT_TO_FLOAT(*src++) : 0.0F;
blue[i] = bflag ? SHORT_TO_FLOAT(*src++) : 0.0F;
}
alpha[i] = aflag ? SHORT_TO_FLOAT(*src++) : 1.0F;
}
}
break;
/*TODO: implement rest of data types */
case GL_FLOAT:
{
GLfloat *src = (GLfloat *) pixels + row * width *elements;
for (i=0;i<width;i++) {
if (lflag) {
red[i] = green[i] = blue[i] = *src++;
}
else {
red[i] = rflag ? *src++ : 0.0F;
green[i] = gflag ? *src++ : 0.0F;
blue[i] = bflag ? *src++ : 0.0F;
}
alpha[i] = aflag ? *src++ : 1.0F;
}
}
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glTexImage1/2D(type)" );
} /* switch */
/* apply scale and/or bias */
if (scale_or_bias) {
for (i=0;i<width;i++) {
register GLfloat r, g, b, a;
r = red[i] * ctx->Pixel.RedScale + ctx->Pixel.RedBias;
g = green[i] * ctx->Pixel.GreenScale + ctx->Pixel.GreenBias;
b = blue[i] * ctx->Pixel.BlueScale + ctx->Pixel.BlueBias;
a = alpha[i] * ctx->Pixel.AlphaScale + ctx->Pixel.AlphaBias;
red[i] = CLAMP( r, 0.0F, 1.0F );
green[i] = CLAMP( g, 0.0F, 1.0F );
blue[i] = CLAMP( b, 0.0F, 1.0F );
alpha[i] = CLAMP( a, 0.0F, 1.0F );
}
}
/* save 8-bit components */
switch (iformat) {
case GL_ALPHA:
for (i=0;i<width;i++) {
*texptr++ = (GLubyte) (GLint) (alpha[i] * 255.0F);
}
break;
case GL_LUMINANCE:
for (i=0;i<width;i++) {
*texptr++ = (GLubyte) (GLint) (red[i] * 255.0F);
}
break;
case GL_LUMINANCE_ALPHA:
for (i=0;i<width;i++) {
*texptr++ = (GLubyte) (GLint) (red[i] * 255.0F);
*texptr++ = (GLubyte) (GLint) (alpha[i] * 255.0F);
}
break;
case GL_INTENSITY:
for (i=0;i<width;i++) {
*texptr++ = (GLubyte) (GLint) (red[i] * 255.0F);
}
break;
case GL_RGB:
for (i=0;i<width;i++) {
*texptr++ = (GLubyte) (GLint) (red[i] * 255.0F);
*texptr++ = (GLubyte) (GLint) (green[i] * 255.0F);
*texptr++ = (GLubyte) (GLint) (blue[i] * 255.0F);
}
break;
case GL_RGBA:
for (i=0;i<width;i++) {
*texptr++ = (GLubyte) (GLint) (red[i] * 255.0F);
*texptr++ = (GLubyte) (GLint) (green[i] * 255.0F);
*texptr++ = (GLubyte) (GLint) (blue[i] * 255.0F);
*texptr++ = (GLubyte) (GLint) (alpha[i] * 255.0F);
}
break;
default:
abort();
} /* switch iformat */
} /* if general solution */
} /* for row */
}
/* If we get here we must have a valid, error-free texture image */
teximage = gl_alloc_texture_image();
if (teximage) {
int log2_width = logbase2(width);
int log2_height = logbase2(height);
teximage->Format = (GLenum) iformat;
teximage->Border = border;
teximage->Width = width;
teximage->Height = height;
teximage->WidthLog2 = log2_width;
teximage->HeightLog2 = log2_height;
teximage->MaxLog2 = MAX2( log2_width, log2_height );
teximage->Data = texture;
teximage->DeleteFlag = GL_TRUE; /* gl_save_TexImage*D may change this */
}
return teximage;
}
/*
* Called when there's an error in glTexImage1D with proxy target.
*/
static void proxy_1D_error( GLcontext *ctx, GLint level )
{
MEMSET( ctx->Texture.Proxy1D->Image[level], 0,
sizeof(struct gl_texture_image) );
}
/*
* Called when there's an error in glTexImage1D with proxy target.
*/
static void proxy_2D_error( GLcontext *ctx, GLint level )
{
MEMSET( ctx->Texture.Proxy2D->Image[level], 0,
sizeof(struct gl_texture_image) );
}
/*
* Called from the API. Note that width includes the border.
*/
void gl_TexImage1D( GLcontext *ctx,
GLenum target, GLint level, GLint internalformat,
GLsizei width, GLint border, GLenum format,
GLenum type, struct gl_texture_image *teximage )
{
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glTexImage1D" );
return;
}
if (teximage) {
/* if teximage is not NULL then it must be valid */
if (target==GL_TEXTURE_1D) {
/* free current texture image, if any */
if (ctx->Texture.Current1D->Image[level]) {
gl_free_texture_image( ctx->Texture.Current1D->Image[level] );
}
/* install new texture image */
ctx->Texture.Current1D->Image[level] = teximage;
ctx->NewState |= NEW_TEXTURING;
}
else {
/* Proxy texture: update proxy state */
MEMCPY( ctx->Texture.Proxy1D->Image[level], teximage,
sizeof(struct gl_texture_image) );
}
}
else {
/* An error must have occured during texture unpacking. Record the
* error now.
*/
GLint iformat;
if (target!=GL_TEXTURE_1D && target!=GL_PROXY_TEXTURE_1D) {
gl_error( ctx, GL_INVALID_ENUM, "glTexImage1D" );
return;
}
if (level<0 || level>=MAX_TEXTURE_LEVELS) {
gl_error( ctx, GL_INVALID_VALUE, "glTexImage1D(level)" );
return;
}
iformat = decode_internal_format( internalformat );
if (iformat<0) {
gl_error( ctx, GL_INVALID_VALUE, "glTexImage1D(internalformat)" );
if (target==GL_PROXY_TEXTURE_1D) {
proxy_1D_error( ctx, level );
}
return;
}
if (width<2*border || width>2+MAX_TEXTURE_SIZE) {
gl_error( ctx, GL_INVALID_VALUE, "glTexImage1D(width)" );
if (target==GL_PROXY_TEXTURE_1D) {
proxy_1D_error( ctx, level );
}
return;
}
if (border!=0 && border!=1) {
gl_error( ctx, GL_INVALID_VALUE, "glTexImage1D(border)" );
if (target==GL_PROXY_TEXTURE_1D) {
proxy_1D_error( ctx, level );
}
return;
}
if (logbase2( width-2*border )<0) {
gl_error( ctx, GL_INVALID_VALUE,
"glTexImage1D(width != 2^k + 2*border))");
if (target==GL_PROXY_TEXTURE_1D) {
proxy_1D_error( ctx, level );
}
return;
}
switch (format) {
case GL_COLOR_INDEX:
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:
/* OK */
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glTexImage1D(format)" );
if (target==GL_PROXY_TEXTURE_1D) {
proxy_1D_error( ctx, level );
}
return;
}
switch (type) {
case GL_UNSIGNED_BYTE:
case GL_BYTE:
case GL_UNSIGNED_SHORT:
case GL_SHORT:
case GL_FLOAT:
/* OK */
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glTexImage1D(type)" );
if (target==GL_PROXY_TEXTURE_1D) {
proxy_1D_error( ctx, level );
}
return;
}
}
}
/*
* Called by the API or display list executor.
* Note that width and height include the border.
*/
void gl_TexImage2D( GLcontext *ctx,
GLenum target, GLint level, GLint internalformat,
GLsizei width, GLsizei height, GLint border,
GLenum format, GLenum type,
struct gl_texture_image *teximage )
{
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glTexImage2D" );
return;
}
if (teximage) {
/* if teximage is not NULL then it must be valid */
if (target==GL_TEXTURE_2D) {
/* free current texture image, if any */
if (ctx->Texture.Current2D->Image[level]) {
gl_free_texture_image( ctx->Texture.Current2D->Image[level] );
}
/* install new texture image */
ctx->Texture.Current2D->Image[level] = teximage;
ctx->NewState |= NEW_TEXTURING;
}
else {
/* Proxy texture: update proxy state */
MEMCPY( ctx->Texture.Proxy1D->Image[level], teximage,
sizeof(struct gl_texture_image) );
}
}
else {
/* An error must have occured during texture unpacking. Record the
* error now.
*/
GLint iformat;
if (target!=GL_TEXTURE_2D && target!=GL_PROXY_TEXTURE_2D) {
gl_error( ctx, GL_INVALID_ENUM, "glTexImage2D(target)" );
return;
}
if (level<0 || level>=MAX_TEXTURE_LEVELS) {
gl_error( ctx, GL_INVALID_VALUE, "glTexImage2D(level)" );
return;
}
iformat = decode_internal_format( internalformat );
if (iformat<0) {
gl_error( ctx, GL_INVALID_VALUE, "glTexImage2D(internalformat)" );
if (target==GL_PROXY_TEXTURE_2D) {
proxy_2D_error( ctx, level );
}
return;
}
if (width<2*border || width>2+MAX_TEXTURE_SIZE) {
gl_error( ctx, GL_INVALID_VALUE, "glTexImage2D(width)" );
if (target==GL_PROXY_TEXTURE_2D) {
proxy_2D_error( ctx, level );
}
return;
}
if (height<2*border || height>2+MAX_TEXTURE_SIZE) {
gl_error( ctx, GL_INVALID_VALUE, "glTexImage2D(height)" );
if (target==GL_PROXY_TEXTURE_2D) {
proxy_2D_error( ctx, level );
}
return;
}
if (border!=0 && border!=1) {
gl_error( ctx, GL_INVALID_VALUE, "glTexImage2D(border)" );
if (target==GL_PROXY_TEXTURE_2D) {
proxy_2D_error( ctx, level );
}
return;
}
if (logbase2( width-2*border )<0) {
gl_error( ctx,GL_INVALID_VALUE,
"glTexImage2D(width != 2^k + 2*border))");
if (target==GL_PROXY_TEXTURE_2D) {
proxy_2D_error( ctx, level );
}
return;
}
if (logbase2( height-2*border )<0) {
gl_error( ctx,GL_INVALID_VALUE,
"glTexImage2D(height != 2^k + 2*border))");
if (target==GL_PROXY_TEXTURE_2D) {
proxy_2D_error( ctx, level );
}
return;
}
switch (format) {
case GL_COLOR_INDEX:
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:
/* OK */
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glTexImage2D(format)" );
if (target==GL_PROXY_TEXTURE_2D) {
proxy_2D_error( ctx, level );
}
return;
}
switch (type) {
case GL_UNSIGNED_BYTE:
case GL_BYTE:
case GL_UNSIGNED_SHORT:
case GL_SHORT:
case GL_FLOAT:
/* OK */
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glTexImage2D(type)" );
if (target==GL_PROXY_TEXTURE_2D) {
proxy_2D_error( ctx, level );
}
return;
}
}
}
void gl_GetTexImage( GLcontext *ctx, GLenum target, GLint level, GLenum format,
GLenum type, GLvoid *pixels )
{
/* TODO */
}
/*
* GL_EXT_copy_texture
*/
/*
* Unpack the image data given to glTexSubImage[12]D.
*/
struct gl_image *
gl_unpack_texsubimage( GLcontext *ctx, GLint width, GLint height,
GLenum format, GLenum type, const GLvoid *pixels )
{
GLint components;
GLenum desttype;
if (width<0 || height<0 || !pixels) {
return NULL;
}
components = components_in_intformat( format );
if (components<0 || format==GL_STENCIL_INDEX || format==GL_DEPTH_COMPONENT){
return NULL;
}
if (gl_sizeof_type(type)<=0) {
return NULL;
}
if (type==GL_UNSIGNED_BYTE) {
desttype = GL_UNSIGNED_BYTE;
}
else {
desttype = GL_FLOAT;
}
return gl_unpack_image( ctx, width, height, components, type,
desttype, pixels, GL_FALSE );
}
void gl_TexSubImage1D( GLcontext *ctx,
GLenum target, GLint level, GLint xoffset,
GLsizei width, GLenum format, GLenum type,
struct gl_image *image )
{
struct gl_texture_image *teximage;
if (target!=GL_TEXTURE_1D) {
gl_error( ctx, GL_INVALID_ENUM, "glTexSubImage1D(target)" );
return;
}
if (level<0 || level>=MAX_TEXTURE_LEVELS) {
gl_error( ctx, GL_INVALID_ENUM, "glTexSubImage1D(level)" );
return;
}
teximage = ctx->Texture.Current1D->Image[level];
if (!teximage) {
gl_error( ctx, GL_INVALID_OPERATION, "glTexSubImage1D" );
return;
}
if (xoffset < -teximage->Border) {
gl_error( ctx, GL_INVALID_VALUE, "glTexSubImage1D(xoffset)" );
return;
}
if (xoffset + width > teximage->Width+teximage->Border) {
gl_error( ctx, GL_INVALID_VALUE, "glTexSubImage1D(xoffset+width)" );
return;
}
if (image) {
/* unpacking must have been error-free */
GLint texcomponents, i, k;
GLubyte *dst, *src;
/* TODO: this is temporary. If Type==GL_FLOAT or scale&bias needed */
/* then do more work. */
if (image->Type==GL_FLOAT) {
gl_warning( ctx, "unimplemented texture type in glTexSubImage1D" );
return;
}
texcomponents = components_in_intformat(teximage->Format);
dst = teximage->Data + texcomponents * xoffset;
if (texcomponents == image->Components) {
MEMCPY( dst, image->Data, width * texcomponents );
}
else {
/* TODO: this is a hack */
gl_warning( ctx, "component mismatch in glTexSubImage1D" );
for (i=0;i<width;i++) {
for (k=0;k<texcomponents;k++) {
dst[k] = src[k];
}
dst += texcomponents;
src += image->Components;
}
}
}
else {
/* if no image, an error must have occured, do more testing now */
GLint components, size;
if (width<0) {
gl_error( ctx, GL_INVALID_VALUE, "glTexSubImage1D(width)" );
return;
}
components = components_in_intformat( format );
if (components<0 || format==GL_STENCIL_INDEX
|| format==GL_DEPTH_COMPONENT){
gl_error( ctx, GL_INVALID_ENUM, "glTexSubImage1D(format)" );
return;
}
size = gl_sizeof_type( type );
if (size<=0) {
gl_error( ctx, GL_INVALID_ENUM, "glTexSubImage1D(type)" );
return;
}
/* if we get here, probably ran out of memory during unpacking */
gl_error( ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D" );
}
}
void gl_TexSubImage2D( GLcontext *ctx,
GLenum target, GLint level,
GLint xoffset, GLint yoffset,
GLsizei width, GLsizei height,
GLenum format, GLenum type,
struct gl_image *image )
{
struct gl_texture_image *teximage;
if (target!=GL_TEXTURE_2D) {
gl_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(target)" );
return;
}
if (level<0 || level>=MAX_TEXTURE_LEVELS) {
gl_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(level)" );
return;
}
teximage = ctx->Texture.Current2D->Image[level];
if (!teximage) {
gl_error( ctx, GL_INVALID_OPERATION, "glTexSubImage2D" );
return;
}
if (xoffset < -teximage->Border) {
gl_error( ctx, GL_INVALID_VALUE, "glTexSubImage2D(xoffset)" );
return;
}
if (yoffset < -teximage->Border) {
gl_error( ctx, GL_INVALID_VALUE, "glTexSubImage2D(yoffset)" );
return;
}
if (xoffset + width > teximage->Width+teximage->Border) {
gl_error( ctx, GL_INVALID_VALUE, "glTexSubImage2D(xoffset+width)" );
return;
}
if (yoffset + height > teximage->Height+teximage->Border) {
gl_error( ctx, GL_INVALID_VALUE, "glTexSubImage2D(yoffset+height)" );
return;
}
if (image) {
/* unpacking must have been error-free */
GLint texcomponents, i, j, k;
GLubyte *dst, *src;
/* TODO: this is temporary. If Type==GL_FLOAT or scale&bias needed */
/* then do more work. */
if (image->Type==GL_FLOAT) {
gl_warning( ctx, "unimplemented texture type in glTexSubImage2D" );
return;
}
texcomponents = components_in_intformat(teximage->Format);
if (texcomponents == image->Components) {
dst = teximage->Data
+ (yoffset * teximage->Width + xoffset) * texcomponents;
src = image->Data;
for (j=0;j<height;j++) {
MEMCPY( dst, src, width * texcomponents );
dst += teximage->Width * texcomponents;
src += width * texcomponents;
}
}
else {
/* TODO: this is a hack */
gl_warning( ctx, "component mismatch in glTexSubImage2D" );
for (j=0;j<height;j++) {
dst = teximage->Data
+ ((yoffset+j) * teximage->Width + xoffset) * texcomponents;
src = (GLubyte *) image->Data + j * width * image->Components;
for (i=0;i<width;i++) {
for (k=0;k<texcomponents;k++) {
dst[k] = src[k];
}
dst += texcomponents;
src += image->Components;
}
}
}
}
else {
/* if no image, an error must have occured, do more testing now */
GLint components, size;
if (width<0) {
gl_error( ctx, GL_INVALID_VALUE, "glTexSubImage2D(width)" );
return;
}
if (height<0) {
gl_error( ctx, GL_INVALID_VALUE, "glTexSubImage2D(height)" );
return;
}
components = components_in_intformat( format );
if (components<0 || format==GL_STENCIL_INDEX
|| format==GL_DEPTH_COMPONENT){
gl_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(format)" );
return;
}
size = gl_sizeof_type( type );
if (size<=0) {
gl_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(type)" );
return;
}
/* if we get here, probably ran out of memory during unpacking */
gl_error( ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D" );
}
}
/*
* Read pixels from the color buffer to make a new texture image.
* This does the real work of glCopyTexImage[12]D().
* Return pointer to new gl_texture_image struct or NULL if we run
* out of memory.
*/
static struct gl_texture_image *
read_texture_image( GLcontext *ctx, GLint x, GLint y,
GLsizei width, GLsizei height, GLint border,
GLint format )
{
struct gl_texture_image *teximage;
GLubyte *texture, *texptr;
GLint components;
GLint i, j;
components = components_in_intformat( format );
/* allocate texel space */
texture = (GLubyte *) malloc( width * height * components );
if (!texture) {
gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D" );
return NULL;
}
texptr = texture;
/* Select buffer to read from */
(void) (*ctx->Driver.SetBuffer)( ctx, ctx->Pixel.ReadBuffer );
for (j=0;j<height;j++) {
GLubyte red[MAX_WIDTH], green[MAX_WIDTH];
GLubyte blue[MAX_WIDTH], alpha[MAX_WIDTH];
gl_read_color_span( ctx, width, x, y+j, red, green, blue, alpha );
if (!ctx->Visual->EightBitColor) {
/* scale red, green, blue, alpha values to range [0,255] */
GLfloat rscale = 255.0f * ctx->Visual->InvRedScale;
GLfloat gscale = 255.0f * ctx->Visual->InvGreenScale;
GLfloat bscale = 255.0f * ctx->Visual->InvBlueScale;
GLfloat ascale = 255.0f * ctx->Visual->InvAlphaScale;
for (i=0;i<width;i++) {
red[i] = (GLubyte) (GLint) (red[i] * rscale);
green[i] = (GLubyte) (GLint) (green[i] * gscale);
blue[i] = (GLubyte) (GLint) (blue[i] * bscale);
alpha[i] = (GLubyte) (GLint) (alpha[i] * ascale);
}
}
switch (format) {
case GL_ALPHA:
for (i=0;i<width;i++) {
*texptr++ = alpha[i];
}
break;
case GL_LUMINANCE:
for (i=0;i<width;i++) {
*texptr++ = red[i];
}
break;
case GL_LUMINANCE_ALPHA:
for (i=0;i<width;i++) {
*texptr++ = red[i];
*texptr++ = alpha[i];
}
break;
case GL_INTENSITY:
for (i=0;i<width;i++) {
*texptr++ = red[i];
}
break;
case GL_RGB:
for (i=0;i<width;i++) {
*texptr++ = red[i];
*texptr++ = green[i];
*texptr++ = blue[i];
}
break;
case GL_RGBA:
for (i=0;i<width;i++) {
*texptr++ = red[i];
*texptr++ = green[i];
*texptr++ = blue[i];
*texptr++ = alpha[i];
}
break;
} /*switch*/
} /*for*/
/* Restore drawing buffer */
(void) (*ctx->Driver.SetBuffer)( ctx, ctx->Color.DrawBuffer );
teximage = gl_alloc_texture_image();
if (teximage) {
int log2_width = logbase2(width);
int log2_height = logbase2(height);
teximage->Format = (GLenum) format;
teximage->Border = border;
teximage->Width = width;
teximage->Height = height;
teximage->WidthLog2 = log2_width;
teximage->HeightLog2 = log2_height;
teximage->MaxLog2 = MAX2( log2_width, log2_height );
teximage->Data = texture;
teximage->DeleteFlag = GL_TRUE;
}
return teximage;
}
void gl_CopyTexImage1D( GLcontext *ctx,
GLenum target, GLint level,
GLenum internalformat,
GLint x, GLint y,
GLsizei width, GLint border )
{
GLint format;
struct gl_texture_image *teximage;
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glCopyTexImage1D" );
return;
}
if (target!=GL_TEXTURE_1D) {
gl_error( ctx, GL_INVALID_ENUM, "glCopyTexImage1D(target)" );
return;
}
if (level<0 || level>=MAX_TEXTURE_LEVELS) {
gl_error( ctx, GL_INVALID_VALUE, "glCopyTexImage1D(level)" );
return;
}
if (border!=0 && border!=1) {
gl_error( ctx, GL_INVALID_VALUE, "glCopyTexImage1D(border)" );
return;
}
if (width<2*border || width>2+MAX_TEXTURE_SIZE || width<0) {
gl_error( ctx, GL_INVALID_VALUE, "glCopyTexImage1D(width)" );
return;
}
format = decode_internal_format( internalformat );
if (format<0 || (internalformat>=1 && internalformat<=4)) {
gl_error( ctx, GL_INVALID_VALUE, "glCopyTexImage1D(format)" );
return;
}
teximage = read_texture_image( ctx, x, y, width, 1, border, format );
gl_TexImage1D( ctx, target, level, internalformat, width,
border, GL_RGBA, GL_UNSIGNED_BYTE, teximage );
}
void gl_CopyTexImage2D( GLcontext *ctx,
GLenum target, GLint level, GLenum internalformat,
GLint x, GLint y, GLsizei width, GLsizei height,
GLint border )
{
GLint format;
struct gl_texture_image *teximage;
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glCopyTexImage2D" );
return;
}
if (target!=GL_TEXTURE_2D) {
gl_error( ctx, GL_INVALID_ENUM, "glCopyTexImage2D(target)" );
return;
}
if (level<0 || level>=MAX_TEXTURE_LEVELS) {
gl_error( ctx, GL_INVALID_VALUE, "glCopyTexImage2D(level)" );
return;
}
if (border!=0 && border!=1) {
gl_error( ctx, GL_INVALID_VALUE, "glCopyTexImage2D(border)" );
return;
}
if (width<2*border || width>2+MAX_TEXTURE_SIZE || width<0) {
gl_error( ctx, GL_INVALID_VALUE, "glCopyTexImage2D(width)" );
return;
}
if (height<2*border || height>2+MAX_TEXTURE_SIZE || height<0) {
gl_error( ctx, GL_INVALID_VALUE, "glCopyTexImage2D(height)" );
return;
}
format = decode_internal_format( internalformat );
if (format<0 || (internalformat>=1 && internalformat<=4)) {
gl_error( ctx, GL_INVALID_VALUE, "glCopyTexImage2D(format)" );
return;
}
teximage = read_texture_image( ctx, x, y, width, height, border, format );
gl_TexImage2D( ctx, target, level, internalformat, width, height,
border, GL_RGBA, GL_UNSIGNED_BYTE, teximage );
}
/*
* Do the work of glCopyTexSubImage[12]D.
*/
static void copy_tex_sub_image( GLcontext *ctx, struct gl_texture_image *dest,
GLint width, GLint height,
GLint srcx, GLint srcy,
GLint dstx, GLint dsty )
{
GLint i, j;
GLint format, components;
format = dest->Format;
components = components_in_intformat( format );
for (j=0;j<height;j++) {
GLubyte red[MAX_WIDTH], green[MAX_WIDTH];
GLubyte blue[MAX_WIDTH], alpha[MAX_WIDTH];
GLubyte *texptr;
gl_read_color_span( ctx, width, srcx, srcy+j, red, green, blue, alpha );
if (!ctx->Visual->EightBitColor) {
/* scale red, green, blue, alpha values to range [0,255] */
GLfloat rscale = 255.0f * ctx->Visual->InvRedScale;
GLfloat gscale = 255.0f * ctx->Visual->InvGreenScale;
GLfloat bscale = 255.0f * ctx->Visual->InvBlueScale;
GLfloat ascale = 255.0f * ctx->Visual->InvAlphaScale;
for (i=0;i<width;i++) {
red[i] = (GLubyte) (GLint) (red[i] * rscale);
green[i] = (GLubyte) (GLint) (green[i] * gscale);
blue[i] = (GLubyte) (GLint) (blue[i] * bscale);
alpha[i] = (GLubyte) (GLint) (alpha[i] * ascale);
}
}
texptr = dest->Data + ((dsty+j) * width + dstx) * components;
switch (format) {
case GL_ALPHA:
for (i=0;i<width;i++) {
*texptr++ = alpha[i];
}
break;
case GL_LUMINANCE:
for (i=0;i<width;i++) {
*texptr++ = red[i];
}
break;
case GL_LUMINANCE_ALPHA:
for (i=0;i<width;i++) {
*texptr++ = red[i];
*texptr++ = alpha[i];
}
break;
case GL_INTENSITY:
for (i=0;i<width;i++) {
*texptr++ = red[i];
}
break;
case GL_RGB:
for (i=0;i<width;i++) {
*texptr++ = red[i];
*texptr++ = green[i];
*texptr++ = blue[i];
}
break;
case GL_RGBA:
for (i=0;i<width;i++) {
*texptr++ = red[i];
*texptr++ = green[i];
*texptr++ = blue[i];
*texptr++ = alpha[i];
}
break;
} /*switch*/
} /*for*/
}
void gl_CopyTexSubImage1D( GLcontext *ctx,
GLenum target, GLint level,
GLint xoffset, GLint x, GLint y, GLsizei width )
{
struct gl_texture_image *teximage;
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glCopyTexSubImage1D" );
return;
}
if (target!=GL_TEXTURE_1D) {
gl_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage1D(target)" );
return;
}
if (level<0 || level>=MAX_TEXTURE_LEVELS) {
gl_error( ctx, GL_INVALID_VALUE, "glCopyTexSubImage1D(level)" );
return;
}
if (width<0) {
gl_error( ctx, GL_INVALID_VALUE, "glCopyTexSubImage1D(width)" );
return;
}
teximage = ctx->Texture.Current1D->Image[level];
if (teximage) {
if (xoffset < -teximage->Border) {
gl_error( ctx, GL_INVALID_VALUE, "glCopyTexSubImage1D(xoffset)" );
return;
}
/* NOTE: we're adding the border here, not subtracting! */
if (xoffset+width > teximage->Width+teximage->Border) {
gl_error( ctx, GL_INVALID_VALUE,
"glCopyTexSubImage1D(xoffset+width)" );
return;
}
if (teximage->Data) {
copy_tex_sub_image( ctx, teximage, width, 1, x, y, xoffset, 0 );
}
}
else {
gl_error( ctx, GL_INVALID_OPERATION, "glCopyTexSubImage1D" );
}
}
void gl_CopyTexSubImage2D( GLcontext *ctx,
GLenum target, GLint level,
GLint xoffset, GLint yoffset,
GLint x, GLint y, GLsizei width, GLsizei height )
{
struct gl_texture_image *teximage;
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glCopyTexSubImage2D" );
return;
}
if (target!=GL_TEXTURE_2D) {
gl_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage2D(target)" );
return;
}
if (level<0 || level>=MAX_TEXTURE_LEVELS) {
gl_error( ctx, GL_INVALID_VALUE, "glCopyTexSubImage2D(level)" );
return;
}
if (width<0) {
gl_error( ctx, GL_INVALID_VALUE, "glCopyTexSubImage2D(width)" );
return;
}
if (height<0) {
gl_error( ctx, GL_INVALID_VALUE, "glCopyTexSubImage2D(height)" );
return;
}
teximage = ctx->Texture.Current2D->Image[level];
if (teximage) {
if (xoffset < -teximage->Border) {
gl_error( ctx, GL_INVALID_VALUE, "glCopyTexSubImage2D(xoffset)" );
return;
}
if (yoffset < -teximage->Border) {
gl_error( ctx, GL_INVALID_VALUE, "glCopyTexSubImage2D(yoffset)" );
return;
}
/* NOTE: we're adding the border here, not subtracting! */
if (xoffset+width > teximage->Width+teximage->Border) {
gl_error( ctx, GL_INVALID_VALUE,
"glCopyTexSubImage2D(xoffset+width)" );
return;
}
if (yoffset+height > teximage->Height+teximage->Border) {
gl_error( ctx, GL_INVALID_VALUE,
"glCopyTexSubImage2D(yoffset+height)" );
return;
}
if (teximage->Data) {
copy_tex_sub_image( ctx, teximage, width, height,
x, y, xoffset, yoffset );
}
}
else {
gl_error( ctx, GL_INVALID_OPERATION, "glCopyTexSubImage2D" );
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.