mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00

Looks good Btw it won't be possible to make a common function, because like others `RB_Surface*`, both functions use a different struct (even if some of the fields have the same name between structures)
870 lines
23 KiB
C
870 lines
23 KiB
C
/*
|
|
===========================================================================
|
|
Copyright (C) 1999-2005 Id Software, Inc.
|
|
|
|
This file is part of Quake III Arena source code.
|
|
|
|
Quake III Arena source code 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.
|
|
|
|
Quake III Arena source code 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 Foobar; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
// tr_surf.c
|
|
#include "tr_local.h"
|
|
|
|
/*
|
|
|
|
THIS ENTIRE FILE IS BACK END
|
|
|
|
backEnd.currentEntity will be valid.
|
|
|
|
Tess_Begin has already been called for the surface's shader.
|
|
|
|
The modelview matrix will be set.
|
|
|
|
It is safe to actually issue drawing commands here if you don't want to
|
|
use the shader system.
|
|
*/
|
|
|
|
|
|
//============================================================================
|
|
|
|
|
|
/*
|
|
==============
|
|
RB_CheckOverflow
|
|
==============
|
|
*/
|
|
void RB_CheckOverflow( int verts, int indexes ) {
|
|
if (tess.numVertexes + verts < SHADER_MAX_VERTEXES
|
|
&& tess.numIndexes + indexes < SHADER_MAX_INDEXES) {
|
|
return;
|
|
}
|
|
|
|
RB_EndSurface();
|
|
|
|
if ( verts >= SHADER_MAX_VERTEXES ) {
|
|
ri.Error(ERR_DROP, "RB_CheckOverflow: verts > MAX (%d > %d)", verts, SHADER_MAX_VERTEXES );
|
|
}
|
|
if ( indexes >= SHADER_MAX_INDEXES ) {
|
|
ri.Error(ERR_DROP, "RB_CheckOverflow: indices > MAX (%d > %d)", indexes, SHADER_MAX_INDEXES );
|
|
}
|
|
|
|
RB_BeginSurface(tess.shader);
|
|
}
|
|
|
|
|
|
/*
|
|
==============
|
|
RB_AddQuadStampExt
|
|
==============
|
|
*/
|
|
void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, float s1, float t1, float s2, float t2 ) {
|
|
vec3_t normal;
|
|
int ndx;
|
|
|
|
RB_CHECKOVERFLOW( 4, 6 );
|
|
|
|
ndx = tess.numVertexes;
|
|
|
|
// triangle indexes for a simple quad
|
|
tess.indexes[ tess.numIndexes ] = ndx;
|
|
tess.indexes[ tess.numIndexes + 1 ] = ndx + 1;
|
|
tess.indexes[ tess.numIndexes + 2 ] = ndx + 3;
|
|
|
|
tess.indexes[ tess.numIndexes + 3 ] = ndx + 3;
|
|
tess.indexes[ tess.numIndexes + 4 ] = ndx + 1;
|
|
tess.indexes[ tess.numIndexes + 5 ] = ndx + 2;
|
|
|
|
tess.xyz[ndx][0] = origin[0] + left[0] + up[0];
|
|
tess.xyz[ndx][1] = origin[1] + left[1] + up[1];
|
|
tess.xyz[ndx][2] = origin[2] + left[2] + up[2];
|
|
|
|
tess.xyz[ndx+1][0] = origin[0] - left[0] + up[0];
|
|
tess.xyz[ndx+1][1] = origin[1] - left[1] + up[1];
|
|
tess.xyz[ndx+1][2] = origin[2] - left[2] + up[2];
|
|
|
|
tess.xyz[ndx+2][0] = origin[0] - left[0] - up[0];
|
|
tess.xyz[ndx+2][1] = origin[1] - left[1] - up[1];
|
|
tess.xyz[ndx+2][2] = origin[2] - left[2] - up[2];
|
|
|
|
tess.xyz[ndx+3][0] = origin[0] + left[0] - up[0];
|
|
tess.xyz[ndx+3][1] = origin[1] + left[1] - up[1];
|
|
tess.xyz[ndx+3][2] = origin[2] + left[2] - up[2];
|
|
|
|
|
|
// constant normal all the way around
|
|
VectorSubtract( vec3_origin, backEnd.viewParms.ori.axis[0], normal );
|
|
|
|
tess.normal[ndx][0] = tess.normal[ndx+1][0] = tess.normal[ndx+2][0] = tess.normal[ndx+3][0] = normal[0];
|
|
tess.normal[ndx][1] = tess.normal[ndx+1][1] = tess.normal[ndx+2][1] = tess.normal[ndx+3][1] = normal[1];
|
|
tess.normal[ndx][2] = tess.normal[ndx+1][2] = tess.normal[ndx+2][2] = tess.normal[ndx+3][2] = normal[2];
|
|
|
|
// standard square texture coordinates
|
|
tess.texCoords[ndx][0][0] = tess.texCoords[ndx][1][0] = s1;
|
|
tess.texCoords[ndx][0][1] = tess.texCoords[ndx][1][1] = t1;
|
|
|
|
tess.texCoords[ndx+1][0][0] = tess.texCoords[ndx+1][1][0] = s2;
|
|
tess.texCoords[ndx+1][0][1] = tess.texCoords[ndx+1][1][1] = t1;
|
|
|
|
tess.texCoords[ndx+2][0][0] = tess.texCoords[ndx+2][1][0] = s2;
|
|
tess.texCoords[ndx+2][0][1] = tess.texCoords[ndx+2][1][1] = t2;
|
|
|
|
tess.texCoords[ndx+3][0][0] = tess.texCoords[ndx+3][1][0] = s1;
|
|
tess.texCoords[ndx+3][0][1] = tess.texCoords[ndx+3][1][1] = t2;
|
|
|
|
// constant color all the way around
|
|
// should this be identity and let the shader specify from entity?
|
|
* ( unsigned int * ) &tess.vertexColors[ndx] =
|
|
* ( unsigned int * ) &tess.vertexColors[ndx+1] =
|
|
* ( unsigned int * ) &tess.vertexColors[ndx+2] =
|
|
* ( unsigned int * ) &tess.vertexColors[ndx+3] =
|
|
* ( unsigned int * )color;
|
|
|
|
|
|
tess.numVertexes += 4;
|
|
tess.numIndexes += 6;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
RB_AddQuadStamp
|
|
==============
|
|
*/
|
|
void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, byte *color ) {
|
|
RB_AddQuadStampExt( origin, left, up, color, 0, 0, 1, 1 );
|
|
}
|
|
|
|
/*
|
|
==============
|
|
RB_SurfaceSprite
|
|
==============
|
|
*/
|
|
static void RB_SurfaceSprite( void ) {
|
|
vec3_t left, up;
|
|
float radius;
|
|
|
|
// calculate the xyz locations for the four corners
|
|
radius = backEnd.currentEntity->e.radius;
|
|
if ( backEnd.currentEntity->e.rotation == 0 ) {
|
|
VectorScale( backEnd.viewParms.ori.axis[1], radius, left );
|
|
VectorScale( backEnd.viewParms.ori.axis[2], radius, up );
|
|
} else {
|
|
float s, c;
|
|
float ang;
|
|
|
|
ang = M_PI * backEnd.currentEntity->e.rotation / 180;
|
|
s = sin( ang );
|
|
c = cos( ang );
|
|
|
|
VectorScale( backEnd.viewParms.ori.axis[1], c * radius, left );
|
|
VectorMA( left, -s * radius, backEnd.viewParms.ori.axis[2], left );
|
|
|
|
VectorScale( backEnd.viewParms.ori.axis[2], c * radius, up );
|
|
VectorMA( up, s * radius, backEnd.viewParms.ori.axis[1], up );
|
|
}
|
|
if ( backEnd.viewParms.isMirror ) {
|
|
VectorSubtract( vec3_origin, left, left );
|
|
}
|
|
|
|
RB_AddQuadStamp( backEnd.currentEntity->e.origin, left, up, backEnd.currentEntity->e.shaderRGBA );
|
|
}
|
|
|
|
|
|
/*
|
|
=============
|
|
RB_SurfacePolychain
|
|
=============
|
|
*/
|
|
void RB_SurfacePolychain( srfPoly_t *p ) {
|
|
int i;
|
|
int numv;
|
|
|
|
RB_CHECKOVERFLOW( p->numVerts, 3*(p->numVerts - 2) );
|
|
|
|
// fan triangles into the tess array
|
|
numv = tess.numVertexes;
|
|
for ( i = 0; i < p->numVerts; i++ ) {
|
|
VectorCopy( p->verts[i].xyz, tess.xyz[numv] );
|
|
tess.texCoords[numv][0][0] = p->verts[i].st[0];
|
|
tess.texCoords[numv][0][1] = p->verts[i].st[1];
|
|
*(int *)&tess.vertexColors[numv] = *(int *)p->verts[ i ].modulate;
|
|
|
|
numv++;
|
|
}
|
|
|
|
// generate fan indexes into the tess array
|
|
for ( i = 0; i < p->numVerts-2; i++ ) {
|
|
tess.indexes[tess.numIndexes + 0] = tess.numVertexes;
|
|
tess.indexes[tess.numIndexes + 1] = tess.numVertexes + i + 1;
|
|
tess.indexes[tess.numIndexes + 2] = tess.numVertexes + i + 2;
|
|
tess.numIndexes += 3;
|
|
}
|
|
|
|
tess.vertexColorValid = qtrue;
|
|
tess.numVertexes = numv;
|
|
}
|
|
|
|
/*
|
|
=============
|
|
RB_SurfaceMarkFragment
|
|
=============
|
|
*/
|
|
void RB_SurfaceMarkFragment(srfMarkFragment_t* p) {
|
|
int i;
|
|
int numv;
|
|
|
|
RB_CHECKOVERFLOW( p->numVerts, 3*(p->numVerts - 2) );
|
|
|
|
if (p->iIndex <= 0 || R_TerrainHeightForPoly(&tr.world->terraPatches[p->iIndex - 1], p->verts, p->numVerts))
|
|
{
|
|
// FIXME: from here on out, it's mostly the same code as in RB_SurfacePolychain,
|
|
// common part could be extracted into an inline func
|
|
|
|
// fan triangles into the tess array
|
|
numv = tess.numVertexes;
|
|
for ( i = 0; i < p->numVerts; i++ )
|
|
{
|
|
VectorCopy( p->verts[i].xyz, tess.xyz[numv] );
|
|
tess.texCoords[numv][0][0] = p->verts[i].st[0];
|
|
tess.texCoords[numv][0][1] = p->verts[i].st[1];
|
|
*(int *)&tess.vertexColors[numv] = *(int *)p->verts[ i ].modulate;
|
|
|
|
numv++;
|
|
}
|
|
|
|
// generate fan indexes into the tess array
|
|
for ( i = 0; i < p->numVerts - 2; i++ ) {
|
|
tess.indexes[tess.numIndexes + 0] = tess.numVertexes;
|
|
tess.indexes[tess.numIndexes + 1] = tess.numVertexes + i + 1;
|
|
tess.indexes[tess.numIndexes + 2] = tess.numVertexes + i + 2;
|
|
tess.numIndexes += 3;
|
|
}
|
|
|
|
tess.vertexColorValid = qtrue;
|
|
tess.numVertexes = numv;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=============
|
|
RB_SurfaceTriangles
|
|
=============
|
|
*/
|
|
void RB_SurfaceTriangles( srfTriangles_t *srf ) {
|
|
int i;
|
|
drawVert_t *dv;
|
|
float *xyz, *normal, *texCoords;
|
|
byte *color;
|
|
int dlightBits;
|
|
qboolean needsNormal;
|
|
|
|
dlightBits = srf->dlightBits[backEnd.smpFrame];
|
|
tess.dlightBits |= dlightBits;
|
|
|
|
RB_CHECKOVERFLOW( srf->numVerts, srf->numIndexes );
|
|
|
|
for ( i = 0 ; i < srf->numIndexes ; i += 3 ) {
|
|
tess.indexes[ tess.numIndexes + i + 0 ] = tess.numVertexes + srf->indexes[ i + 0 ];
|
|
tess.indexes[ tess.numIndexes + i + 1 ] = tess.numVertexes + srf->indexes[ i + 1 ];
|
|
tess.indexes[ tess.numIndexes + i + 2 ] = tess.numVertexes + srf->indexes[ i + 2 ];
|
|
}
|
|
tess.numIndexes += srf->numIndexes;
|
|
|
|
dv = srf->verts;
|
|
xyz = tess.xyz[ tess.numVertexes ];
|
|
normal = tess.normal[ tess.numVertexes ];
|
|
texCoords = tess.texCoords[ tess.numVertexes ][0];
|
|
color = tess.vertexColors[ tess.numVertexes ];
|
|
needsNormal = tess.shader->needsNormal;
|
|
|
|
for ( i = 0 ; i < srf->numVerts ; i++, dv++, xyz += 4, normal += 4, texCoords += 4, color += 4 ) {
|
|
xyz[0] = dv->xyz[0];
|
|
xyz[1] = dv->xyz[1];
|
|
xyz[2] = dv->xyz[2];
|
|
|
|
if ( needsNormal ) {
|
|
normal[0] = dv->normal[0];
|
|
normal[1] = dv->normal[1];
|
|
normal[2] = dv->normal[2];
|
|
}
|
|
|
|
texCoords[0] = dv->st[0];
|
|
texCoords[1] = dv->st[1];
|
|
|
|
texCoords[2] = dv->lightmap[0];
|
|
texCoords[3] = dv->lightmap[1];
|
|
|
|
*(int *)color = *(int *)dv->color;
|
|
}
|
|
|
|
for ( i = 0 ; i < srf->numVerts ; i++ ) {
|
|
tess.vertexDlightBits[ tess.numVertexes + i] = dlightBits;
|
|
}
|
|
|
|
tess.numVertexes += srf->numVerts;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
==============
|
|
RB_SurfaceBeam
|
|
==============
|
|
*/
|
|
void RB_SurfaceBeam( void )
|
|
{
|
|
#define NUM_BEAM_SEGS 6
|
|
refEntity_t *e;
|
|
int i;
|
|
vec3_t perpvec;
|
|
vec3_t direction, normalized_direction;
|
|
vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];
|
|
vec3_t oldorigin, origin;
|
|
|
|
e = &backEnd.currentEntity->e;
|
|
|
|
oldorigin[0] = e->oldorigin[0];
|
|
oldorigin[1] = e->oldorigin[1];
|
|
oldorigin[2] = e->oldorigin[2];
|
|
|
|
origin[0] = e->origin[0];
|
|
origin[1] = e->origin[1];
|
|
origin[2] = e->origin[2];
|
|
|
|
normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];
|
|
normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];
|
|
normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];
|
|
|
|
if ( VectorNormalize( normalized_direction ) == 0 )
|
|
return;
|
|
|
|
PerpendicularVector( perpvec, normalized_direction );
|
|
|
|
VectorScale( perpvec, 4, perpvec );
|
|
|
|
for ( i = 0; i < NUM_BEAM_SEGS ; i++ )
|
|
{
|
|
RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );
|
|
// VectorAdd( start_points[i], origin, start_points[i] );
|
|
VectorAdd( start_points[i], direction, end_points[i] );
|
|
}
|
|
|
|
GL_Bind( tr.whiteImage );
|
|
|
|
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
|
|
|
|
qglColor3f( 1, 0, 0 );
|
|
|
|
qglBegin( GL_TRIANGLE_STRIP );
|
|
for ( i = 0; i <= NUM_BEAM_SEGS; i++ ) {
|
|
qglVertex3fv( start_points[ i % NUM_BEAM_SEGS] );
|
|
qglVertex3fv( end_points[ i % NUM_BEAM_SEGS] );
|
|
}
|
|
qglEnd();
|
|
}
|
|
|
|
/*
|
|
==============
|
|
RB_SurfaceFace
|
|
==============
|
|
*/
|
|
void RB_SurfaceFace( srfSurfaceFace_t *surf ) {
|
|
int i;
|
|
qboolean needsNormal;
|
|
unsigned *indices, *tessIndexes;
|
|
float *v;
|
|
float *normal;
|
|
int ndx;
|
|
int Bob;
|
|
int numPoints;
|
|
int dlightBits;
|
|
|
|
RB_CHECKOVERFLOW( surf->numPoints, surf->numIndices );
|
|
|
|
dlightBits = surf->dlightBits[backEnd.smpFrame];
|
|
tess.dlightBits |= dlightBits;
|
|
|
|
indices = ( unsigned * ) ( ( ( char * ) surf ) + surf->ofsIndices );
|
|
|
|
Bob = tess.numVertexes;
|
|
tessIndexes = tess.indexes + tess.numIndexes;
|
|
for ( i = surf->numIndices-1 ; i >= 0 ; i-- ) {
|
|
tessIndexes[i] = indices[i] + Bob;
|
|
}
|
|
|
|
tess.numIndexes += surf->numIndices;
|
|
|
|
numPoints = surf->numPoints;
|
|
|
|
needsNormal = qfalse;
|
|
if (tess.shader->needsNormal || tess.shader->needsLSpherical || tr.refdef.num_dlights) {
|
|
needsNormal = qtrue;
|
|
}
|
|
|
|
v = surf->points[0];
|
|
|
|
ndx = tess.numVertexes;
|
|
|
|
if (needsNormal) {
|
|
normal = surf->plane.normal;
|
|
for ( i = 0, ndx = tess.numVertexes; i < numPoints; i++, ndx++ ) {
|
|
VectorCopy( normal, tess.normal[ndx] );
|
|
}
|
|
}
|
|
|
|
if (tess.dlightMap)
|
|
{
|
|
|
|
for (i = 0, v = surf->points[0], ndx = tess.numVertexes; i < numPoints; i++, v += VERTEXSIZE, ndx++) {
|
|
VectorCopy(v, tess.xyz[ndx]);
|
|
tess.texCoords[ndx][0][0] = v[3];
|
|
tess.texCoords[ndx][0][1] = v[4];
|
|
tess.texCoords[ndx][1][0] = v[5] + surf->lightmapOffset[0];
|
|
tess.texCoords[ndx][1][1] = v[6] + surf->lightmapOffset[1];
|
|
*(unsigned int*)&tess.vertexColors[ndx] = *(unsigned int*)&v[7];
|
|
tess.vertexDlightBits[ndx] = dlightBits;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0, v = surf->points[0], ndx = tess.numVertexes; i < numPoints; i++, v += VERTEXSIZE, ndx++) {
|
|
VectorCopy(v, tess.xyz[ndx]);
|
|
tess.texCoords[ndx][0][0] = v[3];
|
|
tess.texCoords[ndx][0][1] = v[4];
|
|
tess.texCoords[ndx][1][0] = v[5];
|
|
tess.texCoords[ndx][1][1] = v[6];
|
|
*(unsigned int*)&tess.vertexColors[ndx] = *(unsigned int*)&v[7];
|
|
tess.vertexDlightBits[ndx] = dlightBits;
|
|
}
|
|
}
|
|
|
|
|
|
tess.numVertexes += surf->numPoints;
|
|
}
|
|
|
|
|
|
static float LodErrorForVolume( vec3_t local, float radius ) {
|
|
vec3_t world;
|
|
float d;
|
|
|
|
// never let it go negative
|
|
if ( r_lodCurveError->value < 0 ) {
|
|
return 0;
|
|
}
|
|
|
|
world[0] = local[0] * backEnd.ori.axis[0][0] + local[1] * backEnd.ori.axis[1][0] +
|
|
local[2] * backEnd.ori.axis[2][0] + backEnd.ori.origin[0];
|
|
world[1] = local[0] * backEnd.ori.axis[0][1] + local[1] * backEnd.ori.axis[1][1] +
|
|
local[2] * backEnd.ori.axis[2][1] + backEnd.ori.origin[1];
|
|
world[2] = local[0] * backEnd.ori.axis[0][2] + local[1] * backEnd.ori.axis[1][2] +
|
|
local[2] * backEnd.ori.axis[2][2] + backEnd.ori.origin[2];
|
|
|
|
VectorSubtract( world, backEnd.viewParms.ori.origin, world );
|
|
d = DotProduct( world, backEnd.viewParms.ori.axis[0] );
|
|
|
|
if ( d < 0 ) {
|
|
d = -d;
|
|
}
|
|
d -= radius;
|
|
if ( d < 1 ) {
|
|
d = 1;
|
|
}
|
|
|
|
return r_lodCurveError->value / d;
|
|
}
|
|
|
|
/*
|
|
=============
|
|
RB_SurfaceGrid
|
|
|
|
Just copy the grid of points and triangulate
|
|
=============
|
|
*/
|
|
void RB_SurfaceGrid( srfGridMesh_t *cv ) {
|
|
int i, j;
|
|
float *xyz;
|
|
float *texCoords;
|
|
float *normal;
|
|
unsigned char *color;
|
|
drawVert_t *dv;
|
|
int rows, irows, vrows;
|
|
int used;
|
|
int widthTable[MAX_GRID_SIZE];
|
|
int heightTable[MAX_GRID_SIZE];
|
|
float lodError;
|
|
int lodWidth, lodHeight;
|
|
int numVertexes;
|
|
int dlightBits;
|
|
int *vDlightBits;
|
|
qboolean needsNormal;
|
|
|
|
dlightBits = cv->dlightBits[backEnd.smpFrame];
|
|
tess.dlightBits |= dlightBits;
|
|
|
|
// determine the allowable discrepance
|
|
lodError = LodErrorForVolume( cv->lodOrigin, cv->lodRadius );
|
|
|
|
// determine which rows and columns of the subdivision
|
|
// we are actually going to use
|
|
widthTable[0] = 0;
|
|
lodWidth = 1;
|
|
for ( i = 1 ; i < cv->width-1 ; i++ ) {
|
|
if ( cv->widthLodError[i] <= lodError ) {
|
|
widthTable[lodWidth] = i;
|
|
lodWidth++;
|
|
}
|
|
}
|
|
widthTable[lodWidth] = cv->width-1;
|
|
lodWidth++;
|
|
|
|
heightTable[0] = 0;
|
|
lodHeight = 1;
|
|
for ( i = 1 ; i < cv->height-1 ; i++ ) {
|
|
if ( cv->heightLodError[i] <= lodError ) {
|
|
heightTable[lodHeight] = i;
|
|
lodHeight++;
|
|
}
|
|
}
|
|
heightTable[lodHeight] = cv->height-1;
|
|
lodHeight++;
|
|
|
|
|
|
// very large grids may have more points or indexes than can be fit
|
|
// in the tess structure, so we may have to issue it in multiple passes
|
|
|
|
used = 0;
|
|
rows = 0;
|
|
while ( used < lodHeight - 1 ) {
|
|
// see how many rows of both verts and indexes we can add without overflowing
|
|
do {
|
|
vrows = ( SHADER_MAX_VERTEXES - tess.numVertexes ) / lodWidth;
|
|
irows = ( SHADER_MAX_INDEXES - tess.numIndexes ) / ( lodWidth * 6 );
|
|
|
|
// if we don't have enough space for at least one strip, flush the buffer
|
|
if ( vrows < 2 || irows < 1 ) {
|
|
RB_EndSurface();
|
|
RB_BeginSurface(tess.shader);
|
|
} else {
|
|
break;
|
|
}
|
|
} while ( 1 );
|
|
|
|
rows = irows;
|
|
if ( vrows < irows + 1 ) {
|
|
rows = vrows - 1;
|
|
}
|
|
if ( used + rows > lodHeight ) {
|
|
rows = lodHeight - used;
|
|
}
|
|
|
|
numVertexes = tess.numVertexes;
|
|
|
|
xyz = tess.xyz[numVertexes];
|
|
normal = tess.normal[numVertexes];
|
|
texCoords = tess.texCoords[numVertexes][0];
|
|
color = ( unsigned char * ) &tess.vertexColors[numVertexes];
|
|
vDlightBits = &tess.vertexDlightBits[numVertexes];
|
|
needsNormal = tess.shader->needsNormal;
|
|
|
|
for ( i = 0 ; i < rows ; i++ ) {
|
|
for ( j = 0 ; j < lodWidth ; j++ ) {
|
|
dv = cv->verts + heightTable[ used + i ] * cv->width
|
|
+ widthTable[ j ];
|
|
|
|
xyz[0] = dv->xyz[0];
|
|
xyz[1] = dv->xyz[1];
|
|
xyz[2] = dv->xyz[2];
|
|
texCoords[0] = dv->st[0];
|
|
texCoords[1] = dv->st[1];
|
|
texCoords[2] = dv->lightmap[0];
|
|
texCoords[3] = dv->lightmap[1];
|
|
if ( needsNormal || tess.shader->needsLSpherical || tr.refdef.num_dlights ) {
|
|
normal[0] = dv->normal[0];
|
|
normal[1] = dv->normal[1];
|
|
normal[2] = dv->normal[2];
|
|
}
|
|
* ( unsigned int * ) color = * ( unsigned int * ) dv->color;
|
|
*vDlightBits++ = dlightBits;
|
|
xyz += 4;
|
|
normal += 4;
|
|
texCoords += 4;
|
|
color += 4;
|
|
}
|
|
}
|
|
|
|
|
|
// add the indexes
|
|
{
|
|
int numIndexes;
|
|
int w, h;
|
|
|
|
h = rows - 1;
|
|
w = lodWidth - 1;
|
|
numIndexes = tess.numIndexes;
|
|
for (i = 0 ; i < h ; i++) {
|
|
for (j = 0 ; j < w ; j++) {
|
|
int v1, v2, v3, v4;
|
|
|
|
// vertex order to be reckognized as tristrips
|
|
v1 = numVertexes + i*lodWidth + j + 1;
|
|
v2 = v1 - 1;
|
|
v3 = v2 + lodWidth;
|
|
v4 = v3 + 1;
|
|
|
|
tess.indexes[numIndexes] = v2;
|
|
tess.indexes[numIndexes+1] = v3;
|
|
tess.indexes[numIndexes+2] = v1;
|
|
|
|
tess.indexes[numIndexes+3] = v1;
|
|
tess.indexes[numIndexes+4] = v3;
|
|
tess.indexes[numIndexes+5] = v4;
|
|
numIndexes += 6;
|
|
}
|
|
}
|
|
|
|
tess.numIndexes = numIndexes;
|
|
}
|
|
|
|
tess.numVertexes += rows * lodWidth;
|
|
|
|
used += rows - 1;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
NULL MODEL
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
/*
|
|
===================
|
|
RB_SurfaceAxis
|
|
|
|
Draws x/y/z lines from the origin for orientation debugging
|
|
===================
|
|
*/
|
|
void RB_SurfaceAxis( void ) {
|
|
GL_Bind( tr.whiteImage );
|
|
qglLineWidth( 3 );
|
|
qglBegin( GL_LINES );
|
|
qglColor3f( 1,0,0 );
|
|
qglVertex3f( 0,0,0 );
|
|
qglVertex3f( 16,0,0 );
|
|
qglColor3f( 0,1,0 );
|
|
qglVertex3f( 0,0,0 );
|
|
qglVertex3f( 0,16,0 );
|
|
qglColor3f( 0,0,1 );
|
|
qglVertex3f( 0,0,0 );
|
|
qglVertex3f( 0,0,16 );
|
|
qglEnd();
|
|
qglLineWidth( 1 );
|
|
}
|
|
|
|
//===========================================================================
|
|
|
|
/*
|
|
====================
|
|
RB_SurfaceEntity
|
|
|
|
Entities that have a single procedurally generated surface
|
|
====================
|
|
*/
|
|
void RB_SurfaceEntity( surfaceType_t *surfType ) {
|
|
switch( backEnd.currentEntity->e.reType ) {
|
|
case RT_SPRITE:
|
|
RB_SurfaceSprite();
|
|
break;
|
|
case RT_BEAM:
|
|
RB_SurfaceBeam();
|
|
break;
|
|
default:
|
|
RB_SurfaceAxis();
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void RB_SurfaceBad( surfaceType_t *surfType ) {
|
|
ri.Printf( PRINT_ALL, "Bad surface tesselated.\n" );
|
|
}
|
|
|
|
#if 0
|
|
|
|
void RB_SurfaceFlare( srfFlare_t *surf ) {
|
|
vec3_t left, up;
|
|
float radius;
|
|
byte color[4];
|
|
vec3_t dir;
|
|
vec3_t origin;
|
|
float d;
|
|
|
|
// calculate the xyz locations for the four corners
|
|
radius = 30;
|
|
VectorScale( backEnd.viewParms.ori.axis[1], radius, left );
|
|
VectorScale( backEnd.viewParms.ori.axis[2], radius, up );
|
|
if ( backEnd.viewParms.isMirror ) {
|
|
VectorSubtract( vec3_origin, left, left );
|
|
}
|
|
|
|
color[0] = color[1] = color[2] = color[3] = 255;
|
|
|
|
VectorMA( surf->origin, 3, surf->normal, origin );
|
|
VectorSubtract( origin, backEnd.viewParms.ori.origin, dir );
|
|
VectorNormalize( dir );
|
|
VectorMA( origin, r_ignore->value, dir, origin );
|
|
|
|
d = -DotProduct( dir, surf->normal );
|
|
if ( d < 0 ) {
|
|
return;
|
|
}
|
|
#if 0
|
|
color[0] *= d;
|
|
color[1] *= d;
|
|
color[2] *= d;
|
|
#endif
|
|
|
|
RB_AddQuadStamp( origin, left, up, color );
|
|
}
|
|
|
|
#else
|
|
|
|
void RB_SurfaceFlare( srfFlare_t *surf ) {
|
|
#if 0
|
|
vec3_t left, up;
|
|
byte color[4];
|
|
|
|
color[0] = surf->color[0] * 255;
|
|
color[1] = surf->color[1] * 255;
|
|
color[2] = surf->color[2] * 255;
|
|
color[3] = 255;
|
|
|
|
VectorClear( left );
|
|
VectorClear( up );
|
|
|
|
left[0] = r_ignore->value;
|
|
|
|
up[1] = r_ignore->value;
|
|
|
|
RB_AddQuadStampExt( surf->origin, left, up, color, 0, 0, 1, 1 );
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void RB_SurfaceDisplayList( srfDisplayList_t *surf ) {
|
|
// all apropriate state must be set in RB_BeginSurface
|
|
// this isn't implemented yet...
|
|
qglCallList( surf->listNum );
|
|
}
|
|
|
|
void RB_SurfaceSkip( void *surf ) {
|
|
}
|
|
|
|
void RB_DrawTerrainTris(srfTerrain_t* p) {
|
|
int i;
|
|
terraInt numv;
|
|
int dlightBits;
|
|
|
|
RB_CHECKOVERFLOW(p->nVerts, p->nTris * 3);
|
|
|
|
dlightBits = p->dlightBits[backEnd.smpFrame];
|
|
tess.dlightBits |= dlightBits;
|
|
if (p->dlightMap[backEnd.smpFrame])
|
|
{
|
|
float lmScale = (1 / 128.0) / p->lmapStep;
|
|
|
|
for (i = p->iVertHead; i; i = g_pVert[i].iNext) {
|
|
assert(tess.numVertexes < SHADER_MAX_VERTEXES);
|
|
|
|
VectorCopy(g_pVert[i].xyz, tess.xyz[tess.numVertexes]);
|
|
tess.texCoords[tess.numVertexes][0][0] = g_pVert[i].texCoords[0][0];
|
|
tess.texCoords[tess.numVertexes][0][1] = g_pVert[i].texCoords[0][1];
|
|
tess.texCoords[tess.numVertexes][1][0] = g_pVert[i].texCoords[1][0] * lmScale + p->lmapX;
|
|
tess.texCoords[tess.numVertexes][1][1] = g_pVert[i].texCoords[1][1] * lmScale + p->lmapY;
|
|
tess.normal[tess.numVertexes][0] = 0;
|
|
tess.normal[tess.numVertexes][1] = 0;
|
|
tess.normal[tess.numVertexes][2] = 1.0;
|
|
tess.vertexColors[tess.numVertexes][0] = -1;
|
|
tess.vertexColors[tess.numVertexes][1] = -1;
|
|
tess.vertexColors[tess.numVertexes][2] = -1;
|
|
tess.vertexColors[tess.numVertexes][3] = -1;
|
|
|
|
g_pVert[i].iVertArray = tess.numVertexes;
|
|
tess.numVertexes++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = p->iVertHead; i; i = g_pVert[i].iNext) {
|
|
assert(tess.numVertexes < SHADER_MAX_VERTEXES);
|
|
|
|
VectorCopy(g_pVert[i].xyz, tess.xyz[tess.numVertexes]);
|
|
tess.texCoords[tess.numVertexes][0][0] = g_pVert[i].texCoords[0][0];
|
|
tess.texCoords[tess.numVertexes][0][1] = g_pVert[i].texCoords[0][1];
|
|
tess.texCoords[tess.numVertexes][1][0] = g_pVert[i].texCoords[1][0];
|
|
tess.texCoords[tess.numVertexes][1][1] = g_pVert[i].texCoords[1][1];
|
|
tess.vertexDlightBits[tess.numVertexes] = dlightBits;
|
|
tess.normal[tess.numVertexes][0] = 0;
|
|
tess.normal[tess.numVertexes][1] = 0;
|
|
tess.normal[tess.numVertexes][2] = 1.0;
|
|
tess.vertexColors[tess.numVertexes][0] = -1;
|
|
tess.vertexColors[tess.numVertexes][1] = -1;
|
|
tess.vertexColors[tess.numVertexes][2] = -1;
|
|
tess.vertexColors[tess.numVertexes][3] = -1;
|
|
|
|
g_pVert[i].iVertArray = tess.numVertexes;
|
|
tess.numVertexes++;
|
|
}
|
|
}
|
|
|
|
for (i = p->iTriHead; i; i = g_pTris[i].iNext)
|
|
{
|
|
assert(tess.numVertexes < SHADER_MAX_INDEXES);
|
|
|
|
//
|
|
// Make sure these can be drawn
|
|
//
|
|
if (g_pTris[i].byConstChecks & 4)
|
|
{
|
|
tess.indexes[tess.numIndexes] = g_pVert[g_pTris[i].iPt[0]].iVertArray;
|
|
tess.indexes[tess.numIndexes + 1] = g_pVert[g_pTris[i].iPt[1]].iVertArray;
|
|
tess.indexes[tess.numIndexes + 2] = g_pVert[g_pTris[i].iPt[2]].iVertArray;
|
|
tess.numIndexes += 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = {
|
|
(void(*)(void*))RB_SurfaceBad, // SF_BAD,
|
|
(void(*)(void*))RB_SurfaceSkip, // SF_SKIP,
|
|
(void(*)(void*))RB_SurfaceFace, // SF_FACE,
|
|
(void(*)(void*))RB_SurfaceGrid, // SF_GRID,
|
|
(void(*)(void*))RB_SurfacePolychain, // SF_POLY,
|
|
(void(*)(void*))RB_SurfaceMarkFragment, // SF_MARK_FRAG
|
|
(void(*)(void*))RB_SurfaceFlare, // SF_FLARE
|
|
(void(*)(void*))RB_SurfaceEntity, // SF_ENTITY
|
|
(void(*)(void*))RB_SurfaceDisplayList, // SF_DISPLAY_LIST
|
|
(void(*)(void*))RB_SkelMesh, // SF_TIKI_SKEL
|
|
(void(*)(void*))RB_StaticMesh, // SF_TIKI_STATIC
|
|
(void(*)(void*))RB_DrawSwipeSurface, // SF_SWIPE
|
|
(void(*)(void*))RB_DrawSprite, // SF_SPRITE
|
|
(void(*)(void*))RB_DrawTerrainTris, // SF_TERRAIN_PATCH
|
|
(void(*)(void*))RB_SurfaceTriangles, // SF_TRIANGLES,
|
|
};
|