2004-08-22 22:29:09 +00:00
# include "quakedef.h"
# include "glquake.h"
# include "shader.h"
# ifdef RGLQUAKE
2004-10-19 16:10:14 +00:00
# define MAX_TEXTURE_UNITS 8
typedef struct {
GLenum currenttextures [ MAX_TEXTURE_UNITS ] ;
GLenum texenvmode [ MAX_TEXTURE_UNITS ] ;
int currenttmu ;
qboolean in2d ;
} gl_state_t ;
gl_state_t gl_state ;
2005-08-26 22:56:51 +00:00
void GL_SetShaderState2D ( qboolean is2d )
{
gl_state . in2d = is2d ;
}
2004-10-19 16:10:14 +00:00
extern int * lightmap_textures ;
2005-01-07 02:54:59 +00:00
extern int * deluxmap_textures ;
2004-10-19 16:10:14 +00:00
void GL_SelectTexture ( GLenum target )
{
gl_state . currenttmu = target - mtexid0 ;
if ( qglClientActiveTextureARB )
{
qglClientActiveTextureARB ( target ) ;
qglActiveTextureARB ( target ) ;
}
else
qglSelectTextureSGIS ( target ) ;
}
2004-12-11 03:44:40 +00:00
void GL_CheckTMUIs0 ( void )
{
if ( gl_state . currenttmu ! = 0 )
{
Con_Printf ( " TMU is not 0 \n " ) ;
GL_SelectTexture ( mtexid0 ) ;
}
}
2004-10-19 16:10:14 +00:00
void GL_MBind ( GLenum target , int texnum )
{
GL_SelectTexture ( target ) ;
2004-11-13 17:31:04 +00:00
if ( gl_state . currenttextures [ gl_state . currenttmu ] = = texnum )
return ;
2004-10-19 16:10:14 +00:00
2004-10-27 23:33:35 +00:00
gl_state . currenttextures [ gl_state . currenttmu ] = texnum ;
2004-10-19 16:10:14 +00:00
bindTexFunc ( GL_TEXTURE_2D , texnum ) ;
}
void GL_Bind ( int texnum )
{
if ( gl_state . currenttextures [ gl_state . currenttmu ] = = texnum )
return ;
2004-12-11 03:44:40 +00:00
2004-10-19 16:10:14 +00:00
gl_state . currenttextures [ gl_state . currenttmu ] = texnum ;
bindTexFunc ( GL_TEXTURE_2D , texnum ) ;
}
void GL_BindType ( int type , int texnum )
{
2004-11-13 17:31:04 +00:00
if ( gl_state . currenttextures [ gl_state . currenttmu ] = = texnum )
return ;
2004-11-29 01:21:00 +00:00
gl_state . currenttextures [ gl_state . currenttmu ] = texnum ;
2004-11-13 17:31:04 +00:00
bindTexFunc ( type , texnum ) ;
2004-10-19 16:10:14 +00:00
}
2004-11-15 12:59:57 +00:00
void GL_TexEnv ( GLenum mode )
{
2004-11-27 08:16:25 +00:00
if ( mode ! = gl_state . texenvmode [ gl_state . currenttmu ] )
2004-11-15 12:59:57 +00:00
{
2004-12-15 19:53:30 +00:00
qglTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , mode ) ;
2004-11-27 08:16:25 +00:00
gl_state . texenvmode [ gl_state . currenttmu ] = mode ;
2004-11-15 12:59:57 +00:00
}
}
2004-10-19 16:10:14 +00:00
//vid restarted.
2004-11-23 01:23:45 +00:00
void GL_FlushBackEnd ( void )
2004-10-19 16:10:14 +00:00
{
int i ;
for ( i = 0 ; i < MAX_TEXTURE_UNITS ; i + + )
{
gl_state . currenttextures [ i ] = - 1 ;
gl_state . texenvmode [ i ] = - 1 ;
}
}
2004-11-18 17:55:04 +00:00
typedef vec3_t mat3_t [ 3 ] ;
2004-10-19 16:10:14 +00:00
# ifndef Q3SHADERS
2004-11-15 12:59:57 +00:00
qboolean varrayactive ;
void R_IBrokeTheArrays ( void )
{
}
2004-08-22 22:29:09 +00:00
2004-10-19 16:10:14 +00:00
void R_BackendInit ( void )
{
}
# else
/*
Copyright ( C ) 2002 - 2003 Victor Luchits
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 .
*/
# define MAX_ARRAY_VERTS 8192
# define MAX_ARRAY_INDEXES 8192
# define MAX_ARRAY_NEIGHBORS 8192
# define MAX_ARRAY_TRIANGLES (8192 / 3)
# define M_TWO_PI (M_PI*2)
cvar_t r_detailtextures = { " r_detailtextures " , " 1 " } ;
cvar_t r_showtris = { " r_showtris " , " 1 " } ;
cvar_t r_shownormals = { " r_shownormals " , " 1 " } ;
float Q_rsqrt ( float number )
{
long i ;
float x2 , y ;
const float threehalfs = 1.5F ;
x2 = number * 0.5F ;
y = number ;
i = * ( long * ) & y ; // evil floating point bit level hacking
i = 0x5f3759df - ( i > > 1 ) ; // what the fuck?
y = * ( float * ) & i ;
y = y * ( threehalfs - ( x2 * y * y ) ) ; // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
return y ;
}
void VectorNormalizeFast ( vec3_t v )
{
float ilength ;
ilength = Q_rsqrt ( DotProduct ( v , v ) ) ;
v [ 0 ] * = ilength ;
v [ 1 ] * = ilength ;
v [ 2 ] * = ilength ;
}
mat3_t axisDefault = { { 1 , 0 , 0 } ,
{ 0 , 1 , 0 } ,
{ 0 , 0 , 1 } } ;
void Matrix3_Transpose ( mat3_t in , mat3_t out )
{
out [ 0 ] [ 0 ] = in [ 0 ] [ 0 ] ;
out [ 1 ] [ 1 ] = in [ 1 ] [ 1 ] ;
out [ 2 ] [ 2 ] = in [ 2 ] [ 2 ] ;
out [ 0 ] [ 1 ] = in [ 1 ] [ 0 ] ;
out [ 0 ] [ 2 ] = in [ 2 ] [ 0 ] ;
out [ 1 ] [ 0 ] = in [ 0 ] [ 1 ] ;
out [ 1 ] [ 2 ] = in [ 2 ] [ 1 ] ;
out [ 2 ] [ 0 ] = in [ 0 ] [ 2 ] ;
out [ 2 ] [ 1 ] = in [ 1 ] [ 2 ] ;
}
void Matrix3_Multiply_Vec3 ( mat3_t a , vec3_t b , vec3_t product )
{
product [ 0 ] = a [ 0 ] [ 0 ] * b [ 0 ] + a [ 0 ] [ 1 ] * b [ 1 ] + a [ 0 ] [ 2 ] * b [ 2 ] ;
product [ 1 ] = a [ 1 ] [ 0 ] * b [ 0 ] + a [ 1 ] [ 1 ] * b [ 1 ] + a [ 1 ] [ 2 ] * b [ 2 ] ;
product [ 2 ] = a [ 2 ] [ 0 ] * b [ 0 ] + a [ 2 ] [ 1 ] * b [ 1 ] + a [ 2 ] [ 2 ] * b [ 2 ] ;
}
int Matrix3_Compare ( mat3_t in , mat3_t out )
{
return memcmp ( in , out , sizeof ( mat3_t ) ) ;
}
extern model_t * currentmodel ;
# define clamp(v,min,max) (v) = (((v)<(min))?(min):(((v)>(max))?(max):(v)))
extern qbyte FloatToByte ( float x ) ;
# define FTABLE_SIZE 1024
# define FTABLE_CLAMP(x) (((int)((x)*FTABLE_SIZE) & (FTABLE_SIZE-1)))
# define FTABLE_EVALUATE(table,x) (table ? table[FTABLE_CLAMP(x)] : frand()*((x)-floor(x)))
static float r_sintable [ FTABLE_SIZE ] ;
static float r_triangletable [ FTABLE_SIZE ] ;
static float r_squaretable [ FTABLE_SIZE ] ;
static float r_sawtoothtable [ FTABLE_SIZE ] ;
static float r_inversesawtoothtable [ FTABLE_SIZE ] ;
index_t * indexesArray ;
int * neighborsArray ;
vec3_t * trNormalsArray ;
vec2_t * coordsArray ;
vec2_t * lightmapCoordsArray ;
2005-05-13 10:42:48 +00:00
vec3_t vertexArray [ MAX_ARRAY_VERTS * 2 ] ;
2004-10-19 16:10:14 +00:00
vec3_t normalsArray [ MAX_ARRAY_VERTS ] ;
2005-05-13 10:42:48 +00:00
vec3_t tempVertexArray [ MAX_ARRAY_VERTS ] ;
2004-10-19 16:10:14 +00:00
vec3_t tempNormalsArray [ MAX_ARRAY_VERTS ] ;
index_t tempIndexesArray [ MAX_ARRAY_INDEXES ] ;
index_t inIndexesArray [ MAX_ARRAY_INDEXES ] ;
int inNeighborsArray [ MAX_ARRAY_NEIGHBORS ] ;
vec3_t inTrNormalsArray [ MAX_ARRAY_TRIANGLES ] ;
vec2_t inCoordsArray [ MAX_ARRAY_VERTS ] ;
vec2_t inLightmapCoordsArray [ MAX_ARRAY_VERTS ] ;
byte_vec4_t inColorsArray [ MAX_ARRAY_VERTS ] ;
static vec2_t tUnitCoordsArray [ MAX_TEXTURE_UNITS ] [ MAX_ARRAY_VERTS ] ;
static byte_vec4_t colorArray [ MAX_ARRAY_VERTS ] ;
int numVerts , numIndexes , numColors ;
qboolean r_arrays_locked ;
qboolean r_blocked ;
int r_features ;
static int r_lmtex ;
static int r_texNums [ SHADER_PASS_MAX ] ;
static int r_numUnits ;
index_t * currentIndex ;
int * currentTrNeighbor ;
float * currentTrNormal ;
float * currentVertex ;
float * currentNormal ;
float * currentCoords ;
float * currentLightmapCoords ;
qbyte * currentColor ;
static int r_identityLighting ;
static float r_localShaderTime ;
unsigned int r_numverts ;
unsigned int r_numtris ;
unsigned int r_numflushes ;
int r_backendStart ;
2005-09-08 22:52:46 +00:00
int r_dlighttexture ;
void R_InitDynamicLightTexture ( void )
{
int x , y ;
int dx2 , dy , d ;
qbyte data [ 64 * 64 * 4 ] ;
//
// dynamic light texture
//
for ( x = 0 ; x < 64 ; x + + )
{
dx2 = x - 32 ;
dx2 = dx2 * dx2 + 8 ;
for ( y = 0 ; y < 64 ; y + + )
{
dy = y - 32 ;
d = ( int ) ( 65536.0f * ( ( 1.0f / ( dx2 + dy * dy + 32.0f ) ) - 0.0005 ) + 0.5f ) ;
if ( d < 50 ) d = 0 ; else if ( d > 255 ) d = 255 ;
data [ ( y * 64 + x ) * 4 + 0 ] = d ;
data [ ( y * 64 + x ) * 4 + 1 ] = d ;
data [ ( y * 64 + x ) * 4 + 2 ] = d ;
data [ ( y * 64 + x ) * 4 + 3 ] = 255 ;
}
}
r_dlighttexture = GL_LoadTexture32 ( " " , 64 , 64 , ( unsigned int * ) data , true , false ) ;
qglTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP ) ;
qglTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP ) ;
}
2004-10-19 16:10:14 +00:00
void R_ResetTexState ( void )
{
coordsArray = inCoordsArray ;
lightmapCoordsArray = inLightmapCoordsArray ;
currentCoords = coordsArray [ 0 ] ;
currentLightmapCoords = lightmapCoordsArray [ 0 ] ;
numColors = 0 ;
currentColor = inColorsArray [ 0 ] ;
}
void R_PushIndexes ( index_t * indexes , int * neighbors , vec3_t * trnormals , int numindexes , int features )
{
int i ;
int numTris ;
// this is a fast path for non-batched geometry, use carefully
// used on pics, sprites, .dpm, .md3 and .md2 models
if ( features & MF_NONBATCHED ) {
if ( numindexes > MAX_ARRAY_INDEXES ) {
numindexes = MAX_ARRAY_INDEXES ;
}
// simply change indexesArray to point at indexes
numIndexes = numindexes ;
indexesArray = indexes ;
currentIndex = indexesArray + numIndexes ;
if ( neighbors ) {
neighborsArray = neighbors ;
currentTrNeighbor = neighborsArray + numIndexes ;
}
if ( trnormals & & ( features & MF_TRNORMALS ) ) {
numTris = numIndexes / 3 ;
trNormalsArray = trnormals ;
currentTrNormal = trNormalsArray [ 0 ] + numTris ;
}
}
else
{
// clamp
if ( numIndexes + numindexes > MAX_ARRAY_INDEXES ) {
numindexes = MAX_ARRAY_INDEXES - numIndexes ;
}
numTris = numindexes / 3 ;
numIndexes + = numindexes ;
// the following code assumes that R_PushIndexes is fed with triangles...
for ( i = 0 ; i < numTris ; i + + , indexes + = 3 , currentIndex + = 3 )
{
currentIndex [ 0 ] = numVerts + indexes [ 0 ] ;
currentIndex [ 1 ] = numVerts + indexes [ 1 ] ;
currentIndex [ 2 ] = numVerts + indexes [ 2 ] ;
if ( neighbors ) {
currentTrNeighbor [ 0 ] = numTris + neighbors [ 0 ] ;
currentTrNeighbor [ 1 ] = numTris + neighbors [ 1 ] ;
currentTrNeighbor [ 2 ] = numTris + neighbors [ 2 ] ;
neighbors + = 3 ;
currentTrNeighbor + = 3 ;
}
if ( trnormals & & ( features & MF_TRNORMALS ) ) {
VectorCopy ( trnormals [ i ] , currentTrNormal ) ;
currentTrNormal + = 3 ;
}
}
}
}
void R_PushMesh ( mesh_t * mesh , int features )
{
int numverts ;
if ( ! mesh - > indexes | | ! mesh - > xyz_array ) {
return ;
}
r_features = features ;
R_PushIndexes ( mesh - > indexes , mesh - > trneighbors , mesh - > trnormals , mesh - > numindexes , features ) ;
numverts = mesh - > numvertexes ;
if ( numVerts + numverts > MAX_ARRAY_VERTS ) {
numverts = MAX_ARRAY_VERTS - numVerts ;
}
2005-05-13 10:42:48 +00:00
memcpy ( currentVertex , mesh - > xyz_array , numverts * sizeof ( vec3_t ) ) ;
currentVertex + = numverts * 3 ;
2004-10-19 16:10:14 +00:00
if ( mesh - > normals_array & & ( features & MF_NORMALS ) ) {
memcpy ( currentNormal , mesh - > normals_array , numverts * sizeof ( vec3_t ) ) ;
currentNormal + = numverts * 3 ;
}
if ( mesh - > st_array & & ( features & MF_STCOORDS ) ) {
if ( features & MF_NONBATCHED ) {
coordsArray = mesh - > st_array ;
currentCoords = coordsArray [ 0 ] ;
} else {
memcpy ( currentCoords , mesh - > st_array , numverts * sizeof ( vec2_t ) ) ;
}
currentCoords + = numverts * 2 ;
}
if ( mesh - > lmst_array & & ( features & MF_LMCOORDS ) ) {
if ( features & MF_NONBATCHED ) {
lightmapCoordsArray = mesh - > lmst_array ;
currentLightmapCoords = lightmapCoordsArray [ 0 ] ;
} else {
memcpy ( currentLightmapCoords , mesh - > lmst_array , numverts * sizeof ( vec2_t ) ) ;
}
currentLightmapCoords + = numverts * 2 ;
}
if ( mesh - > colors_array & & ( features & MF_COLORS ) ) {
memcpy ( currentColor , mesh - > colors_array , numverts * sizeof ( byte_vec4_t ) ) ;
currentColor + = numverts * 4 ;
}
numVerts + = numverts ;
r_numverts + = numverts ;
}
2005-05-13 10:42:48 +00:00
qboolean R_MeshWillExceed ( mesh_t * mesh )
{
if ( numVerts + mesh - > numvertexes > MAX_ARRAY_VERTS )
return true ;
if ( numIndexes + mesh - > numindexes > MAX_ARRAY_INDEXES )
return true ;
return false ;
}
2004-10-19 16:10:14 +00:00
extern index_t r_quad_indexes [ 6 ] ; // = { 0, 1, 2, 0, 2, 3 };
void R_FinishMeshBuffer ( meshbuffer_t * mb ) ;
static float frand ( void )
{
return ( rand ( ) & 32767 ) * ( 1.0 / 32767 ) ;
}
2004-10-26 23:06:29 +00:00
//static float crand(void)
//{
// return (rand()&32767)* (2.0/32767) - 1;
//}
2004-10-19 16:10:14 +00:00
/*
= = = = = = = = = = = = = =
R_BackendInit
= = = = = = = = = = = = = =
*/
2004-11-13 17:31:04 +00:00
void R_IBrokeTheArrays ( void ) ;
2004-10-19 16:10:14 +00:00
void R_BackendInit ( void )
{
int i ;
double t ;
numVerts = 0 ;
numIndexes = 0 ;
numColors = 0 ;
indexesArray = inIndexesArray ;
currentIndex = indexesArray ;
neighborsArray = inNeighborsArray ;
trNormalsArray = inTrNormalsArray ;
coordsArray = inCoordsArray ;
lightmapCoordsArray = inLightmapCoordsArray ;
currentTrNeighbor = neighborsArray ;
currentTrNormal = trNormalsArray [ 0 ] ;
currentVertex = vertexArray [ 0 ] ;
currentNormal = normalsArray [ 0 ] ;
currentCoords = coordsArray [ 0 ] ;
currentLightmapCoords = lightmapCoordsArray [ 0 ] ;
currentColor = inColorsArray [ 0 ] ;
r_arrays_locked = false ;
r_blocked = false ;
2004-11-13 17:31:04 +00:00
R_IBrokeTheArrays ( ) ;
2004-10-19 16:10:14 +00:00
//FIZME: FTE already has some stuff along these lines, surly...
// if ( !r_ignorehwgamma->value )
// r_identityLighting = (int)(255.0f / pow(2, max(0, floor(r_overbrightbits->value))));
// else
r_identityLighting = 255 ;
for ( i = 0 ; i < FTABLE_SIZE ; i + + ) {
t = ( double ) i / ( double ) FTABLE_SIZE ;
r_sintable [ i ] = sin ( t * M_TWO_PI ) ;
if ( t < 0.25 )
r_triangletable [ i ] = t * 4.0 ;
else if ( t < 0.75 )
r_triangletable [ i ] = 2 - 4.0 * t ;
else
r_triangletable [ i ] = ( t - 0.75 ) * 4.0 - 1.0 ;
if ( t < 0.5 )
r_squaretable [ i ] = 1.0f ;
else
r_squaretable [ i ] = - 1.0f ;
r_sawtoothtable [ i ] = t ;
r_inversesawtoothtable [ i ] = 1.0 - t ;
}
2005-09-08 22:52:46 +00:00
R_InitDynamicLightTexture ( ) ;
2004-10-19 16:10:14 +00:00
}
2004-11-13 17:31:04 +00:00
qboolean varrayactive ;
2004-10-19 16:10:14 +00:00
void R_IBrokeTheArrays ( void )
{
2004-11-13 17:31:04 +00:00
varrayactive = true ;
2005-05-13 10:42:48 +00:00
qglVertexPointer ( 3 , GL_FLOAT , 0 , vertexArray ) ;
2004-10-19 16:10:14 +00:00
qglColorPointer ( 4 , GL_UNSIGNED_BYTE , 0 , colorArray ) ;
qglEnableClientState ( GL_VERTEX_ARRAY ) ;
}
/*
= = = = = = = = = = = = = =
R_BackendShutdown
= = = = = = = = = = = = = =
*/
void R_BackendShutdown ( void )
{
}
/*
= = = = = = = = = = = = = =
R_FastSin
= = = = = = = = = = = = = =
*/
float R_FastSin ( float t )
{
return r_sintable [ FTABLE_CLAMP ( t ) ] ;
}
/*
= = = = = = = = = = = = = =
R_TableForFunc
= = = = = = = = = = = = = =
*/
static float * R_TableForFunc ( unsigned int func )
{
switch ( func )
{
case SHADER_FUNC_SIN :
return r_sintable ;
case SHADER_FUNC_TRIANGLE :
return r_triangletable ;
case SHADER_FUNC_SQUARE :
return r_squaretable ;
case SHADER_FUNC_SAWTOOTH :
return r_sawtoothtable ;
case SHADER_FUNC_INVERSESAWTOOTH :
return r_inversesawtoothtable ;
}
// assume noise
return NULL ;
}
/*
= = = = = = = = = = = = = =
R_BackendStartFrame
= = = = = = = = = = = = = =
*/
void R_BackendStartFrame ( void )
{
r_numverts = 0 ;
r_numtris = 0 ;
r_numflushes = 0 ;
// r_backendStart = Sys_Milliseconds();
}
/*
= = = = = = = = = = = = = =
R_BackendEndFrame
= = = = = = = = = = = = = =
*/
void R_BackendEndFrame ( void )
{
if ( r_speeds . value )
{
Con_Printf ( " %4i wpoly %4i leafs %4i verts %4i tris %4i flushes \n " ,
c_brush_polys ,
0 /*c_world_leafs*/ ,
r_numverts ,
r_numtris ,
r_numflushes ) ;
}
// time_backend = Sys_Milliseconds() - r_backendStart;
// r_backendStart = 0;
}
/*
= = = = = = = = = = = = = =
R_LockArrays
= = = = = = = = = = = = = =
*/
void R_LockArrays ( int numverts )
{
if ( r_arrays_locked )
return ;
if ( qglLockArraysEXT ! = 0 ) {
qglLockArraysEXT ( 0 , numverts ) ;
r_arrays_locked = true ;
}
}
/*
= = = = = = = = = = = = = =
R_UnlockArrays
= = = = = = = = = = = = = =
*/
void R_UnlockArrays ( void )
{
if ( ! r_arrays_locked )
return ;
if ( qglUnlockArraysEXT ! = 0 ) {
qglUnlockArraysEXT ( ) ;
r_arrays_locked = false ;
}
}
/*
= = = = = = = = = = = = = =
R_DrawTriangleStrips
This function looks for and sends tristrips .
Original code by Stephen C . Taylor ( Aftershock 3 D rendering engine )
= = = = = = = = = = = = = =
*/
void R_DrawTriangleStrips ( index_t * indexes , int numindexes )
{
int toggle ;
index_t a , b , c , * index ;
c = 0 ;
index = indexes ;
while ( c < numindexes ) {
toggle = 1 ;
qglBegin ( GL_TRIANGLE_STRIP ) ;
qglArrayElement ( index [ 0 ] ) ;
qglArrayElement ( b = index [ 1 ] ) ;
qglArrayElement ( a = index [ 2 ] ) ;
c + = 3 ;
index + = 3 ;
while ( c < numindexes ) {
if ( a ! = index [ 0 ] | | b ! = index [ 1 ] ) {
break ;
}
if ( toggle ) {
qglArrayElement ( b = index [ 2 ] ) ;
} else {
qglArrayElement ( a = index [ 2 ] ) ;
}
c + = 3 ;
index + = 3 ;
toggle = ! toggle ;
}
qglEnd ( ) ;
}
}
/*
= = = = = = = = = = = = = =
R_ClearArrays
= = = = = = = = = = = = = =
*/
void R_ClearArrays ( void )
{
numVerts = 0 ;
numIndexes = 0 ;
indexesArray = inIndexesArray ;
currentIndex = indexesArray ;
neighborsArray = inNeighborsArray ;
trNormalsArray = inTrNormalsArray ;
currentTrNeighbor = neighborsArray ;
currentTrNormal = trNormalsArray [ 0 ] ;
currentVertex = vertexArray [ 0 ] ;
currentNormal = normalsArray [ 0 ] ;
R_ResetTexState ( ) ;
r_blocked = false ;
}
/*
= = = = = = = = = = = = = =
R_FlushArrays
= = = = = = = = = = = = = =
*/
void R_FlushArrays ( void )
{
if ( ! numVerts | | ! numIndexes ) {
return ;
}
if ( numColors > 1 ) {
qglEnableClientState ( GL_COLOR_ARRAY ) ;
} else if ( numColors = = 1 ) {
qglColor4ubv ( colorArray [ 0 ] ) ;
}
qglEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
if ( ! r_arrays_locked ) {
R_DrawTriangleStrips ( indexesArray , numIndexes ) ;
} else {
qglDrawElements ( GL_TRIANGLES , numIndexes , GL_UNSIGNED_INT , indexesArray ) ;
}
r_numtris + = numIndexes / 3 ;
qglDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
if ( numColors > 1 ) {
qglDisableClientState ( GL_COLOR_ARRAY ) ;
}
r_numflushes + + ;
}
/*
= = = = = = = = = = = = = =
R_FlushArraysMtex
= = = = = = = = = = = = = =
*/
void R_FlushArraysMtex ( void )
{
int i ;
if ( ! numVerts | | ! numIndexes ) {
return ;
}
if ( numColors > 1 ) {
qglEnableClientState ( GL_COLOR_ARRAY ) ;
} else if ( numColors = = 1 ) {
qglColor4ubv ( colorArray [ 0 ] ) ;
}
2005-06-04 04:20:20 +00:00
GL_MBind ( mtexid0 , r_texNums [ 0 ] ) ;
qglEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
2004-10-19 16:10:14 +00:00
for ( i = 1 ; i < r_numUnits ; i + + )
{
GL_MBind ( mtexid0 + i , r_texNums [ i ] ) ;
qglEnable ( GL_TEXTURE_2D ) ;
qglEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
}
if ( ! r_arrays_locked ) {
R_DrawTriangleStrips ( indexesArray , numIndexes ) ;
} else {
qglDrawElements ( GL_TRIANGLES , numIndexes , GL_UNSIGNED_INT , indexesArray ) ;
}
r_numtris + = numIndexes / 3 ;
for ( i = r_numUnits - 1 ; i > = 0 ; i - - )
{
GL_SelectTexture ( mtexid0 + i ) ;
if ( i ) {
qglDisable ( GL_TEXTURE_2D ) ;
}
qglDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
}
if ( numColors > 1 ) {
qglDisableClientState ( GL_COLOR_ARRAY ) ;
}
r_numflushes + + ;
}
/*
= = = = = = = = = = = = = = = =
R_DeformVertices
= = = = = = = = = = = = = = = =
*/
void R_DeformVertices ( meshbuffer_t * mb )
{
int i , j , k , pw , ph , p ;
float args [ 4 ] , deflect ;
float * quad [ 4 ] , * table ;
shader_t * shader ;
deformv_t * deformv ;
vec3_t tv , rot_centre ;
shader = mb - > shader ;
deformv = & shader - > deforms [ 0 ] ;
for ( i = 0 ; i < shader - > numdeforms ; i + + , deformv + + )
{
switch ( deformv - > type )
{
case DEFORMV_NONE :
break ;
case DEFORMV_WAVE :
args [ 0 ] = deformv - > func . args [ 0 ] ;
args [ 1 ] = deformv - > func . args [ 1 ] ;
args [ 3 ] = deformv - > func . args [ 2 ] + deformv - > func . args [ 3 ] * r_localShaderTime ;
table = R_TableForFunc ( deformv - > func . type ) ;
for ( j = 0 ; j < numVerts ; j + + ) {
deflect = deformv - > args [ 0 ] * ( vertexArray [ j ] [ 0 ] + vertexArray [ j ] [ 1 ] + vertexArray [ j ] [ 2 ] ) + args [ 3 ] ;
deflect = FTABLE_EVALUATE ( table , deflect ) * args [ 1 ] + args [ 0 ] ;
// Deflect vertex along its normal by wave amount
VectorMA ( vertexArray [ j ] , deflect , normalsArray [ j ] , vertexArray [ j ] ) ;
}
break ;
case DEFORMV_NORMAL :
args [ 0 ] = deformv - > args [ 1 ] * r_localShaderTime ;
for ( j = 0 ; j < numVerts ; j + + ) {
args [ 1 ] = normalsArray [ j ] [ 2 ] * args [ 0 ] ;
deflect = deformv - > args [ 0 ] * R_FastSin ( args [ 1 ] ) ;
normalsArray [ j ] [ 0 ] * = deflect ;
deflect = deformv - > args [ 0 ] * R_FastSin ( args [ 1 ] + 0.25 ) ;
normalsArray [ j ] [ 1 ] * = deflect ;
VectorNormalizeFast ( normalsArray [ j ] ) ;
}
break ;
case DEFORMV_MOVE :
table = R_TableForFunc ( deformv - > func . type ) ;
deflect = deformv - > func . args [ 2 ] + r_localShaderTime * deformv - > func . args [ 3 ] ;
deflect = FTABLE_EVALUATE ( table , deflect ) * deformv - > func . args [ 1 ] + deformv - > func . args [ 0 ] ;
for ( j = 0 ; j < numVerts ; j + + )
VectorMA ( vertexArray [ j ] , deflect , deformv - > args , vertexArray [ j ] ) ;
break ;
case DEFORMV_BULGE :
pw = mb - > mesh - > patchWidth ;
ph = mb - > mesh - > patchHeight ;
args [ 0 ] = deformv - > args [ 0 ] / ( float ) ph ;
args [ 1 ] = deformv - > args [ 1 ] ;
args [ 2 ] = r_localShaderTime / ( deformv - > args [ 2 ] * pw ) ;
for ( k = 0 , p = 0 ; k < ph ; k + + ) {
deflect = R_FastSin ( ( float ) k * args [ 0 ] + args [ 2 ] ) * args [ 1 ] ;
for ( j = 0 ; j < pw ; j + + , p + + )
VectorMA ( vertexArray [ p ] , deflect , normalsArray [ p ] , vertexArray [ p ] ) ;
}
break ;
case DEFORMV_AUTOSPRITE :
if ( numIndexes < 6 )
break ;
for ( k = 0 ; k < numIndexes ; k + = 6 )
{
mat3_t m0 , m1 , result ;
quad [ 0 ] = ( float * ) ( vertexArray + indexesArray [ k + 0 ] ) ;
quad [ 1 ] = ( float * ) ( vertexArray + indexesArray [ k + 1 ] ) ;
quad [ 2 ] = ( float * ) ( vertexArray + indexesArray [ k + 2 ] ) ;
for ( j = 2 ; j > = 0 ; j - - ) {
quad [ 3 ] = ( float * ) ( vertexArray + indexesArray [ k + 3 + j ] ) ;
if ( ! VectorCompare ( quad [ 3 ] , quad [ 0 ] ) & &
! VectorCompare ( quad [ 3 ] , quad [ 1 ] ) & &
! VectorCompare ( quad [ 3 ] , quad [ 2 ] ) ) {
break ;
}
}
VectorSubtract ( quad [ 0 ] , quad [ 1 ] , m0 [ 0 ] ) ;
VectorSubtract ( quad [ 2 ] , quad [ 1 ] , m0 [ 1 ] ) ;
CrossProduct ( m0 [ 0 ] , m0 [ 1 ] , m0 [ 2 ] ) ;
VectorNormalizeFast ( m0 [ 2 ] ) ;
VectorVectors ( m0 [ 2 ] , m0 [ 1 ] , m0 [ 0 ] ) ;
2005-07-01 19:23:00 +00:00
VectorCopy ( ( & r_view_matrix [ 0 ] ) , m1 [ 0 ] ) ;
VectorCopy ( ( & r_view_matrix [ 4 ] ) , m1 [ 1 ] ) ;
VectorCopy ( ( & r_view_matrix [ 8 ] ) , m1 [ 2 ] ) ;
2004-10-19 16:10:14 +00:00
Matrix3_Multiply ( m1 , m0 , result ) ;
for ( j = 0 ; j < 3 ; j + + )
rot_centre [ j ] = ( quad [ 0 ] [ j ] + quad [ 1 ] [ j ] + quad [ 2 ] [ j ] + quad [ 3 ] [ j ] ) * 0.25 + currententity - > origin [ j ] ;
for ( j = 0 ; j < 4 ; j + + ) {
VectorSubtract ( quad [ j ] , rot_centre , tv ) ;
Matrix3_Multiply_Vec3 ( result , tv , quad [ j ] ) ;
VectorAdd ( rot_centre , quad [ j ] , quad [ j ] ) ;
}
}
break ;
case DEFORMV_AUTOSPRITE2 :
if ( numIndexes < 6 )
break ;
for ( k = 0 ; k < numIndexes ; k + = 6 )
{
int long_axis , short_axis ;
vec3_t axis ;
float len [ 3 ] ;
mat3_t m0 , m1 , m2 , result ;
quad [ 0 ] = ( float * ) ( vertexArray + indexesArray [ k + 0 ] ) ;
quad [ 1 ] = ( float * ) ( vertexArray + indexesArray [ k + 1 ] ) ;
quad [ 2 ] = ( float * ) ( vertexArray + indexesArray [ k + 2 ] ) ;
for ( j = 2 ; j > = 0 ; j - - ) {
quad [ 3 ] = ( float * ) ( vertexArray + indexesArray [ k + 3 + j ] ) ;
if ( ! VectorCompare ( quad [ 3 ] , quad [ 0 ] ) & &
! VectorCompare ( quad [ 3 ] , quad [ 1 ] ) & &
! VectorCompare ( quad [ 3 ] , quad [ 2 ] ) ) {
break ;
}
}
// build a matrix were the longest axis of the billboard is the Y-Axis
VectorSubtract ( quad [ 1 ] , quad [ 0 ] , m0 [ 0 ] ) ;
VectorSubtract ( quad [ 2 ] , quad [ 0 ] , m0 [ 1 ] ) ;
VectorSubtract ( quad [ 2 ] , quad [ 1 ] , m0 [ 2 ] ) ;
len [ 0 ] = DotProduct ( m0 [ 0 ] , m0 [ 0 ] ) ;
len [ 1 ] = DotProduct ( m0 [ 1 ] , m0 [ 1 ] ) ;
len [ 2 ] = DotProduct ( m0 [ 2 ] , m0 [ 2 ] ) ;
if ( ( len [ 2 ] > len [ 1 ] ) & & ( len [ 2 ] > len [ 0 ] ) )
{
if ( len [ 1 ] > len [ 0 ] )
{
long_axis = 1 ;
short_axis = 0 ;
}
else
{
long_axis = 0 ;
short_axis = 1 ;
}
}
else if ( ( len [ 1 ] > len [ 2 ] ) & & ( len [ 1 ] > len [ 0 ] ) )
{
if ( len [ 2 ] > len [ 0 ] )
{
long_axis = 2 ;
short_axis = 0 ;
}
else
{
long_axis = 0 ;
short_axis = 2 ;
}
}
2004-10-26 23:06:29 +00:00
else //if ( (len[0] > len[1]) && (len[0] > len[2]) )
2004-10-19 16:10:14 +00:00
{
if ( len [ 2 ] > len [ 1 ] )
{
long_axis = 2 ;
short_axis = 1 ;
}
else
{
long_axis = 1 ;
short_axis = 2 ;
}
}
if ( DotProduct ( m0 [ long_axis ] , m0 [ short_axis ] ) ) {
VectorNormalize2 ( m0 [ long_axis ] , axis ) ;
VectorCopy ( axis , m0 [ 1 ] ) ;
if ( axis [ 0 ] | | axis [ 1 ] ) {
VectorVectors ( m0 [ 1 ] , m0 [ 2 ] , m0 [ 0 ] ) ;
} else {
VectorVectors ( m0 [ 1 ] , m0 [ 0 ] , m0 [ 2 ] ) ;
}
} else {
VectorNormalize2 ( m0 [ long_axis ] , axis ) ;
VectorNormalize2 ( m0 [ short_axis ] , m0 [ 0 ] ) ;
VectorCopy ( axis , m0 [ 1 ] ) ;
CrossProduct ( m0 [ 0 ] , m0 [ 1 ] , m0 [ 2 ] ) ;
}
for ( j = 0 ; j < 3 ; j + + )
rot_centre [ j ] = ( quad [ 0 ] [ j ] + quad [ 1 ] [ j ] + quad [ 2 ] [ j ] + quad [ 3 ] [ j ] ) * 0.25 ;
if ( currententity ) {
VectorAdd ( currententity - > origin , rot_centre , tv ) ;
} else {
VectorCopy ( rot_centre , tv ) ;
}
VectorSubtract ( r_origin , tv , tv ) ;
// filter any longest-axis-parts off the camera-direction
deflect = - DotProduct ( tv , axis ) ;
VectorMA ( tv , deflect , axis , m1 [ 2 ] ) ;
VectorNormalizeFast ( m1 [ 2 ] ) ;
VectorCopy ( axis , m1 [ 1 ] ) ;
CrossProduct ( m1 [ 1 ] , m1 [ 2 ] , m1 [ 0 ] ) ;
Matrix3_Transpose ( m1 , m2 ) ;
Matrix3_Multiply ( m2 , m0 , result ) ;
for ( j = 0 ; j < 4 ; j + + ) {
VectorSubtract ( quad [ j ] , rot_centre , tv ) ;
Matrix3_Multiply_Vec3 ( result , tv , quad [ j ] ) ;
VectorAdd ( rot_centre , quad [ j ] , quad [ j ] ) ;
}
}
break ;
case DEFORMV_PROJECTION_SHADOW :
break ;
default :
break ;
}
}
}
2005-08-26 22:56:51 +00:00
void RB_CalcEnvironmentTexCoords ( float * st )
{
int i ;
float * v , * normal ;
vec3_t viewer , reflected ;
float d ;
v = vertexArray [ 0 ] ;
normal = normalsArray [ 0 ] ;
for ( i = 0 ; i < numVerts ; i + + , v + = 3 , normal + = 3 , st + = 2 )
{
VectorSubtract ( r_origin , v , viewer ) ;
VectorNormalizeFast ( viewer ) ;
d = DotProduct ( normal , viewer ) ;
reflected [ 0 ] = normal [ 0 ] * 2 * d - viewer [ 0 ] ;
reflected [ 1 ] = normal [ 1 ] * 2 * d - viewer [ 1 ] ;
reflected [ 2 ] = normal [ 2 ] * 2 * d - viewer [ 2 ] ;
st [ 0 ] = 0.5 + reflected [ 1 ] * 0.5 ;
st [ 1 ] = 0.5 - reflected [ 2 ] * 0.5 ;
}
}
2004-10-19 16:10:14 +00:00
/*
= = = = = = = = = = = = = =
R_VertexTCBase
= = = = = = = = = = = = = =
*/
void R_VertexTCBase ( int tcgen , int unit )
{
int i ;
2005-08-26 22:56:51 +00:00
// vec3_t t, n;
2004-10-19 16:10:14 +00:00
float * outCoords ;
2005-08-26 22:56:51 +00:00
// vec3_t transform;
// mat3_t inverse_axis;
// mat3_t axis;
2004-10-19 16:10:14 +00:00
outCoords = tUnitCoordsArray [ unit ] [ 0 ] ;
qglTexCoordPointer ( 2 , GL_FLOAT , 0 , outCoords ) ;
if ( tcgen = = TC_GEN_BASE )
{
memcpy ( outCoords , coordsArray [ 0 ] , sizeof ( float ) * 2 * numVerts ) ;
} else if ( tcgen = = TC_GEN_LIGHTMAP )
{
memcpy ( outCoords , lightmapCoordsArray [ 0 ] , sizeof ( float ) * 2 * numVerts ) ;
}
else if ( tcgen = = TC_GEN_ENVIRONMENT )
{
2005-08-26 22:56:51 +00:00
RB_CalcEnvironmentTexCoords ( outCoords ) ; //use genuine q3 code, to get it totally identical
//plus, it looks like less overhead too
//I guess it depends on the size of the mesh
/*
//the old qfusion code
2004-10-19 16:10:14 +00:00
if ( ! currentmodel )
{
VectorSubtract ( vec3_origin , currententity - > origin , transform ) ;
AngleVectors ( currententity - > angles , axis [ 0 ] , axis [ 1 ] , axis [ 2 ] ) ;
Matrix3_Transpose ( axis , inverse_axis ) ;
}
else if ( currentmodel = = cl . worldmodel )
{
VectorSubtract ( vec3_origin , r_origin , transform ) ;
}
else if ( currentmodel - > type = = mod_brush )
{
VectorNegate ( currententity - > origin , t ) ;
VectorSubtract ( t , r_origin , transform ) ;
AngleVectors ( currententity - > angles , axis [ 0 ] , axis [ 1 ] , axis [ 2 ] ) ;
Matrix3_Transpose ( axis , inverse_axis ) ;
}
else
{
VectorSubtract ( vec3_origin , currententity - > origin , transform ) ;
AngleVectors ( currententity - > angles , axis [ 0 ] , axis [ 1 ] , axis [ 2 ] ) ;
Matrix3_Transpose ( axis , inverse_axis ) ;
}
for ( i = 0 ; i < numVerts ; i + + , outCoords + = 2 )
{
VectorAdd ( vertexArray [ i ] , transform , t ) ;
// project vector
if ( currentmodel & & ( currentmodel = = cl . worldmodel ) )
{
n [ 0 ] = normalsArray [ i ] [ 0 ] ;
n [ 1 ] = normalsArray [ i ] [ 1 ] ;
n [ 2 ] = Q_rsqrt ( DotProduct ( t , t ) ) ;
}
else
{
n [ 0 ] = DotProduct ( normalsArray [ i ] , inverse_axis [ 0 ] ) ;
n [ 1 ] = DotProduct ( normalsArray [ i ] , inverse_axis [ 1 ] ) ;
n [ 2 ] = Q_rsqrt ( DotProduct ( t , t ) ) ;
}
outCoords [ 0 ] = t [ 0 ] * n [ 2 ] - n [ 0 ] ;
outCoords [ 1 ] = t [ 1 ] * n [ 2 ] - n [ 1 ] ;
}
2005-08-26 22:56:51 +00:00
*/
2004-10-19 16:10:14 +00:00
}
else if ( tcgen = = TC_GEN_VECTOR )
{
for ( i = 0 ; i < numVerts ; i + + , outCoords + = 2 )
{
static vec3_t tc_gen_s = { 1.0f , 0.0f , 0.0f } ;
static vec3_t tc_gen_t = { 0.0f , 1.0f , 0.0f } ;
outCoords [ 0 ] = DotProduct ( tc_gen_s , vertexArray [ i ] ) ;
outCoords [ 1 ] = DotProduct ( tc_gen_t , vertexArray [ i ] ) ;
}
}
}
/*
= = = = = = = = = = = = = =
R_ShaderpassTex
= = = = = = = = = = = = = =
*/
int R_ShaderpassTex ( shaderpass_t * pass )
{
2005-08-26 22:56:51 +00:00
if ( pass - > flags & ( SHADER_PASS_ANIMMAP | SHADER_PASS_LIGHTMAP | SHADER_PASS_DELUXMAP ) )
2004-10-19 16:10:14 +00:00
{
2005-08-26 22:56:51 +00:00
if ( pass - > flags & SHADER_PASS_ANIMMAP ) {
return pass - > anim_frames [ ( int ) ( pass - > anim_fps * r_localShaderTime ) % pass - > anim_numframes ] ;
}
else if ( ( pass - > flags & SHADER_PASS_LIGHTMAP ) & & r_lmtex > = 0 )
{
return lightmap_textures [ r_lmtex ] ;
}
else if ( ( pass - > flags & SHADER_PASS_DELUXMAP ) & & r_lmtex > = 0 )
{
return deluxmap_textures [ r_lmtex ] ;
}
2005-01-07 02:54:59 +00:00
}
2004-10-19 16:10:14 +00:00
return pass - > anim_frames [ 0 ] ? pass - > anim_frames [ 0 ] : 0 ;
}
/*
= = = = = = = = = = = = = = = =
R_ModifyTextureCoords
= = = = = = = = = = = = = = = =
*/
void R_ModifyTextureCoords ( shaderpass_t * pass , int unit )
{
int i , j ;
float * table ;
float t1 , t2 , sint , cost ;
float * tcArray ;
tcmod_t * tcmod ;
r_texNums [ unit ] = R_ShaderpassTex ( pass ) ;
// we're smart enough not to copy data and simply switch the pointer
if ( ! pass - > numtcmods ) {
if ( pass - > tcgen = = TC_GEN_BASE ) {
qglTexCoordPointer ( 2 , GL_FLOAT , 0 , coordsArray ) ;
} else if ( pass - > tcgen = = TC_GEN_LIGHTMAP ) {
qglTexCoordPointer ( 2 , GL_FLOAT , 0 , lightmapCoordsArray ) ;
} else {
R_VertexTCBase ( pass - > tcgen , unit ) ;
}
return ;
}
R_VertexTCBase ( pass - > tcgen , unit ) ;
for ( i = 0 , tcmod = pass - > tcmods ; i < pass - > numtcmods ; i + + , tcmod + + )
{
tcArray = tUnitCoordsArray [ unit ] [ 0 ] ;
switch ( tcmod - > type )
{
case SHADER_TCMOD_ROTATE :
cost = tcmod - > args [ 0 ] * r_localShaderTime ;
sint = R_FastSin ( cost ) ;
cost = R_FastSin ( cost + 0.25 ) ;
for ( j = 0 ; j < numVerts ; j + + , tcArray + = 2 ) {
t1 = cost * ( tcArray [ 0 ] - 0.5f ) - sint * ( tcArray [ 1 ] - 0.5f ) + 0.5f ;
t2 = cost * ( tcArray [ 1 ] - 0.5f ) + sint * ( tcArray [ 0 ] - 0.5f ) + 0.5f ;
tcArray [ 0 ] = t1 ;
tcArray [ 1 ] = t2 ;
}
break ;
case SHADER_TCMOD_SCALE :
t1 = tcmod - > args [ 0 ] ;
t2 = tcmod - > args [ 1 ] ;
for ( j = 0 ; j < numVerts ; j + + , tcArray + = 2 ) {
tcArray [ 0 ] = tcArray [ 0 ] * t1 ;
tcArray [ 1 ] = tcArray [ 1 ] * t2 ;
}
break ;
case SHADER_TCMOD_TURB :
t1 = tcmod - > args [ 2 ] + r_localShaderTime * tcmod - > args [ 3 ] ;
t2 = tcmod - > args [ 1 ] ;
for ( j = 0 ; j < numVerts ; j + + , tcArray + = 2 ) {
tcArray [ 0 ] = tcArray [ 0 ] + R_FastSin ( tcArray [ 0 ] * t2 + t1 ) * t2 ;
tcArray [ 1 ] = tcArray [ 1 ] + R_FastSin ( tcArray [ 1 ] * t2 + t1 ) * t2 ;
}
break ;
case SHADER_TCMOD_STRETCH :
table = R_TableForFunc ( tcmod - > args [ 0 ] ) ;
t2 = tcmod - > args [ 3 ] + r_localShaderTime * tcmod - > args [ 4 ] ;
t1 = FTABLE_EVALUATE ( table , t2 ) * tcmod - > args [ 2 ] + tcmod - > args [ 1 ] ;
t1 = t1 ? 1.0f / t1 : 1.0f ;
t2 = 0.5f - 0.5f * t1 ;
for ( j = 0 ; j < numVerts ; j + + , tcArray + = 2 ) {
tcArray [ 0 ] = tcArray [ 0 ] * t1 + t2 ;
tcArray [ 1 ] = tcArray [ 1 ] * t1 + t2 ;
}
break ;
case SHADER_TCMOD_SCROLL :
t1 = tcmod - > args [ 0 ] * r_localShaderTime ;
t2 = tcmod - > args [ 1 ] * r_localShaderTime ;
for ( j = 0 ; j < numVerts ; j + + , tcArray + = 2 ) {
tcArray [ 0 ] = tcArray [ 0 ] + t1 ;
tcArray [ 1 ] = tcArray [ 1 ] + t2 ;
}
break ;
case SHADER_TCMOD_TRANSFORM :
for ( j = 0 ; j < numVerts ; j + + , tcArray + = 2 ) {
t1 = tcArray [ 0 ] ;
t2 = tcArray [ 1 ] ;
tcArray [ 0 ] = t1 * tcmod - > args [ 0 ] + t2 * tcmod - > args [ 2 ] + tcmod - > args [ 4 ] ;
tcArray [ 1 ] = t2 * tcmod - > args [ 1 ] + t1 * tcmod - > args [ 3 ] + tcmod - > args [ 5 ] ;
}
break ;
default :
break ;
}
}
}
# define PlaneDiff(point,plane) (((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) - (plane)->dist)
# define VectorScalef(a, b, c) c[0]=a[0]*b;c[1]=a[1]*b;c[2]=a[2]*b
/*
= = = = = = = = = = = = = = = =
R_ModifyColor
= = = = = = = = = = = = = = = =
*/
void R_ModifyColor ( meshbuffer_t * mb , shaderpass_t * pass )
{
2005-02-06 02:47:36 +00:00
extern qbyte * host_basepal ;
extern qboolean gammaworks ;
extern qbyte gammatable [ 256 ] ;
2004-10-19 16:10:14 +00:00
int i , b ;
float * table , c , a ;
vec3_t t , v ;
shader_t * shader ;
qbyte * bArray , * vArray ;
qboolean fogged , noArray ;
shaderfunc_t * rgbgenfunc , * alphagenfunc ;
shader = mb - > shader ;
fogged = mb - > fog & & ( shader - > sort > = SHADER_SORT_UNDERWATER ) & &
! ( pass - > flags & SHADER_PASS_DEPTHWRITE ) & & ! shader - > fog_dist ;
noArray = ( pass - > flags & SHADER_PASS_NOCOLORARRAY ) & & ! fogged ;
rgbgenfunc = & pass - > rgbgen_func ;
alphagenfunc = & pass - > alphagen_func ;
if ( noArray ) {
numColors = 1 ;
} else {
numColors = numVerts ;
}
bArray = colorArray [ 0 ] ;
vArray = inColorsArray [ 0 ] ;
switch ( pass - > rgbgen )
{
case RGB_GEN_IDENTITY :
memset ( bArray , 255 , sizeof ( byte_vec4_t ) * numColors ) ;
break ;
case RGB_GEN_IDENTITY_LIGHTING :
memset ( bArray , r_identityLighting , sizeof ( byte_vec4_t ) * numColors ) ;
break ;
case RGB_GEN_CONST :
for ( i = 0 ; i < numColors ; i + + , bArray + = 4 ) {
bArray [ 0 ] = FloatToByte ( rgbgenfunc - > args [ 0 ] ) ;
bArray [ 1 ] = FloatToByte ( rgbgenfunc - > args [ 1 ] ) ;
bArray [ 2 ] = FloatToByte ( rgbgenfunc - > args [ 2 ] ) ;
}
break ;
case RGB_GEN_WAVE :
table = R_TableForFunc ( rgbgenfunc - > type ) ;
c = rgbgenfunc - > args [ 2 ] + r_localShaderTime * rgbgenfunc - > args [ 3 ] ;
c = FTABLE_EVALUATE ( table , c ) * rgbgenfunc - > args [ 1 ] + rgbgenfunc - > args [ 0 ] ;
clamp ( c , 0.0f , 1.0f ) ;
memset ( bArray , FloatToByte ( c ) , sizeof ( byte_vec4_t ) * numColors ) ;
break ;
case RGB_GEN_ENTITY :
2004-12-24 08:45:56 +00:00
for ( i = 0 ; i < numColors ; i + + , bArray + = 4 )
{
2004-10-19 16:10:14 +00:00
* ( int * ) bArray = * ( int * ) currententity - > shaderRGBA ;
}
break ;
2004-12-24 08:45:56 +00:00
2004-10-19 16:10:14 +00:00
case RGB_GEN_ONE_MINUS_ENTITY :
2004-12-24 08:45:56 +00:00
for ( i = 0 ; i < numColors ; i + + , bArray + = 4 )
{
2004-10-19 16:10:14 +00:00
bArray [ 0 ] = 255 - currententity - > shaderRGBA [ 0 ] ;
bArray [ 1 ] = 255 - currententity - > shaderRGBA [ 1 ] ;
bArray [ 2 ] = 255 - currententity - > shaderRGBA [ 2 ] ;
}
break ;
2004-12-24 08:45:56 +00:00
2004-10-19 16:10:14 +00:00
case RGB_GEN_VERTEX :
case RGB_GEN_EXACT_VERTEX :
memcpy ( bArray , vArray , sizeof ( byte_vec4_t ) * numColors ) ;
break ;
2005-02-06 02:47:36 +00:00
case RGB_GEN_TOPCOLOR : //multiply vertex by topcolor (for player models)
{
int rc , gc , bc ;
if ( currententity - > scoreboard )
{
i = currententity - > scoreboard - > topcolor ;
//colour forcing
if ( cl . splitclients < 2 & & ! ( cl . fpd & FPD_NO_FORCE_COLOR ) ) //no colour/skin forcing in splitscreen.
{
if ( cl . teamplay & & ! strcmp ( currententity - > scoreboard - > team , cl . players [ cl . playernum [ 0 ] ] . team ) )
{
if ( cl_teamtopcolor > = 0 )
i = cl_teamtopcolor ;
}
else
{
if ( cl_enemytopcolor > = 0 )
i = cl_enemytopcolor ;
}
}
}
else
i = TOP_RANGE > > 4 ;
2005-08-07 13:11:23 +00:00
if ( i > 8 )
{
i < < = 4 ;
}
else
{
i < < = 4 ;
i + = 15 ;
}
i * = 3 ;
rc = host_basepal [ i + 0 ] ;
gc = host_basepal [ i + 1 ] ;
bc = host_basepal [ i + 2 ] ;
2005-02-06 02:47:36 +00:00
if ( ! gammaworks )
{
rc = gammatable [ rc ] ;
gc = gammatable [ gc ] ;
bc = gammatable [ bc ] ;
}
for ( i = 0 ; i < numColors ; i + + , bArray + = 4 , vArray + = 4 ) {
bArray [ 0 ] = ( vArray [ 0 ] * rc ) > > 8 ;
bArray [ 1 ] = ( vArray [ 1 ] * gc ) > > 8 ;
bArray [ 2 ] = ( vArray [ 2 ] * bc ) > > 8 ;
}
break ;
}
case RGB_GEN_BOTTOMCOLOR : //multiply vertex by bottomcolor (for player models)
{
int rc , gc , bc ;
if ( currententity - > scoreboard )
{
i = currententity - > scoreboard - > bottomcolor ;
//colour forcing
if ( cl . splitclients < 2 & & ! ( cl . fpd & FPD_NO_FORCE_COLOR ) ) //no colour/skin forcing in splitscreen.
{
if ( cl . teamplay & & ! strcmp ( currententity - > scoreboard - > team , cl . players [ cl . playernum [ 0 ] ] . team ) )
{
if ( cl_teambottomcolor > = 0 )
i = cl_teambottomcolor ;
}
else
{
if ( cl_enemybottomcolor > = 0 )
i = cl_enemybottomcolor ;
}
}
}
else
i = BOTTOM_RANGE > > 4 ;
2005-08-07 13:11:23 +00:00
if ( i > 8 )
{
i < < = 4 ;
}
else
{
i < < = 4 ;
i + = 15 ;
}
i * = 3 ;
rc = host_basepal [ i + 0 ] ;
gc = host_basepal [ i + 1 ] ;
bc = host_basepal [ i + 2 ] ;
2005-02-06 02:47:36 +00:00
if ( ! gammaworks )
{
rc = gammatable [ rc ] ;
gc = gammatable [ gc ] ;
bc = gammatable [ bc ] ;
}
for ( i = 0 ; i < numColors ; i + + , bArray + = 4 , vArray + = 4 ) {
bArray [ 0 ] = ( vArray [ 0 ] * rc ) > > 8 ;
bArray [ 1 ] = ( vArray [ 1 ] * gc ) > > 8 ;
bArray [ 2 ] = ( vArray [ 2 ] * bc ) > > 8 ;
}
break ;
}
2004-10-19 16:10:14 +00:00
case RGB_GEN_ONE_MINUS_VERTEX :
for ( i = 0 ; i < numColors ; i + + , bArray + = 4 , vArray + = 4 ) {
bArray [ 0 ] = 255 - vArray [ 0 ] ;
bArray [ 1 ] = 255 - vArray [ 1 ] ;
bArray [ 2 ] = 255 - vArray [ 2 ] ;
}
break ;
case RGB_GEN_LIGHTING_DIFFUSE :
if ( ! currententity )
{
memset ( bArray , 255 , sizeof ( byte_vec4_t ) * numColors ) ;
}
else
{
memcpy ( bArray , vArray , sizeof ( byte_vec4_t ) * numColors ) ;
/*
vec3_t dif , amb , dir ;
cl . worldmodel - > funcs . LightPointValues ( currententity - > origin , dif , amb , dir ) ;
bArray [ 0 ] = dif [ 0 ] * 255 ;
bArray [ 1 ] = dif [ 1 ] * 255 ;
bArray [ 2 ] = dif [ 2 ] * 255 ;
//R_LightForEntity ( currententity, bArray );
*/
}
break ;
default :
break ;
}
bArray = colorArray [ 0 ] ;
vArray = inColorsArray [ 0 ] ;
switch ( pass - > alphagen )
{
case ALPHA_GEN_IDENTITY :
for ( i = 0 ; i < numColors ; i + + , bArray + = 4 ) {
bArray [ 3 ] = 255 ;
}
break ;
case ALPHA_GEN_CONST :
b = FloatToByte ( alphagenfunc - > args [ 0 ] ) ;
for ( i = 0 ; i < numColors ; i + + , bArray + = 4 ) {
bArray [ 3 ] = b ;
}
break ;
case ALPHA_GEN_WAVE :
table = R_TableForFunc ( alphagenfunc - > type ) ;
a = alphagenfunc - > args [ 2 ] + r_localShaderTime * alphagenfunc - > args [ 3 ] ;
a = FTABLE_EVALUATE ( table , a ) * alphagenfunc - > args [ 1 ] + alphagenfunc - > args [ 0 ] ;
b = FloatToByte ( bound ( 0.0f , a , 1.0f ) ) ;
for ( i = 0 ; i < numColors ; i + + , bArray + = 4 ) {
bArray [ 3 ] = b ;
}
break ;
case ALPHA_GEN_PORTAL :
VectorAdd ( vertexArray [ 0 ] , currententity - > origin , v ) ;
VectorSubtract ( r_origin , v , t ) ;
a = VectorLength ( t ) * ( 1.0 / 255.0 ) ;
clamp ( a , 0.0f , 1.0f ) ;
b = FloatToByte ( a ) ;
for ( i = 0 ; i < numColors ; i + + , bArray + = 4 ) {
bArray [ 3 ] = b ;
}
break ;
case ALPHA_GEN_VERTEX :
for ( i = 0 ; i < numColors ; i + + , bArray + = 4 , vArray + = 4 ) {
bArray [ 3 ] = vArray [ 3 ] ;
}
break ;
case ALPHA_GEN_ENTITY :
for ( i = 0 ; i < numColors ; i + + , bArray + = 4 ) {
bArray [ 3 ] = currententity - > alpha * 255 ;
}
break ;
case ALPHA_GEN_SPECULAR :
{
mat3_t axis ;
AngleVectors ( currententity - > angles , axis [ 0 ] , axis [ 1 ] , axis [ 2 ] ) ;
VectorSubtract ( r_origin , currententity - > origin , t ) ;
if ( ! Matrix3_Compare ( axis , axisDefault ) ) {
Matrix3_Multiply_Vec3 ( axis , t , v ) ;
} else {
VectorCopy ( t , v ) ;
}
for ( i = 0 ; i < numColors ; i + + , bArray + = 4 ) {
VectorSubtract ( v , vertexArray [ i ] , t ) ;
a = DotProduct ( t , normalsArray [ i ] ) * Q_rsqrt ( DotProduct ( t , t ) ) ;
a = a * a * a * a * a ;
bArray [ 3 ] = FloatToByte ( bound ( 0.0f , a , 1.0f ) ) ;
}
}
break ;
}
if ( fogged )
{
float dist , vdist ;
mplane_t * fogplane ;
vec3_t diff , viewtofog , fog_vpn ;
fogplane = mb - > fog - > visibleplane ;
2005-04-26 16:04:12 +00:00
if ( ! fogplane )
return ;
2004-10-19 16:10:14 +00:00
dist = PlaneDiff ( r_origin , fogplane ) ;
if ( shader - > flags & SHADER_SKY )
{
if ( dist > 0 )
VectorScale ( fogplane - > normal , - dist , viewtofog ) ;
else
VectorClear ( viewtofog ) ;
}
else
{
VectorCopy ( currententity - > origin , viewtofog ) ;
}
VectorScalef ( vpn , mb - > fog - > shader - > fog_dist , fog_vpn ) ;
bArray = colorArray [ 0 ] ;
for ( i = 0 ; i < numColors ; i + + , bArray + = 4 )
{
VectorAdd ( vertexArray [ i ] , viewtofog , diff ) ;
// camera is inside the fog
if ( dist < 0 ) {
VectorSubtract ( diff , r_origin , diff ) ;
c = DotProduct ( diff , fog_vpn ) ;
a = ( 1.0f - bound ( 0 , c , 1.0f ) ) * ( 1.0 / 255.0 ) ;
} else {
vdist = PlaneDiff ( diff , fogplane ) ;
if ( vdist < 0 ) {
VectorSubtract ( diff , r_origin , diff ) ;
c = vdist / ( vdist - dist ) ;
c * = DotProduct ( diff , fog_vpn ) ;
a = ( 1.0f - bound ( 0 , c , 1.0f ) ) * ( 1.0 / 255.0 ) ;
} else {
a = 1.0 / 255.0 ;
}
}
if ( pass - > blendmode = = GL_ADD | |
( ( pass - > blendsrc = = GL_ZERO ) & & ( pass - > blenddst = = GL_ONE_MINUS_SRC_COLOR ) ) ) {
bArray [ 0 ] = FloatToByte ( ( float ) bArray [ 0 ] * a ) ;
bArray [ 1 ] = FloatToByte ( ( float ) bArray [ 1 ] * a ) ;
bArray [ 2 ] = FloatToByte ( ( float ) bArray [ 2 ] * a ) ;
} else {
bArray [ 3 ] = FloatToByte ( ( float ) bArray [ 3 ] * a ) ;
}
}
}
}
/*
= = = = = = = = = = = = = = = =
R_SetShaderState
= = = = = = = = = = = = = = = =
*/
void R_SetShaderState ( shader_t * shader )
{
// Face culling
if ( ! gl_cull . value | | ( r_features & MF_NOCULL ) )
{
qglDisable ( GL_CULL_FACE ) ;
}
else
{
if ( shader - > flags & SHADER_CULL_FRONT )
{
qglEnable ( GL_CULL_FACE ) ;
qglCullFace ( GL_FRONT ) ;
}
else if ( shader - > flags & SHADER_CULL_BACK )
{
qglEnable ( GL_CULL_FACE ) ;
qglCullFace ( GL_BACK ) ;
}
else
{
qglDisable ( GL_CULL_FACE ) ;
}
}
if ( shader - > flags & SHADER_POLYGONOFFSET )
{
qglEnable ( GL_POLYGON_OFFSET_FILL ) ;
}
else
{
qglDisable ( GL_POLYGON_OFFSET_FILL ) ;
}
}
/*
= = = = = = = = = = = = = = = =
R_SetShaderpassState
= = = = = = = = = = = = = = = =
*/
void R_SetShaderpassState ( shaderpass_t * pass , qboolean mtex )
{
if ( ( mtex & & ( pass - > blendmode ! = GL_REPLACE ) ) | | ( pass - > flags & SHADER_PASS_BLEND ) )
{
qglEnable ( GL_BLEND ) ;
qglBlendFunc ( pass - > blendsrc , pass - > blenddst ) ;
}
else
{
qglDisable ( GL_BLEND ) ;
}
if ( pass - > flags & SHADER_PASS_ALPHAFUNC )
{
qglEnable ( GL_ALPHA_TEST ) ;
if ( pass - > alphafunc = = SHADER_ALPHA_GT0 )
{
qglAlphaFunc ( GL_GREATER , 0 ) ;
}
else if ( pass - > alphafunc = = SHADER_ALPHA_LT128 )
{
qglAlphaFunc ( GL_LESS , 0.5f ) ;
}
else if ( pass - > alphafunc = = SHADER_ALPHA_GE128 )
{
qglAlphaFunc ( GL_GEQUAL , 0.5f ) ;
}
}
else
{
qglDisable ( GL_ALPHA_TEST ) ;
}
// nasty hack!!!
if ( ! gl_state . in2d )
{
extern int gldepthfunc ;
if ( gldepthfunc = = GL_LEQUAL )
qglDepthFunc ( pass - > depthfunc ) ;
else
{
switch ( pass - > depthfunc )
{
case GL_LESS :
qglDepthFunc ( GL_GREATER ) ;
break ;
case GL_LEQUAL :
qglDepthFunc ( GL_GEQUAL ) ;
break ;
case GL_GREATER :
qglDepthFunc ( GL_LESS ) ;
break ;
case GL_GEQUAL :
qglDepthFunc ( GL_LEQUAL ) ;
break ;
case GL_NEVER :
case GL_EQUAL :
case GL_ALWAYS :
case GL_NOTEQUAL :
default :
qglDepthFunc ( pass - > depthfunc ) ;
}
}
if ( pass - > flags & SHADER_PASS_DEPTHWRITE )
{
qglDepthMask ( GL_TRUE ) ;
}
else
{
qglDepthMask ( GL_FALSE ) ;
}
}
2005-08-26 22:56:51 +00:00
else
{
qglDepthFunc ( GL_ALWAYS ) ;
qglDepthMask ( GL_FALSE ) ;
}
2004-10-19 16:10:14 +00:00
}
/*
= = = = = = = = = = = = = = = =
R_RenderMeshGeneric
= = = = = = = = = = = = = = = =
*/
void R_RenderMeshGeneric ( meshbuffer_t * mb , shaderpass_t * pass )
{
R_SetShaderpassState ( pass , false ) ;
R_ModifyTextureCoords ( pass , 0 ) ;
R_ModifyColor ( mb , pass ) ;
if ( pass - > blendmode = = GL_REPLACE )
GL_TexEnv ( GL_REPLACE ) ;
else
GL_TexEnv ( GL_MODULATE ) ;
GL_Bind ( r_texNums [ 0 ] ) ;
R_FlushArrays ( ) ;
}
/*
= = = = = = = = = = = = = = = =
R_RenderMeshMultitextured
= = = = = = = = = = = = = = = =
*/
void R_RenderMeshMultitextured ( meshbuffer_t * mb , shaderpass_t * pass )
{
int i ;
r_numUnits = pass - > numMergedPasses ;
2005-05-26 12:55:34 +00:00
GL_SelectTexture ( mtexid0 ) ;
GL_TexEnv ( pass - > blendmode ) ;
2004-10-19 16:10:14 +00:00
R_SetShaderpassState ( pass , true ) ;
R_ModifyTextureCoords ( pass , 0 ) ;
2005-05-26 12:55:34 +00:00
R_ModifyColor ( mb , pass ) ;
2004-10-19 16:10:14 +00:00
for ( i = 1 , pass + + ; i < r_numUnits ; i + + , pass + + )
{
GL_SelectTexture ( mtexid0 + i ) ;
GL_TexEnv ( pass - > blendmode ) ;
R_ModifyTextureCoords ( pass , i ) ;
}
R_FlushArraysMtex ( ) ;
}
/*
= = = = = = = = = = = = = = = =
R_RenderMeshCombined
= = = = = = = = = = = = = = = =
*/
void R_RenderMeshCombined ( meshbuffer_t * mb , shaderpass_t * pass )
{
int i ;
r_numUnits = pass - > numMergedPasses ;
R_SetShaderpassState ( pass , true ) ;
R_ModifyColor ( mb , pass ) ;
GL_SelectTexture ( mtexid0 ) ;
if ( pass - > blendmode = = GL_REPLACE )
GL_TexEnv ( GL_REPLACE ) ;
else
GL_TexEnv ( GL_MODULATE ) ;
2005-06-04 04:20:20 +00:00
R_ModifyTextureCoords ( pass , 0 ) ;
2004-10-19 16:10:14 +00:00
for ( i = 1 , pass + + ; i < r_numUnits ; i + + , pass + + )
{
2005-06-04 04:20:20 +00:00
GL_SelectTexture ( mtexid0 + i ) ;
2004-10-19 16:10:14 +00:00
if ( pass - > blendmode )
{
switch ( pass - > blendmode )
{
case GL_REPLACE :
case GL_MODULATE :
case GL_ADD :
// these modes are best set with TexEnv, Combine4 would need much more setup
GL_TexEnv ( pass - > blendmode ) ;
break ;
case GL_DECAL :
2005-01-24 23:47:32 +00:00
// mimics Alpha-Blending in upper texture stage, but instead of multiplying the alpha-channel, theyre added
2004-10-19 16:10:14 +00:00
// this way it can be possible to use GL_DECAL in both texture-units, while still looking good
// normal mutlitexturing would multiply the alpha-channel which looks ugly
GL_TexEnv ( GL_COMBINE_EXT ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_COMBINE_RGB_EXT , GL_INTERPOLATE_EXT ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_COMBINE_ALPHA_EXT , GL_ADD ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE0_RGB_EXT , GL_TEXTURE ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND0_RGB_EXT , GL_SRC_COLOR ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE0_ALPHA_EXT , GL_TEXTURE ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND0_ALPHA_EXT , GL_SRC_ALPHA ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_RGB_EXT , GL_PREVIOUS_EXT ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND1_RGB_EXT , GL_SRC_COLOR ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_ALPHA_EXT , GL_PREVIOUS_EXT ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND1_ALPHA_EXT , GL_SRC_ALPHA ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE2_RGB_EXT , GL_TEXTURE ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND2_RGB_EXT , GL_SRC_ALPHA ) ;
break ;
}
}
else
{
GL_TexEnv ( GL_COMBINE4_NV ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_COMBINE_RGB_EXT , GL_ADD ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_COMBINE_ALPHA_EXT , GL_ADD ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE0_RGB_EXT , GL_TEXTURE ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND0_RGB_EXT , GL_SRC_COLOR ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE0_ALPHA_EXT , GL_TEXTURE ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND0_ALPHA_EXT , GL_SRC_ALPHA ) ;
switch ( pass - > blendsrc )
{
case GL_ONE :
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_RGB_EXT , GL_ZERO ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND1_RGB_EXT , GL_ONE_MINUS_SRC_COLOR ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_ALPHA_EXT , GL_ZERO ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND1_ALPHA_EXT , GL_ONE_MINUS_SRC_ALPHA ) ;
break ;
case GL_ZERO :
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_RGB_EXT , GL_ZERO ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND1_RGB_EXT , GL_SRC_COLOR ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_ALPHA_EXT , GL_ZERO ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND1_ALPHA_EXT , GL_SRC_ALPHA ) ;
break ;
case GL_DST_COLOR :
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_RGB_EXT , GL_PREVIOUS_EXT ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND1_RGB_EXT , GL_SRC_COLOR ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_ALPHA_EXT , GL_PREVIOUS_EXT ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND1_ALPHA_EXT , GL_SRC_ALPHA ) ;
break ;
case GL_ONE_MINUS_DST_COLOR :
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_RGB_EXT , GL_PREVIOUS_EXT ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND1_RGB_EXT , GL_ONE_MINUS_SRC_COLOR ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_ALPHA_EXT , GL_PREVIOUS_EXT ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND1_ALPHA_EXT , GL_ONE_MINUS_SRC_ALPHA ) ;
break ;
case GL_SRC_ALPHA :
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_RGB_EXT , GL_TEXTURE ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND1_RGB_EXT , GL_SRC_ALPHA ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_ALPHA_EXT , GL_TEXTURE ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND1_ALPHA_EXT , GL_SRC_ALPHA ) ;
break ;
case GL_ONE_MINUS_SRC_ALPHA :
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_RGB_EXT , GL_TEXTURE ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND1_RGB_EXT , GL_ONE_MINUS_SRC_ALPHA ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_ALPHA_EXT , GL_TEXTURE ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND1_ALPHA_EXT , GL_ONE_MINUS_SRC_ALPHA ) ;
break ;
case GL_DST_ALPHA :
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_RGB_EXT , GL_PREVIOUS_EXT ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_ALPHA_EXT , GL_PREVIOUS_EXT ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND1_RGB_EXT , GL_SRC_ALPHA ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND1_ALPHA_EXT , GL_SRC_ALPHA ) ;
break ;
case GL_ONE_MINUS_DST_ALPHA :
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_RGB_EXT , GL_PREVIOUS_EXT ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_ALPHA_EXT , GL_PREVIOUS_EXT ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND1_RGB_EXT , GL_ONE_MINUS_SRC_ALPHA ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND1_ALPHA_EXT , GL_ONE_MINUS_SRC_ALPHA ) ;
break ;
}
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE2_RGB_EXT , GL_PREVIOUS_EXT ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND2_RGB_EXT , GL_SRC_COLOR ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE2_ALPHA_EXT , GL_PREVIOUS_EXT ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND2_ALPHA_EXT , GL_SRC_ALPHA ) ;
switch ( pass - > blenddst )
{
case GL_ONE :
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE3_RGB_NV , GL_ZERO ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND3_RGB_NV , GL_ONE_MINUS_SRC_COLOR ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE3_ALPHA_NV , GL_ZERO ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND3_ALPHA_NV , GL_ONE_MINUS_SRC_ALPHA ) ;
break ;
case GL_ZERO :
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE3_RGB_NV , GL_ZERO ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND3_RGB_NV , GL_SRC_COLOR ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE3_ALPHA_NV , GL_ZERO ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND3_ALPHA_NV , GL_SRC_ALPHA ) ;
break ;
case GL_SRC_COLOR :
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE3_RGB_NV , GL_TEXTURE ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND3_RGB_NV , GL_SRC_COLOR ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE3_ALPHA_NV , GL_TEXTURE ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND3_ALPHA_NV , GL_SRC_ALPHA ) ;
break ;
case GL_ONE_MINUS_SRC_COLOR :
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE3_RGB_NV , GL_TEXTURE ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND3_RGB_NV , GL_ONE_MINUS_SRC_COLOR ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE3_ALPHA_NV , GL_TEXTURE ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND3_ALPHA_NV , GL_ONE_MINUS_SRC_ALPHA ) ;
break ;
case GL_SRC_ALPHA :
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE3_RGB_NV , GL_TEXTURE ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND3_RGB_NV , GL_SRC_ALPHA ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE3_ALPHA_NV , GL_TEXTURE ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND3_ALPHA_NV , GL_SRC_ALPHA ) ;
break ;
case GL_ONE_MINUS_SRC_ALPHA :
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE3_RGB_NV , GL_TEXTURE ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND3_RGB_NV , GL_ONE_MINUS_SRC_ALPHA ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE3_ALPHA_NV , GL_TEXTURE ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND3_ALPHA_NV , GL_ONE_MINUS_SRC_ALPHA ) ;
break ;
case GL_DST_ALPHA :
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE3_RGB_NV , GL_PREVIOUS_EXT ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND3_RGB_NV , GL_SRC_ALPHA ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE3_ALPHA_NV , GL_PREVIOUS_EXT ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND3_ALPHA_NV , GL_SRC_ALPHA ) ;
break ;
case GL_ONE_MINUS_DST_ALPHA :
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE3_RGB_NV , GL_PREVIOUS_EXT ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND3_RGB_NV , GL_ONE_MINUS_SRC_ALPHA ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE3_ALPHA_NV , GL_PREVIOUS_EXT ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_OPERAND3_ALPHA_NV , GL_ONE_MINUS_SRC_ALPHA ) ;
break ;
}
}
R_ModifyTextureCoords ( pass , i ) ;
}
R_FlushArraysMtex ( ) ;
}
/*
= = = = = = = = = = = = = = = =
R_RenderMeshBuffer
= = = = = = = = = = = = = = = =
*/
void R_RenderMeshBuffer ( meshbuffer_t * mb , qboolean shadowpass )
{
int i ;
shader_t * shader ;
shaderpass_t * pass ;
2005-09-14 04:23:18 +00:00
if ( ! numVerts )
{
2004-10-19 16:10:14 +00:00
return ;
}
2004-11-13 17:31:04 +00:00
// R_IBrokeTheArrays();
// qglVertexPointer( 3, GL_FLOAT, 16, vertexArray ); // padded for SIMD
// qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray );
// qglEnableClientState( GL_VERTEX_ARRAY );
2004-10-19 16:10:14 +00:00
shader = mb - > shader ;
r_lmtex = mb - > infokey ;
2005-09-14 04:23:18 +00:00
if ( currententity & & ! gl_state . in2d )
{
2005-02-09 19:32:09 +00:00
r_localShaderTime = r_refdef . time - currententity - > shaderTime ;
2005-09-14 04:23:18 +00:00
} else
{
2005-02-09 19:32:09 +00:00
r_localShaderTime = realtime ;
2004-10-19 16:10:14 +00:00
}
R_SetShaderState ( shader ) ;
2005-09-14 04:23:18 +00:00
if ( shader - > numdeforms )
{
2004-10-19 16:10:14 +00:00
R_DeformVertices ( mb ) ;
}
2005-09-14 04:23:18 +00:00
if ( ! numIndexes | | shadowpass )
{
2004-10-19 16:10:14 +00:00
return ;
}
R_LockArrays ( numVerts ) ;
for ( i = 0 , pass = shader - > passes ; i < shader - > numpasses ; )
{
2005-09-14 04:23:18 +00:00
if ( ! ( pass - > flags & SHADER_PASS_DETAIL ) | | r_detailtextures . value )
{
2004-10-19 16:10:14 +00:00
pass - > flush ( mb , pass ) ;
}
i + = pass - > numMergedPasses ;
pass + = pass - > numMergedPasses ;
}
R_FinishMeshBuffer ( mb ) ;
}
/*
= = = = = = = = = = = = = = = =
R_RenderFogOnMesh
= = = = = = = = = = = = = = = =
*/
int r_fogtexture ;
# define PlaneDiff(point,plane) (((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) - (plane)->dist)
void R_RenderFogOnMesh ( shader_t * shader , struct mfog_s * fog )
{
# define FOG_TEXTURE_HEIGHT 32
int i ;
vec3_t diff , viewtofog , fog_vpn ;
float dist , vdist ;
shader_t * fogshader ;
mplane_t * fogplane ;
if ( ! fog - > numplanes | | ! fog - > shader | | ! fog - > visibleplane )
{
return ;
}
R_ResetTexState ( ) ;
fogshader = fog - > shader ;
fogplane = fog - > visibleplane ;
GL_Bind ( r_fogtexture ) ;
qglBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
2005-05-26 12:55:34 +00:00
GL_TexEnv ( GL_MODULATE ) ;
2004-10-19 16:10:14 +00:00
if ( ! shader - > numpasses | | shader - > fog_dist | | ( shader - > flags & SHADER_SKY ) )
{
2004-10-27 23:33:35 +00:00
extern int gldepthfunc ;
qglDepthFunc ( gldepthfunc ) ;
2004-10-19 16:10:14 +00:00
}
else
{
qglDepthFunc ( GL_EQUAL ) ;
}
qglColor4ubv ( fogshader - > fog_color ) ;
// distance to fog
dist = PlaneDiff ( r_origin , fogplane ) ;
if ( shader - > flags & SHADER_SKY )
{
if ( dist > 0 )
VectorMA ( r_origin , - dist , fogplane - > normal , viewtofog ) ;
else
VectorCopy ( r_origin , viewtofog ) ;
}
else
{
VectorCopy ( currententity - > origin , viewtofog ) ;
}
VectorScale ( vpn , fogshader - > fog_dist , fog_vpn ) ;
for ( i = 0 ; i < numVerts ; i + + , currentCoords + = 2 )
{
VectorAdd ( viewtofog , vertexArray [ i ] , diff ) ;
vdist = PlaneDiff ( diff , fogplane ) ;
VectorSubtract ( diff , r_origin , diff ) ;
if ( dist < 0 )
{ // camera is inside the fog brush
currentCoords [ 0 ] = DotProduct ( diff , fog_vpn ) ;
}
else
{
if ( vdist < 0 )
{
currentCoords [ 0 ] = vdist / ( vdist - dist ) ;
currentCoords [ 0 ] * = DotProduct ( diff , fog_vpn ) ;
}
else
{
currentCoords [ 0 ] = 0.0f ;
}
}
currentCoords [ 1 ] = - vdist * fogshader - > fog_dist + 1.5f / ( float ) FOG_TEXTURE_HEIGHT ;
}
if ( ! shader - > numpasses )
{
R_LockArrays ( numVerts ) ;
}
R_FlushArrays ( ) ;
}
/*
= = = = = = = = = = = = = = = =
R_DrawTriangleOutlines
= = = = = = = = = = = = = = = =
*/
void R_DrawTriangleOutlines ( void )
{
R_ResetTexState ( ) ;
qglDisable ( GL_TEXTURE_2D ) ;
qglDisable ( GL_DEPTH_TEST ) ;
qglColor4f ( 1 , 1 , 1 , 1 ) ;
qglDisable ( GL_BLEND ) ;
qglPolygonMode ( GL_FRONT_AND_BACK , GL_LINE ) ;
R_FlushArrays ( ) ;
qglPolygonMode ( GL_FRONT_AND_BACK , GL_FILL ) ;
qglEnable ( GL_DEPTH_TEST ) ;
qglEnable ( GL_TEXTURE_2D ) ;
}
/*
= = = = = = = = = = = = = = = =
R_DrawNormals
= = = = = = = = = = = = = = = =
*/
void R_DrawNormals ( void )
{
int i ;
R_ResetTexState ( ) ;
qglDisable ( GL_TEXTURE_2D ) ;
qglColor4f ( 1 , 1 , 1 , 1 ) ;
qglDisable ( GL_BLEND ) ;
if ( gl_state . in2d ) {
qglBegin ( GL_POINTS ) ;
for ( i = 0 ; i < numVerts ; i + + ) {
qglVertex3fv ( vertexArray [ i ] ) ;
}
qglEnd ( ) ;
} else {
qglDisable ( GL_DEPTH_TEST ) ;
qglBegin ( GL_LINES ) ;
for ( i = 0 ; i < numVerts ; i + + ) {
qglVertex3fv ( vertexArray [ i ] ) ;
qglVertex3f ( vertexArray [ i ] [ 0 ] + normalsArray [ i ] [ 0 ] ,
vertexArray [ i ] [ 1 ] + normalsArray [ i ] [ 1 ] ,
vertexArray [ i ] [ 2 ] + normalsArray [ i ] [ 2 ] ) ;
}
qglEnd ( ) ;
qglEnable ( GL_DEPTH_TEST ) ;
}
qglEnable ( GL_TEXTURE_2D ) ;
}
2005-09-08 22:52:46 +00:00
/*
= = = = = = = = = = = = = = = = =
R_AddDynamicLights
= = = = = = = = = = = = = = = = =
*/
void R_AddDynamicLights ( meshbuffer_t * mb )
{
dlight_t * light ;
int i , j , lnum ;
vec3_t point , tvec , dlorigin ;
vec3_t vright , vup ;
vec3_t dir1 , dir2 , normal , right , up , oldnormal ;
float * v [ 3 ] , dist , scale ;
index_t * oldIndexesArray , index [ 3 ] ;
int dlightNumIndexes , oldNumIndexes ;
oldNumIndexes = numIndexes ;
oldIndexesArray = indexesArray ;
VectorClear ( oldnormal ) ;
GL_Bind ( r_dlighttexture ) ;
qglDepthFunc ( GL_EQUAL ) ;
qglBlendFunc ( GL_DST_COLOR , GL_ONE ) ;
GL_TexEnv ( GL_MODULATE ) ;
light = cl_dlights ;
for ( lnum = 0 ; lnum < 32 ; lnum + + , light + + )
{
if ( ! ( mb - > dlightbits & ( 1 < < lnum ) ) )
continue ; // not lit by this light
if ( ! light - > radius )
continue ; //urm
VectorSubtract ( light - > origin , currententity - > origin , dlorigin ) ;
if ( ! Matrix3_Compare ( currententity - > axis , axisDefault ) )
{
VectorCopy ( dlorigin , point ) ;
Matrix3_Multiply_Vec3 ( currententity - > axis , point , dlorigin ) ;
}
qglColor4f ( light - > color [ 0 ] * 2 , light - > color [ 1 ] * 2 , light - > color [ 2 ] * 2 ,
1 ) ; //light->color[3]);
R_ResetTexState ( ) ;
dlightNumIndexes = 0 ;
for ( i = 0 ; i < oldNumIndexes ; i + = 3 )
{
index [ 0 ] = oldIndexesArray [ i + 0 ] ;
index [ 1 ] = oldIndexesArray [ i + 1 ] ;
index [ 2 ] = oldIndexesArray [ i + 2 ] ;
v [ 0 ] = ( float * ) ( vertexArray + index [ 0 ] ) ;
v [ 1 ] = ( float * ) ( vertexArray + index [ 1 ] ) ;
v [ 2 ] = ( float * ) ( vertexArray + index [ 2 ] ) ;
// calculate two mostly perpendicular edge directions
VectorSubtract ( v [ 0 ] , v [ 1 ] , dir1 ) ;
VectorSubtract ( v [ 2 ] , v [ 1 ] , dir2 ) ;
// we have two edge directions, we can calculate a third vector from
// them, which is the direction of the surface normal
CrossProduct ( dir1 , dir2 , normal ) ;
VectorNormalize ( normal ) ;
VectorSubtract ( v [ 0 ] , dlorigin , tvec ) ;
dist = DotProduct ( tvec , normal ) ;
if ( dist < 0 )
dist = - dist ;
if ( dist > = light - > radius ) {
continue ;
}
VectorMA ( dlorigin , - dist , normal , point ) ;
scale = 1 / ( light - > radius - dist ) ;
if ( ! VectorCompare ( normal , oldnormal ) ) {
MakeNormalVectors ( normal , right , up ) ;
VectorCopy ( normal , oldnormal ) ;
}
VectorScale ( right , scale , vright ) ;
VectorScale ( up , scale , vup ) ;
for ( j = 0 ; j < 3 ; j + + )
{
// Get our texture coordinates
// Project the light image onto the face
VectorSubtract ( v [ j ] , point , tvec ) ;
coordsArray [ index [ j ] ] [ 0 ] = DotProduct ( tvec , vright ) + 0.5f ;
coordsArray [ index [ j ] ] [ 1 ] = DotProduct ( tvec , vup ) + 0.5f ;
}
tempIndexesArray [ dlightNumIndexes + + ] = index [ 0 ] ;
tempIndexesArray [ dlightNumIndexes + + ] = index [ 1 ] ;
tempIndexesArray [ dlightNumIndexes + + ] = index [ 2 ] ;
}
if ( dlightNumIndexes ) {
R_PushIndexes ( tempIndexesArray , NULL , NULL , dlightNumIndexes , MF_NONBATCHED ) ;
R_FlushArrays ( ) ;
dlightNumIndexes = 0 ;
}
}
numIndexes = oldNumIndexes ;
indexesArray = oldIndexesArray ;
}
2004-10-19 16:10:14 +00:00
/*
= = = = = = = = = = = = = = = =
R_FinishMeshBuffer
Render dynamic lights , fog , triangle outlines , normals and clear arrays
= = = = = = = = = = = = = = = =
*/
void R_FinishMeshBuffer ( meshbuffer_t * mb )
{
shader_t * shader ;
qboolean fogged ;
qboolean dlight ;
shader = mb - > shader ;
dlight = ( mb - > dlightbits ! = 0 ) & & ! ( shader - > flags & SHADER_FLARE ) ;
fogged = mb - > fog & & ( ( shader - > sort < SHADER_SORT_UNDERWATER & &
( shader - > flags & ( SHADER_DEPTHWRITE | SHADER_SKY ) ) ) | | shader - > fog_dist ) ;
if ( dlight | | fogged ) {
GL_DisableMultitexture ( ) ;
qglTexCoordPointer ( 2 , GL_FLOAT , 0 , inCoordsArray [ 0 ] ) ;
qglEnable ( GL_BLEND ) ;
qglDisable ( GL_ALPHA_TEST ) ;
2005-05-26 12:55:34 +00:00
qglDepthMask ( GL_FALSE ) ;
2004-10-19 16:10:14 +00:00
2005-09-08 22:52:46 +00:00
if ( dlight & & ( currententity - > model - > type = = mod_brush & & currententity - > model - > fromgame = = fg_quake3 ) ) //HACK: the extra check is because we play with the lightmaps in q1/q2
{
R_AddDynamicLights ( mb ) ;
}
2004-10-19 16:10:14 +00:00
2005-09-08 22:52:46 +00:00
if ( fogged )
{
2004-10-19 16:10:14 +00:00
R_RenderFogOnMesh ( shader , mb - > fog ) ;
}
}
if ( r_showtris . value | | r_shownormals . value ) {
GL_DisableMultitexture ( ) ;
if ( r_showtris . value ) {
R_DrawTriangleOutlines ( ) ;
}
if ( r_shownormals . value ) {
R_DrawNormals ( ) ;
}
}
R_UnlockArrays ( ) ;
R_ClearArrays ( ) ;
}
# endif
2005-01-24 23:47:32 +00:00
# endif