Newer
Older
/*
* OpenGL texture (etc.) handling.
* Stuart Levy, slevy@ncsa.uiuc.edu
* National Center for Supercomputing Applications,
* University of Illinois 2001.
* This file is part of partiview, released under the
* Illinois Open Source License; see the file LICENSE.partiview for details.
#else /*unix?*/
#include <unistd.h>
#endif /*!WIN32*/
#include <stdlib.h>
#include <stdio.h>
#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#else
#include <GL/gl.h> /* for GLuint */
#include <string.h>
#include "textures.h"
#include "shmem.h"
#include "findfile.h"
#if sgi && mips
# define glBindTexture glBindTextureEXT
# define glGenTextures glGenTexturesEXT
#endif
#if CAVE
#include "vd_util.h"
#endif
extern int mg_inhaletexture( Texture *tx, int rgba );
{
#if CAVE
/* assume virdir */
int id = CAT_get_display_slot();
if(id < 0 || id >= MAXDSPCTX) id = MAXDSPCTX-1;
return id;
#else /* stand-alone -- single GLX context */
return 0;
#endif
}
#define TEXTURENO(enab) ((enab) & 0xFFFFFF)
#define BLEND_ON 0x40000000
#define BLEND_OFF 0x20000000
int txbind( Texture *tx, int *enabled )
{
static GLint format[5] =
{ 0, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA };
static GLfloat minfilts[] = {
GL_NEAREST, GL_LINEAR,
GL_NEAREST, GL_LINEAR,
GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR,
GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR
};
int wantblend = 0;
if(enabled == NULL || *enabled != 0) {
glBindTexture( GL_TEXTURE_2D, 0 );
glDisable( GL_TEXTURE_2D );
if(any3d) {
glDisable( GL_TEXTURE_3D );
glBindTexture( GL_TEXTURE_3D, 0 );
}
glDisable( GL_ALPHA_TEST );
}
txenv = -1;
txtarget = (tx->flags & TXF_3D) ? GL_TEXTURE_3D : GL_TEXTURE_2D;
if(txtarget == GL_TEXTURE_3D)
any3d = 1;
#if unix
if(tx->report & (1<<ctx)) {
fprintf(stderr, "tx %x pid %d ctx %d txid[ctx] %d data %x loaded %d isTexture %d\n",
tx, getpid(), ctx, tx->txid[ctx], tx->data, tx->loaded,
glIsTexture(tx->txid[ctx]));
tx->report &= ~(1<<ctx);
}
#endif
wantblend = (tx->flags & (TXF_ALPHA|TXF_INTENSITY|TXF_ADD)) ? BLEND_ON : BLEND_OFF;
wantenv =
tx->apply == TXF_DECAL ? GL_DECAL
: tx->apply == TXF_BLEND ? GL_BLEND
: GL_MODULATE;
if(txenv != wantenv) {
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, wantenv);
txenv = wantenv;
}
if(!mustload && TEXTURENO(*enabled) == tx->txid[ctx])
glGenTextures( 1, &id );
wanted = tx->txid[ctx] | wantblend;
if(mustload) {
if(tx->data == NULL) {
fprintf(stderr,
"Hey! Why are we having to reload the data for texture \"%s\"?\n",
tx->filename);
tx->loaded = 0;
txload(tx);
wanted = (tx->data != NULL);
}
unsigned char *txdata = (unsigned char *)tx->data;
int channels = tx->channels;
if((tx->flags&TXF_INTENSITY) && (channels == 1 || channels == 3)) {
int npix = tx->xsize * tx->ysize;
int k;
unsigned char *ip, *op;
txdata = (unsigned char *)malloc( npix * channels );
k = npix;
ip = (unsigned char *)tx->data;
op = txdata;
switch(channels) {
case 2:
do {
op[1] = *ip++;
op[0] = 255;
op += 2;
} while(--k > 0);
break;
case 4:
do {
op[3] = 77*ip[0] + 150*ip[1] + 28*ip[2];
op[0] = ip[0]>=op[3] ? 255 : ip[0]/op[3];
op[1] = ip[1]>=op[3] ? 255 : ip[0]/op[3];
op[2] = ip[2]>=op[3] ? 255 : ip[2]/op[3];
if(tx->xsize % 4 != 0)
glPixelStorei( GL_PACK_ALIGNMENT, 1 );
if(tx->flags & TXF_3D) {
tx->qualflags &= ~TXQ_MIPMAP;
glTexImage3D( GL_TEXTURE_3D, 0, channels,
tx->xsize, tx->ysize, tx->zsize,
0, /* border */
channels==1 && (tx->flags&TXF_ALPHA)
? GL_ALPHA : format[channels],
GL_UNSIGNED_BYTE,
txdata );
} else {
gluBuild2DMipmaps( GL_TEXTURE_2D, channels,
channels==1 && (tx->flags&TXF_ALPHA)
? GL_ALPHA : format[channels],
GL_UNSIGNED_BYTE,
txdata);
if(tx->xsize % 4 != 0)
glPixelStorei( GL_PACK_ALIGNMENT, 4 ); /* restore default */
if(txdata != (unsigned char *)tx->data)
(tx->qualflags&0x07) ? GL_LINEAR : GL_NEAREST);
#if !CAVE
/* We won't need texture data again -- opengl has it now */
Free(tx->data);
tx->data = NULL;
#endif
}
}
if((wanted ^ *enabled) & (BLEND_ON|BLEND_OFF)) {
if(wanted & BLEND_ON) {
glEnable( GL_BLEND );
if(tx->flags & TXF_ADD) {
glBlendFunc( GL_SRC_ALPHA, GL_ONE );
glDisable( GL_ALPHA_TEST );
} else {
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glEnable( GL_ALPHA_TEST );
glAlphaFunc( GL_GREATER, 0.03 );
}
} else if(wanted & BLEND_OFF) {
glDisable( GL_BLEND );
glDisable(GL_ALPHA_TEST);
}
if(TEXTURENO(wanted)) {
} else {
glDisable(GL_TEXTURE_2D);
}
*enabled = wanted = tx->txid[ctx] | wantblend;
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
}
return wanted;
}
Texture *txmake( char *fname, int apply, int txflags, int qualflags )
{
Texture *tx = NewN( Texture, 1 );
memset(tx, 0, sizeof(*tx));
tx->tfm = Tidentity;
tx->filename = fname;
tx->apply = apply;
tx->flags = txflags;
tx->qualflags = qualflags;
return tx;
}
int txload( Texture *tx )
{
if(tx == NULL || tx->loaded < 0) return 0;
if(tx->loaded == 1) return 1; /* already loaded */
if(tx->loaded == 2) return 0; /* busy loading now! */
tx->loaded = 2; /* set this to make multiprocess collisions unlikely */
if(mg_inhaletexture( tx, TXF_RGBA ) <= 0) {
tx->loaded = -1;
return 0;
}
tx->loaded = 1;
return 1;
}
int txaddentry( Texture ***tp, int *ntextures, char *fromfile,
int txno, char *txfname, int apply, int txflags, int qualflags )
{
char *realfname;
if(txno < 0) {
fprintf(stderr, "Texture indices must be >= 0 (texture %d %s)\n", txno, txfname);
return 0;
}
realfname = findfile(fromfile, txfname);
if(realfname == NULL) {
fprintf(stderr, "Can't find texture file \"%s\", ignoring it.\n", txfname);
return 0;
}
if(txno >= *ntextures) {
int ontex = *ntextures;
if(*ntextures == 0) {
*ntextures = txno + 62;
*tp = NewN( Texture *, *ntextures );
} else {
*ntextures = (txno > ontex*2+1 ? txno+ontex : ontex*2+1);
*tp = RenewN( *tp, Texture *, *ntextures );
}
memset(&(*tp)[ontex], 0, (*ntextures - ontex) * sizeof(Texture *));
}