This is texture.c in view mode; [Download] [Up]
/* $Id: texture.c,v 1.4 1996/09/27 01:30:24 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: texture.c,v $
* Revision 1.4 1996/09/27 01:30:24 brianp
* added missing default cases to switches
*
* 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 <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "context.h"
#include "dlist.h"
#include "macros.h"
#include "pb.h"
#include "teximage.h"
#include "texture.h"
#include "types.h"
/**********************************************************************/
/* Texture Environment */
/**********************************************************************/
void gl_TexEnvfv( GLcontext *ctx,
GLenum target, GLenum pname, const GLfloat *param )
{
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glTexEnv" );
return;
}
if (target!=GL_TEXTURE_ENV) {
gl_error( ctx, GL_INVALID_ENUM, "glTexEnv(target)" );
return;
}
if (pname==GL_TEXTURE_ENV_MODE) {
GLenum mode = (GLenum) (GLint) *param;
switch (mode) {
case GL_MODULATE:
case GL_BLEND:
case GL_DECAL:
case GL_REPLACE_EXT:
ctx->Texture.EnvMode = mode;
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glTexEnv(param)" );
return;
}
}
else if (pname==GL_TEXTURE_ENV_COLOR) {
ctx->Texture.EnvColor[0] = CLAMP( param[0], 0.0, 1.0 );
ctx->Texture.EnvColor[1] = CLAMP( param[1], 0.0, 1.0 );
ctx->Texture.EnvColor[2] = CLAMP( param[2], 0.0, 1.0 );
ctx->Texture.EnvColor[3] = CLAMP( param[3], 0.0, 1.0 );
}
else {
gl_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname)" );
return;
}
}
void gl_GetTexEnvfv( GLcontext *ctx,
GLenum target, GLenum pname, GLfloat *params )
{
if (target!=GL_TEXTURE_ENV) {
gl_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(target)" );
return;
}
switch (pname) {
case GL_TEXTURE_ENV_MODE:
*params = (GLfloat) ctx->Texture.EnvMode;
break;
case GL_TEXTURE_ENV_COLOR:
COPY_4V( params, ctx->Texture.EnvColor );
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)" );
}
}
void gl_GetTexEnviv( GLcontext *ctx,
GLenum target, GLenum pname, GLint *params )
{
if (target!=GL_TEXTURE_ENV) {
gl_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(target)" );
return;
}
switch (pname) {
case GL_TEXTURE_ENV_MODE:
*params = (GLint) ctx->Texture.EnvMode;
break;
case GL_TEXTURE_ENV_COLOR:
params[0] = FLOAT_TO_INT( ctx->Texture.EnvColor[0] );
params[1] = FLOAT_TO_INT( ctx->Texture.EnvColor[1] );
params[2] = FLOAT_TO_INT( ctx->Texture.EnvColor[2] );
params[3] = FLOAT_TO_INT( ctx->Texture.EnvColor[3] );
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)" );
}
}
/**********************************************************************/
/* Texture Parameters */
/**********************************************************************/
void gl_TexParameterfv( GLcontext *ctx,
GLenum target, GLenum pname, const GLfloat *params )
{
GLenum eparam = (GLenum) (GLint) params[0];
if (target==GL_TEXTURE_1D) {
switch (pname) {
case GL_TEXTURE_MIN_FILTER:
if (eparam==GL_NEAREST || eparam==GL_LINEAR
|| eparam==GL_NEAREST_MIPMAP_NEAREST
|| eparam==GL_LINEAR_MIPMAP_NEAREST
|| eparam==GL_NEAREST_MIPMAP_LINEAR
|| eparam==GL_LINEAR_MIPMAP_LINEAR) {
ctx->Texture.Current1D->MinFilter = eparam;
ctx->NewState |= NEW_TEXTURING;
}
else {
gl_error( ctx, GL_INVALID_VALUE, "glTexParameter(param)" );
}
break;
case GL_TEXTURE_MAG_FILTER:
if (eparam==GL_NEAREST || eparam==GL_LINEAR) {
ctx->Texture.Current1D->MagFilter = eparam;
ctx->NewState |= NEW_TEXTURING;
}
else {
gl_error( ctx, GL_INVALID_VALUE, "glTexParameter(param)" );
}
break;
case GL_TEXTURE_WRAP_S:
if (eparam==GL_CLAMP || eparam==GL_REPEAT) {
ctx->Texture.Current1D->WrapS = eparam;
}
else {
gl_error( ctx, GL_INVALID_VALUE, "glTexParameter(param)" );
}
break;
case GL_TEXTURE_WRAP_T:
if (eparam==GL_CLAMP || eparam==GL_REPEAT) {
ctx->Texture.Current1D->WrapT = eparam;
}
else {
gl_error( ctx, GL_INVALID_VALUE, "glTexParameter(param)" );
}
break;
case GL_TEXTURE_BORDER_COLOR:
{
GLint *bc = ctx->Texture.Current2D->BorderColor;
bc[0] = CLAMP((GLint)(params[0]*255.0), 0, 255);
bc[1] = CLAMP((GLint)(params[1]*255.0), 0, 255);
bc[2] = CLAMP((GLint)(params[2]*255.0), 0, 255);
bc[3] = CLAMP((GLint)(params[3]*255.0), 0, 255);
}
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glTexParameter(pname)" );
}
}
else if (target==GL_TEXTURE_2D) {
switch (pname) {
case GL_TEXTURE_MIN_FILTER:
if (eparam==GL_NEAREST || eparam==GL_LINEAR
|| eparam==GL_NEAREST_MIPMAP_NEAREST
|| eparam==GL_LINEAR_MIPMAP_NEAREST
|| eparam==GL_NEAREST_MIPMAP_LINEAR
|| eparam==GL_LINEAR_MIPMAP_LINEAR) {
ctx->Texture.Current2D->MinFilter = eparam;
ctx->NewState |= NEW_TEXTURING;
}
else {
gl_error( ctx, GL_INVALID_VALUE, "glTexParameter(param)" );
}
break;
case GL_TEXTURE_MAG_FILTER:
if (eparam==GL_NEAREST || eparam==GL_LINEAR) {
ctx->Texture.Current2D->MagFilter = eparam;
ctx->NewState |= NEW_TEXTURING;
}
else {
gl_error( ctx, GL_INVALID_VALUE, "glTexParameter(param)" );
}
break;
case GL_TEXTURE_WRAP_S:
if (eparam==GL_CLAMP || eparam==GL_REPEAT) {
ctx->Texture.Current2D->WrapS = eparam;
}
else {
gl_error( ctx, GL_INVALID_VALUE, "glTexParameter(param)" );
}
break;
case GL_TEXTURE_WRAP_T:
if (eparam==GL_CLAMP || eparam==GL_REPEAT) {
ctx->Texture.Current2D->WrapT = eparam;
}
else {
gl_error( ctx, GL_INVALID_VALUE, "glTexParameter(param)" );
}
break;
case GL_TEXTURE_BORDER_COLOR:
{
GLint *bc = ctx->Texture.Current2D->BorderColor;
bc[0] = CLAMP((GLint)(params[0]*255.0), 0, 255);
bc[1] = CLAMP((GLint)(params[1]*255.0), 0, 255);
bc[2] = CLAMP((GLint)(params[2]*255.0), 0, 255);
bc[3] = CLAMP((GLint)(params[3]*255.0), 0, 255);
}
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glTexParameter(pname)" );
}
}
else {
gl_error( ctx, GL_INVALID_ENUM, "glTexParameter(target)" );
}
}
void gl_GetTexLevelParameterfv( GLcontext *ctx, GLenum target, GLint level,
GLenum pname, GLfloat *params )
{
struct gl_texture_image *tex;
if (level<0 || level>=MAX_TEXTURE_LEVELS) {
gl_error( ctx, GL_INVALID_VALUE, "glGetTexLevelParameterfv" );
return;
}
switch (target) {
case GL_TEXTURE_1D:
tex = ctx->Texture.Current1D->Image[level];
switch (pname) {
case GL_TEXTURE_WIDTH:
*params = (GLfloat) (tex->Width + tex->Border);
break;
case GL_TEXTURE_COMPONENTS:
*params = (GLfloat) tex->Format;
break;
case GL_TEXTURE_BORDER:
*params = (GLfloat) tex->Border;
break;
default:
gl_error( ctx, GL_INVALID_ENUM,
"glGetTexLevelParameterfv(pname)" );
}
break;
case GL_TEXTURE_2D:
tex = ctx->Texture.Current2D->Image[level];
switch (pname) {
case GL_TEXTURE_WIDTH:
*params = (GLfloat) (tex->Width + tex->Border);
break;
case GL_TEXTURE_HEIGHT:
*params = (GLfloat) (tex->Height + tex->Border);
break;
case GL_TEXTURE_COMPONENTS:
*params = (GLfloat) tex->Format;
break;
case GL_TEXTURE_BORDER:
*params = (GLfloat) tex->Border;
break;
default:
gl_error( ctx, GL_INVALID_ENUM,
"glGetTexLevelParameterfv(pname)" );
}
break;
#ifdef GL_VERSION_1_1
case GL_PROXY_TEXTURE_1D:
tex = ctx->Texture.Proxy1D->Image[level];
switch (pname) {
case GL_TEXTURE_WIDTH:
*params = (GLfloat) (tex->Width + tex->Border);
break;
case GL_TEXTURE_COMPONENTS:
*params = (GLfloat) tex->Format;
break;
case GL_TEXTURE_BORDER:
*params = (GLfloat) tex->Border;
break;
default:
gl_error( ctx, GL_INVALID_ENUM,
"glGetTexLevelParameterfv(pname)" );
}
break;
case GL_PROXY_TEXTURE_2D:
tex = ctx->Texture.Proxy2D->Image[level];
switch (pname) {
case GL_TEXTURE_WIDTH:
*params = (GLfloat) (tex->Width + tex->Border);
break;
case GL_TEXTURE_HEIGHT:
*params = (GLfloat) (tex->Height + tex->Border);
break;
case GL_TEXTURE_COMPONENTS:
*params = (GLfloat) tex->Format;
break;
case GL_TEXTURE_BORDER:
*params = (GLfloat) tex->Border;
break;
default:
gl_error( ctx, GL_INVALID_ENUM,
"glGetTexLevelParameterfv(pname)" );
}
break;
#endif
default:
gl_error( ctx, GL_INVALID_ENUM, "glGetTexLevelParameterfv(target)" );
}
}
void gl_GetTexLevelParameteriv( GLcontext *ctx, GLenum target, GLint level,
GLenum pname, GLint *params )
{
struct gl_texture_image *tex;
if (level<0 || level>=MAX_TEXTURE_LEVELS) {
gl_error( ctx, GL_INVALID_VALUE, "glGetTexLevelParameteriv" );
return;
}
switch (target) {
case GL_TEXTURE_1D:
tex = ctx->Texture.Current1D->Image[level];
switch (pname) {
case GL_TEXTURE_WIDTH:
*params = tex->Width + tex->Border;
break;
case GL_TEXTURE_COMPONENTS:
*params = tex->Format;
break;
case GL_TEXTURE_BORDER:
*params = tex->Border;
break;
default:
gl_error( ctx, GL_INVALID_ENUM,
"glGetTexLevelParameteriv(pname)" );
}
break;
case GL_TEXTURE_2D:
tex = ctx->Texture.Current2D->Image[level];
switch (pname) {
case GL_TEXTURE_WIDTH:
*params = tex->Width + tex->Border;
break;
case GL_TEXTURE_HEIGHT:
*params = tex->Height + tex->Border;
break;
case GL_TEXTURE_COMPONENTS:
*params = tex->Format;
break;
case GL_TEXTURE_BORDER:
*params = tex->Border;
break;
default:
gl_error( ctx, GL_INVALID_ENUM,
"glGetTexLevelParameteriv(pname)" );
}
break;
#ifdef GL_VERSION_1_1
case GL_PROXY_TEXTURE_1D:
tex = ctx->Texture.Proxy1D->Image[level];
switch (pname) {
case GL_TEXTURE_WIDTH:
*params = tex->Width + tex->Border;
break;
case GL_TEXTURE_COMPONENTS:
*params = tex->Format;
break;
case GL_TEXTURE_BORDER:
*params = tex->Border;
break;
default:
gl_error( ctx, GL_INVALID_ENUM,
"glGetTexLevelParameteriv(pname)" );
}
break;
case GL_PROXY_TEXTURE_2D:
tex = ctx->Texture.Proxy2D->Image[level];
switch (pname) {
case GL_TEXTURE_WIDTH:
*params = tex->Width + tex->Border;
break;
case GL_TEXTURE_HEIGHT:
*params = tex->Height + tex->Border;
break;
case GL_TEXTURE_COMPONENTS:
*params = tex->Format;
break;
case GL_TEXTURE_BORDER:
*params = tex->Border;
break;
default:
gl_error( ctx, GL_INVALID_ENUM,
"glGetTexLevelParameteriv(pname)" );
}
break;
#endif
default:
gl_error( ctx, GL_INVALID_ENUM, "glGetTexLevelParameteriv(target)" );
}
}
void gl_GetTexParameterfv( GLcontext *ctx,
GLenum target, GLenum pname, GLfloat *params )
{
switch (target) {
case GL_TEXTURE_1D:
switch (pname) {
case GL_TEXTURE_MAG_FILTER:
*params = (GLfloat) ctx->Texture.Current1D->MagFilter;
break;
case GL_TEXTURE_MIN_FILTER:
*params = (GLfloat) ctx->Texture.Current1D->MinFilter;
break;
case GL_TEXTURE_WRAP_S:
*params = (GLfloat) ctx->Texture.Current1D->WrapS;
break;
case GL_TEXTURE_WRAP_T:
*params = (GLfloat) ctx->Texture.Current1D->WrapT;
break;
case GL_TEXTURE_BORDER_COLOR:
params[0] = ctx->Texture.Current1D->BorderColor[0] / 255.0f;
params[1] = ctx->Texture.Current1D->BorderColor[1] / 255.0f;
params[2] = ctx->Texture.Current1D->BorderColor[2] / 255.0f;
params[3] = ctx->Texture.Current1D->BorderColor[3] / 255.0f;
break;
case GL_TEXTURE_RESIDENT_EXT:
*params = (GLfloat) GL_TRUE;
break;
case GL_TEXTURE_PRIORITY_EXT:
*params = ctx->Texture.Current1D->Priority;
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glGetTexParameterfv(pname)" );
}
break;
case GL_TEXTURE_2D:
switch (pname) {
case GL_TEXTURE_MAG_FILTER:
*params = (GLfloat) ctx->Texture.Current2D->MagFilter;
break;
case GL_TEXTURE_MIN_FILTER:
*params = (GLfloat) ctx->Texture.Current2D->MinFilter;
break;
case GL_TEXTURE_WRAP_S:
*params = (GLfloat) ctx->Texture.Current2D->WrapS;
break;
case GL_TEXTURE_WRAP_T:
*params = (GLfloat) ctx->Texture.Current2D->WrapT;
break;
case GL_TEXTURE_BORDER_COLOR:
params[0] = ctx->Texture.Current2D->BorderColor[0] / 255.0f;
params[1] = ctx->Texture.Current2D->BorderColor[1] / 255.0f;
params[2] = ctx->Texture.Current2D->BorderColor[2] / 255.0f;
params[3] = ctx->Texture.Current2D->BorderColor[3] / 255.0f;
break;
case GL_TEXTURE_RESIDENT_EXT:
*params = (GLfloat) GL_TRUE;
break;
case GL_TEXTURE_PRIORITY_EXT:
*params = ctx->Texture.Current2D->Priority;
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glGetTexParameterfv(pname)" );
}
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glGetTexParameterfv(target)" );
}
}
void gl_GetTexParameteriv( GLcontext *ctx,
GLenum target, GLenum pname, GLint *params )
{
switch (target) {
case GL_TEXTURE_1D:
switch (pname) {
case GL_TEXTURE_MAG_FILTER:
*params = (GLint) ctx->Texture.Current1D->MagFilter;
break;
case GL_TEXTURE_MIN_FILTER:
*params = (GLint) ctx->Texture.Current1D->MinFilter;
break;
case GL_TEXTURE_WRAP_S:
*params = (GLint) ctx->Texture.Current1D->WrapS;
break;
case GL_TEXTURE_WRAP_T:
*params = (GLint) ctx->Texture.Current1D->WrapT;
break;
case GL_TEXTURE_BORDER_COLOR:
{
GLfloat color[4];
color[0] = ctx->Texture.Current1D->BorderColor[0]/255.0;
color[1] = ctx->Texture.Current1D->BorderColor[1]/255.0;
color[2] = ctx->Texture.Current1D->BorderColor[2]/255.0;
color[3] = ctx->Texture.Current1D->BorderColor[3]/255.0;
params[0] = FLOAT_TO_INT( color[0] );
params[1] = FLOAT_TO_INT( color[1] );
params[2] = FLOAT_TO_INT( color[2] );
params[3] = FLOAT_TO_INT( color[3] );
}
break;
case GL_TEXTURE_RESIDENT_EXT:
*params = (GLint) GL_TRUE;
break;
case GL_TEXTURE_PRIORITY_EXT:
*params = (GLint) ctx->Texture.Current1D->Priority;
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glGetTexParameteriv(pname)" );
}
break;
case GL_TEXTURE_2D:
switch (pname) {
case GL_TEXTURE_MAG_FILTER:
*params = (GLint) ctx->Texture.Current2D->MagFilter;
break;
case GL_TEXTURE_MIN_FILTER:
*params = (GLint) ctx->Texture.Current2D->MinFilter;
break;
case GL_TEXTURE_WRAP_S:
*params = (GLint) ctx->Texture.Current2D->WrapS;
break;
case GL_TEXTURE_WRAP_T:
*params = (GLint) ctx->Texture.Current2D->WrapT;
break;
case GL_TEXTURE_BORDER_COLOR:
{
GLfloat color[4];
color[0] = ctx->Texture.Current2D->BorderColor[0]/255.0;
color[1] = ctx->Texture.Current2D->BorderColor[1]/255.0;
color[2] = ctx->Texture.Current2D->BorderColor[2]/255.0;
color[3] = ctx->Texture.Current2D->BorderColor[3]/255.0;
params[0] = FLOAT_TO_INT( color[0] );
params[1] = FLOAT_TO_INT( color[1] );
params[2] = FLOAT_TO_INT( color[2] );
params[3] = FLOAT_TO_INT( color[3] );
}
break;
case GL_TEXTURE_RESIDENT_EXT:
*params = (GLint) GL_TRUE;
break;
case GL_TEXTURE_PRIORITY_EXT:
*params = (GLint) ctx->Texture.Current2D->Priority;
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glGetTexParameteriv(pname)" );
}
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glGetTexParameteriv(target)" );
}
}
/**********************************************************************/
/* Texture Coord Generation */
/**********************************************************************/
void gl_TexGenfv( GLcontext *ctx,
GLenum coord, GLenum pname, const GLfloat *params )
{
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glTexGenfv" );
return;
}
switch( coord ) {
case GL_S:
if (pname==GL_TEXTURE_GEN_MODE) {
GLenum mode = (GLenum) (GLint) *params;
if (mode==GL_OBJECT_LINEAR ||
mode==GL_EYE_LINEAR ||
mode==GL_SPHERE_MAP) {
ctx->Texture.GenModeS = mode;
}
else {
gl_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" );
return;
}
}
else if (pname==GL_OBJECT_PLANE) {
ctx->Texture.ObjectPlaneS[0] = params[0];
ctx->Texture.ObjectPlaneS[1] = params[1];
ctx->Texture.ObjectPlaneS[2] = params[2];
ctx->Texture.ObjectPlaneS[3] = params[3];
}
else if (pname==GL_EYE_PLANE) {
/* TODO: xform plane by modelview??? */
ctx->Texture.EyePlaneS[0] = params[0];
ctx->Texture.EyePlaneS[1] = params[1];
ctx->Texture.EyePlaneS[2] = params[2];
ctx->Texture.EyePlaneS[3] = params[3];
}
else {
gl_error( ctx, GL_INVALID_ENUM, "glTexGenfv(pname)" );
return;
}
break;
case GL_T:
if (pname==GL_TEXTURE_GEN_MODE) {
GLenum mode = (GLenum) (GLint) *params;
if (mode==GL_OBJECT_LINEAR ||
mode==GL_EYE_LINEAR ||
mode==GL_SPHERE_MAP) {
ctx->Texture.GenModeT = mode;
}
else {
gl_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" );
return;
}
}
else if (pname==GL_OBJECT_PLANE) {
ctx->Texture.ObjectPlaneT[0] = params[0];
ctx->Texture.ObjectPlaneT[1] = params[1];
ctx->Texture.ObjectPlaneT[2] = params[2];
ctx->Texture.ObjectPlaneT[3] = params[3];
}
else if (pname==GL_EYE_PLANE) {
ctx->Texture.EyePlaneT[0] = params[0];
ctx->Texture.EyePlaneT[1] = params[1];
ctx->Texture.EyePlaneT[2] = params[2];
ctx->Texture.EyePlaneT[3] = params[3];
}
else {
gl_error( ctx, GL_INVALID_ENUM, "glTexGenfv(pname)" );
return;
}
break;
case GL_R:
if (pname==GL_TEXTURE_GEN_MODE) {
GLenum mode = (GLenum) (GLint) *params;
if (mode==GL_OBJECT_LINEAR ||
mode==GL_EYE_LINEAR) {
ctx->Texture.GenModeR = mode;
}
else {
gl_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" );
return;
}
}
else if (pname==GL_OBJECT_PLANE) {
ctx->Texture.ObjectPlaneR[0] = params[0];
ctx->Texture.ObjectPlaneR[1] = params[1];
ctx->Texture.ObjectPlaneR[2] = params[2];
ctx->Texture.ObjectPlaneR[3] = params[3];
}
else if (pname==GL_EYE_PLANE) {
ctx->Texture.EyePlaneR[0] = params[0];
ctx->Texture.EyePlaneR[1] = params[1];
ctx->Texture.EyePlaneR[2] = params[2];
ctx->Texture.EyePlaneR[3] = params[3];
}
else {
gl_error( ctx, GL_INVALID_ENUM, "glTexGenfv(pname)" );
return;
}
break;
case GL_Q:
if (pname==GL_TEXTURE_GEN_MODE) {
GLenum mode = (GLenum) (GLint) *params;
if (mode==GL_OBJECT_LINEAR ||
mode==GL_EYE_LINEAR) {
ctx->Texture.GenModeQ = mode;
}
else {
gl_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" );
return;
}
}
else if (pname==GL_OBJECT_PLANE) {
ctx->Texture.ObjectPlaneQ[0] = params[0];
ctx->Texture.ObjectPlaneQ[1] = params[1];
ctx->Texture.ObjectPlaneQ[2] = params[2];
ctx->Texture.ObjectPlaneQ[3] = params[3];
}
else if (pname==GL_EYE_PLANE) {
ctx->Texture.EyePlaneQ[0] = params[0];
ctx->Texture.EyePlaneQ[1] = params[1];
ctx->Texture.EyePlaneQ[2] = params[2];
ctx->Texture.EyePlaneQ[3] = params[3];
}
else {
gl_error( ctx, GL_INVALID_ENUM, "glTexGenfv(pname)" );
return;
}
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glTexGenfv(coord)" );
return;
}
ctx->NewState |= NEW_TEXTURING;
}
void gl_GetTexGendv( GLcontext *ctx,
GLenum coord, GLenum pname, GLdouble *params )
{
/* TODO */
}
void gl_GetTexGenfv( GLcontext *ctx,
GLenum coord, GLenum pname, GLfloat *params )
{
/* TODO */
}
void gl_GetTexGeniv( GLcontext *ctx,
GLenum coord, GLenum pname, GLint *params )
{
/* TODO */
}
/*
* Perform automatic texture coordinate generation.
* Input: obj - vertex in object coordinate system
* eye - vertex in eye coordinate system
* normal - normal vector in eye coordinate system
* Output: texcoord - the resuling texture coordinate, if TexGen enabled.
*/
void gl_do_texgen( GLcontext *ctx,
const GLfloat obj[4],
const GLfloat eye[4],
const GLfloat normal[3],
GLfloat texcoord[4] )
{
GLfloat u[3], two_nn, m, fx, fy, fz;
if (ctx->Texture.TexGenEnabled & S_BIT) {
switch( ctx->Texture.GenModeS) {
case GL_OBJECT_LINEAR:
texcoord[0] = DOT4( obj, ctx->Texture.ObjectPlaneS );
break;
case GL_EYE_LINEAR:
texcoord[0] = DOT4( eye, ctx->Texture.EyePlaneS );
break;
case GL_SPHERE_MAP:
COPY_3V( u, eye );
NORMALIZE_3V( u );
two_nn = 2.0*DOT3(normal,normal);
fx = u[0] - two_nn * u[0];
fy = u[1] - two_nn * u[1];
fz = u[2] - two_nn * u[2];
m = 2.0 * sqrt( fx*fx + fy*fy + (fz+1.0)*(fz+1.0) );
if (m==0.0) {
texcoord[0] = 0.0;
}
else {
texcoord[0] = fx / m + 0.5;
}
break;
default:
abort();
}
}
if (ctx->Texture.TexGenEnabled & T_BIT) {
switch( ctx->Texture.GenModeT) {
case GL_OBJECT_LINEAR:
texcoord[1] = DOT4( obj, ctx->Texture.ObjectPlaneT );
break;
case GL_EYE_LINEAR:
texcoord[1] = DOT4( eye, ctx->Texture.EyePlaneT );
break;
case GL_SPHERE_MAP:
/* TODO: safe to assume that m and fy valid from above??? */
if (m==0.0) {
texcoord[1] = 0.0;
}
else {
texcoord[1] = fy / m + 0.5;
}
break;
default:
abort();
}
}
if (ctx->Texture.TexGenEnabled & R_BIT) {
switch( ctx->Texture.GenModeR) {
case GL_OBJECT_LINEAR:
texcoord[2] = DOT4( obj, ctx->Texture.ObjectPlaneR );
break;
case GL_EYE_LINEAR:
texcoord[2] = DOT4( eye, ctx->Texture.EyePlaneR );
break;
default:
abort();
}
}
if (ctx->Texture.TexGenEnabled & Q_BIT) {
switch( ctx->Texture.GenModeQ) {
case GL_OBJECT_LINEAR:
texcoord[3] = DOT4( obj, ctx->Texture.ObjectPlaneQ );
break;
case GL_EYE_LINEAR:
texcoord[3] = DOT4( eye, ctx->Texture.EyePlaneQ );
break;
default:
abort();
}
}
}
/**********************************************************************/
/* 1-D Texture Sampling Functions */
/**********************************************************************/
/*
* Return the fractional part of x.
*/
#define frac(x) ((GLfloat)(x)-floor((GLfloat)x))
/*
* Given 1-D texture image and an (i) texel column coordinate, return the
* texel color.
*/
static void get_1d_texel( struct gl_texture_image *img, GLint i,
GLubyte *red, GLubyte *green, GLubyte *blue,
GLubyte *alpha )
{
GLubyte *texel;
/* DEBUG */
GLint width = img->Width;
if (i<0 || i>=width) abort();
switch (img->Format) {
case GL_ALPHA:
case GL_LUMINANCE:
case GL_INTENSITY:
*red = img->Data[ i ];
return;
case GL_LUMINANCE_ALPHA:
texel = img->Data + i * 2;
*red = texel[0];
*alpha = texel[1];
return;
case GL_RGB:
texel = img->Data + i * 3;
*red = texel[0];
*green = texel[1];
*blue = texel[2];
return;
case GL_RGBA:
texel = img->Data + i * 4;
*red = texel[0];
*green = texel[1];
*blue = texel[2];
*alpha = texel[3];
return;
default:
abort();
}
}
/*
* Return a texture sample for (s) using GL_NEAREST filter.
*/
static void sample_1d_nearest( GLcontext *ctx,
struct gl_texture_image *img,
GLfloat s,
GLubyte *red, GLubyte *green,
GLubyte *blue, GLubyte *alpha )
{
GLint width = img->Width; /* width is a power of two */
GLint i;
GLubyte *texel;
/* Clamp/Repeat S and convert to integer texel coordinate */
if (ctx->Texture.Current1D->WrapS==GL_REPEAT) {
/* s limited to [0,1) */
/* i limited to [0,width-1] */
i = (GLint) (s * width);
i &= (width-1);
}
else {
/* s limited to [0,1] */
/* i limited to [0,width-1] */
if (s<0.0F) {
i = 0;
}
else if (s>1.0F) {
i = width-1;
}
else {
i = (GLint) (s * width);
}
}
/* Get the texel */
switch (img->Format) {
case GL_ALPHA:
case GL_LUMINANCE:
case GL_INTENSITY:
*red = img->Data[i];
return;
case GL_LUMINANCE_ALPHA:
texel = img->Data + i * 2;
*red = texel[0];
*alpha = texel[1];
return;
case GL_RGB:
texel = img->Data + i * 3;
*red = texel[0];
*green = texel[1];
*blue = texel[2];
return;
case GL_RGBA:
texel = img->Data + i * 4;
*red = texel[0];
*green = texel[1];
*blue = texel[2];
*alpha = texel[3];
return;
default:
abort();
}
}
/*
* Return a texture sample for (s) using GL_LINEAR filter.
*/
static void sample_1d_linear( GLcontext *ctx,
struct gl_texture_image *img,
GLfloat s,
GLubyte *red, GLubyte *green,
GLubyte *blue, GLubyte *alpha )
{
GLint width = img->Width;
GLint i0, i1;
GLfloat u;
GLint i0border, i1border;
u = s * width;
if (ctx->Texture.Current1D->WrapS==GL_REPEAT) {
i0 = ((GLint) floor( u - 0.5F)) & (width-1);
i1 = (i0 + 1) & (width-1);
i0border = i1border = 0;
}
else {
i0 = (GLint) floor( u - 0.5F );
i1 = i0 + 1;
i0border = (i0<0) | (i0>=width);
i1border = (i1<0) | (i1>=width);
}
{
GLfloat a = frac(u - 0.5F);
GLint w0 = (GLint) ((1.0F-a) * 256.0F);
GLint w1 = (GLint) ( a * 256.0F);
GLubyte red0, green0, blue0, alpha0;
GLubyte red1, green1, blue1, alpha1;
if (i0border) {
red0 = ctx->Texture.Current1D->BorderColor[0];
green0 = ctx->Texture.Current1D->BorderColor[1];
blue0 = ctx->Texture.Current1D->BorderColor[2];
alpha0 = ctx->Texture.Current1D->BorderColor[3];
}
else {
get_1d_texel( img, i0, &red0, &green0, &blue0, &alpha0 );
}
if (i1border) {
red1 = ctx->Texture.Current1D->BorderColor[0];
green1 = ctx->Texture.Current1D->BorderColor[1];
blue1 = ctx->Texture.Current1D->BorderColor[2];
alpha1 = ctx->Texture.Current1D->BorderColor[3];
}
else {
get_1d_texel( img, i1, &red1, &green1, &blue1, &alpha1 );
}
*red = (w0*red0 + w1*red1) >> 8;
*green = (w0*green0 + w1*green1) >> 8;
*blue = (w0*blue0 + w1*blue1) >> 8;
*alpha = (w0*alpha0 + w1*alpha1) >> 8;
}
}
static void sample_1d_nearest_mipmap_nearest( GLcontext *ctx,
GLfloat lambda, GLfloat s,
GLubyte *red, GLubyte *green,
GLubyte *blue, GLubyte *alpha )
{
GLint level;
if (lambda<=0.5F) {
level = 0;
}
else {
GLint widthlog2 = ctx->Texture.Current1D->Image[0]->WidthLog2;
level = (GLint) (lambda + 0.499999F);
if (level>widthlog2 ) {
level = widthlog2;
}
}
sample_1d_nearest( ctx, ctx->Texture.Current1D->Image[level],
s, red, green, blue, alpha );
}
static void sample_1d_linear_mipmap_nearest( GLcontext *ctx,
GLfloat lambda, GLfloat s,
GLubyte *red, GLubyte *green,
GLubyte *blue, GLubyte *alpha )
{
GLint level;
if (lambda<=0.5F) {
level = 0;
}
else {
GLint widthlog2 = ctx->Texture.Current1D->Image[0]->WidthLog2;
level = (GLint) (lambda + 0.499999F);
if (level>widthlog2 ) {
level = widthlog2;
}
}
sample_1d_linear( ctx, ctx->Texture.Current1D->Image[level],
s, red, green, blue, alpha );
}
static void sample_1d_nearest_mipmap_linear( GLcontext *ctx,
GLfloat lambda, GLfloat s,
GLubyte *red, GLubyte *green,
GLubyte *blue, GLubyte *alpha )
{
GLint max = ctx->Texture.Current1D->Image[0]->MaxLog2;
if (lambda>=max) {
sample_1d_nearest( ctx, ctx->Texture.Current1D->Image[max],
s, red, green, blue, alpha );
}
else {
GLubyte red0, green0, blue0, alpha0;
GLubyte red1, green1, blue1, alpha1;
GLfloat f = frac(lambda);
GLint level = (GLint) (lambda + 1.0F);
level = CLAMP( level, 1, max );
sample_1d_nearest( ctx, ctx->Texture.Current1D->Image[level-1],
s, &red0, &green0, &blue0, &alpha0 );
sample_1d_nearest( ctx, ctx->Texture.Current1D->Image[level],
s, &red1, &green1, &blue1, &alpha1 );
*red = (1.0F-f)*red1 + f*red0;
*green = (1.0F-f)*green1 + f*green0;
*blue = (1.0F-f)*blue1 + f*blue0;
*alpha = (1.0F-f)*alpha1 + f*alpha0;
}
}
static void sample_1d_linear_mipmap_linear( GLcontext *ctx,
GLfloat lambda, GLfloat s,
GLubyte *red, GLubyte *green,
GLubyte *blue, GLubyte *alpha )
{
GLint max = ctx->Texture.Current1D->Image[0]->MaxLog2;
if (lambda>=max) {
sample_1d_linear( ctx, ctx->Texture.Current1D->Image[max],
s, red, green, blue, alpha );
}
else {
GLubyte red0, green0, blue0, alpha0;
GLubyte red1, green1, blue1, alpha1;
GLfloat f = frac(lambda);
GLint level = (GLint) (lambda + 1.0F);
level = CLAMP( level, 1, max );
sample_1d_linear( ctx, ctx->Texture.Current1D->Image[level-1],
s, &red0, &green0, &blue0, &alpha0 );
sample_1d_linear( ctx, ctx->Texture.Current1D->Image[level],
s, &red1, &green1, &blue1, &alpha1 );
*red = (1.0F-f)*red1 + f*red0;
*green = (1.0F-f)*green1 + f*green0;
*blue = (1.0F-f)*blue1 + f*blue0;
*alpha = (1.0F-f)*alpha1 + f*alpha0;
}
}
/*
* Given an (s) texture coordinate and lambda (level of detail) value
* return a texture sample (color).
*
*/
static void sample_1d_texture( GLcontext *ctx,
GLfloat s, GLfloat lambda,
GLubyte *red, GLubyte *green, GLubyte *blue,
GLubyte *alpha, GLfloat c )
{
GLint level;
if (lambda>c) {
/* minification */
switch (ctx->Texture.Current1D->MinFilter) {
case GL_NEAREST:
level = 0;
sample_1d_nearest( ctx, ctx->Texture.Current1D->Image[level],
s, red, green, blue, alpha );
break;
case GL_LINEAR:
level = 0;
sample_1d_linear( ctx, ctx->Texture.Current1D->Image[level],
s, red, green, blue, alpha );
break;
case GL_NEAREST_MIPMAP_NEAREST:
sample_1d_nearest_mipmap_nearest( ctx, lambda, s,
red, green, blue, alpha );
break;
case GL_LINEAR_MIPMAP_NEAREST:
sample_1d_linear_mipmap_nearest( ctx, lambda, s,
red, green, blue, alpha );
break;
case GL_NEAREST_MIPMAP_LINEAR:
sample_1d_nearest_mipmap_linear( ctx, lambda, s,
red, green, blue, alpha );
break;
case GL_LINEAR_MIPMAP_LINEAR:
sample_1d_linear_mipmap_linear( ctx, lambda, s,
red, green, blue, alpha );
break;
default:
abort();
}
}
else {
/* magnification */
switch (ctx->Texture.Current1D->MagFilter) {
case GL_NEAREST:
sample_1d_nearest( ctx, ctx->Texture.Current1D->Image[0],
s, red, green, blue, alpha );
break;
case GL_LINEAR:
sample_1d_linear( ctx, ctx->Texture.Current1D->Image[0],
s, red, green, blue, alpha );
break;
default:
abort();
}
}
}
/**********************************************************************/
/* 2-D Texture Sampling Functions */
/**********************************************************************/
/*
* Given a texture image and an (i,j) integer texel coordinate, return the
* texel color.
*/
static void get_2d_texel( struct gl_texture_image *img, GLint i, GLint j,
GLubyte *red, GLubyte *green, GLubyte *blue,
GLubyte *alpha )
{
GLint width = img->Width; /* power of two */
GLint height = img->Height; /* power of two */
GLubyte *texel;
/* DEBUG */
if (i<0 || i>=width) abort();
if (j<0 || j>=height) abort();
switch (img->Format) {
case GL_ALPHA:
case GL_LUMINANCE:
case GL_INTENSITY:
*red = img->Data[ width * j + i ];
return;
case GL_LUMINANCE_ALPHA:
texel = img->Data + (width * j + i) * 2;
*red = texel[0];
*alpha = texel[1];
return;
case GL_RGB:
texel = img->Data + (width * j + i) * 3;
*red = texel[0];
*green = texel[1];
*blue = texel[2];
return;
case GL_RGBA:
texel = img->Data + (width * j + i) * 4;
*red = texel[0];
*green = texel[1];
*blue = texel[2];
*alpha = texel[3];
return;
default:
abort();
}
}
/*
* Return a texture sample for (s,t) using GL_NEAREST filter.
*/
static void sample_2d_nearest( GLcontext *ctx,
struct gl_texture_image *img,
GLfloat s, GLfloat t,
GLubyte *red, GLubyte *green,
GLubyte *blue, GLubyte *alpha )
{
GLint width = img->Width; /* power of two */
GLint height = img->Height; /* power of two */
GLint i, j;
GLubyte *texel;
/* Clamp/Repeat S and convert to integer texel coordinate */
if (ctx->Texture.Current2D->WrapS==GL_REPEAT) {
/* s limited to [0,1) */
/* i limited to [0,width-1] */
i = (GLint) (s * width);
i &= (width-1);
}
else {
/* s limited to [0,1] */
/* i limited to [0,width-1] */
if (s<0.0F) {
i = 0;
}
else if (s>1.0F) {
i = width-1;
}
else {
i = (GLint) (s * width);
}
}
/* Clamp/Repeat T and convert to integer texel coordinate */
if (ctx->Texture.Current2D->WrapT==GL_REPEAT) {
/* t limited to [0,1) */
/* j limited to [0,height-1] */
j = (GLint) (t * height);
j &= (height-1);
}
else {
/* t limited to [0,1] */
/* j limited to [0,height-1] */
if (t<0.0F) {
j = 0;
}
else if (t>1.0F) {
j = height-1;
}
else {
j = (GLint) (t * height);
}
}
switch (img->Format) {
case GL_ALPHA:
case GL_LUMINANCE:
case GL_INTENSITY:
*red = img->Data[ j * width + i ];
return;
case GL_LUMINANCE_ALPHA:
texel = img->Data + ((j * width + i) << 1);
*red = texel[0];
*alpha = texel[1];
return;
case GL_RGB:
texel = img->Data + (j * width + i) * 3;
*red = texel[0];
*green = texel[1];
*blue = texel[2];
return;
case GL_RGBA:
texel = img->Data + ((j * width + i) << 2);
*red = texel[0];
*green = texel[1];
*blue = texel[2];
*alpha = texel[3];
return;
default:
abort();
}
}
/*
* Return a texture sample for (s,t) using GL_LINEAR filter.
*/
static void sample_2d_linear( GLcontext *ctx,
struct gl_texture_image *img,
GLfloat s, GLfloat t,
GLubyte *red, GLubyte *green,
GLubyte *blue, GLubyte *alpha )
{
GLint width = img->Width;
GLint height = img->Height;
GLint i0, j0, i1, j1;
GLint i0border, j0border, i1border, j1border;
GLfloat u, v;
u = s * width;
if (ctx->Texture.Current2D->WrapS==GL_REPEAT) {
i0 = ((GLint) floor( u - 0.5F)) & (width-1);
i1 = (i0 + 1) & (width-1);
i0border = i1border = 0;
}
else {
i0 = (GLint) floor( u - 0.5F );
i1 = i0 + 1;
i0border = (i0<0) | (i0>=width);
i1border = (i1<0) | (i1>=width);
}
v = t * height;
if (ctx->Texture.Current2D->WrapT==GL_REPEAT) {
j0 = ((GLint) floor( v - 0.5F)) & (height-1);
j1 = (j0 + 1) & (height-1);
j0border = j1border = 0;
}
else {
j0 = (GLint) floor( v - 0.5F );
j1 = j0 + 1;
j0border = (j0<0) | (j0>=height);
j1border = (j1<0) | (j1>=height);
}
{
GLfloat a = frac( u - 0.5F );
GLfloat b = frac( v - 0.5F );
GLint w00 = (GLint) ((1.0F-a)*(1.0F-b) * 256.0F);
GLint w10 = (GLint) ( a *(1.0F-b) * 256.0F);
GLint w01 = (GLint) ((1.0F-a)* b * 256.0F);
GLint w11 = (GLint) ( a * b * 256.0F);
GLubyte red00, green00, blue00, alpha00;
GLubyte red10, green10, blue10, alpha10;
GLubyte red01, green01, blue01, alpha01;
GLubyte red11, green11, blue11, alpha11;
if (i0border | j0border) {
red00 = ctx->Texture.Current2D->BorderColor[0];
green00 = ctx->Texture.Current2D->BorderColor[1];
blue00 = ctx->Texture.Current2D->BorderColor[2];
alpha00 = ctx->Texture.Current2D->BorderColor[3];
}
else {
get_2d_texel( img, i0, j0, &red00, &green00, &blue00, &alpha00 );
}
if (i1border | j0border) {
red10 = ctx->Texture.Current2D->BorderColor[0];
green10 = ctx->Texture.Current2D->BorderColor[1];
blue10 = ctx->Texture.Current2D->BorderColor[2];
alpha10 = ctx->Texture.Current2D->BorderColor[3];
}
else {
get_2d_texel( img, i1, j0, &red10, &green10, &blue10, &alpha10 );
}
if (i0border | j1border) {
red01 = ctx->Texture.Current2D->BorderColor[0];
green01 = ctx->Texture.Current2D->BorderColor[1];
blue01 = ctx->Texture.Current2D->BorderColor[2];
alpha01 = ctx->Texture.Current2D->BorderColor[3];
}
else {
get_2d_texel( img, i0, j1, &red01, &green01, &blue01, &alpha01 );
}
if (i1border | j1border) {
red11 = ctx->Texture.Current2D->BorderColor[0];
green11 = ctx->Texture.Current2D->BorderColor[1];
blue11 = ctx->Texture.Current2D->BorderColor[2];
alpha11 = ctx->Texture.Current2D->BorderColor[3];
}
else {
get_2d_texel( img, i1, j1, &red11, &green11, &blue11, &alpha11 );
}
*red = (w00*red00 + w10*red10 + w01*red01 + w11*red11 ) >> 8;
*green = (w00*green00 + w10*green10 + w01*green01 + w11*green11) >> 8;
*blue = (w00*blue00 + w10*blue10 + w01*blue01 + w11*blue11 ) >> 8;
*alpha = (w00*alpha00 + w10*alpha10 + w01*alpha01 + w11*alpha11) >> 8;
}
}
static void sample_2d_nearest_mipmap_nearest( GLcontext *ctx,
GLfloat lambda,
GLfloat s, GLfloat t,
GLubyte *red, GLubyte *green,
GLubyte *blue, GLubyte *alpha )
{
GLint level;
if (lambda<=0.5F) {
level = 0;
}
else {
GLint widthlog2 = ctx->Texture.Current2D->Image[0]->WidthLog2;
level = (GLint) (lambda + 0.499999F);
if (level>widthlog2 ) {
level = widthlog2;
}
}
sample_2d_nearest( ctx, ctx->Texture.Current2D->Image[level],
s, t, red, green, blue, alpha );
}
static void sample_2d_linear_mipmap_nearest( GLcontext *ctx,
GLfloat lambda,
GLfloat s, GLfloat t,
GLubyte *red, GLubyte *green,
GLubyte *blue, GLubyte *alpha )
{
GLint level;
if (lambda<=0.5F) {
level = 0;
}
else {
GLint widthlog2 = ctx->Texture.Current2D->Image[0]->WidthLog2;
level = (GLint) (lambda + 0.499999F);
if (level>widthlog2 ) {
level = widthlog2;
}
}
sample_2d_linear( ctx, ctx->Texture.Current2D->Image[level],
s, t, red, green, blue, alpha );
}
static void sample_2d_nearest_mipmap_linear( GLcontext *ctx,
GLfloat lambda,
GLfloat s, GLfloat t,
GLubyte *red, GLubyte *green,
GLubyte *blue, GLubyte *alpha )
{
GLint max = ctx->Texture.Current2D->Image[0]->MaxLog2;
if (lambda>=max) {
sample_2d_nearest( ctx, ctx->Texture.Current2D->Image[max],
s, t, red, green, blue, alpha );
}
else {
GLubyte red0, green0, blue0, alpha0;
GLubyte red1, green1, blue1, alpha1;
GLfloat f = frac(lambda);
GLint level = (GLint) (lambda + 1.0F);
level = CLAMP( level, 1, max );
sample_2d_nearest( ctx, ctx->Texture.Current2D->Image[level-1], s, t,
&red0, &green0, &blue0, &alpha0 );
sample_2d_nearest( ctx, ctx->Texture.Current2D->Image[level], s, t,
&red1, &green1, &blue1, &alpha1 );
*red = (1.0F-f)*red1 + f*red0;
*green = (1.0F-f)*green1 + f*green0;
*blue = (1.0F-f)*blue1 + f*blue0;
*alpha = (1.0F-f)*alpha1 + f*alpha0;
}
}
static void sample_2d_linear_mipmap_linear( GLcontext *ctx,
GLfloat lambda,
GLfloat s, GLfloat t,
GLubyte *red, GLubyte *green,
GLubyte *blue, GLubyte *alpha )
{
GLint max = ctx->Texture.Current2D->Image[0]->MaxLog2;
if (lambda>=max) {
sample_2d_linear( ctx, ctx->Texture.Current2D->Image[max],
s, t, red, green, blue, alpha );
}
else {
GLubyte red0, green0, blue0, alpha0;
GLubyte red1, green1, blue1, alpha1;
GLfloat f = frac(lambda);
GLint level = (GLint) (lambda + 1.0F);
level = CLAMP( level, 1, max );
sample_2d_linear( ctx, ctx->Texture.Current2D->Image[level-1], s, t,
&red0, &green0, &blue0, &alpha0 );
sample_2d_linear( ctx, ctx->Texture.Current2D->Image[level], s, t,
&red1, &green1, &blue1, &alpha1 );
*red = (1.0F-f)*red1 + f*red0;
*green = (1.0F-f)*green1 + f*green0;
*blue = (1.0F-f)*blue1 + f*blue0;
*alpha = (1.0F-f)*alpha1 + f*alpha0;
}
}
/*
* Given an (s,t) texture coordinate and lambda (level of detail) value
* return a texture sample (color).
*
*/
static void sample_2d_texture( GLcontext *ctx,
GLfloat s, GLfloat t, GLfloat lambda,
GLubyte *red, GLubyte *green, GLubyte *blue,
GLubyte *alpha, GLfloat c )
{
if (lambda>c) {
/* minification */
switch (ctx->Texture.Current2D->MinFilter) {
case GL_NEAREST:
sample_2d_nearest( ctx, ctx->Texture.Current2D->Image[0],
s, t, red, green, blue, alpha );
break;
case GL_LINEAR:
sample_2d_linear( ctx, ctx->Texture.Current2D->Image[0],
s, t, red, green, blue, alpha );
break;
case GL_NEAREST_MIPMAP_NEAREST:
sample_2d_nearest_mipmap_nearest( ctx, lambda, s, t,
red, green, blue, alpha );
break;
case GL_LINEAR_MIPMAP_NEAREST:
sample_2d_linear_mipmap_nearest( ctx, lambda, s, t,
red, green, blue, alpha );
break;
case GL_NEAREST_MIPMAP_LINEAR:
sample_2d_nearest_mipmap_linear( ctx, lambda, s, t,
red, green, blue, alpha );
break;
case GL_LINEAR_MIPMAP_LINEAR:
sample_2d_linear_mipmap_linear( ctx, lambda, s, t,
red, green, blue, alpha );
break;
default:
abort();
}
}
else {
/* magnification */
switch (ctx->Texture.Current2D->MagFilter) {
case GL_NEAREST:
sample_2d_nearest( ctx, ctx->Texture.Current2D->Image[0],
s, t, red, green, blue, alpha );
break;
case GL_LINEAR:
sample_2d_linear( ctx, ctx->Texture.Current2D->Image[0],
s, t, red, green, blue, alpha );
break;
default:
abort();
}
}
}
#undef SAMPLE_MIPMAP_LINEAR
#undef SAMPLE_MIPMAP_NEAREST
/**********************************************************************/
/* Texture Application */
/**********************************************************************/
/*
* Combine incoming fragment color with texel color to produce output color.
* Input: n - number of fragments
* format - base internal texture format
* env_mode - texture environment mode
* Rt, Gt, Bt, At - array of texel colors
* InOut: red, green, blue, alpha - incoming fragment colors modified
* by texel colors according to the
* texture environment mode.
*/
static void apply_texture( GLcontext *ctx,
GLuint n, GLint format, GLenum env_mode,
GLubyte red[], GLubyte green[], GLubyte blue[], GLubyte alpha[],
GLubyte Rt[], GLubyte Gt[], GLubyte Bt[], GLubyte At[] )
{
GLuint i;
GLint Rc, Gc, Bc, Ac;
if (!ctx->Visual->EightBitColor) {
/* This is a hack! Rescale input colors from [0,scale] to [0,255]. */
GLfloat rscale = 255.0 * ctx->Visual->InvRedScale;
GLfloat gscale = 255.0 * ctx->Visual->InvGreenScale;
GLfloat bscale = 255.0 * ctx->Visual->InvBlueScale;
GLfloat ascale = 255.0 * ctx->Visual->InvAlphaScale;
for (i=0;i<n;i++) {
red[i] = (GLint) (red[i] * rscale);
green[i] = (GLint) (green[i] * gscale);
blue[i] = (GLint) (blue[i] * bscale);
alpha[i] = (GLint) (alpha[i] * ascale);
}
}
/*
* Use (A*(B+1)) >> 8 as a fast approximation of (A*B)/255 for A
* and B in [0,255]
*/
#define PROD(A,B) (((GLint)(A) * (GLint)(B)+1) >> 8)
switch (env_mode) {
case GL_REPLACE:
switch (format) {
case GL_ALPHA:
for (i=0;i<n;i++) {
/* Cv = Cf */
/* Av = At */
alpha[i] = At[i];
}
break;
case GL_LUMINANCE:
for (i=0;i<n;i++) {
/* Cv = Lt */
GLint Lt = Rt[i];
red[i] = green[i] = blue[i] = Lt;
/* Av = Af */
}
break;
case GL_LUMINANCE_ALPHA:
for (i=0;i<n;i++) {
GLint Lt = Rt[i];
/* Cv = Lt */
red[i] = green[i] = blue[i] = Lt;
/* Av = At */
alpha[i] = At[i];
}
break;
case GL_INTENSITY:
for (i=0;i<n;i++) {
/* Cv = It */
GLint It = Rt[i];
red[i] = green[i] = blue[i] = It;
/* Av = It */
alpha[i] = It;
}
break;
case GL_RGB:
for (i=0;i<n;i++) {
/* Cv = Ct */
red[i] = Rt[i];
green[i] = Gt[i];
blue[i] = Bt[i];
/* Av = Af */
}
break;
case GL_RGBA:
for (i=0;i<n;i++) {
/* Cv = Ct */
red[i] = Rt[i];
green[i] = Gt[i];
blue[i] = Bt[i];
/* Av = At */
alpha[i] = At[i];
}
break;
default:
abort();
}
break;
case GL_MODULATE:
switch (format) {
case GL_ALPHA:
for (i=0;i<n;i++) {
/* Cv = Cf */
/* Av = AfAt */
alpha[i] = PROD( alpha[i], At[i] );
}
break;
case GL_LUMINANCE:
for (i=0;i<n;i++) {
/* Cv = LtCf */
GLint Lt = Rt[i];
red[i] = PROD( red[i], Lt );
green[i] = PROD( green[i], Lt );
blue[i] = PROD( blue[i], Lt );
/* Av = Af */
}
break;
case GL_LUMINANCE_ALPHA:
for (i=0;i<n;i++) {
/* Cv = CfLt */
GLint Lt = Rt[i];
red[i] = PROD( red[i], Lt );
green[i] = PROD( green[i], Lt );
blue[i] = PROD( blue[i], Lt );
/* Av = AfAt */
alpha[i] = PROD( alpha[i], At[i] );
}
break;
case GL_INTENSITY:
for (i=0;i<n;i++) {
/* Cv = CfIt */
GLint It = Rt[i];
red[i] = PROD( red[i], It );
green[i] = PROD( green[i], It );
blue[i] = PROD( blue[i], It );
/* Av = AfIt */
alpha[i] = PROD( alpha[i], It );
}
break;
case GL_RGB:
for (i=0;i<n;i++) {
/* Cv = CfCt */
red[i] = PROD( red[i], Rt[i] );
green[i] = PROD( green[i], Gt[i] );
blue[i] = PROD( blue[i], Bt[i] );
/* Av = Af */
}
break;
case GL_RGBA:
for (i=0;i<n;i++) {
/* Cv = CfCt */
red[i] = PROD( red[i], Rt[i] );
green[i] = PROD( green[i], Gt[i] );
blue[i] = PROD( blue[i], Bt[i] );
/* Av = AfAt */
alpha[i] = PROD( alpha[i], At[i] );
}
break;
default:
abort();
}
break;
case GL_DECAL:
switch (format) {
case GL_ALPHA:
case GL_LUMINANCE:
case GL_LUMINANCE_ALPHA:
case GL_INTENSITY:
/* undefined */
break;
case GL_RGB:
for (i=0;i<n;i++) {
/* Cv = Ct */
red[i] = Rt[i];
green[i] = Gt[i];
blue[i] = Bt[i];
/* Av = Af */
}
break;
case GL_RGBA:
for (i=0;i<n;i++) {
/* Cv = Cf(1-At) + CtAt */
GLint t = At[i], s = 255 - t;
red[i] = PROD(red[i], s) + PROD(Rt[i],t);
green[i] = PROD(green[i],s) + PROD(Gt[i],t);
blue[i] = PROD(blue[i], s) + PROD(Bt[i],t);
/* Av = Af */
}
break;
default:
abort();
}
break;
case GL_BLEND:
Rc = (GLint) (ctx->Texture.EnvColor[0] * 255.0F);
Gc = (GLint) (ctx->Texture.EnvColor[1] * 255.0F);
Bc = (GLint) (ctx->Texture.EnvColor[2] * 255.0F);
Ac = (GLint) (ctx->Texture.EnvColor[2] * 255.0F);
switch (format) {
case GL_ALPHA:
for (i=0;i<n;i++) {
/* Cv = Cf */
/* Av = AfAt */
alpha[i] = PROD(alpha[i], At[i]);
}
break;
case GL_LUMINANCE:
for (i=0;i<n;i++) {
/* Cv = Cf(1-Lt) + CcLt */
GLint Lt = Rt[i], s = 255 - Lt;
red[i] = PROD(red[i], s) + PROD(Rc, Lt);
green[i] = PROD(green[i],s) + PROD(Gc,Lt);
blue[i] = PROD(blue[i], s) + PROD(Bc, Lt);
/* Av = Af */
}
break;
case GL_LUMINANCE_ALPHA:
for (i=0;i<n;i++) {
/* Cv = Cf(1-Lt) + CcLt */
GLint Lt = Rt[i], s = 255 - Lt;
red[i] = PROD(red[i], s) + PROD(Rc, Lt);
green[i] = PROD(green[i],s) + PROD(Gc,Lt);
blue[i] = PROD(blue[i], s) + PROD(Bc, Lt);
/* Av = AfAt */
alpha[i] = PROD(alpha[i],At[i]);
}
break;
case GL_INTENSITY:
for (i=0;i<n;i++) {
/* Cv = Cf(1-It) + CcLt */
GLint It = Rt[i], s = 255 - It;
red[i] = PROD(red[i], s) + PROD(Rc,It);
green[i] = PROD(green[i],s) + PROD(Gc,It);
blue[i] = PROD(blue[i], s) + PROD(Bc,It);
/* Av = Af(1-It) + Ac*It */
alpha[i] = PROD(alpha[i],s) + PROD(Ac,It);
}
break;
case GL_RGB:
for (i=0;i<n;i++) {
/* Cv = Cf(1-Ct) + CcCt */
red[i] = PROD(red[i], (255-Rt[i])) + PROD(Rc,Rt[i]);
green[i] = PROD(green[i],(255-Gt[i])) + PROD(Gc,Gt[i]);
blue[i] = PROD(blue[i], (255-Bt[i])) + PROD(Bc,Bt[i]);
/* Av = Af */
}
break;
case GL_RGBA:
for (i=0;i<n;i++) {
/* Cv = Cf(1-Ct) + CcCt */
red[i] = PROD(red[i], (255-Rt[i])) + PROD(Rc,Rt[i]);
green[i] = PROD(green[i],(255-Gt[i])) + PROD(Gc,Gt[i]);
blue[i] = PROD(blue[i], (255-Bt[i])) + PROD(Bc,Bt[i]);
/* Av = AfAt */
alpha[i] = PROD(alpha[i],At[i]);
}
break;
}
break;
default:
abort();
}
#undef PROD
if (!ctx->Visual->EightBitColor) {
/* This is a hack! Rescale input colors from [0,255] to [0,scale]. */
GLfloat rscale = ctx->Visual->RedScale * (1.0F/ 255.0F);
GLfloat gscale = ctx->Visual->GreenScale * (1.0F/ 255.0F);
GLfloat bscale = ctx->Visual->BlueScale * (1.0F/ 255.0F);
GLfloat ascale = ctx->Visual->AlphaScale * (1.0F/ 255.0F);
for (i=0;i<n;i++) {
red[i] = (GLint) (red[i] * rscale);
green[i] = (GLint) (green[i] * gscale);
blue[i] = (GLint) (blue[i] * bscale);
alpha[i] = (GLint) (alpha[i] * ascale);
}
}
}
/*
* Given an array of fragment colors and texture coordinates, apply
* 1-D texturing to the fragments.
* Input: n - number of fragments
* s - array of texture coordinate s values
* lambda - array of lambda values
* InOut: red, green, blue, alpha - incoming and modifed fragment colors
*/
void gl_texture_pixels_1d( GLcontext *ctx,
GLuint n, GLfloat s[], GLfloat lambda[],
GLubyte red[], GLubyte green[],
GLubyte blue[], GLubyte alpha[] )
{
GLubyte tred[PB_SIZE];
GLubyte tgreen[PB_SIZE];
GLubyte tblue[PB_SIZE];
GLubyte talpha[PB_SIZE];
GLuint i;
GLfloat c;
/* Decide if texture can be applied. */
if (!ctx->Texture.Current1D->Complete) {
return;
}
/*
* Decide about value of c
*/
if (ctx->Texture.Current1D->MagFilter==GL_LINEAR
&& (ctx->Texture.Current1D->MinFilter==GL_NEAREST_MIPMAP_NEAREST ||
ctx->Texture.Current1D->MinFilter==GL_LINEAR_MIPMAP_NEAREST)) {
c = 0.5F;
}
else {
c = 0.0F;
}
/*
* Compute texel colors.
*/
if (lambda) {
for (i=0;i<n;i++)
sample_1d_texture( ctx, s[i],lambda[i],
&tred[i],&tgreen[i],&tblue[i],&talpha[i],c);
}
else {
for (i=0;i<n;i++)
sample_1d_texture( ctx, s[i],0,
&tred[i],&tgreen[i],&tblue[i],&talpha[i],c);
}
/* Modify incoming fragment colors according to sampled texels */
apply_texture( ctx, n,
ctx->Texture.Current1D->Image[0]->Format,
ctx->Texture.EnvMode,
red, green, blue, alpha,
tred, tgreen, tblue, talpha );
}
/*
* Given an array of fragment colors and texture coordinates, apply
* 2-D texturing to the fragments.
* Input: n - number of fragments
* s,s - array of texture coordinate (s,t) values
* lambda - array of lambda values
* InOut: red, green, blue, alpha - incoming and modifed fragment colors
*/
void gl_texture_pixels_2d( GLcontext *ctx,
GLuint n,
GLfloat s[], GLfloat t[], GLfloat lambda[],
GLubyte red[], GLubyte green[],
GLubyte blue[], GLubyte alpha[] )
{
GLubyte tred[PB_SIZE];
GLubyte tgreen[PB_SIZE];
GLubyte tblue[PB_SIZE];
GLubyte talpha[PB_SIZE];
GLuint i;
GLfloat c;
/* Decide if texture can be applied. */
if (!ctx->Texture.Current2D->Complete) {
return;
}
/*
* Decide about value of c
*/
if (ctx->Texture.Current2D->MagFilter==GL_LINEAR
&& (ctx->Texture.Current2D->MinFilter==GL_NEAREST_MIPMAP_NEAREST ||
ctx->Texture.Current2D->MinFilter==GL_LINEAR_MIPMAP_NEAREST)) {
c = 0.5F;
}
else {
c = 0.0F;
}
/*
* Compute texel colors.
*/
if (lambda) {
for (i=0;i<n;i++) {
sample_2d_texture( ctx, s[i], t[i], lambda[i],
&tred[i], &tgreen[i], &tblue[i], &talpha[i], c);
}
}
else {
for (i=0;i<n;i++)
sample_2d_texture( ctx, s[i], t[i], 0,
&tred[i], &tgreen[i], &tblue[i], &talpha[i], c );
}
apply_texture( ctx, n,
ctx->Texture.Current2D->Image[0]->Format,
ctx->Texture.EnvMode,
red, green, blue, alpha,
tred, tgreen, tblue, talpha );
}
/*
* This is called by gl_update_state() if the NEW_TEXTURING bit in
* ctx->NewState is set. Basically, we check if we have a complete set
* of mipmaps when mipmapping is enabled.
*/
void gl_update_texture_state( GLcontext *ctx )
{
GLint i;
struct gl_texture_object *t;
t = ctx->Shared->TexObjectList;
while (t) {
/*
* Determine if we have a complete set of mipmaps
*/
t->Complete = GL_TRUE; /* be optimistic */
if ( t->MinFilter==GL_NEAREST_MIPMAP_NEAREST
|| t->MinFilter==GL_LINEAR_MIPMAP_NEAREST
|| t->MinFilter==GL_NEAREST_MIPMAP_LINEAR
|| t->MinFilter==GL_LINEAR_MIPMAP_LINEAR) {
/* Test dimension-independent attributes */
for (i=1; i<MAX_TEXTURE_LEVELS; i++) {
if (t->Image[i]) {
if (!t->Image[i]->Data) {
t->Complete = GL_FALSE;
break;
}
if (t->Image[i]->Format != t->Image[0]->Format) {
t->Complete = GL_FALSE;
break;
}
if (t->Image[i]->Border != t->Image[0]->Border) {
t->Complete = GL_FALSE;
break;
}
}
}
if (t->Dimensions==1 && t->Image[0]) {
/* Test 1-D mipmaps */
GLuint width = t->Image[0]->Width;
for (i=1; i<MAX_TEXTURE_LEVELS; i++) {
if (width>1) {
width /= 2;
}
if (!t->Image[i]) {
t->Complete = GL_FALSE;
break;
}
if (!t->Image[i]->Data) {
t->Complete = GL_FALSE;
break;
}
if (t->Image[i]->Format != t->Image[0]->Format) {
t->Complete = GL_FALSE;
break;
}
if (t->Image[i]->Border != t->Image[0]->Border) {
t->Complete = GL_FALSE;
break;
}
if (t->Image[i]->Width != width ) {
t->Complete = GL_FALSE;
break;
}
if (width==1) {
break;
}
}
}
else if (t->Dimensions==2 && t->Image[0]) {
/* Test 2-D mipmaps */
GLuint width = t->Image[0]->Width;
GLuint height = t->Image[0]->Height;
for (i=1; i<MAX_TEXTURE_LEVELS; i++) {
if (width>1) {
width /= 2;
}
if (height>1) {
height /= 2;
}
if (!t->Image[i]) {
t->Complete = GL_FALSE;
break;
}
if (t->Image[i]->Width != width) {
t->Complete = GL_FALSE;
break;
}
if (t->Image[i]->Height != height) {
t->Complete = GL_FALSE;
break;
}
if (width==1 && height==1) {
break;
}
}
}
else {
/* Dimensions = ??? */
}
}
else {
/* not mipmapping, only need the level 0 texture image */
if (!t->Image[0] || !t->Image[0]->Data) {
t->Complete = GL_FALSE;
}
}
t = t->Next; /* Next texture object */
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.