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 );
static int dspcontext = 0;
void set_dsp_context( int ctxno )
{
if(ctxno < 0 || ctxno >= MAXDSPCTX) {
fprintf(stderr, "textures: set_dsp_context(%d): context out of range!\n", ctxno);
ctxno = MAXDSPCTX - 1;
}
dspcontext = ctxno;
}
{
#if CAVE
/* assume virdir */
int id = CAT_get_display_slot();
if(id < 0 || id >= MAXDSPCTX) id = MAXDSPCTX-1;
return dspcontext;
#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
};
static int txenv[MAXDSPCTX];
int wantblend = 0;
if(tx == NULL || txload(tx) == 0
#ifndef GL_TEXTURE_3D
|| tx->flags & TXF_3D
#endif
) {
if(enabled == NULL || *enabled != 0) {
glBindTexture( GL_TEXTURE_2D, 0 );
glDisable( GL_TEXTURE_2D );
#ifdef GL_TEXTURE_3D
if(any3d) {
glDisable( GL_TEXTURE_3D );
glBindTexture( GL_TEXTURE_3D, 0 );
}
#endif
glDisable( GL_ALPHA_TEST );
}
txenv[ctx] = -1;
#ifdef GL_TEXTURE_3D
txtarget = (tx->flags & TXF_3D) ? GL_TEXTURE_3D : GL_TEXTURE_2D;
#else
txtarget = GL_TEXTURE_2D;
#endif
if(tx->flags & TXF_3D)
if(ctx < 0) {
int i;
for(i = 0; i < COUNT(txenv); i++) /* first time -- initialize txenv[] state cache */
txenv[i] = -1;
}
ctx = get_dsp_context();
#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[ctx] != wantenv) {
txenv[ctx] = 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 );
#ifdef GL_TEXTURE_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 );
#endif
} 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)
#if 0
/* yes, we might very well need texture data again, in case window gets re-generated */
#if !CAVE
/* We won't need texture data again -- opengl has it now */
Free(tx->data);
tx->data = NULL;
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);
#ifdef GL_TEXTURE_3D
#endif
}
*enabled = wanted = tx->txid[ctx] | wantblend;
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
}
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 *));
}