This is fxmesa.c in view mode; [Download] [Up]
/* fxmesa.c - 3Dfx VooDoo/Mesa interface */ /* * 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. * * * V0.17 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * optimized the bitmap support (66% faster) * tested with the Mesa 2.3beta2 * * Diego Picciani (d.picciani@novacomp.it) Nova Computer s.r.l. * solved a problem with the drawbitmap() and the Voodoo Rush (GR_ORIGIN_LOWER_LEFT did not work with the Stingray) * * Brian Paul (brianp@elastic.avid.com) Avid Technology * linux stuff * general code clean-up * added attribList parameter to fxMesaCreateContext() * single buffering works now * VB colors are now GLubytes, removed ColorShift stuff. * * Paul Metzger * linux stuff * * V0.16 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * written the quadfunc support (no performance improvement) * written the support for the new Mesa 2.3beta1 driver interface (Wow ! It is faaaster) * rewritten the glBitmap support for the Glide 2.3 (~35% slower !) * written the glBitmap support for the most common case (fonts) * * Jack Palevich * Glide 2.3 porting * * Diego Picciani (d.picciani@novacomp.it) Nova Computer s.r.l. * extended the fxMesaCreateContext() and fxMesaCreateBestContext() functions in order to support also the Voodoo Rush * tested with the Hercules Stingray 128/3D (The rendering in a window works !) * * V0.15 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * written the GL_LUMINANCE_ALPHA support * written the GL_ALPHA support * written the GL_LUMINANCE support * now SETUP correctly set color for mono color sequences * written the 9x1,10x1,...,1x9,1x10,... texture map ratio support * written the no square texture map support * the fog table is no more rebuilt inside setup_fx_units() each time * * Henri Fousse (arnaud@pobox.oleane.com) Thomson Training & Simulation * written (not yet finished: no texture mapping) support for glOrtho * some change to setup functions * the fog support is now fully compatible with the standard OpenGL * rewritten several parts of the driver in order to take advantage of meshes (40% faster !!!) * * V0.14 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * now glAlphaFunc() works * now glDepthMask() works * solved a mipmap problem when using more than one texture * moved ti, texid and wscale inside the fxMesaContext (now we can easy support more ctx and more boards) * the management of the fxMesaContext was completly broken ! * solved several problems about Alpha and texture Alpha * 4 (RGBA) texture channels supported * setting the default color to white * * Henri Fousse (arnaud@pobox.oleane.com) Thomson Training & Simulation * small change to fxMesaCreateContext() and fxMesaMakeCurrent() * written the fog support * setting the default clear color to black * written cleangraphics() for the onexit() function * written fxMesaCreateBestContext() * * V0.13 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * now glBlendFunc() works for all glBlendFunc without DST_ALPHA (because the alpha buffer is not yet implemented) * now fxMesaCreateContext() accept resolution and refresh rate * fixed a bug for texture mapping: the w (alias z) must be set also without depth buffer * fixed a bug for texture image with width!=256 * written texparam() * written all point, line and triangle functions for all possible supported contexts and * the driver is slight faster with points, lines and small triangles * fixed a small bug in fx/fxmesa.h (glOrtho) * * V0.12 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * glDepthFunc supported * introduced a trick to discover the far plane distance (see fxMesaSetFar and fx/fxmesa.h) * now the wbuffer works with homogeneous coordinate (and it doesn't work with a glOrtho projection :) * solved several problems with homogeneous coordinate and texture mapping * fixed a bug in all line functions * fixed a clear framebuffer bug * solved a display list/teximg problem (but use glBindTexture: it is several times faster) * * V0.11 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * introduced texture mapping support (not yet finished !) * tested with Mesa2.2b6 * the driver is faster * written glFlush/glFinish * the driver print a lot of info about the Glide lib * * v0.1 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * Initial revision * */ #ifdef FX #ifdef __WIN32__ #include <windows.h> /* is this really needed? */ #endif #include <math.h> #include <stdio.h> #include <stdlib.h> #include "context.h" #include "macros.h" #include "matrix.h" #include "texture.h" #include "types.h" #include "vb.h" #include "xform.h" #include "GL/fxmesa.h" #define MAXNUM_TEX 128 #define FXCOLOR(r,g,b,a) (( ((unsigned int)(a))<<24 )|( ((unsigned int)(b))<<16 )|( ((unsigned int)(g))<<8 )|(r)) #define FUNC_DEPTH 0x01 #define FUNC_SMOOTH 0x02 #define FUNC_TEX_DECAL 0x04 #define FUNC_TEX_MOD 0x08 typedef struct { GrLOD_t smallLOD; GrLOD_t largeLOD; float sscale,tscale; int levelsdefined; } texinfo; struct fx_mesa_context { GLcontext *gl_ctx; /* the core Mesa context */ GLvisual *gl_vis; /* describes the color buffer */ GLframebuffer *gl_buffer; /* the ancillary buffers */ GLint width, height; /* size of color buffer */ GLboolean double_buffer; GrBuffer_t currentfb; GrColor_t color; GrColor_t clearc; GrAlpha_t cleara; GrMipMapId_t texid[MAXNUM_TEX]; texinfo ti[MAXNUM_TEX]; int currenttex; float wscale,nearval,farval; GLenum fogtablemode; GLfloat fogdensity; GrFog_t fogtable[64]; GrVertex gwin[VB_SIZE]; }; fxMesaContext CurrentfxMesaCtx=NULL; /**********************************************************************/ /***** Miscellaneous functions *****/ /**********************************************************************/ /* return buffer size information */ static void buffer_size(GLcontext *ctx, GLuint *width, GLuint *height) { fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx; #if defined(DEBUG_FXMESA) printf("fxmesa: buffer_size(...)\n"); #endif *width=fxMesa->width; *height=fxMesa->height; } /* Set current drawing color */ static void set_color(GLcontext *ctx, GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha ) { fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx; #if defined(DEBUG_FXMESA) printf("fxmesa: set_color(%d,%d,%d,%d)\n",red,green,blue,alpha); #endif fxMesa->color=FXCOLOR(red,green,blue,alpha); } /* implements glClearColor() */ static void clear_color(GLcontext *ctx, GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha ) { fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx; #if defined(DEBUG_FXMESA) printf("fxmesa: clear_color(%d,%d,%d,%d)\n",red,green,blue,alpha); #endif fxMesa->clearc=FXCOLOR(red,green,blue,255); fxMesa->cleara=alpha; } /* clear the frame buffer */ static void clear(GLcontext *ctx, GLboolean all, GLint x, GLint y, GLint width, GLint height ) { fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx; #if defined(DEBUG_FXMESA) printf("fxmesa: clear(%d,%d,%d,%d)\n",x,y,width,height); #endif grDepthMask(FXFALSE); grBufferClear(fxMesa->clearc,fxMesa->cleara,GR_WDEPTHVALUE_FARTHEST); if(ctx->Depth.Test && ctx->Depth.Mask) grDepthMask(FXTRUE); } /* set the buffer used in double buffering */ static GLboolean set_buffer(GLcontext *ctx, GLenum mode ) { fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx; #if defined(DEBUG_FXMESA) printf("fxmesa: set_buffer(%d)\n",mode); #endif if (fxMesa->double_buffer) { if(mode==GL_FRONT) fxMesa->currentfb = GR_BUFFER_FRONTBUFFER; else if(mode==GL_BACK) fxMesa->currentfb = GR_BUFFER_BACKBUFFER; else return GL_FALSE; } else { if(mode==GL_FRONT) fxMesa->currentfb = GR_BUFFER_FRONTBUFFER; else return GL_FALSE; } grRenderBuffer(fxMesa->currentfb); return GL_TRUE; } static GLboolean drawbitmap(GLcontext *ctx, GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const struct gl_image *bitmap) { fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx; FxU16 *p; GrLfbInfo_t info; GLubyte *pb; int x,y; GLint r,g,b,a,px,py,scrwidth,scrheight,stride; FxU16 color; #define ISCLIPPED(rx) ( ((rx)<0) || ((rx)>=scrwidth) ) #define DRAWBIT(i) { \ if(!ISCLIPPED(x+px)) \ if( (*pb) & (1<<(i)) ) \ (*p)=color; \ p++; \ x++; \ if(x>=width) { \ pb++; \ break; \ } \ } scrwidth=fxMesa->width; scrheight=fxMesa->height; px=(GLint)((ctx->Current.RasterPos[0]-xorig)+0.0F); py=(GLint)((ctx->Current.RasterPos[1]-yorig)+0.0F); if((px>=scrwidth) || (px+width<=0) || (py>=scrheight) || (py+height<=0)) return GL_TRUE; pb=(GLubyte *)bitmap->Data; if(py<0) { pb+=(bitmap->Height*(-py)) >> (3+1); height+=py; py=0; } if(py+height>=scrheight) height-=(py+height)-scrheight; info.size=sizeof(info); if(!grLfbLock(GR_LFB_WRITE_ONLY, fxMesa->currentfb, GR_LFBWRITEMODE_565, GR_ORIGIN_UPPER_LEFT, FXFALSE, &info)) { #ifndef FX_SILENT fprintf(stderr,"3Dfx Driver: error locking the linear frame buffer\n"); #endif return GL_TRUE; } r=(GLint)(ctx->Current.RasterColor[0]*ctx->Visual->RedScale); g=(GLint)(ctx->Current.RasterColor[1]*ctx->Visual->GreenScale); b=(GLint)(ctx->Current.RasterColor[2]*ctx->Visual->BlueScale); a=(GLint)(ctx->Current.RasterColor[3]*ctx->Visual->AlphaScale); color=(FxU16) ( ((FxU16)0xf8 & r) <<(11-3)) | ( ((FxU16)0xfc & g) <<(5-3+1)) | ( ((FxU16)0xf8 & b) >> 3); stride=info.strideInBytes>>1; /* This code is a bit slow... */ for(y=0;y<height;y++) { p=((FxU16 *)info.lfbPtr)+px+((scrheight-(y+py))*stride); for(x=0;;) { DRAWBIT(7); DRAWBIT(6); DRAWBIT(5); DRAWBIT(4); DRAWBIT(3); DRAWBIT(2); DRAWBIT(1); DRAWBIT(0); pb++; } } grLfbUnlock(GR_LFB_WRITE_ONLY,fxMesa->currentfb); #undef ISCLIPPED #undef DRAWBIT return GL_TRUE; } /************************************************************************/ /************************************************************************/ /************************************************************************/ #define GOURAUD_ENABLED 0x1 #define TEXTURE_ENABLED 0x2 #define FOG_ENABLED 0x4 #define WBUFFER_ENABLED 0x8 #define ZBUFFER_ENABLED 0x10 #define GOURAUD(v) {\ (v)->r = (float) (VB->Color[i][0]); \ (v)->g = (float) (VB->Color[i][1]); \ (v)->b = (float) (VB->Color[i][2]); \ (v)->a = (float) (VB->Color[i][3]); } #define WBUFFER(v) { (v)->oow = wscale/VB->Clip[i][3]; } #define TEXTURE(v) { \ (v)->tmuvtx[0].sow = sscale*VB->TexCoord[i][0]*(v)->oow; \ (v)->tmuvtx[0].tow = tscale*VB->TexCoord[i][1]*(v)->oow; \ } #define ZBUFFER(v) { (v)->oow = 1.0/VB->Win[i][2]; } #define NOP(v) #ifdef __WIN32__ #define SETUP( gouraud, texture, depth ) { \ register unsigned int i; \ register struct vertex_buffer *VB = ctx->VB; \ fxMesaContext fxMesa = (fxMesaContext)ctx->DriverCtx; \ register GrVertex *GVB = &fxMesa->gwin[vstart]; \ register float wscale = fxMesa->wscale; \ register float sscale = fxMesa->ti[fxMesa->currenttex].sscale; \ register float tscale = fxMesa->ti[fxMesa->currenttex].tscale; \ unsigned int cw,ocw; \ \ __asm \ { \ __asm fstcw ocw \ __asm fwait \ __asm mov eax, ocw \ __asm and eax, 0fffffcffh \ __asm mov cw, eax \ __asm fldcw cw \ __asm fwait \ } \ for ( i = vstart; i < vend ; i++, GVB++ ) \ { \ GVB->x = (VB->Win[i][0] + 524288.0f) - 524288.0f; \ GVB->y = (VB->Win[i][1] + 524288.0f) - 524288.0f; \ } \ __asm \ { \ __asm fldcw ocw \ __asm fwait \ } \ GVB = &fxMesa->gwin[vstart]; \ for ( i = vstart; i < vend ; i++, GVB++ ) \ { \ gouraud(GVB); \ depth(GVB); \ texture(GVB); \ } \ } #else #define SETUP( gouraud, texture, depth ) { \ register unsigned int i; \ register struct vertex_buffer *VB = ctx->VB; \ fxMesaContext fxMesa = (fxMesaContext)ctx->DriverCtx; \ register GrVertex *GVB = &fxMesa->gwin[vstart]; \ register float wscale = fxMesa->wscale; \ register float sscale = fxMesa->ti[fxMesa->currenttex].sscale; \ register float tscale = fxMesa->ti[fxMesa->currenttex].tscale; \ \ for ( i = vstart; i < vend ; i++, GVB++ ) \ { \ /* trunc (x,y) to multiple of 1/16 */ \ GVB->x = ((int)(VB->Win[i][0]*16.0f))*(1.0f/16.0f); \ GVB->y = ((int)(VB->Win[i][1]*16.0f))*(1.0f/16.0f); \ gouraud(GVB); \ depth(GVB); \ texture(GVB); \ } \ } #endif static void setup( GLcontext *ctx, GLuint vstart, GLuint vend ) { SETUP( NOP, NOP, NOP ); } static void setupG( GLcontext *ctx, GLuint vstart, GLuint vend ) { SETUP( GOURAUD, NOP, NOP ); } static void setupT( GLcontext *ctx, GLuint vstart, GLuint vend ) { SETUP( NOP, TEXTURE, WBUFFER ); } static void setupGT( GLcontext *ctx, GLuint vstart, GLuint vend ) { SETUP( GOURAUD, TEXTURE, WBUFFER ); } static void setupW( GLcontext *ctx, GLuint vstart, GLuint vend ) { SETUP( NOP, NOP, WBUFFER ); } static void setupGW( GLcontext *ctx, GLuint vstart, GLuint vend ) { SETUP( GOURAUD, NOP, WBUFFER ); } static void setupZ( GLcontext *ctx, GLuint vstart, GLuint vend ) { SETUP( NOP, NOP, ZBUFFER ); } static void setupGZ( GLcontext *ctx, GLuint vstart, GLuint vend ) { SETUP( GOURAUD, NOP, ZBUFFER ); } static void setupTZ( GLcontext *ctx, GLuint vstart, GLuint vend ) { SETUP( NOP, TEXTURE, ZBUFFER ); } static void setupGTZ( GLcontext *ctx, GLuint vstart, GLuint vend ) { SETUP( GOURAUD, TEXTURE, ZBUFFER ); } typedef void (*setup_func)(GLcontext *, GLuint, GLuint); setup_func fxSetupFuncs[] = { setup, setupG, setupT, setupGT, setupW, setupGW, setupT, setupGT, setupW, setupGW, setupT, setupGT, setupW, setupGW, setupT, setupGT, setupZ, setupGZ, setupTZ, setupGTZ, setupZ, setupGZ, setupTZ, setupGTZ }; setup_func choose_setup_function( GLcontext *ctx ) { unsigned int setupIndex = 0; if ( ctx->Light.ShadeModel == GL_SMOOTH && !ctx->Light.Model.TwoSide ) setupIndex |= GOURAUD_ENABLED; if ( ctx->Texture.Enabled ) setupIndex |= TEXTURE_ENABLED; if ( ctx->Fog.Enabled ) setupIndex |= FOG_ENABLED; if ( ctx->Depth.Test ) { if ( ctx->ProjectionMatrix[15] == 0.0f ) setupIndex |= WBUFFER_ENABLED; else setupIndex |= ZBUFFER_ENABLED; } return fxSetupFuncs[setupIndex]; } #undef GOURAUD #define GOURAUD(v) { \ fxMesa->gwin[(v)].r = (float) VB->Color[(v)][0]; \ fxMesa->gwin[(v)].g = (float) VB->Color[(v)][1]; \ fxMesa->gwin[(v)].b = (float) VB->Color[(v)][2]; \ fxMesa->gwin[(v)].a = (float) VB->Color[(v)][3]; } static void fxPoint(GLcontext *ctx, GLuint first, GLuint last) { fxMesaContext fxMesa = (fxMesaContext)ctx->DriverCtx; unsigned int i; if(ctx->MonoPixels) grConstantColorValue(fxMesa->color); for ( i = first; i < last ; i++ ) grDrawPoint( &fxMesa->gwin[i] ); } points_func choose_points_function( GLcontext *ctx ) { return fxPoint; } static void fxLineSmooth(GLcontext *ctx, GLuint v1, GLuint v2, GLuint pv) { fxMesaContext fxMesa = (fxMesaContext)ctx->DriverCtx; grDrawLine( &fxMesa->gwin[v1], &fxMesa->gwin[v2] ); } static void fxLineSmoothTwoSide(GLcontext *ctx, GLuint v1, GLuint v2, GLuint pv) { fxMesaContext fxMesa = (fxMesaContext)ctx->DriverCtx; struct vertex_buffer *VB = ctx->VB; GOURAUD(v1); GOURAUD(v2); grDrawLine( &fxMesa->gwin[v1], &fxMesa->gwin[v2] ); } static void fxLineFlat(GLcontext *ctx, GLuint v1, GLuint v2, GLuint pv) { fxMesaContext fxMesa = (fxMesaContext)ctx->DriverCtx; GLubyte *Color = ctx->VB->Color[pv]; grConstantColorValue(FXCOLOR( Color[0], Color[1], Color[2], Color[3])); grDrawLine( &fxMesa->gwin[v1], &fxMesa->gwin[v2] ); } line_func choose_line_function( GLcontext *ctx ) { if ( ctx->Light.ShadeModel == GL_SMOOTH ) if ( ctx->Light.Model.TwoSide ) return fxLineSmoothTwoSide; else return fxLineSmooth; else return fxLineFlat; } /************************************************************************/ /*********************** Triangle functions *****************************/ /************************************************************************/ static void fxTriangleSmooth(GLcontext *ctx, GLuint v1, GLuint v2, GLuint v3, GLuint pv) { fxMesaContext fxMesa = (fxMesaContext)ctx->DriverCtx; grDrawTriangle( &fxMesa->gwin[v1], &fxMesa->gwin[v2], &fxMesa->gwin[v3] ); } static void fxTriangleSmoothTwoSide(GLcontext *ctx, GLuint v1, GLuint v2, GLuint v3, GLuint pv) { fxMesaContext fxMesa = (fxMesaContext)ctx->DriverCtx; struct vertex_buffer *VB = ctx->VB; GOURAUD(v1); GOURAUD(v2); GOURAUD(v3); grDrawTriangle( &fxMesa->gwin[v1], &fxMesa->gwin[v2], &fxMesa->gwin[v3] ); } static void fxTriangleFlat( GLcontext *ctx, GLuint v1, GLuint v2, GLuint v3, GLuint pv) { fxMesaContext fxMesa = (fxMesaContext)ctx->DriverCtx; GLubyte *Color = ctx->VB->Color[pv]; grConstantColorValue(FXCOLOR( Color[0], Color[1], Color[2], Color[3])); grDrawTriangle( &fxMesa->gwin[v1], &fxMesa->gwin[v2], &fxMesa->gwin[v3] ); } triangle_func choose_triangle_function( GLcontext *ctx ) { if ( ctx->Light.ShadeModel == GL_SMOOTH ) if ( ctx->Light.Model.TwoSide ) return fxTriangleSmoothTwoSide; else return fxTriangleSmooth; else return fxTriangleFlat; } /************************************************************************/ /************************* Quads functions ******************************/ /************************************************************************/ static void fxQuadSmooth(GLcontext *ctx, GLuint v1, GLuint v2, GLuint v3, GLuint v4, GLuint pv) { fxMesaContext fxMesa = (fxMesaContext)ctx->DriverCtx; GrVertex *grv2,*grv3; grv2=&fxMesa->gwin[v2]; grv3=&fxMesa->gwin[v3]; grDrawTriangle(&fxMesa->gwin[v1], grv2, grv3); grDrawTriangle(grv3, grv2, &fxMesa->gwin[v4]); } static void fxQuadSmoothTwoSide(GLcontext *ctx, GLuint v1, GLuint v2, GLuint v3, GLuint v4, GLuint pv) { fxMesaContext fxMesa = (fxMesaContext)ctx->DriverCtx; struct vertex_buffer *VB = ctx->VB; GrVertex *grv2,*grv3; GOURAUD(v1); GOURAUD(v2); GOURAUD(v3); GOURAUD(v4); grv2=&fxMesa->gwin[v2]; grv3=&fxMesa->gwin[v3]; grDrawTriangle(&fxMesa->gwin[v1], grv2, grv3); grDrawTriangle(grv3, grv2, &fxMesa->gwin[v4]); } static void fxQuadFlat(GLcontext *ctx, GLuint v1, GLuint v2, GLuint v3,GLuint v4, GLuint pv) { fxMesaContext fxMesa = (fxMesaContext)ctx->DriverCtx; GLubyte *Color = ctx->VB->Color[pv]; GrVertex *grv2,*grv3; grConstantColorValue(FXCOLOR( Color[0], Color[1], Color[2], Color[3])); grv2=&fxMesa->gwin[v2]; grv3=&fxMesa->gwin[v3]; grDrawTriangle(&fxMesa->gwin[v1], grv2, grv3); grDrawTriangle(grv3, grv2, &fxMesa->gwin[v4]); } quad_func choose_quad_function(GLcontext *ctx) { if(ctx->Light.ShadeModel == GL_SMOOTH) if(ctx->Light.Model.TwoSide) return fxQuadSmoothTwoSide; else return fxQuadSmooth; else return fxQuadFlat; } /************************************************************************/ /**************** 3D depth buffer functions *****************************/ /************************************************************************/ /* this is a no-op, since the z-buffer is in hardware */ static void alloc_depth_buffer(GLcontext *ctx) { #if defined(DEBUG_FXMESA) printf("fxmesa: alloc_depth_buffer()\n"); #endif } static void clear_depth_buffer(GLcontext *ctx) { fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx; #if defined(DEBUG_FXMESA) printf("fxmesa: clear_depth_buffer()\n"); #endif if(ctx->Depth.Test && ctx->Depth.Mask) { grDepthMask(FXTRUE); grColorMask(FXFALSE,FXFALSE); /* I don't know how to convert ctx->Depth.Clear */ grBufferClear(fxMesa->clearc,fxMesa->cleara,GR_WDEPTHVALUE_FARTHEST); grColorMask(FXTRUE,FXFALSE); } } /************************************************************************/ /************************************************************************/ /************************************************************************/ static void finish(GLcontext *ctx) { grSstIdle(); } static void flush(GLcontext *ctx) { grSstIdle(); } /************************************************************************/ /*************************** Texture Mapping ****************************/ /************************************************************************/ static void texenv(GLcontext *ctx, GLenum pname, const GLfloat *param) { /* ;) */ } static void texparam(GLcontext *ctx, GLenum target, GLuint texObject, GLenum pname, const GLfloat *params) { GLenum param=(GLenum)(GLint)params[0]; fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx; GrMipMapId_t *texid=fxMesa->texid; #if defined(DEBUG_FXMESA) printf("fxmesa: texparam(%d)\n",texObject); #endif if(target!=GL_TEXTURE_2D) { #ifndef FX_SILENT fprintf(stderr,"3Dfx Driver: unsupported texture in texparam()\n"); #endif return; } switch(pname) { case GL_TEXTURE_MIN_FILTER: switch(param) { case GL_NEAREST: guTexChangeAttributes(texid[texObject],-1,-1,-1, GR_MIPMAP_DISABLE,-1,-1,-1,-1,-1, GR_TEXTUREFILTER_POINT_SAMPLED,-1); break; case GL_LINEAR: guTexChangeAttributes(texid[texObject],-1,-1,-1, GR_MIPMAP_DISABLE,-1,-1,-1,-1,-1, GR_TEXTUREFILTER_BILINEAR,-1); break; case GL_NEAREST_MIPMAP_NEAREST: guTexChangeAttributes(texid[texObject],-1,-1,-1, GR_MIPMAP_NEAREST,-1,-1,-1,-1,-1, GR_TEXTUREFILTER_POINT_SAMPLED,-1); break; case GL_NEAREST_MIPMAP_LINEAR: guTexChangeAttributes(texid[texObject],-1,-1,-1, GR_MIPMAP_NEAREST,-1,-1,-1,-1,-1, GR_TEXTUREFILTER_BILINEAR,-1); break; case GL_LINEAR_MIPMAP_LINEAR: guTexChangeAttributes(texid[texObject],-1,-1,-1, GR_MIPMAP_NEAREST_DITHER,-1,-1,-1,-1,-1, GR_TEXTUREFILTER_BILINEAR,-1); break; default: break; } break; case GL_TEXTURE_MAG_FILTER: switch(param) { case GL_NEAREST: guTexChangeAttributes(texid[texObject],-1,-1,-1, -1,-1,-1,-1,-1,-1, -1,GR_TEXTUREFILTER_POINT_SAMPLED); break; case GL_LINEAR: guTexChangeAttributes(texid[texObject],-1,-1,-1, -1,-1,-1,-1,-1,-1, -1,GR_TEXTUREFILTER_BILINEAR); break; default: break; } break; case GL_TEXTURE_WRAP_S: switch(param) { case GL_CLAMP: guTexChangeAttributes(texid[texObject],-1,-1,-1,-1,-1, -1,-1,GR_TEXTURECLAMP_CLAMP,-1,-1,-1); break; case GL_REPEAT: guTexChangeAttributes(texid[texObject],-1,-1,-1,-1,-1, -1,-1,GR_TEXTURECLAMP_WRAP,-1,-1,-1); break; default: break; } break; case GL_TEXTURE_WRAP_T: switch(param) { case GL_CLAMP: guTexChangeAttributes(texid[texObject],-1,-1,-1,-1,-1,-1, -1,-1,GR_TEXTURECLAMP_CLAMP,-1,-1); break; case GL_REPEAT: guTexChangeAttributes(texid[texObject],-1,-1,-1,-1,-1,-1, -1,-1,GR_TEXTURECLAMP_WRAP,-1,-1); break; default: break; } break; case GL_TEXTURE_BORDER_COLOR: /* TO DO */ break; default: break; } guTexSource(texid[texObject]); fxMesa->currenttex=texObject; } static void texdel(GLcontext *ctx, GLuint texObject) { fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx; fxMesa->texid[texObject]=GR_NULL_MIPMAP_HANDLE; fxMesa->ti[texObject].levelsdefined=0; /* TO DO: Free the texture memory */ } static void texbind(GLcontext *ctx, GLenum target, GLuint texObject) { fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx; #if defined(DEBUG_FXMESA) printf("fxmesa: texbind(%d)\n",texObject); #endif guTexSource(fxMesa->texid[texObject]); fxMesa->currenttex=texObject; } static int logbase2(int n) { GLint i = 1; GLint log2 = 0; if (n<0) { return -1; } while ( n > i ) { i *= 2; log2++; } if (i != n) { return -1; } else { return log2; } } static int texgetinfo(int w, int h, GrLOD_t *lodlevel, GrAspectRatio_t *ar, float *sscale, float *tscale, int *wscale, int *hscale) { static GrLOD_t lod[9]={GR_LOD_256,GR_LOD_128,GR_LOD_64,GR_LOD_32, GR_LOD_16,GR_LOD_8,GR_LOD_4,GR_LOD_2,GR_LOD_1}; int logw,logh,ws,hs; GrLOD_t l; GrAspectRatio_t aspectratio; float s,t; logw=logbase2(w); logh=logbase2(h); switch(logw-logh) { case 0: aspectratio=GR_ASPECT_1x1; l=lod[8-logw]; s=t=255.0; ws=hs=1; break; case 1: aspectratio=GR_ASPECT_2x1; l=lod[8-logw]; s=255.0; t=127.0; ws=1; hs=1; break; case 2: aspectratio=GR_ASPECT_4x1; l=lod[8-logw]; s=255.0; t=63.0; ws=1; hs=1; break; case 3: aspectratio=GR_ASPECT_8x1; l=lod[8-logw]; s=255.0; t=31.0; ws=1; hs=1; break; case 4: aspectratio=GR_ASPECT_8x1; l=lod[8-logw]; s=255.0; t=31.0; ws=1; hs=2; break; case 5: aspectratio=GR_ASPECT_8x1; l=lod[8-logw]; s=255.0; t=31.0; ws=1; hs=4; break; case 6: aspectratio=GR_ASPECT_8x1; l=lod[8-logw]; s=255.0; t=31.0; ws=1; hs=8; break; case 7: aspectratio=GR_ASPECT_8x1; l=lod[8-logw]; s=255.0; t=31.0; ws=1; hs=16; break; case 8: aspectratio=GR_ASPECT_8x1; l=lod[8-logw]; s=255.0; t=31.0; ws=1; hs=32; break; case -1: aspectratio=GR_ASPECT_1x2; l=lod[8-logh]; s=127.0; t=255.0; ws=1; hs=1; break; case -2: aspectratio=GR_ASPECT_1x4; l=lod[8-logh]; s=63.0; t=255.0; ws=1; hs=1; break; case -3: aspectratio=GR_ASPECT_1x8; l=lod[8-logh]; s=31.0; t=255.0; ws=1; hs=1; break; case -4: aspectratio=GR_ASPECT_1x8; l=lod[8-logh]; s=31.0; t=255.0; ws=2; hs=1; break; case -5: aspectratio=GR_ASPECT_1x8; l=lod[8-logh]; s=31.0; t=255.0; ws=4; hs=1; break; case -6: aspectratio=GR_ASPECT_1x8; l=lod[8-logh]; s=31.0; t=255.0; ws=8; hs=1; break; case -7: aspectratio=GR_ASPECT_1x8; l=lod[8-logh]; s=31.0; t=255.0; ws=16; hs=1; break; case -8: aspectratio=GR_ASPECT_1x8; l=lod[8-logh]; s=31.0; t=255.0; ws=32; hs=1; break; default: return 0; break; } if(lodlevel) (*lodlevel)=l; if(ar) (*ar)=aspectratio; if(sscale) (*sscale)=s; if(tscale) (*tscale)=t; if(wscale) (*wscale)=ws; if(hscale) (*hscale)=hs; return 1; } static void texalloc(GLcontext *ctx, GLuint texObject, GLenum glformat, int w, int h) { GrTextureFormat_t format; GrLOD_t l; GrAspectRatio_t aspectratio; fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx; GrMipMapId_t *texid=fxMesa->texid; texinfo *ti=fxMesa->ti; int wscale,hscale; texgetinfo(w,h,&l,&aspectratio,&(ti[texObject].sscale),&(ti[texObject].tscale),&wscale,&hscale); switch(glformat) { case GL_LUMINANCE: case GL_LUMINANCE8: case 1: format=GR_TEXFMT_INTENSITY_8; break; case GL_LUMINANCE_ALPHA: case GL_LUMINANCE8_ALPHA8: case 2: format=GR_TEXFMT_ALPHA_INTENSITY_88; break; case GL_ALPHA8: case GL_ALPHA: format=GR_TEXFMT_ALPHA_8; break; case GL_RGB: case GL_RGB8: case 3: format=GR_TEXFMT_RGB_565; break; case GL_RGBA: case GL_RGBA8: case 4: format=GR_TEXFMT_ARGB_4444; break; default: fprintf(stderr,"3Dfx Driver: wrong internalFormat in texalloc()\n"); grGlideShutdown(); exit(-1); break; } texid[texObject]=guTexAllocateMemory(GR_TMU0,GR_MIPMAPLEVELMASK_BOTH, w*wscale,h*hscale, format,GR_MIPMAP_NEAREST,GR_LOD_1,l,aspectratio, GR_TEXTURECLAMP_WRAP,GR_TEXTURECLAMP_WRAP,GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR,0.0,FXFALSE); if(texid[texObject]==GR_NULL_MIPMAP_HANDLE) { fprintf(stderr,"3Dfx Driver: out of texture memory !\n"); grGlideShutdown(); exit(-1); } ti[texObject].smallLOD=l; ti[texObject].largeLOD=l; ti[texObject].levelsdefined=0; } static int istexsupported(GLenum target, GLint internalFormat, const struct gl_texture_image *image) { if(target!=GL_TEXTURE_2D) return GL_FALSE; switch(internalFormat) { case GL_LUMINANCE: case GL_LUMINANCE8: case 1: case GL_LUMINANCE_ALPHA: case GL_LUMINANCE8_ALPHA8: case 2: case GL_ALPHA8: case GL_ALPHA: case GL_RGB: case GL_RGB8: case 3: case GL_RGBA: case GL_RGBA8: case 4: break; default: return GL_FALSE; } if(image->Width>256) return GL_FALSE; if(image->Height>256) return GL_FALSE; if(!texgetinfo(image->Width,image->Height,NULL,NULL,NULL,NULL,NULL,NULL)) return GL_FALSE; return GL_TRUE; } static unsigned short *texbuildimagemap(const struct gl_texture_image *image, GLint internalFormat) { unsigned short *src,*srccpy; unsigned char r,g,b,a,l,*data,*srcb; int x,y,w,h,wscale,hscale,idx; texgetinfo(image->Width,image->Height,NULL,NULL,NULL,NULL,&wscale,&hscale); w=image->Width*wscale; h=image->Height*hscale; if(!(srccpy=src=(unsigned short *)malloc(sizeof(unsigned short)*w*h))) { fprintf(stderr,"3Dfx Driver: out of memory !\n"); grGlideShutdown(); exit(-1); } data=image->Data; switch(internalFormat) { case GL_ALPHA: case GL_ALPHA8: case GL_LUMINANCE: case GL_LUMINANCE8: case 1: srcb=(unsigned char *)src; for(y=0;y<h;y++) for(x=0;x<w;x++) { idx=(x/wscale+(y/hscale)*(w/wscale)); srcb[x+y*w]=data[idx]; } break; case GL_LUMINANCE_ALPHA: case GL_LUMINANCE8_ALPHA8: case 2: for(y=0;y<h;y++) for(x=0;x<w;x++) { idx=(x/wscale+(y/hscale)*(w/wscale))*2; l=data[idx]; a=data[idx+1]; src[x+y*w]=(unsigned short) ( ((unsigned short) a) << 8) | ( ((unsigned short) l)); } break; case GL_RGB: case GL_RGB8: case 3: for(y=0;y<h;y++) for(x=0;x<w;x++) { idx=(x/wscale+(y/hscale)*(w/wscale))*3; r=data[idx]; g=data[idx+1]; b=data[idx+2]; src[x+y*w]=(unsigned short) ( ((unsigned short)0xf8 & r) <<(11-3)) | ( ((unsigned short)0xfc & g) <<(5-3+1)) | ( ((unsigned short)0xf8 & b) >> 3); } break; case GL_RGBA: case GL_RGBA8: case 4: for(y=0;y<h;y++) for(x=0;x<w;x++) { idx=(x/wscale+(y/hscale)*(w/wscale))*4; r=data[idx]; g=data[idx+1]; b=data[idx+2]; a=data[idx+3]; src[x+y*w]=(unsigned short) ( ((unsigned short)0xf0 & a) << 8) | ( ((unsigned short)0xf0 & r) << 4) | ((unsigned short)0xf0 & g) | ( ((unsigned short)0xf0 & b) >> 4); } break; default: fprintf(stderr,"3Dfx Driver: wrong internalFormat in texbuildimagemap()\n"); grGlideShutdown(); exit(-1); break; } return srccpy; } static void teximg(GLcontext *ctx, GLenum target, GLuint texObject, GLint level, GLint internalFormat, const struct gl_texture_image *image) { unsigned short *src,*srccpy; GrLOD_t lodlev; fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx; GrMipMapId_t *texid=fxMesa->texid; texinfo *ti=fxMesa->ti; #if defined(DEBUG_FXMESA) printf("fxmesa: teximg(...,%d,%d,%d,%d...)\n",target,internalFormat,image->Width,image->Height); #endif if(istexsupported(target,internalFormat,image)) { if(texid[texObject]==GR_NULL_MIPMAP_HANDLE) texalloc(ctx,texObject,image->Format,image->Width,image->Height); else { if(ti[texObject].levelsdefined & (1<<level)) { texdel(ctx,texObject); texalloc(ctx,texObject,image->Format,image->Width,image->Height); } } srccpy=src=texbuildimagemap(image,internalFormat); texgetinfo(image->Width,image->Height,&lodlev,NULL,NULL,NULL,NULL,NULL); if(lodlev>ti[texObject].smallLOD) { guTexChangeAttributes(texid[texObject],-1,-1,-1,-1,lodlev,-1,-1,-1,-1,-1,-1); ti[texObject].smallLOD=lodlev; } if(lodlev<ti[texObject].largeLOD) { guTexChangeAttributes(texid[texObject],-1,-1,-1,-1,-1,lodlev,-1,-1,-1,-1,-1); ti[texObject].largeLOD=lodlev; } guTexDownloadMipMapLevel(texid[texObject],lodlev,(const void**)&src); free(srccpy); ti[texObject].levelsdefined|=(1<<level); guTexSource(texid[texObject]); fxMesa->currenttex=texObject; } #ifndef FX_SILENT else fprintf(stderr,"3Dfx Driver: unsupported texture in teximg()\n"); #endif } /************************************************************************/ /************************************************************************/ /************************************************************************/ static void SetNearFar( GLcontext *ctx, GLfloat n, GLfloat f) { fxMesaContext fxMesa = (fxMesaContext)ctx->DriverCtx; if(fxMesa) { fxMesa->nearval=fabs(n); fxMesa->farval=fabs(f); fxMesa->wscale=fxMesa->farval/65535.0; /* * We need to update fog table because it depends on w * and w is adjusted to the maximum range. */ if(ctx->Fog.Enabled && ctx->Hint.Fog==GL_NICEST) { switch(ctx->Fog.Mode) { case GL_LINEAR: guFogGenerateLinear(fxMesa->fogtable, ctx->Fog.Start/fxMesa->wscale, ctx->Fog.End /fxMesa->wscale); /* works ? */ break; case GL_EXP: guFogGenerateExp(fxMesa->fogtable, ctx->Fog.Density*fxMesa->wscale); break; case GL_EXP2: guFogGenerateExp2(fxMesa->fogtable, ctx->Fog.Density*fxMesa->wscale); break; default: /* That should never happen */ break; } } } } void fxMesaSetNearFar(GLfloat n, GLfloat f) { SetNearFar(CurrentfxMesaCtx->gl_ctx, n, f); } static void setup_fx_units(GLcontext *ctx) { fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx; if(ctx->Color.BlendEnabled) { GrAlphaBlendFnc_t sfact,dfact; if(ctx->Light.ShadeModel==GL_SMOOTH) guAlphaSource(GR_ALPHASOURCE_ITERATED_ALPHA); else guAlphaSource(GR_ALPHASOURCE_CC_ALPHA); switch(ctx->Color.BlendSrc) { case GL_ZERO: sfact=GR_BLEND_ZERO; break; case GL_ONE: sfact=GR_BLEND_ONE; break; case GL_DST_COLOR: sfact=GR_BLEND_DST_COLOR; break; case GL_ONE_MINUS_DST_COLOR: sfact=GR_BLEND_ONE_MINUS_DST_COLOR; break; case GL_SRC_ALPHA: sfact=GR_BLEND_SRC_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: sfact=GR_BLEND_ONE_MINUS_SRC_ALPHA; break; case GL_SRC_ALPHA_SATURATE: case GL_SRC_COLOR: case GL_ONE_MINUS_SRC_COLOR: case GL_DST_ALPHA: case GL_ONE_MINUS_DST_ALPHA: /* USELESS or TO DO */ sfact=GR_BLEND_ONE; break; default: break; } switch(ctx->Color.BlendDst) { case GL_ZERO: dfact=GR_BLEND_ZERO; break; case GL_ONE: dfact=GR_BLEND_ONE; break; case GL_SRC_COLOR: dfact=GR_BLEND_SRC_COLOR; break; case GL_ONE_MINUS_SRC_COLOR: dfact=GR_BLEND_ONE_MINUS_SRC_COLOR; break; case GL_SRC_ALPHA: dfact=GR_BLEND_SRC_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: dfact=GR_BLEND_ONE_MINUS_SRC_ALPHA; break; case GL_SRC_ALPHA_SATURATE: case GL_DST_COLOR: case GL_ONE_MINUS_DST_COLOR: case GL_DST_ALPHA: case GL_ONE_MINUS_DST_ALPHA: /* USELESS or TO DO */ sfact=GR_BLEND_ZERO; break; default: break; } grAlphaBlendFunction(sfact,dfact,GR_BLEND_ONE,GR_BLEND_ZERO); grColorMask(FXTRUE,FXFALSE); } else { grAlphaBlendFunction(GR_BLEND_ONE,GR_BLEND_ZERO,GR_BLEND_ONE,GR_BLEND_ZERO); grColorMask(FXTRUE,FXFALSE); } if(ctx->Color.AlphaEnabled) { switch(ctx->Color.AlphaFunc) { case GL_NEVER: grAlphaTestFunction(GR_CMP_NEVER); break; case GL_LESS: grAlphaTestFunction(GR_CMP_LESS); break; case GL_EQUAL: grAlphaTestFunction(GR_CMP_EQUAL); break; case GL_LEQUAL: grAlphaTestFunction(GR_CMP_LEQUAL); break; case GL_GREATER: grAlphaTestFunction(GR_CMP_GREATER); break; case GL_NOTEQUAL: grAlphaTestFunction(GR_CMP_NOTEQUAL); break; case GL_GEQUAL: grAlphaTestFunction(GR_CMP_GEQUAL); break; case GL_ALWAYS: grAlphaTestFunction(GR_CMP_ALWAYS); break; default: break; } grAlphaTestReferenceValue(ctx->Color.AlphaRefUbyte); } else grAlphaTestFunction(GR_CMP_ALWAYS); if(ctx->Texture.Enabled) { switch(ctx->Texture.EnvMode) { case GL_DECAL: guColorCombineFunction(GR_COLORCOMBINE_DECAL_TEXTURE); guTexCombineFunction(GR_TMU0,GR_TEXTURECOMBINE_DECAL); break; case GL_MODULATE: if(ctx->Color.BlendEnabled) guAlphaSource(GR_ALPHASOURCE_TEXTURE_ALPHA); if(ctx->Light.ShadeModel==GL_SMOOTH) guColorCombineFunction(GR_COLORCOMBINE_TEXTURE_TIMES_ITRGB); else guColorCombineFunction(GR_COLORCOMBINE_TEXTURE_TIMES_CCRGB); guTexCombineFunction(GR_TMU0,GR_TEXTURECOMBINE_DECAL); break; case GL_BLEND: /* TO DO */ break; default: break; } } else { if(ctx->Light.ShadeModel==GL_SMOOTH) guColorCombineFunction(GR_COLORCOMBINE_ITRGB); else guColorCombineFunction(GR_COLORCOMBINE_CCRGB); grTexCombineFunction(GR_TMU0,GR_TEXTURECOMBINE_ZERO); } if(ctx->Depth.Test) { grDepthBufferMode(GR_DEPTHBUFFER_WBUFFER); switch(ctx->Depth.Func) { case GL_NEVER: grDepthBufferFunction(GR_CMP_NEVER); break; case GL_LESS: grDepthBufferFunction(GR_CMP_LESS); break; case GL_GEQUAL: grDepthBufferFunction(GR_CMP_GEQUAL); break; case GL_LEQUAL: grDepthBufferFunction(GR_CMP_LEQUAL); break; case GL_GREATER: grDepthBufferFunction(GR_CMP_GREATER); break; case GL_NOTEQUAL: grDepthBufferFunction(GR_CMP_NOTEQUAL); break; case GL_EQUAL: grDepthBufferFunction(GR_CMP_EQUAL); break; case GL_ALWAYS: grDepthBufferFunction(GR_CMP_ALWAYS); break; default: break; } if(ctx->Depth.Mask) grDepthMask(FXTRUE); else grDepthMask(FXFALSE); } else { grDepthBufferFunction(GR_CMP_ALWAYS); grDepthMask(FXFALSE); } if(ctx->Fog.Enabled && ctx->Hint.Fog==GL_NICEST) { grFogMode(GR_FOG_WITH_TABLE); grFogColorValue FXCOLOR((unsigned int)(255*ctx->Fog.Color[0]), (unsigned int)(255*ctx->Fog.Color[1]), (unsigned int)(255*ctx->Fog.Color[2]), (unsigned int)(255*ctx->Fog.Color[3])); if((fxMesa->fogtablemode!=ctx->Fog.Mode) || (fxMesa->fogdensity!=ctx->Fog.Density)) { float wscale = ((fxMesaContext)ctx->DriverCtx)->wscale; switch(ctx->Fog.Mode) { case GL_LINEAR: guFogGenerateLinear(fxMesa->fogtable, ctx->Fog.Start / wscale, ctx->Fog.End / wscale); break; case GL_EXP: guFogGenerateExp(fxMesa->fogtable,ctx->Fog.Density*wscale); break; case GL_EXP2: guFogGenerateExp2(fxMesa->fogtable,ctx->Fog.Density*wscale); break; default: /* That should never happen */ break; } fxMesa->fogtablemode=ctx->Fog.Mode; fxMesa->fogdensity=ctx->Fog.Density; } grFogTable(fxMesa->fogtable); } else grFogMode(GR_FOG_DISABLE); } static const char *renderer_string(void) { return "Glide"; } static void setup_dd_pointers(GLcontext *ctx) { #if defined(DEBUG_FXMESA) printf("fxmesa: fx_mesa_setup_dd_pointers()\n"); #endif ctx->Driver.UpdateState = setup_dd_pointers; ctx->Driver.RendererString = renderer_string; ctx->Driver.NearFar = SetNearFar; ctx->Driver.ClearIndex = NULL; ctx->Driver.ClearColor = clear_color; ctx->Driver.Clear = clear; ctx->Driver.Index = NULL; ctx->Driver.Color = set_color; ctx->Driver.SetBuffer = set_buffer; ctx->Driver.GetBufferSize = buffer_size; ctx->Driver.AllocDepthBuffer = alloc_depth_buffer; ctx->Driver.ClearDepthBuffer = clear_depth_buffer; /* acc. functions*/ setup_fx_units(ctx); ctx->Driver.PointsFunc = choose_points_function(ctx); ctx->Driver.LineFunc = choose_line_function(ctx); ctx->Driver.TriangleFunc = choose_triangle_function(ctx); ctx->Driver.QuadFunc = choose_quad_function(ctx); ctx->Driver.RectFunc = NULL; ctx->Driver.Bitmap=drawbitmap; ctx->Driver.DrawPixels=NULL; ctx->Driver.RasterSetup = choose_setup_function(ctx); ctx->Driver.RenderVB = NULL; ctx->Driver.Finish=flush; ctx->Driver.Flush=finish; ctx->Driver.TexEnv=texenv; ctx->Driver.TexImage=teximg; ctx->Driver.TexParameter=texparam; ctx->Driver.BindTexture=texbind; ctx->Driver.DeleteTexture=texdel; ctx->Driver.WriteColorSpan = NULL; ctx->Driver.WriteMonocolorSpan = NULL; ctx->Driver.WriteColorPixels = NULL; ctx->Driver.WriteMonocolorPixels = NULL; ctx->Driver.WriteIndexSpan = NULL; ctx->Driver.WriteMonoindexSpan = NULL; ctx->Driver.WriteIndexPixels = NULL; ctx->Driver.WriteMonoindexPixels = NULL; ctx->Driver.ReadIndexSpan = NULL; ctx->Driver.ReadColorSpan = NULL; ctx->Driver.ReadIndexPixels = NULL; ctx->Driver.ReadColorPixels = NULL; } #define NUM_RESOLUTIONS 3 static resolutions[NUM_RESOLUTIONS][3] = { /* { 320, 200, GR_RESOLUTION_320x200 },* { 320, 240, GR_RESOLUTION_320x240 }, { 400, 256, GR_RESOLUTION_400x256 }, { 512, 256, GR_RESOLUTION_512x256 },*/ { 512, 384, GR_RESOLUTION_512x384 }, /* { 640, 200, GR_RESOLUTION_640x200 }, { 640, 350, GR_RESOLUTION_640x350 },*/ { 640, 400, GR_RESOLUTION_640x400 }, { 640, 480, GR_RESOLUTION_640x480 } /*, { 800, 600, GR_RESOLUTION_800x600 }, { 856, 480, GR_RESOLUTION_856x480 }, { 960, 720, GR_RESOLUTION_960x720 }*/ }; GrScreenResolution_t bestResolution(int width, int height) { int i; for(i=0;i<NUM_RESOLUTIONS;i++) if((width<=resolutions[i][0]) && (height<=resolutions[i][1])) return resolutions[i][2]; return GR_RESOLUTION_640x480; } fxMesaContext fxMesaCreateBestContext(GLuint win,GLint width, GLint height, const GLint attribList[]) { return fxMesaCreateContext(win, bestResolution(width,height), GR_REFRESH_75Hz, attribList); } #ifdef __WIN32__ static int cleangraphics(void) { fxMesaDestroyContext(CurrentfxMesaCtx); return 0; } #endif /* * Create a new FX/Mesa context and return a handle to it. */ fxMesaContext fxMesaCreateContext(GLuint win,GrScreenResolution_t res, GrScreenRefresh_t ref, const GLint attribList[]) { fxMesaContext ctx; GrHwConfiguration hwconfig; int i; GLboolean doubleBuffer = GL_FALSE; GLboolean alphaBuffer = GL_FALSE; GLint depthSize = 0; GLint stencilSize = 0; GLint accumSize = 0; i = 0; while (attribList[i]!=FXMESA_NONE) { switch (attribList[i]) { case FXMESA_DOUBLEBUFFER: doubleBuffer = GL_TRUE; break; case FXMESA_ALPHA_SIZE: i++; alphaBuffer = attribList[i] > 0; break; case FXMESA_DEPTH_SIZE: i++; depthSize = attribList[i]; break; case FXMESA_STENCIL_SIZE: i++; stencilSize = attribList[i]; break; case FXMESA_ACCUM_SIZE: i++; accumSize = attribList[i]; break; default: return NULL; } i++; } #if defined(DEBUG_FXMESA) printf("fxmesa: fxMesaCreateContext()\n"); #endif #ifndef FX_SILENT fprintf(stderr,"Mesa 3Dfx Voodoo Device Driver V0.17\nWritten by David Bucciarelli (tech.hmw@plus.it)\n"); #endif grGlideInit(); if (grSstQueryHardware(&hwconfig)) { #ifndef FX_SILENT char buf[80]; grGlideGetVersion(buf); #endif grSstSelect(0); if(hwconfig.SSTs[0].type==GR_SSTTYPE_VOODOO) win = 0; #if USE_GLIDE_FULLSCREEN if(!grSstOpen(res, /* resolution */ ref, /* refresh */ GR_COLORFORMAT_ABGR, /* pixel format */ GR_ORIGIN_LOWER_LEFT, /* origin */ GR_SMOOTHING_ENABLE, /* smoothing mode */ 2)) /* num buffers */ return NULL; #else /* Glide in a window */ if(!grSstWinOpen((FxU32)win,res,ref, GR_COLORFORMAT_ABGR,GR_ORIGIN_LOWER_LEFT,2,1)) return NULL; #endif #ifndef FX_SILENT fprintf(stderr,"Using Glide V%s\nNumber of boards: %d\nGlide screen size: %dx%d\n",buf,hwconfig.num_sst,grSstScreenWidth(),grSstScreenHeight()); #endif } else { printf("ERROR: no Voodoo Graphics or Voodoo Rush !\n"); return NULL; } ctx=(fxMesaContext)malloc(sizeof(struct fx_mesa_context)); if(!ctx) return NULL; ctx->width=grSstScreenWidth(); ctx->height=grSstScreenHeight(); ctx->double_buffer = doubleBuffer; ctx->color=FXCOLOR(255,255,255,255); ctx->clearc=0; ctx->cleara=0; ctx->wscale=65535.0/100.0; ctx->fogdensity=-HUGE_VAL; ctx->currenttex=0; ctx->currentfb=GR_BUFFER_BACKBUFFER; grColorMask(FXTRUE,FXFALSE); if (doubleBuffer) grRenderBuffer(GR_BUFFER_BACKBUFFER); else grRenderBuffer(GR_BUFFER_FRONTBUFFER); for(i=0;i<MAXNUM_TEX;i++) ctx->texid[i]=GR_NULL_MIPMAP_HANDLE; ctx->gl_vis = gl_create_visual(GL_TRUE, /* RGB mode */ alphaBuffer, doubleBuffer, depthSize, /* depth_size */ stencilSize, /* stencil_size */ accumSize, /* accum_size */ 0, /* index bits */ 255.0, /* color scales */ 255.0, 255.0, 255.0, 8, 8, 8, 0); ctx->gl_ctx = gl_create_context(ctx->gl_vis, NULL, /* share list context */ (void *) ctx); ctx->gl_buffer = gl_create_framebuffer( ctx->gl_vis ); setup_dd_pointers(ctx->gl_ctx); #ifdef __WIN32__ onexit(cleangraphics); #endif return ctx; } /* * Destroy the given FX/Mesa context. */ void fxMesaDestroyContext(fxMesaContext ctx) { #if defined(DEBUG_FXMESA) printf("fxmesa: fxMesaDestroyContext()\n"); #endif if(ctx) { gl_destroy_visual(ctx->gl_vis); gl_destroy_context(ctx->gl_ctx); gl_destroy_framebuffer(ctx->gl_buffer); #ifndef FX_SILENT { GrSstPerfStats_t st; grSstPerfStats(&st); fprintf(stderr,"# pixels processed (minus buffer clears): %u\n",(unsigned)st.pixelsIn); fprintf(stderr,"# pixels not drawn due to chroma key test failure: %u\n",(unsigned)st.chromaFail); fprintf(stderr,"# pixels not drawn due to depth test failure: %u\n",(unsigned)st.zFuncFail); fprintf(stderr,"# pixels not drawn due to alpha test failure: %u\n",(unsigned)st.aFuncFail); fprintf(stderr,"# pixels drawn (including buffer clears and LFB writes): %u\n",(unsigned)st.pixelsOut); fprintf(stderr,"Free texture memory: %u bytes\n",(unsigned)guTexMemQueryAvail(GR_TMU0)); } #endif grGlideShutdown(); free(ctx); } if(ctx==CurrentfxMesaCtx) CurrentfxMesaCtx=NULL; } /* * Make the specified FX/Mesa context the current one. */ void fxMesaMakeCurrent(fxMesaContext ctx) { #if defined(DEBUG_FXMESA) printf("fxmesa: fxMesaMakeCurrent()\n"); #endif if(!ctx) { gl_make_current(NULL,NULL); CurrentfxMesaCtx=NULL; return; } CurrentfxMesaCtx=ctx; gl_make_current(ctx->gl_ctx,ctx->gl_buffer); setup_dd_pointers(ctx->gl_ctx); gl_Viewport(ctx->gl_ctx,0,0,ctx->width,ctx->height); } /* * Swap front/back buffers for current context if double buffered. */ void fxMesaSwapBuffers(void) { #if defined(DEBUG_FXMESA) printf("fxmesa: fxMesaSwapBuffers()\n"); #endif if (CurrentfxMesaCtx->double_buffer) grBufferSwap(1); } #else /* * Need this to provide at least one external definition. */ int gl_fx_dummy_function(void) { return 0; } #endif /* FX */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.