summaryrefslogtreecommitdiff
path: root/src/gl_tess.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gl_tess.c')
-rw-r--r--src/gl_tess.c469
1 files changed, 469 insertions, 0 deletions
diff --git a/src/gl_tess.c b/src/gl_tess.c
new file mode 100644
index 0000000..6b80985
--- /dev/null
+++ b/src/gl_tess.c
@@ -0,0 +1,469 @@
+/*
+Copyright (C) 2003-2006 Andrey Nazarov
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "gl_local.h"
+
+tesselator_t tess;
+
+#define FACE_HASH_SIZE 32
+#define FACE_HASH_MASK ( FACE_HASH_SIZE - 1 )
+
+static mface_t *faces_alpha, *faces_warp, *faces_alpha_warp;
+static mface_t *faces_hash[FACE_HASH_SIZE];
+
+void GL_Flush2D( void ) {
+ glStateBits_t bits;
+
+ if( !tess.numverts ) {
+ return;
+ }
+
+ bits = GLS_DEPTHTEST_DISABLE;
+ if( tess.flags & 2 ) {
+ bits |= GLS_BLEND_BLEND;
+ } else if( tess.flags & 1 ) {
+ bits |= GLS_ALPHATEST_ENABLE;
+ }
+
+ GL_BindTexture( tess.texnum[0] );
+ GL_TexEnv( GL_MODULATE );
+ GL_Bits( bits );
+
+ qglEnableClientState( GL_COLOR_ARRAY );
+
+ qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.colors );
+ qglTexCoordPointer( 2, GL_FLOAT, 16, tess.vertices + 2 );
+ qglVertexPointer( 2, GL_FLOAT, 16, tess.vertices );
+
+ if( qglLockArraysEXT ) {
+ qglLockArraysEXT( 0, tess.numverts );
+ }
+
+ qglDrawArrays( GL_QUADS, 0, tess.numverts );
+
+ if( gl_showtris->integer ) {
+ GL_EnableOutlines();
+ qglDrawArrays( GL_QUADS, 0, tess.numverts );
+ GL_DisableOutlines();
+ }
+
+ if( qglUnlockArraysEXT ) {
+ qglUnlockArraysEXT();
+ }
+
+ qglDisableClientState( GL_COLOR_ARRAY );
+
+ tess.numverts = 0;
+ tess.texnum[0] = 0;
+ tess.flags = 0;
+}
+
+void GL_DrawParticles( void ) {
+ particle_t *p;
+ int i;
+ vec3_t transformed;
+ vec_t scale, dist;
+ color_t color;
+ int numverts;
+ vec_t *dst_vert;
+ uint32_t *dst_color;
+
+ if( !glr.fd.num_particles ) {
+ return;
+ }
+
+ GL_BindTexture( TEXNUM_PARTICLE );
+ GL_TexEnv( GL_MODULATE );
+ GL_Bits( GLS_BLEND_BLEND | GLS_DEPTHMASK_FALSE );
+
+ qglEnableClientState( GL_COLOR_ARRAY );
+ qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.colors );
+ qglTexCoordPointer( 2, GL_FLOAT, 20, tess.vertices + 3 );
+ qglVertexPointer( 3, GL_FLOAT, 20, tess.vertices );
+
+ numverts = 0;
+ for( i = 0, p = glr.fd.particles; i < glr.fd.num_particles; i++, p++ ) {
+ VectorSubtract( p->origin, glr.fd.vieworg, transformed );
+ dist = DotProduct( transformed, glr.viewaxis[0] );
+
+ scale = gl_partscale->value;
+ if( dist > 20 ) {
+ scale += dist * 0.01f;
+ }
+
+ if( p->color == 255 ) {
+ *( uint32_t * )color = *( uint32_t * )p->rgb;
+ } else {
+ *( uint32_t * )color = d_8to24table[p->color & 255];
+ }
+ color[3] = p->alpha * 255;
+
+ if( numverts + 3 > TESS_MAX_VERTICES ) {
+ qglDrawArrays( GL_TRIANGLES, 0, numverts );
+ numverts = 0;
+ }
+
+ dst_vert = tess.vertices + numverts * 5;
+ VectorMA( p->origin, scale*0.25f, glr.viewaxis[1], dst_vert );
+ VectorMA( dst_vert, -scale*0.25f, glr.viewaxis[2], dst_vert );
+ VectorMA( dst_vert, scale, glr.viewaxis[2], dst_vert + 5 );
+ VectorMA( dst_vert, -scale, glr.viewaxis[1], dst_vert + 10 );
+
+ dst_vert[ 3] = 0; dst_vert[ 4] = 0;
+ dst_vert[ 8] = 1.75f; dst_vert[ 9] = 0;
+ dst_vert[13] = 0; dst_vert[14] = 1.75f;
+
+ dst_color = ( uint32_t * )tess.colors + numverts;
+ dst_color[0] = *( uint32_t * )color;
+ dst_color[1] = *( uint32_t * )color;
+ dst_color[2] = *( uint32_t * )color;
+
+ numverts += 3;
+ }
+
+ qglDrawArrays( GL_TRIANGLES, 0, numverts );
+ qglDisableClientState( GL_COLOR_ARRAY );
+
+ if( gl_showtris->integer ) {
+ GL_EnableOutlines();
+ qglDrawArrays( GL_TRIANGLES, 0, numverts );
+ GL_DisableOutlines();
+ }
+}
+
+/* all things serve the Beam */
+void GL_DrawBeams( void ) {
+ vec3_t d1, d2, d3;
+ vec_t *start, *end;
+ color_t color;
+ vec_t *dst_vert;
+ uint32_t *dst_color;
+ vec_t length;
+ int numverts;
+ entity_t *ent;
+ int i;
+
+ if( !glr.num_beams ) {
+ return;
+ }
+
+ GL_BindTexture( TEXNUM_BEAM );
+ GL_TexEnv( GL_MODULATE );
+ GL_Bits( GLS_BLEND_BLEND | GLS_DEPTHMASK_FALSE );
+ qglEnableClientState( GL_COLOR_ARRAY );
+ qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.colors );
+ qglTexCoordPointer( 2, GL_FLOAT, 20, tess.vertices + 3 );
+ qglVertexPointer( 3, GL_FLOAT, 20, tess.vertices );
+
+ numverts = 0;
+ for( i = 0, ent = glr.fd.entities; i < glr.fd.num_entities; i++, ent++ ) {
+ if( !( ent->flags & RF_BEAM ) ) {
+ continue;
+ }
+
+ start = ent->origin;
+ end = ent->oldorigin;
+ VectorSubtract( end, start, d1 );
+ VectorSubtract( glr.fd.vieworg, start, d2 );
+ CrossProduct( d1, d2, d3 );
+ VectorNormalize( d3 );
+ VectorScale( d3, ent->frame*1.2f, d3 );
+
+ length = VectorLength( d1 );
+
+ if( ent->lightstyle ) {
+ *( uint32_t * )color = *( uint32_t * )&ent->skinnum;
+ } else {
+ *( uint32_t * )color = d_8to24table[ent->skinnum & 0xFF];
+ }
+ color[3] = 255 * ent->alpha;
+
+ if( numverts + 4 > TESS_MAX_VERTICES ) {
+ qglDrawArrays( GL_QUADS, 0, numverts );
+ numverts = 0;
+ }
+
+ dst_vert = tess.vertices + numverts * 5;
+ VectorAdd( start, d3, dst_vert );
+ VectorSubtract( start, d3, dst_vert + 5 );
+ VectorSubtract( end, d3, dst_vert + 10 );
+ VectorAdd( end, d3, dst_vert + 15 );
+
+ dst_vert[3] = 0; dst_vert[4] = 0;
+ dst_vert[8] = 1; dst_vert[9] = 0;
+ dst_vert[13] = 1; dst_vert[14] = length;
+ dst_vert[18] = 0; dst_vert[19] = length;
+
+ dst_color = ( uint32_t * )tess.colors + numverts;
+ dst_color[0] = *( uint32_t * )color;
+ dst_color[1] = *( uint32_t * )color;
+ dst_color[2] = *( uint32_t * )color;
+ dst_color[3] = *( uint32_t * )color;
+
+ numverts += 4;
+ }
+
+ qglDrawArrays( GL_QUADS, 0, numverts );
+ qglDisableClientState( GL_COLOR_ARRAY );
+}
+
+static void GL_BindArrays( void ) {
+ vec_t *ptr;
+
+ if( gl_static.world.vertices ) {
+ ptr = tess.vertices;
+ } else {
+ ptr = NULL;
+ qglBindBufferARB( GL_ARRAY_BUFFER_ARB, 1 );
+ }
+
+ qglVertexPointer( 3, GL_FLOAT, 4*VERTEX_SIZE, ptr + 0 );
+ qglTexCoordPointer( 2, GL_FLOAT, 4*VERTEX_SIZE,
+ gl_lightmap->integer ? ptr + 5 : ptr + 3 );
+
+ qglClientActiveTextureARB( GL_TEXTURE1_ARB );
+ qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
+ qglTexCoordPointer( 2, GL_FLOAT, 4*VERTEX_SIZE, ptr + 5 );
+ qglClientActiveTextureARB( GL_TEXTURE0_ARB );
+}
+
+static void GL_UnbindArrays( void ) {
+ if( !gl_static.world.vertices ) {
+ qglBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
+ }
+ qglClientActiveTextureARB( GL_TEXTURE1_ARB );
+ qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
+ qglClientActiveTextureARB( GL_TEXTURE0_ARB );
+}
+
+static void GL_Flush3D( void ) {
+ if( !tess.numindices ) {
+ return;
+ }
+
+ if( tess.flags & (SURF_TRANS33|SURF_TRANS66) ) {
+ float f = gl_static.inverse_intensity;
+
+ if( tess.flags & SURF_TRANS33 ) {
+ qglColor4f( f, f, f, 0.33f );
+ } else {
+ qglColor4f( f, f, f, 0.66f );
+ }
+ }
+
+ GL_BindTexture( tess.texnum[0] );
+
+ if( tess.texnum[1] ) {
+ GL_SelectTMU( 1 );
+ qglEnable( GL_TEXTURE_2D );
+ GL_TexEnv( GL_MODULATE );
+ GL_BindTexture( tess.texnum[1] );
+ }
+
+ if( gl_static.world.vertices && qglLockArraysEXT ) {
+ qglLockArraysEXT( 0, tess.numverts );
+ }
+
+ qglDrawElements( GL_TRIANGLES, tess.numindices, GL_UNSIGNED_INT, tess.indices );
+
+ if( tess.texnum[1] ) {
+ qglDisable( GL_TEXTURE_2D );
+ GL_SelectTMU( 0 );
+ }
+
+ if( gl_showtris->integer ) {
+ GL_EnableOutlines();
+ qglDrawElements( GL_TRIANGLES, tess.numindices, GL_UNSIGNED_INT, tess.indices );
+ GL_DisableOutlines();
+ }
+
+ if( gl_static.world.vertices && qglUnlockArraysEXT ) {
+ qglUnlockArraysEXT();
+ }
+
+ c.batchesDrawn++;
+
+ tess.texnum[0] = tess.texnum[1] = 0;
+ tess.numindices = 0;
+ tess.numverts = 0;
+ tess.flags = 0;
+}
+
+static void GL_CopyVerts( mface_t *surf ) {
+ void *src, *dst;
+
+ if( tess.numverts + surf->numsurfedges > TESS_MAX_VERTICES ) {
+ GL_Flush3D();
+ }
+
+ src = gl_static.world.vertices + surf->firstvert * VERTEX_SIZE;
+ dst = tess.vertices + tess.numverts * VERTEX_SIZE;
+ memcpy( dst, src, surf->numsurfedges * VERTEX_SIZE * sizeof( vec_t ) );
+
+ tess.numverts += surf->numsurfedges;
+}
+
+static int GL_TextureAnimation( mtexinfo_t *tex ) {
+ int frame, c;
+
+ if( !tex->next )
+ return tex->image->texnum;
+
+ frame = ( int )( glr.fd.time * 2 );
+ c = frame % tex->numframes;
+ while( c ) {
+ tex = tex->next;
+ c--;
+ }
+
+ return tex->image->texnum;
+}
+
+static void GL_DrawFace( mface_t *surf ) {
+ int numindices = ( surf->numsurfedges - 2 ) * 3;
+ int diff = surf->texinfo->c.flags ^ tess.flags;
+ int texnum = GL_TextureAnimation( surf->texinfo );
+ int *dst_indices;
+ int i, j;
+
+ if( tess.texnum[0] != texnum ||
+ tess.texnum[1] != surf->texnum[1] ||
+ ( diff & (SURF_TRANS33|SURF_TRANS66) ) ||
+ tess.numindices + numindices > TESS_MAX_INDICES )
+ {
+ GL_Flush3D();
+ }
+
+ if( gl_static.world.vertices ) {
+ j = tess.numverts;
+ GL_CopyVerts( surf );
+ } else {
+ j = surf->firstvert;
+ }
+
+ if( gl_lightmap->integer ) {
+ tess.texnum[0] = surf->texnum[1] ? surf->texnum[1] : texnum;
+ tess.texnum[1] = 0;
+ } else {
+ tess.texnum[0] = texnum;
+ tess.texnum[1] = surf->texnum[1];
+ }
+ tess.flags = surf->texinfo->c.flags;
+ dst_indices = tess.indices + tess.numindices;
+ for( i = 0; i < surf->numsurfedges - 2; i++ ) {
+ dst_indices[0] = j;
+ dst_indices[1] = j + ( i + 1 );
+ dst_indices[2] = j + ( i + 2 );
+ dst_indices += 3;
+ }
+ tess.numindices += numindices;
+ c.trisDrawn += surf->numsurfedges - 2;
+}
+
+static inline void GL_DrawChain( mface_t **head ) {
+ mface_t *face;
+
+ for( face = *head; face; face = face->next ) {
+ GL_DrawFace( face );
+ }
+ *head = NULL;
+}
+
+void GL_DrawSolidFaces( void ) {
+ int i;
+
+ GL_BindArrays();
+
+ GL_Bits( GLS_DEFAULT );
+ GL_TexEnv( GL_REPLACE );
+ qglColor4f( 1, 1, 1, 1 );
+
+ if( faces_warp ) {
+ GL_EnableWarp();
+ GL_DrawChain( &faces_warp );
+ GL_Flush3D();
+ GL_DisableWarp();
+ }
+
+ for( i = 0; i < FACE_HASH_SIZE; i++ ) {
+ GL_DrawChain( &faces_hash[i] );
+ }
+
+ GL_Flush3D();
+ GL_UnbindArrays();
+}
+
+
+void GL_DrawAlphaFaces( void ) {
+ GL_BindArrays();
+
+ GL_Bits( GLS_BLEND_BLEND | GLS_DEPTHMASK_FALSE );
+ GL_TexEnv( GL_MODULATE );
+
+ if( faces_alpha_warp ) {
+ GL_EnableWarp();
+ GL_DrawChain( &faces_alpha_warp );
+ GL_Flush3D();
+ GL_DisableWarp();
+ }
+
+ GL_DrawChain( &faces_alpha );
+
+ GL_Flush3D();
+ GL_UnbindArrays();
+}
+
+void GL_AddSolidFace( mface_t *face ) {
+ if( ( face->texinfo->c.flags & SURF_WARP ) && qglBindProgramARB ) {
+ face->next = faces_warp;
+ faces_warp = face;
+ } else {
+ int i = ( face->texnum[0] ^ face->texnum[1] ) & FACE_HASH_MASK;
+ face->next = faces_hash[i];
+ faces_hash[i] = face;
+ }
+ // TODO: SURF_FLOWING support
+ c.facesDrawn++;
+}
+
+void GL_AddFace( mface_t *face ) {
+ int flags = face->texinfo->c.flags;
+
+ if( flags & SURF_SKY ) {
+ R_AddSkySurface( face );
+ return;
+ }
+
+ if( flags & (SURF_TRANS33|SURF_TRANS66) ) {
+ if( ( flags & SURF_WARP ) && qglBindProgramARB ) {
+ face->next = faces_alpha_warp;
+ faces_alpha_warp = face;
+ } else {
+ face->next = faces_alpha;
+ faces_alpha = face;
+ }
+ // TODO: SURF_FLOWING support
+ c.facesDrawn++;
+ return;
+ }
+
+ GL_AddSolidFace( face );
+}
+