diff options
Diffstat (limited to 'source/gl_tess.c')
-rw-r--r-- | source/gl_tess.c | 1242 |
1 files changed, 1242 insertions, 0 deletions
diff --git a/source/gl_tess.c b/source/gl_tess.c new file mode 100644 index 0000000..adbd27e --- /dev/null +++ b/source/gl_tess.c @@ -0,0 +1,1242 @@ +/* +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; + +/* +============================================================================== + +BSP surfaces sorting + +============================================================================== +*/ + +typedef struct { + uint32 key; + bspSurface_t *surf; +} drawSurf_t; + +#define MAX_DRAW_SURFS ( 1 << 16 ) +#define DRAW_SURFS_MASK ( MAX_DRAW_SURFS - 1 ) + +static drawSurf_t drawSurfs[MAX_DRAW_SURFS]; +static drawSurf_t drawSurfsBuffer[MAX_DRAW_SURFS]; +static int numDrawSurfs; + +image_t *GL_TextureAnimation( bspTexinfo_t *texinfo ) { + int count; + + if( !texinfo->animNext ) { + return texinfo->image; + } + + count = ( int )( glr.fd.time * 2 ) % texinfo->numFrames; + while( count ) { + texinfo = texinfo->animNext; + count--; + } + + return texinfo->image; +} + + +void GL_AddBspSurface( bspSurface_t *surf ) { + drawSurf_t *drawsurf; + bspTexinfo_t *texinfo = surf->texinfo; + int idx, istrans, texnum; + image_t *image; + + if( surf->type >= DSURF_NUM_TYPES ) { + Com_Error( ERR_FATAL, "GL_AddBspSurface: bad surf->type" ); + } + + if( surf->dlightframe != glr.drawframe ) { + surf->dlightbits = 0; + } + + istrans = 0; + if( texinfo->flags & SURF_SKY ) { + if( !gl_fastsky->integer ) { + R_AddSkySurface( surf ); + return; + } + texnum = r_whiteimage->texnum; + } else { + if( texinfo->flags & (SURF_TRANS33|SURF_TRANS66) ) { + if( texinfo->flags & SURF_TRANS33 ) { + istrans = 1; + } else { + istrans = 2; + } + } + image = GL_TextureAnimation( texinfo ); + texnum = image->texnum; + } + + idx = numDrawSurfs & DRAW_SURFS_MASK; + drawsurf = &drawSurfs[idx]; + drawsurf->key = ( istrans << 30 ) | ( texnum << 16 ) | surf->lightmapnum; + drawsurf->surf = surf; + + numDrawSurfs++; +} + +#define CopyDrawSurf( dst, src ) \ + ( (( uint32 * )dst)[0] = (( uint32 * )src)[0],\ + (( uint32 * )dst)[1] = (( uint32 * )src)[1] ) + +static void mergeArray( int left, int median, int right ) { + int count; + int i, j; + drawSurf_t *src, *dst; + + dst = drawSurfsBuffer; + i = left; + j = median + 1; + while( i <= median && j <= right ) { + if( drawSurfs[i].key < drawSurfs[j].key ) { + CopyDrawSurf( dst, &drawSurfs[i] ); i++; + } else { + CopyDrawSurf( dst, &drawSurfs[j] ); j++; + } + dst++; + } + + while( i <= median ) { + CopyDrawSurf( dst, &drawSurfs[i] ); i++; dst++; + } + + while( j <= right ) { + CopyDrawSurf( dst, &drawSurfs[j] ); j++; dst++; + } + + src = drawSurfsBuffer; + count = dst - src; + dst = drawSurfs + left; + while( count-- ) { + CopyDrawSurf( dst, src ); src++; dst++; + } +} + +static void mergeSort_r( int left, int right ) { + int median; + + if( left < right ) { + median = ( left + right ) >> 1; + + mergeSort_r( left, median ); + mergeSort_r( median + 1, right ); + + mergeArray( left, median, right ); + } +} + + +/* +============================================================================== + +Surface tesselation + +============================================================================== +*/ + +#define TURB_SCALE ( 256.0f / ( 2 * M_PI ) ) + +static float r_turbsin[256] = { + #include "warpsin.h" +}; + +static qboolean WouldOverflow( drawSurf_t *surf ) { + bspPoly_t *poly; + int numVerts, numIndices; + + if( tess.numFaces + 1 > TESS_MAX_FACES ) { + return qtrue; + } + + numVerts = tess.numVertices; + numIndices = tess.numIndices; + for( poly = surf->surf->polys; poly; poly = poly->next ) { + numVerts += poly->numVerts; + numIndices += poly->numIndices; + } + + if( numVerts > TESS_MAX_VERTICES ) { + return qtrue; + } + if( numIndices > TESS_MAX_INDICES ) { + return qtrue; + } + + return qfalse; +} + +static void Tess_SimplePoly( drawSurf_t *surf ) { + bspSurface_t *bspSurf = surf->surf; + bspPoly_t *poly = bspSurf->polys; + vec_t *src_vert, *dst_vert; + tcoord_t *dst_tc; + int *dst_indices; + int i, count, currentVert; + float scroll; + + scroll = 0; + if( bspSurf->texinfo->flags & SURF_FLOWING ) { + scroll = glr.scroll; + } + + src_vert = poly->vertices; + dst_vert = tess.vertices + tess.numVertices * 4; + dst_tc = tess.tcoords + tess.numVertices; + count = poly->numVerts; + for( i = 0; i < count; i++ ) { + VectorCopy( src_vert, dst_vert ); + dst_tc->st[0] = src_vert[3] + scroll; + dst_tc->st[1] = src_vert[4]; + src_vert += VERTEX_SIZE; dst_vert += 4; + dst_tc++; + } + + dst_indices = tess.indices + tess.numIndices; + count = poly->numVerts - 2; + currentVert = tess.numVertices; + for( i = 0; i < count; i++ ) { + dst_indices[0] = currentVert; + dst_indices[1] = currentVert + ( i + 1 ); + dst_indices[2] = currentVert + ( i + 2 ); + dst_indices += 3; + } + + tess.faces[ tess.numFaces++ ] = bspSurf; + tess.numVertices += poly->numVerts; + tess.numIndices += poly->numIndices; + tess.dlightbits |= bspSurf->dlightbits; + + c.trisDrawn += count; + +} + +static void Tess_LightmappedPoly( drawSurf_t *surf ) { + bspSurface_t *bspSurf = surf->surf; + bspPoly_t *poly = bspSurf->polys; + vec_t *src_vert, *dst_vert; + tcoord_t *dst_tc; + tcoord_t *dst_lmtc; + int *dst_indices; + int i, count, currentVert; + + src_vert = poly->vertices; + dst_vert = tess.vertices + tess.numVertices * 4; + dst_tc = tess.tcoords + tess.numVertices; + dst_lmtc = tess.lmtcoords + tess.numVertices; + count = poly->numVerts; + for( i = 0; i < count; i++ ) { + VectorCopy( src_vert, dst_vert ); + *( uint32 * )&dst_tc->st[0] = *( uint32 * )&src_vert[3]; + *( uint32 * )&dst_tc->st[1] = *( uint32 * )&src_vert[4]; + *( uint32 * )&dst_lmtc->st[0] = *( uint32 * )&src_vert[5]; + *( uint32 * )&dst_lmtc->st[1] = *( uint32 * )&src_vert[6]; + src_vert += VERTEX_SIZE; dst_vert += 4; + dst_tc++; dst_lmtc++; + } + + dst_indices = tess.indices + tess.numIndices; + count = poly->numVerts - 2; + currentVert = tess.numVertices; + for( i = 0; i < count; i++ ) { + dst_indices[0] = currentVert; + dst_indices[1] = currentVert + ( i + 1 ); + dst_indices[2] = currentVert + ( i + 2 ); + dst_indices += 3; + } + + tess.faces[ tess.numFaces++ ] = bspSurf; + tess.numVertices += poly->numVerts; + tess.numIndices += poly->numIndices; + tess.dlightbits |= bspSurf->dlightbits; + + c.trisDrawn += count; + +} + +#define DIV64 ( 1.0f / 64 ) + +static void Tess_WarpPolys( drawSurf_t *surf ) { + bspSurface_t *bspSurf = surf->surf; + bspPoly_t *poly = bspSurf->polys; + vec_t *src_vert, *dst_vert; + tcoord_t *dst_tc; + int *dst_indices; + int i, j, k, count, currentVert; + vec_t s, t; + float scroll; + + scroll = 0; + if( bspSurf->texinfo->flags & SURF_FLOWING ) { + scroll = glr.scroll; + } + + for( poly = bspSurf->polys; poly; poly = poly->next ) { + src_vert = poly->vertices; + dst_vert = tess.vertices + tess.numVertices * 4; + dst_tc = tess.tcoords + tess.numVertices; + count = poly->numVerts; + for( i = 0; i < count; i++ ) { + VectorCopy( src_vert, dst_vert ); + dst_vert += 4; + + s = src_vert[3]; + t = src_vert[4]; + src_vert += VERTEX_SIZE; + + j = Q_ftol( ( t * 0.125f + glr.fd.time ) * TURB_SCALE ); + k = Q_ftol( ( s * 0.125f + glr.fd.time ) * TURB_SCALE ); + s += r_turbsin[ j & 255 ]; + t += r_turbsin[ k & 255 ]; + + dst_tc->st[0] = s * DIV64 + scroll; + dst_tc->st[1] = t * DIV64; + dst_tc++; + } + + dst_indices = tess.indices + tess.numIndices; + count = poly->numVerts - 2; + currentVert = tess.numVertices; + for( i = 0; i < count; i++ ) { + dst_indices[0] = currentVert; + dst_indices[1] = currentVert + ( i + 1 ); + dst_indices[2] = currentVert + ( i + 2 ); + dst_indices += 3; + } + dst_indices[0] = currentVert; + dst_indices[1] = currentVert + ( i + 1 ); + dst_indices[2] = currentVert + 1; + dst_indices += 3; + + tess.numVertices += poly->numVerts; + tess.numIndices += poly->numIndices; + + c.trisDrawn += count + 1; + } + + tess.faces[ tess.numFaces++ ] = bspSurf; + tess.dlightbits |= bspSurf->dlightbits; + +} + +typedef void (*tesselatorFunc_t)( drawSurf_t * ); + +tesselatorFunc_t tessTable[DSURF_NUM_TYPES] = { + Tess_LightmappedPoly, /* DSURF_POLY */ + Tess_WarpPolys, /* DSURF_WARP */ + Tess_SimplePoly /* DSURF_NOLM */ +}; + +/* +============================================================================== + +Surface drawing + +============================================================================== +*/ + +void Tess_DrawSurfaceTriangles( int *indices, int numIndices ) { + qglDisable( GL_TEXTURE_2D ); + qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); + GL_TexEnv( GL_REPLACE ); + qglDisable( GL_DEPTH_TEST ); + qglColor4f( 1, 1, 1, 1 ); + + qglDrawElements( GL_TRIANGLES, numIndices, GL_UNSIGNED_INT, + indices ); + + qglEnable( GL_DEPTH_TEST ); + qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + qglEnable( GL_TEXTURE_2D ); + qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); +} + +#if 0 +static void ProjectDlightTexture( void ) { + bspSurface_t *bspSurf; + bspTexinfo_t *texinfo; + cplane_t *plane; + vec3_t point; + vec2_t local; + vec_t dist, scale, f; + int i, j, faceNum, numIndices; + dlight_t *light; + tcoord_t *src_tc; + vec_t *dst_tc; +static vec_t tcArray[TESS_MAX_VERTICES*2]; +static byte colorsArray[TESS_MAX_VERTICES*4]; + int cfArray[TESS_MAX_VERTICES]; + int idxArray[TESS_MAX_INDICES]; + byte *dst_col; + int v1, v2, v3; + int *src_idx, *dst_idx; + int clipflags; + color_t color; + int currentVert, maxVert; + + GL_BindTexture( r_dlightTex->texnum ); +// qglVertexPointer( 3, GL_FLOAT, 16, tess.vertices ); + qglTexCoordPointer( 2, GL_FLOAT, 0, tcArray ); + qglEnableClientState( GL_COLOR_ARRAY ); + qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorsArray ); + + for( i = 0, light = glr.fd.dlights; i < glr.fd.num_dlights; i++, light++ ) { + currentVert = 0; + for( faceNum = 0; faceNum < tess.numFaces; faceNum++, currentVert = maxVert ) { + bspSurf = tess.faces[faceNum]; + maxVert = currentVert + bspSurf->polys->numVerts; + if( !( bspSurf->dlightbits & ( 1 << i ) ) ) { + //continue; + } + plane = bspSurf->plane; + switch( plane->type ) { + case PLANE_X: + dist = light->transformed[0] - plane->dist; + break; + case PLANE_Y: + dist = light->transformed[1] - plane->dist; + break; + case PLANE_Z: + dist = light->transformed[2] - plane->dist; + break; + default: + dist = DotProduct( light->transformed, plane->normal ) - plane->dist; + break; + } + + if( dist > light->intensity || dist < -light->intensity ) { + //continue; + } + + VectorMA( light->transformed, -dist, plane->normal, point ); + + texinfo = bspSurf->texinfo; + local[0] = DotProduct( point, texinfo->normalizedAxis[0] ); + local[1] = DotProduct( point, texinfo->normalizedAxis[1] ); + + scale = 1.0f / light->intensity; + + dist = fabs( dist ); + f = 1.0f - dist * scale; + if( f < 0 ) f = 0; + + color[0] = 255 * light->color[0] * f; + color[1] = 255 * light->color[1] * f; + color[2] = 255 * light->color[2] * f; + color[3] = 255; + + src_tc = bspSurf->normalizedTC; + dst_tc = tcArray + currentVert * 2; + dst_col = colorsArray + currentVert * 4; + for( j = currentVert; j < maxVert; j++ ) { + dst_tc[0] = ( src_tc->st[0] - local[0] ) * scale + 0.5f; + dst_tc[1] = ( src_tc->st[1] - local[1] ) * scale + 0.5f; + + /*clipflags = 0; + if( dst_tc[0] > 1 ) { + clipflags |= 1; + } else if( dst_tc[0] < 0 ) { + clipflags |= 2; + } + if( dst_tc[1] > 1 ) { + clipflags |= 4; + } else if( dst_tc[1] < 0 ) { + clipflags |= 8; + }*/ + + *( uint32 * )dst_col = *( uint32 * )color; + //cfArray[j] = clipflags; + + dst_col += 4; src_tc++; dst_tc += 2; + } + + } + +#if 0 + numIndices = 0; + src_idx = tess.indices; + dst_idx = idxArray; + for( faceNum = 0; faceNum < tess.numFaces; faceNum++ ) { + bspSurf = tess.faces[faceNum]; + if( !( bspSurf->dlightbits & ( 1 << i ) ) ) { + src_idx += bspSurf->polys->numIndices; + continue; + } + for( j = 0; j < bspSurf->polys->numVerts - 2; j++ ) { + v1 = src_idx[0]; + v2 = src_idx[1]; + v3 = src_idx[2]; + src_idx += 3; + if( cfArray[v1] & cfArray[v2] & cfArray[v3] ) { + continue; + } + dst_idx[0] = v1; + dst_idx[1] = v2; + dst_idx[2] = v3; + + dst_idx += 3; + numIndices += 3; + } + + } + + if( numIndices ) { + qglDrawElements( GL_TRIANGLES, numIndices, + GL_UNSIGNED_INT, idxArray ); + } +#endif + } + +// qglDisableClientState( GL_COLOR_ARRAY ); +} + +// f = ( l + d ) * t + +void EndSurface_Multitextured( void ) { + GL_TexEnv( GL_REPLACE ); + GL_BindTexture( lm.lightmaps[ tess.lightmapnum - 1 ]->texnum ); + qglTexCoordPointer( 2, GL_FLOAT, 0, tess.lmtcoords ); + + GL_SelectTMU( 1 ); + if( tess.dlightbits ) { + + qglEnable( GL_TEXTURE_2D ); + GL_TexEnv( GL_ADD ); + + qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); + /* if( gl_dynamic->integer == 2 ) { + GL_Bits( GLS_BLEND_MODULATE ); + } else { + GL_Bits( GLS_BLEND_ADD ); + }*/ + + ProjectDlightTexture(); + } + + /* enable texturing on TMU1 */ + GL_SelectTMU( 2 ); + qglEnable( GL_TEXTURE_2D ); + GL_BindTexture( tess.texnum ); + GL_TexEnv( GL_MODULATE ); + qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); + qglTexCoordPointer( 2, GL_FLOAT, 0, tess.tcoords ); + + qglVertexPointer( 3, GL_FLOAT, 16, tess.vertices ); + if( qglLockArraysEXT ) { + qglLockArraysEXT( 0, tess.numVertices ); + } + qglDrawElements( GL_TRIANGLES, tess.numIndices, GL_UNSIGNED_INT, + tess.indices ); + + /* disable texturing on TMU1 */ + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); + qglDisable( GL_TEXTURE_2D ); + GL_SelectTMU( 1 ); + + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); + qglDisableClientState( GL_COLOR_ARRAY ); + qglDisable( GL_TEXTURE_2D ); + GL_SelectTMU( 0 ); + + + if( gl_showtris->integer ) { + Tess_DrawSurfaceTriangles( tess.indices, tess.numIndices ); + } + + if( qglUnlockArraysEXT ) { + qglUnlockArraysEXT(); + } + + +} + +#else + +static void ProjectDlightTexture( void ) { + bspSurface_t *bspSurf; + bspTexinfo_t *texinfo; + cplane_t *plane; + vec3_t point; + vec2_t local; + vec_t dist, scale, f; + int i, j, faceNum, numIndices; + dlight_t *light; + tcoord_t *src_tc; + vec_t *dst_tc; + vec_t tcArray[TESS_MAX_VERTICES*2]; + int cfArray[TESS_MAX_VERTICES]; + int idxArray[TESS_MAX_INDICES]; + byte colorsArray[TESS_MAX_VERTICES*4]; + byte *dst_col; + int v1, v2, v3; + int *src_idx, *dst_idx; + int clipflags; + color_t color; + int currentVert, maxVert; + + GL_BindTexture( r_dlightTex->texnum ); + qglTexCoordPointer( 2, GL_FLOAT, 0, tcArray ); + qglEnableClientState( GL_COLOR_ARRAY ); + qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorsArray ); + + for( i = 0, light = glr.fd.dlights; i < glr.fd.num_dlights; i++, light++ ) { + currentVert = 0; + for( faceNum = 0; faceNum < tess.numFaces; faceNum++, currentVert = maxVert ) { + bspSurf = tess.faces[faceNum]; + maxVert = currentVert + bspSurf->polys->numVerts; + if( !( bspSurf->dlightbits & ( 1 << i ) ) ) { + continue; + } + plane = bspSurf->plane; + switch( plane->type ) { + case PLANE_X: + dist = light->transformed[0] - plane->dist; + break; + case PLANE_Y: + dist = light->transformed[1] - plane->dist; + break; + case PLANE_Z: + dist = light->transformed[2] - plane->dist; + break; + default: + dist = DotProduct( light->transformed, plane->normal ) - plane->dist; + break; + } + + if( dist > light->intensity || dist < -light->intensity ) { + continue; + } + + VectorMA( light->transformed, -dist, plane->normal, point ); + + texinfo = bspSurf->texinfo; + local[0] = DotProduct( point, texinfo->normalizedAxis[0] ); + local[1] = DotProduct( point, texinfo->normalizedAxis[1] ); + + scale = 1.0f / light->intensity; + + dist = fabs( dist ); + f = 1.0f - dist * scale; + + color[0] = 255 * light->color[0] * f; + color[1] = 255 * light->color[1] * f; + color[2] = 255 * light->color[2] * f; + color[3] = 255; + + src_tc = bspSurf->normalizedTC; + dst_tc = tcArray + currentVert * 2; + dst_col = colorsArray + currentVert * 4; + for( j = currentVert; j < maxVert; j++ ) { + dst_tc[0] = ( src_tc->st[0] - local[0] ) * scale + 0.5f; + dst_tc[1] = ( src_tc->st[1] - local[1] ) * scale + 0.5f; + + clipflags = 0; + if( dst_tc[0] > 1 ) { + clipflags |= 1; + } else if( dst_tc[0] < 0 ) { + clipflags |= 2; + } + if( dst_tc[1] > 1 ) { + clipflags |= 4; + } else if( dst_tc[1] < 0 ) { + clipflags |= 8; + } + + *( uint32 * )dst_col = *( uint32 * )color; + cfArray[j] = clipflags; + + dst_col += 4; src_tc++; dst_tc += 2; + } + + } + + numIndices = 0; + src_idx = tess.indices; + dst_idx = idxArray; + for( faceNum = 0; faceNum < tess.numFaces; faceNum++ ) { + bspSurf = tess.faces[faceNum]; + if( !( bspSurf->dlightbits & ( 1 << i ) ) ) { + src_idx += bspSurf->polys->numIndices; + continue; + } + for( j = 0; j < bspSurf->polys->numVerts - 2; j++ ) { + v1 = src_idx[0]; + v2 = src_idx[1]; + v3 = src_idx[2]; + src_idx += 3; + if( cfArray[v1] & cfArray[v2] & cfArray[v3] ) { + continue; + } + dst_idx[0] = v1; + dst_idx[1] = v2; + dst_idx[2] = v3; + + dst_idx += 3; + numIndices += 3; + } + + } + + if( numIndices ) { + qglDrawElements( GL_TRIANGLES, numIndices, + GL_UNSIGNED_INT, idxArray ); + } + } + + qglDisableClientState( GL_COLOR_ARRAY ); + +} + +void EndSurface_Multitextured( void ) { + GL_BindTexture( tess.texnum ); + qglTexCoordPointer( 2, GL_FLOAT, 0, tess.tcoords ); + + /* enable texturing on TMU1 */ + GL_SelectTMU( 1 ); + qglEnable( GL_TEXTURE_2D ); + GL_BindTexture( lm.lightmaps[ tess.lightmapnum - 1 ]->texnum ); + GL_TexEnv( GL_MODULATE ); + qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); + qglTexCoordPointer( 2, GL_FLOAT, 0, tess.lmtcoords ); + + qglVertexPointer( 3, GL_FLOAT, 16, tess.vertices ); + if( qglLockArraysEXT ) { + qglLockArraysEXT( 0, tess.numVertices ); + } + qglDrawElements( GL_TRIANGLES, tess.numIndices, GL_UNSIGNED_INT, + tess.indices ); + + /* disable texturing on TMU1 */ + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); + qglDisable( GL_TEXTURE_2D ); + GL_SelectTMU( 0 ); + + if( gl_showtris->integer ) { + Tess_DrawSurfaceTriangles( tess.indices, tess.numIndices ); + } + + if( qglUnlockArraysEXT ) { + qglUnlockArraysEXT(); + } + + if( tess.dlightbits ) { + GL_TexEnv( GL_MODULATE ); + if( gl_dynamic->integer == 2 ) { + GL_Bits( GLS_BLEND_MODULATE ); + } else { + GL_Bits( GLS_BLEND_ADD ); + } + + ProjectDlightTexture(); + } + +} + +#endif + +void EndSurface_Single( void ) { + GL_BindTexture( tess.texnum ); + + qglTexCoordPointer( 2, GL_FLOAT, 0, tess.tcoords ); + qglVertexPointer( 3, GL_FLOAT, 16, tess.vertices ); + if( qglLockArraysEXT ) { + qglLockArraysEXT( 0, tess.numVertices ); + } + qglDrawElements( GL_TRIANGLES, tess.numIndices, GL_UNSIGNED_INT, + tess.indices ); + if( gl_showtris->integer ) { + Tess_DrawSurfaceTriangles( tess.indices, tess.numIndices ); + } + if( qglUnlockArraysEXT ) { + qglUnlockArraysEXT(); + } +} + +typedef void (*drawSurfFunc_t)( void ); + +static drawSurfFunc_t endSurfTable[DSURF_NUM_TYPES] = { + EndSurface_Multitextured, /* DSURF_POLY */ + EndSurface_Single, /* DSURF_WARP */ + EndSurface_Single /* DSURF_NOLM */ +}; + +static void EndSurface( drawSurf_t *surf ) { + int istrans = ( surf->key >> 30 ) & 3; + + if( istrans ) { + GL_Bits( GLS_BLEND_BLEND | GLS_DEPTHMASK_FALSE ); + if( istrans == 1 ) { + qglColor4f( 1, 1, 1, 0.33f ); + } else { + qglColor4f( 1, 1, 1, 0.66f ); + } + } else { + GL_Bits( GLS_DEFAULT ); + qglColor4f( 1, 1, 1, 1 ); + } + + GL_TexEnv( GL_MODULATE ); + + (*endSurfTable[surf->surf->type])(); + + tess.numFaces = 0; + tess.numVertices = 0; + tess.numIndices = 0; + tess.dlightbits = 0; + tess.texnum = 0; + + c.batchesDrawn++; +} + +static void BeginSurface( drawSurf_t *surf ) { + if( WouldOverflow( surf ) ) { + return; + } + + tess.texnum = ( surf->key >> 16 ) & 1023; + tess.lightmapnum = surf->key & 0xFFFF; + + (*tessTable[surf->surf->type])( surf ); +} + +void GL_SortAndDrawSurfs( qboolean doSort ) { + drawSurf_t *surf, *last; + int oldkey; + + if( !numDrawSurfs ) { + return; + } + + if( numDrawSurfs > MAX_DRAW_SURFS ) { + Com_DPrintf( "MAX_DRAW_SURFS exceeded\n" ); + numDrawSurfs = MAX_DRAW_SURFS; + } + + if( doSort && gl_sort->integer ) { + mergeSort_r( 0, numDrawSurfs - 1 ); + } + + surf = drawSurfs; + last = drawSurfs + numDrawSurfs; + oldkey = surf->key; + BeginSurface( surf ); + surf++; + + for( ; surf != last; surf++ ) { + if( oldkey == surf->key && !WouldOverflow( surf ) ) { + (*tessTable[surf->surf->type])( surf ); + continue; + } + + EndSurface( surf - 1 ); + + oldkey = surf->key; + BeginSurface( surf ); + } + + EndSurface( surf - 1 ); + + numDrawSurfs = 0; +} + +void GL_Flush2D( void ) { + glStateBits_t bits; + + if( !tess.numVertices ) { + return; + } + + bits = GLS_DEPTHTEST_DISABLE; + if( tess.istrans & 2 ) { + bits |= GLS_BLEND_BLEND; + } else if( tess.istrans & 1 ) { + bits |= GLS_ALPHATEST_ENABLE; + } + + GL_TexEnv( GL_MODULATE ); + GL_Bits( bits ); + qglEnableClientState( GL_COLOR_ARRAY ); + qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.colors ); + + EndSurface_Single(); + + qglDisableClientState( GL_COLOR_ARRAY ); + + tess.numVertices = 0; + tess.numIndices = 0; + tess.texnum = 0; + tess.istrans = 0; + +} + +void GL_StretchPic( float x, float y, float w, float h, + float s1, float t1, float s2, float t2, const byte *color, image_t *image ) +{ + int currentVert, currentIdx; + vec_t *dst_vert; + int *dst_idx; + tcoord_t *dst_tc; + uint32 *dst_color; + + if( tess.numVertices + 4 > TESS_MAX_VERTICES || + tess.numIndices + 6 > TESS_MAX_INDICES || + ( tess.numVertices && tess.texnum != image->texnum ) ) + { + GL_Flush2D(); + } + + currentVert = tess.numVertices; + currentIdx = tess.numIndices; + tess.numVertices += 4; + tess.numIndices += 6; + tess.texnum = image->texnum; + + dst_vert = tess.vertices + currentVert * 4; + VectorSet( dst_vert + 0, x, y, 0 ); + VectorSet( dst_vert + 4, x + w, y, 0 ); + VectorSet( dst_vert + 8, x + w, y + h, 0 ); + VectorSet( dst_vert + 12, x, y + h, 0 ); + + dst_color = ( uint32 * )tess.colors + currentVert; + dst_color[0] = *( const uint32 * )color; + dst_color[1] = *( const uint32 * )color; + dst_color[2] = *( const uint32 * )color; + dst_color[3] = *( const uint32 * )color; + + if( image->flags & if_transparent ) { + if( ( image->flags & if_paletted ) && draw.scale == 1 ) { + tess.istrans |= 1; + } else { + tess.istrans |= 2; + } + } + if( color[3] != 255 ) { + tess.istrans |= 2; + } + + dst_tc = tess.tcoords + currentVert; + dst_tc[0].st[0] = s1; dst_tc[0].st[1] = t1; + dst_tc[1].st[0] = s2; dst_tc[1].st[1] = t1; + dst_tc[2].st[0] = s2; dst_tc[2].st[1] = t2; + dst_tc[3].st[0] = s1; dst_tc[3].st[1] = t2; + + dst_idx = tess.indices + currentIdx; + dst_idx[0] = currentVert; + dst_idx[1] = currentVert + 1; + dst_idx[2] = currentVert + 2; + dst_idx[3] = currentVert; + dst_idx[4] = currentVert + 2; + dst_idx[5] = currentVert + 3; + +} + +void GL_DrawParticles( void ) { + particle_t *p; + int i; + vec3_t transformed; + vec_t scale; + color_t color; + int currentVert; + vec_t *dst_vert; + uint32 *dst_color; + tcoord_t *dst_tc; + int *dst_idx; + + if( !glr.fd.num_particles ) { + return; + } + + GL_TexEnv( GL_MODULATE ); + GL_Bits( GLS_BLEND_BLEND | GLS_DEPTHMASK_FALSE ); + qglEnableClientState( GL_COLOR_ARRAY ); + qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.colors ); + + tess.texnum = r_particletexture->texnum; + currentVert = 0; + for( i = 0, p = glr.fd.particles; i < glr.fd.num_particles; i++, p++ ) { + VectorSubtract( p->origin, glr.fd.vieworg, transformed ); + scale = DotProduct( transformed, glr.viewaxis[0] ); + + if( scale < 20 ) { + scale = 1.5f; + } else { + scale = 1.5f + scale * 0.006f; + } + + if( p->color == 255 ) { + *( uint32 * )color = *( uint32 * )p->rgb; + } else { + *( uint32 * )color = d_8to24table[p->color & 255]; + } + color[3] = p->alpha * 255; + + if( currentVert + 3 > TESS_MAX_VERTICES || + currentVert + 3 > TESS_MAX_INDICES ) + { + tess.numVertices = tess.numIndices = currentVert; + EndSurface_Single(); + currentVert = 0; + } + + dst_vert = tess.vertices + currentVert * 4; + VectorCopy( p->origin, dst_vert ); + VectorMA( p->origin, scale, glr.viewaxis[2], dst_vert + 4 ); + VectorMA( p->origin, -scale, glr.viewaxis[1], dst_vert + 8 ); + + dst_color = ( uint32 * )tess.colors + currentVert; + dst_color[0] = *( uint32 * )color; + dst_color[1] = *( uint32 * )color; + dst_color[2] = *( uint32 * )color; + + dst_tc = tess.tcoords + currentVert; + dst_tc[0].st[0] = 0.0625f; dst_tc[0].st[1] = 0.0625f; + dst_tc[1].st[0] = 1.0625f; dst_tc[1].st[1] = 0.0625f; + dst_tc[2].st[0] = 0.0625f; dst_tc[2].st[1] = 1.0625f; + + dst_idx = tess.indices + currentVert; + dst_idx[0] = currentVert; + dst_idx[1] = currentVert + 1; + dst_idx[2] = currentVert + 2; + + currentVert += 3; + } + + tess.numVertices = tess.numIndices = currentVert; + EndSurface_Single(); + tess.numVertices = tess.numIndices = 0; + tess.texnum = 0; + + qglDisableClientState( GL_COLOR_ARRAY ); +} + +/* 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 *dst_color; + tcoord_t *dst_tc; + int *dst_idx; + vec_t length; + int currentVert, currentIdx; + entity_t *ent; + int i; + + if( !glr.num_beams ) { + return; + } + + GL_TexEnv( GL_MODULATE ); + GL_Bits( GLS_BLEND_ADD | GLS_DEPTHMASK_FALSE ); + qglEnableClientState( GL_COLOR_ARRAY ); + qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.colors ); + + tess.texnum = r_beamtexture->texnum; + currentVert = 0; + currentIdx = 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 * )color = *( uint32 * )&ent->skinnum; + } else { + *( uint32 * )color = d_8to24table[ent->skinnum & 0xFF]; + } + color[3] = 255 * ent->alpha; + + if( currentVert + 4 > TESS_MAX_VERTICES || + currentIdx + 6 > TESS_MAX_INDICES ) + { + tess.numVertices = currentVert; + tess.numIndices = currentIdx; + EndSurface_Single(); + currentVert = 0; + currentIdx = 0; + } + + dst_vert = tess.vertices + currentVert * 4; + VectorAdd( start, d3, dst_vert ); + VectorSubtract( start, d3, dst_vert + 4 ); + VectorSubtract( end, d3, dst_vert + 8 ); + VectorAdd( end, d3, dst_vert + 12 ); + + dst_color = ( uint32 * )tess.colors + currentVert; + dst_color[0] = *( uint32 * )color; + dst_color[1] = *( uint32 * )color; + dst_color[2] = *( uint32 * )color; + dst_color[3] = *( uint32 * )color; + + dst_tc = tess.tcoords + currentVert; + dst_tc[0].st[0] = 0; dst_tc[0].st[1] = 0; + dst_tc[1].st[0] = 1; dst_tc[1].st[1] = 0; + dst_tc[2].st[0] = 1; dst_tc[2].st[1] = length; + dst_tc[3].st[0] = 0; dst_tc[3].st[1] = length; + + dst_idx = tess.indices + currentIdx; + dst_idx[0] = currentVert + 0; + dst_idx[1] = currentVert + 1; + dst_idx[2] = currentVert + 2; + dst_idx[3] = currentVert + 2; + dst_idx[4] = currentVert + 3; + dst_idx[5] = currentVert + 0; + + currentVert += 4; + currentIdx += 6; + } + + tess.numVertices = currentVert; + tess.numIndices = currentIdx; + EndSurface_Single(); + tess.numVertices = tess.numIndices = 0; + tess.texnum = 0; + + qglDisableClientState( GL_COLOR_ARRAY ); + + qglDisableClientState( GL_COLOR_ARRAY ); + +} + +static void GL_DrawWarpPolys( bspSurface_t *surf ) { + bspPoly_t *poly; + vec_t *vert; + int i, j, k; + vec_t s, t; + + for( poly = surf->polys; poly; poly = poly->next ) { + vert = poly->vertices; + qglBegin( GL_TRIANGLE_FAN ); + for( i = 0; i < poly->numVerts + 1; i++ ) { + if( i == poly->numVerts ) { + vert = poly->vertices + VERTEX_SIZE; + } + + j = Q_ftol( ( vert[4] * 0.125 + glr.fd.time ) * TURB_SCALE ); + k = Q_ftol( ( vert[3] * 0.125 + glr.fd.time ) * TURB_SCALE ); + + s = vert[3] + r_turbsin[j & 255]; + s *= DIV64; + + t = vert[4] + r_turbsin[k & 255]; + t *= DIV64; + + qglTexCoord2f( s, t ); + qglVertex3fv( vert ); + + vert += VERTEX_SIZE; + } + qglEnd(); + } +} + +static void GL_DrawNolmPoly( bspSurface_t *surf ) { + bspPoly_t *poly = surf->polys; + vec_t *vert; + int i; + + qglBegin( GL_POLYGON ); + vert = poly->vertices; + for( i = 0; i < poly->numVerts; i++ ) { + qglTexCoord2fv( vert + 3 ); + qglVertex3fv( vert ); + vert += VERTEX_SIZE; + } + qglEnd(); +} + + +void GL_DrawSurfPoly( bspSurface_t *surf ) { + bspTexinfo_t *texinfo = surf->texinfo; + bspPoly_t *poly; + vec_t *vert; + int i; + + if( ( texinfo->flags & SURF_SKY ) && !gl_fastsky->integer ) { + R_AddSkySurface( surf ); + return; + } + + if( texinfo->flags & (SURF_TRANS33|SURF_TRANS66) ) { + GL_Bits( GLS_BLEND_BLEND | GLS_DEPTHMASK_FALSE ); + if( texinfo->flags & SURF_TRANS33 ) { + qglColor4f( 1, 1, 1, 0.33f ); + } else { + qglColor4f( 1, 1, 1, 0.66f ); + } + } else { + qglColor4f( 1, 1, 1, 1 ); + GL_Bits( GLS_DEFAULT ); + qglColor4ubv( colorWhite ); + } + GL_TexEnv( GL_MODULATE ); + + GL_BindTexture( texinfo->image->texnum ); + + if( surf->type == DSURF_WARP ) { + GL_DrawWarpPolys( surf ); + return; + } + + if( surf->type == DSURF_NOLM ) { + GL_DrawNolmPoly( surf ); + return; + } + + GL_SelectTMU( 1 ); + qglEnable( GL_TEXTURE_2D ); + GL_BindTexture( lm.lightmaps[ surf->lightmapnum - 1 ]->texnum ); + GL_TexEnv( GL_MODULATE ); + + poly = surf->polys; + vert = poly->vertices; + qglBegin( GL_POLYGON ); + for( i = 0; i < poly->numVerts; i++ ) { + qglMultiTexCoord2fvARB( GL_TEXTURE0_ARB, vert + 3 ); + qglMultiTexCoord2fvARB( GL_TEXTURE1_ARB, vert + 5 ); + qglVertex3fv( vert ); + vert += VERTEX_SIZE; + + } + qglEnd(); + + qglDisable( GL_TEXTURE_2D ); + GL_SelectTMU( 0 ); +} + |