This is texobj.c in view mode; [Download] [Up]
/* $Id: texobj.c,v 1.11 1997/05/28 03:26:49 brianp Exp $ */
/*
* Mesa 3-D graphics library
* Version: 2.3
* Copyright (C) 1995-1997 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: texobj.c,v $
* Revision 1.11 1997/05/28 03:26:49 brianp
* added precompiled header (PCH) support
*
* Revision 1.10 1997/05/17 03:41:49 brianp
* added code to update ctx->Texture.Current in gl_BindTexture()
*
* Revision 1.9 1997/05/03 00:52:52 brianp
* removed a few unused variables
*
* Revision 1.8 1997/05/01 02:08:12 brianp
* new implementation of gl_BindTexture()
*
* Revision 1.7 1997/04/28 23:38:45 brianp
* added gl_test_texture_object_completeness()
*
* Revision 1.6 1997/04/14 02:03:05 brianp
* added MinMagThresh to texture object
*
* Revision 1.5 1997/02/09 18:52:15 brianp
* added GL_EXT_texture3D support
*
* Revision 1.4 1997/01/16 03:35:34 brianp
* added calls to device driver DeleteTexture() and BindTexture() functions
*
* Revision 1.3 1997/01/09 19:49:47 brianp
* added a check to switch rasterizers if needed in glBindTexture()
*
* Revision 1.2 1996/09/27 17:09:42 brianp
* removed a redundant return statement
*
* Revision 1.1 1996/09/13 01:38:16 brianp
* Initial revision
*
*/
#ifdef PCH
#include "all.h"
#else
#include <assert.h>
#include <stdlib.h>
#include "context.h"
#include "macros.h"
#include "teximage.h"
#include "texobj.h"
#include "types.h"
#endif
/*
* Allocate a new texture object structure. The name and dimensionality are
* set to zero here and must be initialized by the caller.
*/
struct gl_texture_object *gl_alloc_texture_object( void )
{
struct gl_texture_object *obj;
obj = (struct gl_texture_object *)
calloc(1,sizeof(struct gl_texture_object));
if (obj) {
/* init the non-zero fields */
obj->WrapS = GL_REPEAT;
obj->WrapT = GL_REPEAT;
obj->MinFilter = GL_NEAREST_MIPMAP_LINEAR;
obj->MagFilter = GL_LINEAR;
obj->MinMagThresh = 0.0F;
}
return obj;
}
/*
* Append a gl_texture_object struct to a list of texture objects.
*/
static void append_texture_object( struct gl_texture_object *list,
struct gl_texture_object *obj )
{
struct gl_texture_object *t;
t = list;
assert(t); /* always have proxy textures in the list */
while (t->Next) {
t = t->Next;
}
t->Next = obj;
}
/*
* Deallocate a texture object struct and all children structures
* and image data.
*/
void gl_free_texture_object( struct gl_texture_object *t )
{
GLuint i;
for (i=0;i<MAX_TEXTURE_LEVELS;i++) {
if (t->Image[i]) {
gl_free_texture_image( t->Image[i] );
}
}
free( t );
}
/*
* Given a texture object name, return a pointer to the texture object.
*/
static struct gl_texture_object *
find_texture_object( GLcontext *ctx, GLuint name )
{
struct gl_texture_object *t;
assert( name>0 );
t = ctx->Shared->TexObjectList;
while (t) {
if (t->Name == name) {
return t;
}
t = t->Next;
}
return NULL;
}
/*
* Examine a texture object to determine if it is complete or not.
* The t->Complete flag will be set to GL_TRUE or GL_FALSE accordingly.
*/
void gl_test_texture_object_completeness( struct gl_texture_object *t )
{
t->Complete = GL_TRUE; /* be optimistic */
/* Always need level zero image */
if (!t->Image[0] || !t->Image[0]->Data) {
t->Complete = GL_FALSE;
return;
}
if (t->MinFilter!=GL_NEAREST && t->MinFilter!=GL_LINEAR) {
/*
* Mipmapping: determine if we have a complete set of mipmaps
*/
int i;
/* 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;
return;
}
if (t->Image[i]->Format != t->Image[0]->Format) {
t->Complete = GL_FALSE;
return;
}
if (t->Image[i]->Border != t->Image[0]->Border) {
t->Complete = GL_FALSE;
return;
}
}
}
/* Test things which depend on number of texture image dimensions */
if (t->Dimensions==1) {
/* Test 1-D mipmaps */
GLuint width = t->Image[0]->Width2;
for (i=1; i<MAX_TEXTURE_LEVELS; i++) {
if (width>1) {
width /= 2;
}
if (!t->Image[i]) {
t->Complete = GL_FALSE;
return;
}
if (!t->Image[i]->Data) {
t->Complete = GL_FALSE;
return;
}
if (t->Image[i]->Format != t->Image[0]->Format) {
t->Complete = GL_FALSE;
return;
}
if (t->Image[i]->Border != t->Image[0]->Border) {
t->Complete = GL_FALSE;
return;
}
if (t->Image[i]->Width2 != width ) {
t->Complete = GL_FALSE;
return;
}
if (width==1) {
return; /* found smallest needed mipmap, all done! */
}
}
}
else if (t->Dimensions==2) {
/* Test 2-D mipmaps */
GLuint width = t->Image[0]->Width2;
GLuint height = t->Image[0]->Height2;
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;
return;
}
if (t->Image[i]->Width2 != width) {
t->Complete = GL_FALSE;
return;
}
if (t->Image[i]->Height2 != height) {
t->Complete = GL_FALSE;
return;
}
if (width==1 && height==1) {
return; /* found smallest needed mipmap, all done! */
}
}
}
else if (t->Dimensions==3) {
/* Test 3-D mipmaps */
GLuint width = t->Image[0]->Width2;
GLuint height = t->Image[0]->Height2;
GLuint depth = t->Image[0]->Depth2;
for (i=1; i<MAX_TEXTURE_LEVELS; i++) {
if (width>1) {
width /= 2;
}
if (height>1) {
height /= 2;
}
if (depth>1) {
depth /= 2;
}
if (!t->Image[i]) {
t->Complete = GL_FALSE;
return;
}
if (t->Image[i]->Width2 != width) {
t->Complete = GL_FALSE;
return;
}
if (t->Image[i]->Height2 != height) {
t->Complete = GL_FALSE;
return;
}
if (t->Image[i]->Depth2 != depth) {
t->Complete = GL_FALSE;
return;
}
if (width==1 && height==1 && depth==1) {
return; /* found smallest needed mipmap, all done! */
}
}
}
else {
/* Dimensions = ??? */
gl_problem(NULL, "Bug in gl_test_texture_object_completeness\n");
}
}
}
/*
* Execute glGenTextures
*/
void gl_GenTextures( GLcontext *ctx, GLsizei n, GLuint *texName )
{
GLuint i;
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glGenTextures" );
return;
}
if (n<0) {
gl_error( ctx, GL_INVALID_VALUE, "glGenTextures" );
return;
}
for (i=0;i<n;i++) {
texName[i] = ctx->Shared->NextFreeTextureName++;
}
}
/*
* Execute glDeleteTextures
*/
void gl_DeleteTextures( GLcontext *ctx, GLsizei n, const GLuint *texName)
{
GLuint i;
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glAreTexturesResident" );
return;
}
for (i=0;i<n;i++) {
struct gl_texture_object *t, *tprev, *tcurr;
if (texName[i]>0) {
t = find_texture_object( ctx, texName[i] );
if (t) {
if (ctx->Texture.Current1D==t) {
/* revert to default 1-D texture */
ctx->Texture.Current1D = ctx->Shared->TexObjectList;
t->RefCount--;
assert( t->RefCount >= 0 );
}
else if (ctx->Texture.Current2D==t) {
/* revert to default 2-D texture */
ctx->Texture.Current2D = ctx->Shared->TexObjectList->Next;
t->RefCount--;
assert( t->RefCount >= 0 );
}
else if (ctx->Texture.Current3D==t) {
/* revert to default 3-D texture */
ctx->Texture.Current3D = ctx->Shared->TexObjectList->Next;
t->RefCount--;
assert( t->RefCount >= 0 );
}
if (t->RefCount==0) {
/* remove texture object t from the linked list */
tprev = NULL;
tcurr = ctx->Shared->TexObjectList;
while (tcurr) {
if (tcurr==t) {
assert( tprev );
tprev->Next = t->Next;
gl_free_texture_object( t );
break;
}
tprev = tcurr;
tcurr = tcurr->Next;
}
}
/* tell device driver to delete texture */
if (ctx->Driver.DeleteTexture) {
(*ctx->Driver.DeleteTexture)( ctx, texName[i] );
}
}
}
}
}
/*
* Execute glBindTextures
*/
void gl_BindTexture( GLcontext *ctx, GLenum target, GLuint texName )
{
struct gl_texture_object *oldTexObj;
struct gl_texture_object *newTexObj;
struct gl_texture_object **targetPointer;
GLuint targetDimensions;
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glAreTexturesResident" );
return;
}
switch (target) {
case GL_TEXTURE_1D:
oldTexObj = ctx->Texture.Current1D;
targetPointer = &ctx->Texture.Current1D;
targetDimensions = 1;
break;
case GL_TEXTURE_2D:
oldTexObj = ctx->Texture.Current2D;
targetPointer = &ctx->Texture.Current2D;
targetDimensions = 2;
break;
case GL_TEXTURE_3D_EXT:
oldTexObj = ctx->Texture.Current3D;
targetPointer = &ctx->Texture.Current3D;
targetDimensions = 3;
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glBindTexture" );
return;
}
if (texName==0) {
/* use default n-D texture */
switch (target) {
case GL_TEXTURE_1D:
/* default 1-D texture is first in list */
*targetPointer = ctx->Shared->TexObjectList;
break;
case GL_TEXTURE_2D:
/* default 2-D texture is second in list */
*targetPointer = ctx->Shared->TexObjectList->Next;
break;
case GL_TEXTURE_3D_EXT:
/* default 3-D texture is third in list */
*targetPointer = ctx->Shared->TexObjectList->Next->Next;
break;
default:
gl_problem(ctx, "Bad target in gl_BindTexture");
return;
}
}
else {
newTexObj = find_texture_object( ctx, texName );
if (newTexObj) {
if (newTexObj->Dimensions==targetDimensions) {
/* success! */
*targetPointer = newTexObj;
}
else {
/* wrong dimensionality */
gl_error( ctx, GL_INVALID_OPERATION, "glBindTextureEXT" );
return;
}
}
else {
/* create new texture object */
newTexObj = gl_alloc_texture_object();
append_texture_object( ctx->Shared->TexObjectList, newTexObj );
newTexObj->Name = texName;
newTexObj->Dimensions = targetDimensions;
*targetPointer = newTexObj;
}
}
/* Tidy up reference counting */
if (*targetPointer != oldTexObj && oldTexObj->Name>0) {
/* decrement reference count of the prev texture object */
oldTexObj->RefCount--;
assert( oldTexObj->RefCount >= 0 );
}
if (newTexObj->Name>0) {
newTexObj->RefCount++;
}
/* Check if we may have to use a new triangle rasterizer */
if ( oldTexObj->WrapS != newTexObj->WrapS
|| oldTexObj->WrapT != newTexObj->WrapT
|| oldTexObj->WrapR != newTexObj->WrapR
|| oldTexObj->MinFilter != newTexObj->MinFilter
|| oldTexObj->MagFilter != newTexObj->MagFilter) {
ctx->NewState |= NEW_RASTER_OPS;
}
/* If we've changed the "Current" texture object (1,2, or 3) update the
* ctx->Texture.Current pointer to point to the new texture object.
*/
if (oldTexObj==ctx->Texture.Current) {
ctx->Texture.Current = newTexObj;
}
/* The current n-D texture object can never be NULL! */
assert(*targetPointer);
/* Pass BindTexture to device driver */
if (ctx->Driver.BindTexture) {
(*ctx->Driver.BindTexture)( ctx, target, texName );
}
}
/*
* Execute glPrioritizeTextures
*/
void gl_PrioritizeTextures( GLcontext *ctx,
GLsizei n, const GLuint *texName,
const GLclampf *priorities )
{
GLuint i;
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glAreTexturesResident" );
return;
}
if (n<0) {
gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)" );
return;
}
for (i=0;i<n;i++) {
struct gl_texture_object *t;
if (texName[i]>0) {
t = find_texture_object( ctx, texName[i] );
if (t) {
t->Priority = CLAMP( priorities[i], 0.0F, 1.0F );
}
}
}
}
/*
* Execute glAreTexturesResident
*/
GLboolean gl_AreTexturesResident( GLcontext *ctx, GLsizei n,
const GLuint *texName,
GLboolean *residences )
{
GLboolean resident = GL_TRUE;
GLuint i;
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glAreTexturesResident" );
return GL_FALSE;
}
if (n<0) {
gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)" );
return GL_FALSE;
}
for (i=0;i<n;i++) {
struct gl_texture_object *t;
if (texName[i]==0) {
gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(textures)" );
return GL_FALSE;
}
t = find_texture_object( ctx, texName[i] );
if (t) {
/* we consider all valid texture objects to be resident */
residences[i] = GL_TRUE;
}
else {
gl_error( ctx, GL_INVALID_VALUE, "glAreTexturesResident(textures)" );
return GL_FALSE;
}
}
return resident;
}
/*
* Execute glIsTexture
*/
GLboolean gl_IsTexture( GLcontext *ctx, GLuint texture )
{
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glIsTextures" );
return GL_FALSE;
}
if (texture>0 && find_texture_object(ctx,texture)) {
return GL_TRUE;
}
else {
return GL_FALSE;
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.