From d6c869cb41ef605f6fbf9686007f942b737f8e75 Mon Sep 17 00:00:00 2001 From: leilei- Date: Thu, 8 Feb 2024 07:55:16 -0500 Subject: [PATCH 01/20] - s_interrupt - allows sounds to be interrupted by the same sound or entity channel - new dynamic light calculation for vertex lighting, affecting vertex color (no projected dlight textures) - rgbGen material for allowing calculation for diffuse, specular, emmissive vertex colors by hex values - rgbMod shader command allowing new vertex color effects - removed deprecated R_ParseStageSimple, it never worked as intended --- code/client/snd_dma.c | 24 + code/client/snd_local.h | 2 + code/client/snd_main.c | 3 + code/renderer_oa/tr_image.c | 3 - code/renderer_oa/tr_init.c | 2 - code/renderer_oa/tr_local.h | 32 +- code/renderer_oa/tr_scene.c | 2 +- code/renderer_oa/tr_shade.c | 141 ++-- code/renderer_oa/tr_shade_calc.c | 512 +++++++++++ code/renderer_oa/tr_shader.c | 1359 +++++++----------------------- 10 files changed, 951 insertions(+), 1129 deletions(-) diff --git a/code/client/snd_dma.c b/code/client/snd_dma.c index 0f7ec1576a..729cd5305f 100644 --- a/code/client/snd_dma.c +++ b/code/client/snd_dma.c @@ -576,6 +576,30 @@ static void S_Base_StartSoundEx( vec3_t origin, int entityNum, int entchannel, s } ch = s_channels; + + + // leilei - check if this sound is already playing and kill it + if (s_interrupts->integer == 1) + { + for ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) { + if (ch->entnum == entityNum && ch->thesfx == sfx) + { + S_ChannelFree(ch); + } + } + } + + // leilei - check if this channel is being used, and kill that too + else if (s_interrupts->integer == 2) + { + for ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) { + if (ch->entnum == entityNum && ch->entchannel == entchannel && ch->thesfx && (entchannel != CHAN_AUTO)) + { + S_ChannelFree(ch); + } + } + } + inplay = 0; for ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) { if (ch->entnum == entityNum && ch->thesfx == sfx) { diff --git a/code/client/snd_local.h b/code/client/snd_local.h index e0f5b1d08b..42fa7c5844 100644 --- a/code/client/snd_local.h +++ b/code/client/snd_local.h @@ -199,6 +199,8 @@ extern cvar_t *s_musicVolume; extern cvar_t *s_muted; extern cvar_t *s_doppler; +extern cvar_t *s_interrupts; + extern cvar_t *s_testsound; qboolean S_LoadSound( sfx_t *sfx ); diff --git a/code/client/snd_main.c b/code/client/snd_main.c index 91ab161c69..e51ec580fb 100644 --- a/code/client/snd_main.c +++ b/code/client/snd_main.c @@ -34,6 +34,8 @@ cvar_t *s_backend; cvar_t *s_muteWhenMinimized; cvar_t *s_muteWhenUnfocused; +cvar_t *s_interrupts; + static soundInterface_t si; /* @@ -485,6 +487,7 @@ void S_Init( void ) s_muted = Cvar_Get("s_muted", "0", CVAR_ROM); s_doppler = Cvar_Get( "s_doppler", "1", CVAR_ARCHIVE ); s_backend = Cvar_Get( "s_backend", "", CVAR_ROM ); + s_interrupts = Cvar_Get( "s_interrupts", "0", CVAR_ARCHIVE ); // leilei - pre-1.25 sound behavior s_muteWhenMinimized = Cvar_Get( "s_muteWhenMinimized", "0", CVAR_ARCHIVE ); s_muteWhenUnfocused = Cvar_Get( "s_muteWhenUnfocused", "0", CVAR_ARCHIVE ); diff --git a/code/renderer_oa/tr_image.c b/code/renderer_oa/tr_image.c index ab60e48d0e..4b38d140eb 100644 --- a/code/renderer_oa/tr_image.c +++ b/code/renderer_oa/tr_image.c @@ -1129,9 +1129,6 @@ static void Upload32( unsigned *data, int forceBits = 0; - if (lightMap && r_parseStageSimple->integer) hackoperation = 4; - - // // convert to exact power of 2 sizes // diff --git a/code/renderer_oa/tr_init.c b/code/renderer_oa/tr_init.c index 7a436b96c6..fc3871a6d9 100644 --- a/code/renderer_oa/tr_init.c +++ b/code/renderer_oa/tr_init.c @@ -208,7 +208,6 @@ cvar_t *r_flaresDlightScale; //cvar_t *r_flaresSurfradii; cvar_t *r_alternateBrightness; // leilei - linux overbright fix cvar_t *r_mockvr; // Leilei - for debugging PVR only! -cvar_t *r_parseStageSimple; // Leilei - for debugging PVR only! cvar_t *r_leifx; // Leilei - leifx nostalgia filter cvar_t *r_modelshader; // Leilei cvar_t *r_particles; // Leilei - particle effects motif @@ -1327,7 +1326,6 @@ void R_Register( void ) r_mockvr = ri.Cvar_Get( "r_mockvr", "0" , CVAR_CHEAT); - r_parseStageSimple = ri.Cvar_Get( "r_parseStageSimple", "0" , CVAR_CHEAT); r_leifx = ri.Cvar_Get( "r_leifx", "0" , CVAR_ARCHIVE | CVAR_LATCH); r_modelshader = ri.Cvar_Get( "r_modelshader", "0" , CVAR_ARCHIVE | CVAR_LATCH); // leilei - load and use special shaders for lightDiffuse models r_detailTextureScale = ri.Cvar_Get( "r_detailtextureScale", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - adjust scale of detail textures diff --git a/code/renderer_oa/tr_local.h b/code/renderer_oa/tr_local.h index 20bb4bc048..f30505dbc1 100644 --- a/code/renderer_oa/tr_local.h +++ b/code/renderer_oa/tr_local.h @@ -187,6 +187,7 @@ typedef enum { CGEN_FOG, // standard fog CGEN_CONST, // fixed color CGEN_VERTEX_LIT, // leilei - tess.vertexColors * tr.identityLight * ambientlight*directlight + CGEN_MATERIAL, // leilei - material system CGEN_LIGHTING_DIFFUSE_SPECULAR // leilei - LIGHTING_DIFFUSE, capped by specular exponent } colorGen_t; @@ -265,6 +266,17 @@ typedef enum { TMOD_ENTITY_TRANSLATE } texMod_t; +// leilei - rgbMod - color modulations +typedef enum { + CMOD_BAD, + CMOD_GLOW, + CMOD_LIGHTING, + CMOD_NORMALIZETOALPHA, + CMOD_NORMALIZETOALPHAFAST, + CMOD_UVCOL, + CMOD_OPAQUE +} colorMod_t; + #define MAX_SHADER_DEFORMS 3 typedef struct { deform_t deformation; // vertex coordinate modification type @@ -361,6 +373,17 @@ typedef struct { int imgWidth; int imgHeight; //leilei for glsl shaders + colorMod_t rgbMod; // leilei - rgbMod + int rgbModCol; + int rgbModMode; + + int matAmb; // leilei - material ambience + int matDif; // leilei - material diffuse + int matSpec; // leilei - material specular + int matEmis; // leilei - material emissive + int matHard; // leilei - material specular hardness + int matAlpha; // leilei - material alpha + } shaderStage_t; struct shaderCommands_s; @@ -1399,7 +1422,6 @@ extern cvar_t *r_flaresMotionBlur; //extern cvar_t *r_flaresSurfradii; extern cvar_t *r_alternateBrightness; // leilei - alternate brightness -extern cvar_t *r_parseStageSimple; // Leilei - handling textures into alphas extern cvar_t *r_leifx; // Leilei - leifx nostalgia filter extern cvar_t *r_modelshader; // Leilei - new model shading @@ -2189,6 +2211,14 @@ void RB_CalcFlatAmbient( unsigned char *colors ); // leilei - cel hack void RB_CalcFlatDirect( unsigned char *colors ); // leilei - cel hack void RB_CalcNormal( unsigned char *colors ); // leilei - normal hack +void RB_CalcGlowBlend( unsigned char *colors, int glowcol, int fx ); // leilei - rgbMod +void RB_CalcUVColor( unsigned char *colors, int glowcol, int fx ); // leilei - rgbMod +void RB_CalcNormalizeToAlpha( unsigned char *colors); // leilei - rgbMod + +void RB_CalcMaterials( unsigned char *colors, int ambient, int diffuse, int specular, int emissive, int spechard, int alpha ); // leilei - materials + +void RB_CalcVertLights( unsigned char *colors ); // leilei - dynamic vertex lights + /* ============================================================= diff --git a/code/renderer_oa/tr_scene.c b/code/renderer_oa/tr_scene.c index b05578ca12..c1259048d2 100644 --- a/code/renderer_oa/tr_scene.c +++ b/code/renderer_oa/tr_scene.c @@ -361,7 +361,7 @@ void RE_RenderScene( const refdef_t *fd ) { // turn off dynamic lighting globally by clearing all the // dlights if it needs to be disabled or if vertex lighting is enabled if ( r_dynamiclight->integer == 0 || - r_vertexLight->integer == 1 || + // r_vertexLight->integer == 1 || // leilei - commented this out, as we can now do dynamic lights with vertex light glConfig.hardwareType == GLHW_PERMEDIA2 ) { tr.refdef.num_dlights = 0; } diff --git a/code/renderer_oa/tr_shade.c b/code/renderer_oa/tr_shade.c index c09cceed6f..aa254ba0ff 100644 --- a/code/renderer_oa/tr_shade.c +++ b/code/renderer_oa/tr_shade.c @@ -807,6 +807,7 @@ static void ProjectDlightTexture( void ) { return; } #endif + if ( !r_vertexLight->integer ) ProjectDlightTexture_scalar(); } @@ -944,35 +945,10 @@ static void ComputeColors( shaderStage_t *pStage ) } } break; - case CGEN_VERTEX_LIT: // leilei - mixing vertex colors with lighting through a glorious light hack - { // should only be used for entity models, not map assets! - vec3_t dcolor, acolor; // to save the color from actual light - vec3_t vcolor; - int y; - - - // Backup our colors - VectorCopy( backEnd.currentEntity->ambientLight, acolor ); - VectorCopy( backEnd.currentEntity->directedLight, dcolor ); - VectorCopy( backEnd.currentEntity->e.shaderRGBA, vcolor ); - - // Make our vertex color take over - - for(y=0;y<3;y++){ - backEnd.currentEntity->ambientLight[y] *= (vcolor[y] / 255); - - if (backEnd.currentEntity->ambientLight[y] < 1) backEnd.currentEntity->ambientLight[y] = 1; // black!!! - if (backEnd.currentEntity->ambientLight[y] > 255) backEnd.currentEntity->ambientLight[y] = 255; // white!!!!! - // backEnd.currentEntity->ambientLight[y] *= (vcolor[y] / 255); - // backEnd.currentEntity->directedLight[y] *= (vcolor[y] / 255); - } - - // run it through our favorite preferred lighting calculation functions - RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors ); - - // Restore light color for any other stage that doesn't do it - VectorCopy( acolor, backEnd.currentEntity->ambientLight); - VectorCopy( dcolor, backEnd.currentEntity->directedLight); + case CGEN_VERTEX_LIT: // leilei - for world only + { + Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) ); + RB_CalcVertLights( ( unsigned char * ) tess.svars.colors ); } break; case CGEN_ONE_MINUS_VERTEX: @@ -1031,42 +1007,14 @@ static void ComputeColors( shaderStage_t *pStage ) } } break; - } - - // leilei PowerVR Hack - - if (r_parseStageSimple->integer) - { - float scale; - vec3_t normme; - if ((pStage->isBlend == 1) || (pStage->isBlend == 3)){ // additive or subtracive - - for(i = 0; i < tess.numVertexes; i++) - { - scale = LUMA(tess.svars.colors[i][0], tess.svars.colors[i][1], tess.svars.colors[i][2]); - tess.svars.colors[i][3] = scale - tess.svars.colors[i][3]; - if (tess.svars.colors[i][3] > 255) tess.svars.colors[i][3] = 255; - - - normme[0] = tess.svars.colors[i][0]; - normme[1] = tess.svars.colors[i][1]; - normme[2] = tess.svars.colors[i][2]; - - // normme[0] *= (4 * tr.identityLight); - // normme[1] *= (4 * tr.identityLight); - // normme[2] *= (4 * tr.identityLight); - - - VectorNormalize(normme); - - - tess.svars.colors[i][0] = normme[0]*255; - tess.svars.colors[i][1] = normme[1]*255; - tess.svars.colors[i][2] = normme[2]*255; - } + case CGEN_MATERIAL: + if (r_shownormals->integer > 1 || (pStage->isLeiShade)){ + RB_CalcNormal( ( unsigned char * ) tess.svars.colors ); // leilei - debug normals, or use the normals as a color for a lighting shader + break; } - - } + RB_CalcMaterials( ( unsigned char * ) tess.svars.colors, pStage->matAmb, pStage->matDif, pStage->matSpec, pStage->matEmis, pStage->matHard, pStage->matAlpha ); + break; + } // // alphaGen @@ -1153,6 +1101,34 @@ static void ComputeColors( shaderStage_t *pStage ) break; } + // + // rgbMod + // + switch ( pStage->rgbMod ) + { + case CMOD_GLOW: + RB_CalcGlowBlend( ( unsigned char * ) tess.svars.colors, pStage->rgbModCol, pStage->rgbModMode ); + break; + case CMOD_UVCOL: + RB_CalcUVColor( ( unsigned char * ) tess.svars.colors, pStage->rgbModCol, pStage->rgbModMode ); + break; + case CMOD_NORMALIZETOALPHA: + RB_CalcNormalizeToAlpha( ( unsigned char * ) tess.svars.colors ); + break; + case CMOD_NORMALIZETOALPHAFAST: // TODO: use first vert + RB_CalcNormalizeToAlpha( ( unsigned char * ) tess.svars.colors ); + break; + case CMOD_OPAQUE: + for ( i = 0; i < tess.numVertexes; i++ ) + tess.svars.colors[i][3] = 0xff; + break; + case CMOD_LIGHTING: + // TODO + break; + case CMOD_BAD: + return; + } + // // fog adjustment for colors to fade out as fog increases // @@ -1198,6 +1174,43 @@ static void ComputeColors( shaderStage_t *pStage ) } } + +/* +=============== +ComputeUVColors +=============== +*/ +static void ComputeUVColors( shaderStage_t *pStage ) +{ + int i; + + // + // rgbMod + // + switch ( pStage->rgbMod ) + { + case CMOD_GLOW: + // we do this elsewhere + break; + case CMOD_UVCOL: + RB_CalcUVColor( ( unsigned char * ) tess.svars.colors, pStage->rgbModCol, pStage->rgbModMode ); + break; + case CMOD_NORMALIZETOALPHA: + break; + case CMOD_NORMALIZETOALPHAFAST: // TODO: use first vert + break; + case CMOD_OPAQUE: + break; + case CMOD_LIGHTING: + break; + case CMOD_BAD: + return; + } + + +} + + /* =============== ComputeTexCoords diff --git a/code/renderer_oa/tr_shade_calc.c b/code/renderer_oa/tr_shade_calc.c index 31236a56eb..e7faafa0a8 100644 --- a/code/renderer_oa/tr_shade_calc.c +++ b/code/renderer_oa/tr_shade_calc.c @@ -1577,6 +1577,158 @@ int i; } + + +/* +** RB_GlowBlend +** +** leilei - blends a specific color (specified in hex) +*/ + +static void RB_GlowBlend( unsigned char *colors, int glowcol, int fx ) +{ + int i; + float *v, *normal; + float incoming; + vec3_t lightDir; + vec3_t directedLight; + int numVertexes; + + directedLight[0] = (glowcol >> 16) & 0xFF; + directedLight[1] = (glowcol >> 8 ) & 0xFF; + directedLight[2] = glowcol & 0xFF; + + // if we don't have overbrights, we need to beef up the colors + if (tr.identityLight == 1){ + int f; + for (f=0;f<3;f++) + { + directedLight[f] *=2; + if (directedLight[f]>255)directedLight[f]=255; + } + } + + VectorCopy( backEnd.or.viewOrigin, lightDir ); + + v = tess.xyz[0]; + normal = tess.normal[0]; + VectorNormalizeFast( lightDir ); + + numVertexes = tess.numVertexes; + for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) { + + if (fx == 1) + incoming = sin(i+(tess.shaderTime * 12)) * DotProduct (normal, lightDir); // fluctuate! + else if (fx == 2) + incoming = sin((tess.shaderTime * 12)) * DotProduct (normal, lightDir); // pulsate! + else if (fx == 3){ + incoming = DotProduct (normal, lightDir) * 4.0; + incoming = sin(incoming+tess.shaderTime * 16); // wave + } + else if (fx == 6) + { + float eh, off; + vec3_t the; + + eh = (v[0] + v[1] + v[2]) * 3; + off = sin(eh + tess.shaderTime * 5); + + VectorScale( normal, off, the); + + incoming = VectorNormalize(the); + if (colors[i*4+3] < 128) incoming = 0; + + // clamp + if (incoming > 1) incoming = 1; + if (incoming < 0) incoming = 0; + + // blend the new color over the current color + colors[i*4+0] = (colors[i*4+0] * (1-incoming)) + ((incoming) * directedLight[0]); + colors[i*4+1] = (colors[i*4+1] * (1-incoming)) + ((incoming) * directedLight[1]); + colors[i*4+2] = (colors[i*4+2] * (1-incoming)) + ((incoming) * directedLight[2]); + return; + } + else // generic glow + { + incoming = DotProduct (normal, lightDir) * 0.8f; + } + + // clamp + if (incoming > 1) incoming = 1; + if (incoming < 0) incoming = 0; + + // blend the new color over the current color + colors[i*4+0] = (colors[i*4+0] * (incoming)) + ((1-incoming) * directedLight[0]); + colors[i*4+1] = (colors[i*4+1] * (incoming)) + ((1-incoming) * directedLight[1]); + colors[i*4+2] = (colors[i*4+2] * (incoming)) + ((1-incoming) * directedLight[2]); + } +} + + + +/* +** RB_UVColor +** +** leilei - blends a specific color (specified in hex) +*/ + +static void RB_UVColor( unsigned char *colors, int glowcol, int fx ) +{ + int i; + float *v, *normal; + float incoming; + vec3_t lightDir; + vec3_t directedLight; + float *texc; + vec3_t col; + + int numVertexes; + vec3_t newcol; + + directedLight[0] = (glowcol >> 16) & 0xFF; + directedLight[1] = (glowcol >> 8 ) & 0xFF; + directedLight[2] = glowcol & 0xFF; + + + VectorCopy( backEnd.or.viewOrigin, lightDir ); + + v = tess.xyz[0]; + normal = tess.normal[0]; + texc = tess.texCoords[0]; + + numVertexes = tess.numVertexes; + for (i = 0 ; i < numVertexes ; i++, v += 4, texc+=2 ) { + int tf; + // For each mode, deal with fading for towards the edge of a uvmap + + incoming = 0; + if (fx == 0) // Off the top edge, set it to the color + { + if (texc[1] < 0.0f) incoming = 1; + } + if (fx == 1) // Fade it + { + if (v[4] < 0.0f) incoming = 255; + } + + for(tf=0 ; tf<3 ; tf++ ) + { + newcol[tf] = incoming; + + if (newcol[tf] > 255) newcol[tf] = 255; + if (newcol[tf] < 0) newcol[tf] = 0; + } + + // blend the new color over the current color + colors[i*4+0] = newcol[0]; + colors[i*4+1] = newcol[1]; + colors[i*4+2] = newcol[2]; + } +} + + + + /* ** RB_CalcDiffuseColor ** @@ -1905,6 +2057,7 @@ void RB_CalcDiffuseColor( unsigned char *colors ) } + /* ** RB_CalcUniformColor ** @@ -1974,6 +2127,136 @@ void RB_CalcDynamicColor( unsigned char *colors ) } +void RB_CalcGlowBlend( unsigned char *colors, int glowcol, int fx ) +{ + RB_GlowBlend( colors, glowcol, fx ); +} + +void RB_CalcUVColor( unsigned char *colors, int glowcol, int fx ) +{ + RB_UVColor( colors, glowcol, fx ); +} + + +// normalize colors but alpha has the intensity of the colors. +void RB_CalcNormalizeToAlpha( unsigned char *colors) +{ + int i; + float *v, *normal; + int numVertexes; + + v = tess.xyz[0]; + normal = tess.normal[0]; // do we even need this + + numVertexes = tess.numVertexes; + for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) { + + colors[i*4+3] = LUMA(colors[i*4+0], colors[i*4+1], colors[i*4+2]); + // leilei - boost it up a little more to fight pvr1's subtractive modulation + //colors[i*4+3] = pow(colors[i*4+3]/255,0.7f)*255; + { + int max; + + max = colors[i*4+0] > colors[i*4+1] ? colors[i*4+0] : colors[i*4+1]; + max = max > colors[i*4+2] ? max : colors[i*4+2]; + max += 1; + colors[i*4+0] = colors[i*4+0] * 255 / max; + colors[i*4+1] = colors[i*4+1] * 255 / max; + colors[i*4+2] = colors[i*4+2] * 255 / max; + + } + } +} + + + +/* +** RB_VertLightsPerVert +** +** leilei - for maps, try to light up vertex lighting with dynamic lights +*/ + + +static void RB_VertLightsPerVert( unsigned char *colors ) +{ + int i, f; + float *v, *normal; + int numVertexes; + + vec3_t cl; + vec3_t cv; + + v = tess.xyz[0]; + normal = tess.normal[0]; + + numVertexes = tess.numVertexes; + for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) { + // get the world colors + cl[0] = colors[i*4+0]; + cl[1] = colors[i*4+1]; + cl[2] = colors[i*4+2]; + + + if(r_dynamiclight->integer) + { + for (f=0 ; fradius >= 1) // if light is good, mark the map + { + // calc the light against the world verts + VectorSubtract( l->origin, v, cv ); + float power = 2048 * ( l->radius ); + float d = VectorNormalize( cv ); + power = power / ( d * d ); + if (power < 0) power = 0; + + // add the color of the light + cl[0] += (l->color[0] * power); + cl[1] += (l->color[1] * power); + cl[2] += (l->color[2] * power); + + // clamp stuff + // normalize by color instead of saturating to white + if ( ( (int)cl[0] | (int)cl[1] | (int)cl[2] ) > 255 ) { + int max; + + max = cl[0] > cl[1] ? cl[0] : cl[1]; + max = max > cl[2] ? max : cl[2]; + cl[0] = cl[0] * 255 / max; + cl[1] = cl[1] * 255 / max; + cl[2] = cl[2] * 255 / max; + } + if (cl[0] < 0) cl[0] = 0; + if (cl[1] < 0) cl[1] = 0; + if (cl[2] < 0) cl[2] = 0; + + // if (cl[0] > 255) cl[0] = 255; + // if (cl[1] > 255) cl[1] = 255; + // if (cl[2] > 255) cl[2] = 255; + } + } + } + // give the world our new modulated color + colors[i*4+0] = cl[0]; + colors[i*4+1] = cl[1]; + colors[i*4+2] = cl[2]; + + } +} + + +void RB_CalcVertLights( unsigned char *colors ) +{ + RB_VertLightsPerVert( colors ); +} + + + + // leilei celsperiment @@ -2065,8 +2348,237 @@ void RB_CalcFlatDirect( unsigned char *colors ) +#define MAXFRESLIGHTS 512 + +/* +** RB_CalcMaterialColor +** +** leilei - for more control on diffuse/ambient/emiss/specular colors rather than diffuse only. Possibly could use some SIMD magic here +*/ + +static void RB_CalcMaterialColor( unsigned char *colors, int maxl, int ambient, int diffuse, int specular, int emissive, int spechard, int alpha ) +{ + int i, j, l; + float *v, *normal; + trRefEntity_t *ent; + vec3_t ambientLight; + int numVertexes; + vec3_t lorigin; + + vec3_t matAmb, matDif, matSpec, matEmis; + float matHard = spechard / 128.0f; + int specenabled = 0; + + + if (spechard == 128) + matHard = 1; + + if (specular) + specenabled = 1; + + // Parse material colors + + matAmb[0] = ((ambient >> 16) & 0xFF); + matAmb[1] = ((ambient >> 8 ) & 0xFF); + matAmb[2] = (ambient & 0xFF); + + matDif[0] = ((diffuse >> 16) & 0xFF); + matDif[1] = ((diffuse >> 8 ) & 0xFF); + matDif[2] = (diffuse & 0xFF); + + matSpec[0] = ((specular >> 16) & 0xFF); + matSpec[1] = ((specular >> 8 ) & 0xFF); + matSpec[2] = (specular & 0xFF); + + matEmis[0] = (emissive >> 16) & 0xFF; + matEmis[1] = (emissive >> 8 ) & 0xFF; + matEmis[2] = emissive & 0xFF; + + VectorNormalize( matAmb ); + VectorNormalize( matDif ); + VectorNormalize( matSpec ); + VectorNormalize( matEmis ); + + // Overbright clamp + + matEmis[0] *= tr.identityLight; + matEmis[1] *= tr.identityLight; + matEmis[2] *= tr.identityLight; + + // setup ent + + ent = backEnd.currentEntity; + + if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) + VectorCopy( ent->e.lightingOrigin, lorigin ); + else + VectorCopy( ent->e.origin, lorigin ); + + + VectorCopy( ent->ambientLight, ambientLight ); + + int liteOn[maxl]; + vec3_t liteOrg[maxl]; + vec3_t liteCol[maxl]; + int active = 1; + + if (maxl > MAXFRESLIGHTS) maxl = MAXFRESLIGHTS; + + // first light is always the world + liteOn[0] = 1; + VectorCopy( ent->directedLight, liteCol[0] ); + VectorCopy( ent->lightDir, liteOrg[0] ); + + ambientLight[0] *= matAmb[0]*2; + ambientLight[1] *= matAmb[1]*2; + ambientLight[2] *= matAmb[2]*2; + + + + if (maxl>1) + { + // add dynamic lights + { + dlight_t *l; + + for (i=0 ; imaxl) + continue; + + l = &backEnd.refdef.dlights[i]; + + VectorCopy( l->color, liteCol[active] ); + + VectorSubtract( l->origin, lorigin, liteOrg[active] ); + + // attenuation + float d = VectorNormalize( liteOrg[active] ); + float power = 16 * ( l->radius ); + power = power / ( d * d ); + if (power < 0) power = 0; + if (power > 1) power = 1; // needed to prevent powerup light overflow, as quad/flagcarriers players should not glow themselves + + // transform + liteOrg[active][0] = DotProduct( liteOrg[active], ent->e.axis[0] ); + liteOrg[active][1] = DotProduct( liteOrg[active], ent->e.axis[1] ); + liteOrg[active][2] = DotProduct( liteOrg[active], ent->e.axis[2] ); + + liteCol[active][0] *= (255 * power); + liteCol[active][1] *= (255 * power); + liteCol[active][2] *= (255 * power); + + liteOn[active] = 1; + active++; + + } + } + } + + + // Set up our model + v = tess.xyz[0]; + normal = tess.normal[0]; + + numVertexes = tess.numVertexes; + + + for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) { + vec3_t difs; + vec3_t specs; + + // clear + difs[0] = difs[1] = difs[2] = 0; + specs[0] = specs[1] = specs[2] = 0; + + // HACK - Fix the world light + VectorCopy( ent->lightDir, liteOrg[0] ); + + // go through lights and add them + for (l=0;l 1) { + b = 1; + } + } + + specs[0] += b * liteCol[l][0]; + specs[1] += b * liteCol[l][1]; + specs[2] += b * liteCol[l][2]; + } + + if (c<0) c=0; + if (c>255) c=255; + if (liteOn[l] != 2){ + difs[0] += c * liteCol[l][0]; + difs[1] += c * liteCol[l][1]; + difs[2] += c * liteCol[l][2]; + } + + } + + // Add Ambient and CLAMP + j = ri.ftol(ambientLight[0] + (difs[0] * matDif[0]) + (specs[0] * matSpec[0])); + if ( j > 255 ) { + j = 255; + } + colors[i*4+0] = j; + + j = ri.ftol(ambientLight[1] + (difs[1] * matDif[1]) + (specs[1] * matSpec[1])); + if ( j > 255 ) { + j = 255; + } + colors[i*4+1] = j; + + j = ri.ftol(ambientLight[2] + (difs[2] * matDif[2]) + (specs[2] * matSpec[2])); + if ( j > 255 ) { + j = 255; + } + colors[i*4+2] = j; + + colors[i*4+3] = alpha; + } +} +void RB_CalcMaterials( unsigned char *colors, int ambient, int diffuse, int specular, int emissive, int spechard, int alpha ) +{ + // TODO: Low detail materials + RB_CalcMaterialColor( colors, 1, ambient, diffuse, specular, emissive, spechard, alpha ); +} diff --git a/code/renderer_oa/tr_shader.c b/code/renderer_oa/tr_shader.c index df5092289c..b99552ab0f 100644 --- a/code/renderer_oa/tr_shader.c +++ b/code/renderer_oa/tr_shader.c @@ -993,7 +993,6 @@ static void ParseTexMod( char *_text, shaderStage_t *stage ) return; } tmi->atlas.width = atof( token ); - ri.Printf( PRINT_WARNING, "shader '%s' has width %f\n", shader.name, tmi->atlas.width ); token = COM_ParseExt( text, qfalse ); if ( token[0] == 0 ) @@ -1096,14 +1095,56 @@ static void ParseTexMod( char *_text, shaderStage_t *stage ) } + +/* +============== +ParseNum / ParseHex +============== +*/ +int ShParseHex (const char *hex) +{ + const char *str; + int num; + + num = 0; + str = hex; + + while (*str) + { + num <<= 4; + if (*str >= '0' && *str <= '9') + num += *str-'0'; + else if (*str >= 'a' && *str <= 'f') + num += 10 + *str-'a'; + else if (*str >= 'A' && *str <= 'F') + num += 10 + *str-'A'; + else + return 0; + str++; + } + + return num; +} + + +static int ShParseNum (const char *str) +{ + if (str[0] == '$') + return ShParseHex (str+1); + if (str[0] == '0' && str[1] == 'x') + return ShParseHex (str+2); + return atol (str); +} + + + /* =================== ParseStage =================== */ -qboolean ParseStageSimple( shaderStage_t *stage, char **text ); -extern cvar_t *r_parseStageSimple; // Leilei - for debugging PVR only! + static qboolean ParseStage( shaderStage_t *stage, char **text ) { @@ -1118,13 +1159,6 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) qboolean stageMipmaps = !shader.noMipMaps; - // leilei - switch to simple for simple cards - if (r_parseStageSimple->integer){ - - return ParseStageSimple(stage, text); - } - - stage->active = qtrue; Com_Memset(programName, 0, sizeof(programName)); @@ -2323,899 +2357,24 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) stage->bundle[6].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags ); - if ( !stage->bundle[6].image[num] ) - { - ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - stage->bundle[6].numImageAnimations++; - } - } - } - else if ( !Q_stricmp( token, "clampAnimMap7" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampAnimMmap7' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - stage->bundle[7].imageAnimationSpeed = atof( token ); - - // parse up to MAX_IMAGE_ANIMATIONS animations - while ( 1 ) { - int num; - - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) { - break; - } - num = stage->bundle[7].numImageAnimations; - if ( num < MAX_IMAGE_ANIMATIONS ) { - imgFlags_t flags = IMGFLAG_SRGB; - - if (stageMipmaps) - flags |= IMGFLAG_MIPMAP; - - if (!shader.noPicMip) - flags |= IMGFLAG_PICMIP; - - stage->bundle[7].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags ); - - if ( !stage->bundle[7].image[num] ) - { - ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - stage->bundle[7].numImageAnimations++; - } - } - } - else if ( !Q_stricmp( token, "videoMap" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMmap' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - stage->bundle[0].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); - if (stage->bundle[0].videoMapHandle != -1) { - stage->bundle[0].isVideoMap = qtrue; - stage->bundle[0].image[0] = tr.scratchImage[stage->bundle[0].videoMapHandle]; - } - } - // - // videoMap2 - // - else if ( !Q_stricmp( token, "videoMap2" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMap2' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - stage->bundle[2].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); - if (stage->bundle[2].videoMapHandle != -1) { - stage->bundle[2].isVideoMap = qtrue; - stage->bundle[2].image[0] = tr.scratchImage[stage->bundle[2].videoMapHandle]; - } - } - // - // videoMap3 - // - else if ( !Q_stricmp( token, "videoMap3" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMap3' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - stage->bundle[3].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); - if (stage->bundle[3].videoMapHandle != -1) { - stage->bundle[3].isVideoMap = qtrue; - stage->bundle[3].image[0] = tr.scratchImage[stage->bundle[3].videoMapHandle]; - } - } - // - // videoMap4 - // - else if ( !Q_stricmp( token, "videoMap4" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMap4' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - stage->bundle[4].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); - if (stage->bundle[4].videoMapHandle != -1) { - stage->bundle[4].isVideoMap = qtrue; - stage->bundle[4].image[0] = tr.scratchImage[stage->bundle[4].videoMapHandle]; - } - } - // - // videoMap5 - // - else if ( !Q_stricmp( token, "videoMap5" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMap5' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - stage->bundle[5].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); - if (stage->bundle[5].videoMapHandle != -1) { - stage->bundle[5].isVideoMap = qtrue; - stage->bundle[5].image[0] = tr.scratchImage[stage->bundle[5].videoMapHandle]; - } - } - // - // videoMap6 - // - else if ( !Q_stricmp( token, "videoMap6" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMap6' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - stage->bundle[6].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); - if (stage->bundle[6].videoMapHandle != -1) { - stage->bundle[6].isVideoMap = qtrue; - stage->bundle[6].image[0] = tr.scratchImage[stage->bundle[6].videoMapHandle]; - } - } - // - // videoMap7 - // - else if ( !Q_stricmp( token, "videoMap7" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMap7' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - stage->bundle[7].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); - if (stage->bundle[7].videoMapHandle != -1) { - stage->bundle[7].isVideoMap = qtrue; - stage->bundle[7].image[0] = tr.scratchImage[stage->bundle[7].videoMapHandle]; - } - } - // - // alphafunc - // - else if ( !Q_stricmp( token, "alphaFunc" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'alphaFunc' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - atestBits = NameToAFunc( token ); - } - // - // depthFunc - // - else if ( !Q_stricmp( token, "depthfunc" ) ) - { - token = COM_ParseExt( text, qfalse ); - - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'depthfunc' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - if ( !Q_stricmp( token, "lequal" ) ) - { - depthFuncBits = 0; - } - else if ( !Q_stricmp( token, "equal" ) ) - { - depthFuncBits = GLS_DEPTHFUNC_EQUAL; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown depthfunc '%s' in shader '%s'\n", token, shader.name ); - continue; - } - } - // - // detail - // - else if ( !Q_stricmp( token, "detail" ) ) - { - stage->isDetail = qtrue; - } - // - // blendfunc - // or blendfunc - // - else if ( !Q_stricmp( token, "blendfunc" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name ); - continue; - } - // check for "simple" blends first - if ( !Q_stricmp( token, "add" ) ) { - blendSrcBits = GLS_SRCBLEND_ONE; - blendDstBits = GLS_DSTBLEND_ONE; - - } else if ( !Q_stricmp( token, "filter" ) ) { - blendSrcBits = GLS_SRCBLEND_DST_COLOR; - blendDstBits = GLS_DSTBLEND_ZERO; - } else if ( !Q_stricmp( token, "blend" ) ) { - blendSrcBits = GLS_SRCBLEND_SRC_ALPHA; - blendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } else { - // complex double blends - blendSrcBits = NameToSrcBlendMode( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name ); - continue; - } - blendDstBits = NameToDstBlendMode( token ); - } - - stage->isBlend = 1; // 2x2 - - // clear depth mask for blended surfaces - if ( !depthMaskExplicit ) - { - depthMaskBits = 0; - } - - - } - // - // rgbGen - // - else if ( !Q_stricmp( token, "rgbGen" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameters for rgbGen in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "wave" ) ) - { - ParseWaveForm( text, &stage->rgbWave ); - stage->rgbGen = CGEN_WAVEFORM; - } - else if ( !Q_stricmp( token, "const" ) ) - { - vec3_t color; - - ParseVector( text, 3, color ); - stage->constantColor[0] = 255 * color[0]; - stage->constantColor[1] = 255 * color[1]; - stage->constantColor[2] = 255 * color[2]; - - stage->rgbGen = CGEN_CONST; - } - else if ( !Q_stricmp( token, "identity" ) ) - { - stage->rgbGen = CGEN_IDENTITY; - } - else if ( !Q_stricmp( token, "identityLighting" ) ) - { - stage->rgbGen = CGEN_IDENTITY_LIGHTING; - } - else if ( !Q_stricmp( token, "entity" ) ) - { - stage->rgbGen = CGEN_ENTITY; - } - else if ( !Q_stricmp( token, "oneMinusEntity" ) ) - { - stage->rgbGen = CGEN_ONE_MINUS_ENTITY; - } - else if ( !Q_stricmp( token, "vertex" ) ) - { - stage->rgbGen = CGEN_VERTEX; - if ( stage->alphaGen == 0 ) { - stage->alphaGen = AGEN_VERTEX; - } - } - else if ( !Q_stricmp( token, "exactVertex" ) ) - { - stage->rgbGen = CGEN_EXACT_VERTEX; - } - else if ( !Q_stricmp( token, "vertexLighting" ) ) // leilei - vertex WITH a lighting pass after - { - stage->rgbGen = CGEN_VERTEX_LIT; - if ( stage->alphaGen == 0 ) { - stage->alphaGen = AGEN_VERTEX; - } - } - else if ( !Q_stricmp( token, "vertexLighting2" ) ) // leilei - second vertex color - { - stage->rgbGen = CGEN_VERTEX_LIT; - if ( stage->alphaGen == 0 ) { - stage->alphaGen = AGEN_VERTEX; - } - } - else if ( !Q_stricmp( token, "lightingDiffuse" ) ) - { - stage->rgbGen = CGEN_LIGHTING_DIFFUSE; - } - else if ( !Q_stricmp( token, "lightingUniform" ) ) - { - stage->rgbGen = CGEN_LIGHTING_UNIFORM; - } - else if ( !Q_stricmp( token, "lightingDynamic" ) ) - { - stage->rgbGen = CGEN_LIGHTING_DYNAMIC; - } - else if ( !Q_stricmp( token, "flatAmbient" ) ) - { - stage->rgbGen = CGEN_LIGHTING_FLAT_AMBIENT; - } - else if ( !Q_stricmp( token, "flatDirect" ) ) - { - stage->rgbGen = CGEN_LIGHTING_FLAT_DIRECT; - } - else if ( !Q_stricmp( token, "oneMinusVertex" ) ) - { - stage->rgbGen = CGEN_ONE_MINUS_VERTEX; - } - else if ( !Q_stricmp( token, "lightingSpecularDiffuse" ) ) // leilei - deprecated - { - stage->rgbGen = CGEN_LIGHTING_DIFFUSE; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown rgbGen parameter '%s' in shader '%s'\n", token, shader.name ); - continue; - } - } - // - // alphaGen - // - else if ( !Q_stricmp( token, "alphaGen" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameters for alphaGen in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "wave" ) ) - { - ParseWaveForm( text, &stage->alphaWave ); - stage->alphaGen = AGEN_WAVEFORM; - } - else if ( !Q_stricmp( token, "const" ) ) - { - token = COM_ParseExt( text, qfalse ); - stage->constantColor[3] = 255 * atof( token ); - stage->alphaGen = AGEN_CONST; - } - else if ( !Q_stricmp( token, "identity" ) ) - { - stage->alphaGen = AGEN_IDENTITY; - } - else if ( !Q_stricmp( token, "entity" ) ) - { - stage->alphaGen = AGEN_ENTITY; - } - else if ( !Q_stricmp( token, "oneMinusEntity" ) ) - { - stage->alphaGen = AGEN_ONE_MINUS_ENTITY; - } - else if ( !Q_stricmp( token, "vertex" ) ) - { - stage->alphaGen = AGEN_VERTEX; - } - else if ( !Q_stricmp( token, "lightingSpecular" ) ) - { - stage->alphaGen = AGEN_LIGHTING_SPECULAR; - } - else if ( !Q_stricmp( token, "oneMinusVertex" ) ) - { - stage->alphaGen = AGEN_ONE_MINUS_VERTEX; - } - else if ( !Q_stricmp( token, "portal" ) ) - { - stage->alphaGen = AGEN_PORTAL; - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - shader.portalRange = 256; - ri.Printf( PRINT_WARNING, "WARNING: missing range parameter for alphaGen portal in shader '%s', defaulting to 256\n", shader.name ); - } - else - { - shader.portalRange = atof( token ); - } - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown alphaGen parameter '%s' in shader '%s'\n", token, shader.name ); - continue; - } - } - // - // tcGen - // - else if ( !Q_stricmp(token, "texgen") || !Q_stricmp( token, "tcGen" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing texgen parm in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "environment" ) ) - { - stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED; - } - else if ( !Q_stricmp( token, "cel" ) ) - { - stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_CELSHADE_MAPPED; - } - else if ( !Q_stricmp( token, "celshading" ) ) // leilei - my technique is different - { - stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_CELSHADE_LEILEI; - } - else if ( !Q_stricmp( token, "eyeleft" ) ) // leilei - eye tracking - { - stage->bundle[0].tcGen = TCGEN_EYE_LEFT; - } - else if ( !Q_stricmp( token, "eyeright" ) ) // leilei - eye tracking - { - stage->bundle[0].tcGen = TCGEN_EYE_RIGHT; - } - else if ( !Q_stricmp( token, "environmentWater" ) ) - { - stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED_WATER; // leilei - water's envmaps - } - else if ( !Q_stricmp( token, "lightmap" ) ) - { - stage->bundle[0].tcGen = TCGEN_LIGHTMAP; - } - else if ( !Q_stricmp( token, "texture" ) || !Q_stricmp( token, "base" ) ) - { - stage->bundle[0].tcGen = TCGEN_TEXTURE; - } - else if ( !Q_stricmp( token, "vector" ) ) - { - ParseVector( text, 3, stage->bundle[0].tcGenVectors[0] ); - ParseVector( text, 3, stage->bundle[0].tcGenVectors[1] ); - - stage->bundle[0].tcGen = TCGEN_VECTOR; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown texgen parm in shader '%s'\n", shader.name ); - } - } - // - // tcMod <...> - // - else if ( !Q_stricmp( token, "tcMod" ) ) - { - char buffer[1024] = ""; - - while ( 1 ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - break; - strcat( buffer, token ); - strcat( buffer, " " ); - } - - ParseTexMod( buffer, stage ); - - continue; - } - // - // depthmask - // - else if ( !Q_stricmp( token, "depthwrite" ) ) - { - depthMaskBits = GLS_DEPTHMASK_TRUE; - depthMaskExplicit = qtrue; - - continue; - } - - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - - - - - // END DITHER TEST - } - - // - // if cgen isn't explicitly specified, use either identity or identitylighting - // - if ( stage->rgbGen == CGEN_BAD ) { - if ( blendSrcBits == 0 || - blendSrcBits == GLS_SRCBLEND_ONE || - blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) { - stage->rgbGen = CGEN_IDENTITY_LIGHTING; - } else { - stage->rgbGen = CGEN_IDENTITY; - } - } - - - // - // implicitly assume that a GL_ONE GL_ZERO blend mask disables blending - // - if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && - ( blendDstBits == GLS_DSTBLEND_ZERO ) ) - { - blendDstBits = blendSrcBits = 0; - depthMaskBits = GLS_DEPTHMASK_TRUE; - } - - // decide which agens we can skip - if ( stage->alphaGen == AGEN_IDENTITY ) { - if ( stage->rgbGen == CGEN_IDENTITY - || stage->rgbGen == CGEN_LIGHTING_DIFFUSE - || stage->rgbGen == CGEN_LIGHTING_UNIFORM - || stage->rgbGen == CGEN_LIGHTING_DYNAMIC) { - stage->alphaGen = AGEN_SKIP; - } - } - - // - // compute state bits - // - stage->stateBits = depthMaskBits | - blendSrcBits | blendDstBits | - atestBits | - depthFuncBits; - - - return qtrue; -} - - -/* -=================== -ParseStageSimple - - -leilei - the purpose of this is to load textures after processing their blending properties, - so we can approximate effects on incapable hardware such as Matrox Mystique, S3 ViRGE, - PowerVR PCX2, software rendering... - A lot of things are stripped out (like GLSL and multitexture stuff) -=================== -*/ - -extern int hackoperation; -extern int ismaptexture; -int surfaceflagsy; -qboolean ParseStageSimple( shaderStage_t *stage, char **text ) -{ - char *token; - char programName[MAX_QPATH]; - char programVertexObjects[MAX_PROGRAM_OBJECTS][MAX_QPATH]; - char programFragmentObjects[MAX_PROGRAM_OBJECTS][MAX_QPATH]; - char imageName[MAX_QPATH]; // for loading later - char imageNameAnim0[MAX_QPATH]; - char imageNameAnim1[MAX_QPATH]; - char imageNameAnim2[MAX_QPATH]; - char imageNameAnim3[MAX_QPATH]; - char imageNameAnim4[MAX_QPATH]; - char imageNameAnim5[MAX_QPATH]; - char imageNameAnim6[MAX_QPATH]; - char imageNameAnim7[MAX_QPATH]; - char imageNameAnim8[MAX_QPATH]; - imgType_t itype = IMGTYPE_COLORALPHA; - imgFlags_t iflags = IMGFLAG_NONE; - int numVertexObjects = 0; - int numFragmentObjects = 0; - int loadlater = 0; - int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0; - qboolean depthMaskExplicit = qfalse; - - qboolean stageMipmaps = !shader.noMipMaps; - stage->active = qtrue; - Com_Memset(programName, 0, sizeof(programName)); - - - hackoperation = 2; // reset the hackop - - while ( 1 ) - { - - - - //stage->isBlend = 0; - token = COM_ParseExt( text, qtrue ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: no matching '}' found\n" ); - return qfalse; - } - - if ( token[0] == '}' ) - { -#ifdef GLSL_TEXTURES - if (programName[0]) { - if (!Q_stricmp(programName, "skip")) { - stage->program = tr.skipProgram; - } else { - if (!numVertexObjects) { - ri.Printf(PRINT_WARNING, "WARNING: no 'vertexProgram' specified for 'program %s' in shader '%s'\n", programName, shader.name); - return qfalse; - } - - if (!numFragmentObjects) { - ri.Printf(PRINT_WARNING, "WARNING: no 'fragmentProgram' specified for 'program %s' in shader '%s'\n", programName, shader.name); - return qfalse; - } - - stage->isGLSL=0; - stage->program = RE_GLSL_RegisterProgram(programName, (const char *)programVertexObjects, numVertexObjects, (const char *)programFragmentObjects, numFragmentObjects); - if (!stage->program) { - ri.Printf(PRINT_WARNING, "WARNING: RE_GLSL_RegisterProgram failed for 'program %s' in shader '%s'\n", programName, shader.name); - //return qfalse; - } - else - stage->isGLSL=1; - } - } else if (numVertexObjects) { - ri.Printf(PRINT_WARNING, "WARNING: no 'program' specified for 'vertexProgram' in shader '%s'\n", shader.name); - return qfalse; - } else if (numFragmentObjects) { - ri.Printf(PRINT_WARNING, "WARNING: no 'program' specified for 'fragmentProgram' in shader '%s'\n", shader.name); - return qfalse; - } -#endif - break; - } - // - // program - // - else if (!Q_stricmp(token, "program")) { - token = COM_ParseExt(text, qfalse); - - if (!vertexShaders) - continue; - - if (!token[0]) { - ri.Printf(PRINT_WARNING, "WARNING: missing parameter for 'program' keyword in shader '%s'\n", shader.name); - return qfalse; - } - - Q_strncpyz(programName, token, sizeof(programName)); - } - // - // vertexProgram .... - // - else if (!Q_stricmp(token, "vertexProgram")) { - token = COM_ParseExt(text, qfalse); - - if (!vertexShaders) { - while (token[0]) - token = COM_ParseExt(text, qfalse); - - continue; - } - - if (!token[0]) { - ri.Printf(PRINT_WARNING, "WARNING: missing parameter(s) for 'vertexProgram' keyword in shader '%s'\n", shader.name); - return qfalse; - } - - // parse up to MAX_PROGRAM_OBJECTS files - for(;;) { - if (numVertexObjects < MAX_PROGRAM_OBJECTS) { - Q_strncpyz(programVertexObjects[numVertexObjects], token, sizeof(programVertexObjects[numVertexObjects])); - numVertexObjects++; - } else { - ri.Printf(PRINT_WARNING, "WARNING: Too many parameters for 'vertexProgram' keyword in shader '%s'\n", shader.name); - return qfalse; - } - - token = COM_ParseExt(text, qfalse); - if (!token[0]) - break; - } - } - // - // fragmentProgram .... - // - else if (!Q_stricmp(token, "fragmentProgram")) { - token = COM_ParseExt(text, qfalse); - - if (!vertexShaders) { - while (token[0]) - token = COM_ParseExt(text, qfalse); - - continue; - } - - if (!token[0]) { - ri.Printf(PRINT_WARNING, "WARNING: missing parameter(s) for 'fragmentProgram' keyword in shader '%s'\n", shader.name); - return qfalse; - } - - // parse up to MAX_PROGRAM_OBJECTS files - for(;;) { - if (numFragmentObjects < MAX_PROGRAM_OBJECTS) { - Q_strncpyz(programFragmentObjects[numFragmentObjects], token, sizeof(programFragmentObjects[numFragmentObjects])); - numFragmentObjects++; - } else { - ri.Printf(PRINT_WARNING, "WARNING: Too many parameters for 'fragmentProgram' keyword in shader '%s'\n", shader.name); - return qfalse; - } - - token = COM_ParseExt(text, qfalse); - if (!token[0]) - break; - } - } - else if ( !Q_stricmp( token, "mipOffset" ) ){ - token = COM_ParseExt(text,qfalse); - stage->mipBias = atoi(token); - } - else if ( !Q_stricmp( token, "nomipmaps" ) ){ - stageMipmaps = qfalse; - } - // - // map - // - else if ( !Q_stricmp( token, "map" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'map' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - if ( !Q_stricmp( token, "$whiteimage" ) ) - { - stage->bundle[0].image[0] = tr.whiteImage; - continue; - } - else if ( !Q_stricmp( token, "$lightmap" ) ) - { - stage->bundle[0].isLightmap = qtrue; - if ( shader.lightmapIndex < 0 || !tr.lightmaps ) { - stage->bundle[0].image[0] = tr.whiteImage; - } else { - stage->bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; - } - continue; - } - else - { - imgType_t type = IMGTYPE_COLORALPHA; - imgFlags_t flags = IMGFLAG_NONE; - - if (!shader.noMipMaps) - flags |= IMGFLAG_MIPMAP; - - if (!shader.noPicMip) - flags |= IMGFLAG_PICMIP; - - //stage->bundle[0].image[0] = R_FindImageFile( token, type, flags ); - stage->bundle[0].image[0] = tr.whiteImage; - COM_StripExtension( token, imageName, MAX_QPATH ); - itype = type; iflags = flags; - loadlater = 1; -// imageName = va("%s",token); - - // if ( !stage->bundle[0].image[0] ) - // { - // ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); - // return qfalse; - // } - } - } - // - // clampmap - // - else if ( !Q_stricmp( token, "clampmap" ) ) - { - imgType_t type = IMGTYPE_COLORALPHA; - imgFlags_t flags = IMGFLAG_CLAMPTOEDGE; - - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampmap' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - if (!shader.noMipMaps) - flags |= IMGFLAG_MIPMAP; - - if (!shader.noPicMip) { - flags |= IMGFLAG_PICMIP; - } - - stage->bundle[0].image[0] = tr.whiteImage; - COM_StripExtension( token, imageName, MAX_QPATH ); - itype = type; iflags = flags; - loadlater = 1; - } - // - // animMap .... - // - else if ( !Q_stricmp( token, "animMap" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'animMmap' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - stage->bundle[0].imageAnimationSpeed = atof( token ); - - // parse up to MAX_IMAGE_ANIMATIONS animations - while ( 1 ) { - int num; - - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) { - break; - } - num = stage->bundle[0].numImageAnimations; - if ( num < MAX_IMAGE_ANIMATIONS ) { - imgFlags_t flags = IMGFLAG_NONE; - - if (!shader.noMipMaps) - flags |= IMGFLAG_MIPMAP; - - if (!shader.noPicMip) - flags |= IMGFLAG_PICMIP; - - //stage->bundle[0].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags ); - stage->bundle[0].image[num] = tr.whiteImage; - if(num == 0) COM_StripExtension( token, imageNameAnim0, MAX_QPATH ); - if(num == 1) COM_StripExtension( token, imageNameAnim1, MAX_QPATH ); - if(num == 2) COM_StripExtension( token, imageNameAnim2, MAX_QPATH ); - if(num == 3) COM_StripExtension( token, imageNameAnim3, MAX_QPATH ); - if(num == 4) COM_StripExtension( token, imageNameAnim4, MAX_QPATH ); - if(num == 5) COM_StripExtension( token, imageNameAnim5, MAX_QPATH ); - if(num == 6) COM_StripExtension( token, imageNameAnim6, MAX_QPATH ); - if(num == 7) COM_StripExtension( token, imageNameAnim7, MAX_QPATH ); - if(num == 8) COM_StripExtension( token, imageNameAnim8, MAX_QPATH ); - iflags = flags; - loadlater = 1; - stage->bundle[0].numImageAnimations++; + if ( !stage->bundle[6].image[num] ) + { + ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); + return qfalse; + } + stage->bundle[6].numImageAnimations++; } } } - else if ( !Q_stricmp( token, "clampAnimMap" ) ) + else if ( !Q_stricmp( token, "clampAnimMap7" ) ) { token = COM_ParseExt( text, qfalse ); if ( !token[0] ) { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampAnimMmap' keyword in shader '%s'\n", shader.name ); + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampAnimMmap7' keyword in shader '%s'\n", shader.name ); return qfalse; } - stage->bundle[0].imageAnimationSpeed = atof( token ); + stage->bundle[7].imageAnimationSpeed = atof( token ); // parse up to MAX_IMAGE_ANIMATIONS animations while ( 1 ) { @@ -3225,7 +2384,7 @@ qboolean ParseStageSimple( shaderStage_t *stage, char **text ) if ( !token[0] ) { break; } - num = stage->bundle[0].numImageAnimations; + num = stage->bundle[7].numImageAnimations; if ( num < MAX_IMAGE_ANIMATIONS ) { imgFlags_t flags = IMGFLAG_SRGB; @@ -3235,14 +2394,14 @@ qboolean ParseStageSimple( shaderStage_t *stage, char **text ) if (!shader.noPicMip) flags |= IMGFLAG_PICMIP; - stage->bundle[0].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags ); + stage->bundle[7].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags ); - if ( !stage->bundle[0].image[num] ) + if ( !stage->bundle[7].image[num] ) { ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); return qfalse; } - stage->bundle[0].numImageAnimations++; + stage->bundle[7].numImageAnimations++; } } } @@ -3261,6 +2420,108 @@ qboolean ParseStageSimple( shaderStage_t *stage, char **text ) } } // + // videoMap2 + // + else if ( !Q_stricmp( token, "videoMap2" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMap2' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + stage->bundle[2].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); + if (stage->bundle[2].videoMapHandle != -1) { + stage->bundle[2].isVideoMap = qtrue; + stage->bundle[2].image[0] = tr.scratchImage[stage->bundle[2].videoMapHandle]; + } + } + // + // videoMap3 + // + else if ( !Q_stricmp( token, "videoMap3" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMap3' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + stage->bundle[3].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); + if (stage->bundle[3].videoMapHandle != -1) { + stage->bundle[3].isVideoMap = qtrue; + stage->bundle[3].image[0] = tr.scratchImage[stage->bundle[3].videoMapHandle]; + } + } + // + // videoMap4 + // + else if ( !Q_stricmp( token, "videoMap4" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMap4' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + stage->bundle[4].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); + if (stage->bundle[4].videoMapHandle != -1) { + stage->bundle[4].isVideoMap = qtrue; + stage->bundle[4].image[0] = tr.scratchImage[stage->bundle[4].videoMapHandle]; + } + } + // + // videoMap5 + // + else if ( !Q_stricmp( token, "videoMap5" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMap5' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + stage->bundle[5].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); + if (stage->bundle[5].videoMapHandle != -1) { + stage->bundle[5].isVideoMap = qtrue; + stage->bundle[5].image[0] = tr.scratchImage[stage->bundle[5].videoMapHandle]; + } + } + // + // videoMap6 + // + else if ( !Q_stricmp( token, "videoMap6" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMap6' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + stage->bundle[6].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); + if (stage->bundle[6].videoMapHandle != -1) { + stage->bundle[6].isVideoMap = qtrue; + stage->bundle[6].image[0] = tr.scratchImage[stage->bundle[6].videoMapHandle]; + } + } + // + // videoMap7 + // + else if ( !Q_stricmp( token, "videoMap7" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMap7' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + stage->bundle[7].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); + if (stage->bundle[7].videoMapHandle != -1) { + stage->bundle[7].isVideoMap = qtrue; + stage->bundle[7].image[0] = tr.scratchImage[stage->bundle[7].videoMapHandle]; + } + } + // // alphafunc // else if ( !Q_stricmp( token, "alphaFunc" ) ) @@ -3314,32 +2575,27 @@ qboolean ParseStageSimple( shaderStage_t *stage, char **text ) // else if ( !Q_stricmp( token, "blendfunc" ) ) { - hackoperation = 0; token = COM_ParseExt( text, qfalse ); if ( token[0] == 0 ) { ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name ); - hackoperation = 0; continue; } // check for "simple" blends first if ( !Q_stricmp( token, "add" ) ) { blendSrcBits = GLS_SRCBLEND_ONE; blendDstBits = GLS_DSTBLEND_ONE; - hackoperation = 1; + } else if ( !Q_stricmp( token, "filter" ) ) { blendSrcBits = GLS_SRCBLEND_DST_COLOR; blendDstBits = GLS_DSTBLEND_ZERO; - // hackoperation = 4; } else if ( !Q_stricmp( token, "blend" ) ) { blendSrcBits = GLS_SRCBLEND_SRC_ALPHA; blendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - hackoperation = 0; - } else { // complex double blends blendSrcBits = NameToSrcBlendMode( token ); - hackoperation = 0; + token = COM_ParseExt( text, qfalse ); if ( token[0] == 0 ) { @@ -3414,20 +2670,6 @@ qboolean ParseStageSimple( shaderStage_t *stage, char **text ) { stage->rgbGen = CGEN_EXACT_VERTEX; } - else if ( !Q_stricmp( token, "vertexLighting" ) ) // leilei - vertex WITH a lighting pass after - { - stage->rgbGen = CGEN_VERTEX_LIT; - if ( stage->alphaGen == 0 ) { - stage->alphaGen = AGEN_VERTEX; - } - } - else if ( !Q_stricmp( token, "vertexLighting2" ) ) // leilei - second vertex color - { - stage->rgbGen = CGEN_VERTEX_LIT; - if ( stage->alphaGen == 0 ) { - stage->alphaGen = AGEN_VERTEX; - } - } else if ( !Q_stricmp( token, "lightingDiffuse" ) ) { stage->rgbGen = CGEN_LIGHTING_DIFFUSE; @@ -3456,6 +2698,58 @@ qboolean ParseStageSimple( shaderStage_t *stage, char **text ) { stage->rgbGen = CGEN_LIGHTING_DIFFUSE; } + else if ( !Q_stricmp( token, "material" ) ) // leilei - material system + { + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) { + ri.Printf( PRINT_WARNING, "WARNING: missing ambient color in shader '%s', using white\n", shader.name ); + stage->matAmb = 0xFFFFFF; + } + else + stage->matAmb = ShParseNum( token ); + + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) { + ri.Printf( PRINT_WARNING, "WARNING: missing diffuse color in shader '%s', using gray\n", shader.name ); + stage->matSpec = 0xEEEEEE; + } + else + stage->matDif = ShParseNum( token ); + + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) { + ri.Printf( PRINT_WARNING, "WARNING: missing specular color for material in shader '%s', using none\n", shader.name ); + stage->matSpec = 0x000000; + } + else + stage->matSpec = ShParseNum( token ); + + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) { + ri.Printf( PRINT_WARNING, "WARNING: missing emissive color for material in shader '%s', using none\n", shader.name ); + stage->matEmis = 0x000000; + } + else + stage->matEmis = ShParseNum( token ); + + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) { + ri.Printf( PRINT_WARNING, "WARNING: missing specular hardness for material in shader '%s', using none\n", shader.name ); + stage->matHard = 0; + } + else + stage->matHard = atoi( token ); + + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) { + ri.Printf( PRINT_WARNING, "WARNING: missing alpha for material in shader '%s', using opaque\n", shader.name ); + stage->matAlpha = 255; + } + else + stage->matAlpha = atoi( token ); + + stage->rgbGen = CGEN_MATERIAL; + } else { ri.Printf( PRINT_WARNING, "WARNING: unknown rgbGen parameter '%s' in shader '%s'\n", token, shader.name ); @@ -3530,6 +2824,83 @@ qboolean ParseStageSimple( shaderStage_t *stage, char **text ) } } // + // rgbMod + // + else if ( !Q_stricmp( token, "rgbMod" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameters for rgbMod in shader '%s'\n", shader.name ); + continue; + } + if ( !Q_stricmp( token, "glow" ) ) + { + // TODO: Parse "entity" and "vertex" for their colors, for railguns and maps + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) { + ri.Printf( PRINT_WARNING, "WARNING: missing hex color in shader '%s'\n", shader.name ); + return qfalse; + } + stage->rgbModCol = ShParseNum( token ); + + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) { + stage->rgbModMode = 0; + stage->rgbMod = CMOD_GLOW; + return qtrue; + } + stage->rgbModMode = atoi( token ); + + stage->rgbMod = CMOD_GLOW; + } + if ( !Q_stricmp( token, "uvcol" ) ) + { + // Parse color + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) { + ri.Printf( PRINT_WARNING, "WARNING: missing hex color in shader '%s'\n", shader.name ); + return qfalse; + } + stage->rgbModCol = ShParseNum( token ); + + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) { + stage->rgbModMode = 0; + stage->rgbMod = CMOD_UVCOL; + return qtrue; + } + stage->rgbModMode = atoi( token ); + + stage->rgbMod = CMOD_UVCOL; + } + if ( !Q_stricmp( token, "normtoalpha" ) ) + { + // normalize colors, but average color prior is alpha. + stage->rgbMod = CMOD_NORMALIZETOALPHA; + } + if ( !Q_stricmp( token, "normtoalphafast" ) ) + { + // normalize and use the first vert's color on whole surface, but average color prior is alpha. + stage->rgbMod = CMOD_NORMALIZETOALPHAFAST; + } + if ( !Q_stricmp( token, "lighting" ) ) + { + // modulate a standard diffuse light on top of existing vertex colors + stage->rgbMod = CMOD_LIGHTING; + } + if ( !Q_stricmp( token, "opaque" ) ) + { + // modulate a standard diffuse light on top of existing vertex colors + stage->rgbMod = CMOD_OPAQUE; + } + else + { + ri.Printf( PRINT_WARNING, "WARNING: unknown rgbMod parameter '%s' in shader '%s'\n", token, shader.name ); + continue; + } + } + // // tcGen // else if ( !Q_stricmp(token, "texgen") || !Q_stricmp( token, "tcGen" ) ) @@ -3625,6 +2996,7 @@ qboolean ParseStageSimple( shaderStage_t *stage, char **text ) + // END DITHER TEST } // @@ -3668,81 +3040,16 @@ qboolean ParseStageSimple( shaderStage_t *stage, char **text ) blendSrcBits | blendDstBits | atestBits | depthFuncBits; - // - // now load our image! - // - - //hackoperation = 2; - if (loadlater){ - if (!blendDstBits) hackoperation = 2; - - if (ismaptexture){ - - if (surfaceflagsy & CONTENTS_TRANSLUCENT) - hackoperation = 0; - else - hackoperation = 2; - } - - if (blendSrcBits == GLS_SRCBLEND_ONE) hackoperation = 1; - if (blendDstBits == GLS_DSTBLEND_ONE) hackoperation = 1; - - - if (blendSrcBits == GLS_SRCBLEND_SRC_ALPHA) hackoperation = 0; - if (blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA) hackoperation = 0; - - if (blendSrcBits == GLS_SRCBLEND_DST_COLOR && - blendDstBits == GLS_DSTBLEND_SRC_COLOR) - hackoperation = 4; - - if (blendSrcBits == GLS_SRCBLEND_DST_COLOR && - blendDstBits == GLS_SRCBLEND_ONE) - hackoperation = 1; - - if (blendSrcBits == GLS_SRCBLEND_SRC_ALPHA && - blendDstBits == GLS_SRCBLEND_ONE) // additive, but blended away by alpha - hackoperation = 1; - - if (!ismaptexture){ - if (blendSrcBits == GLS_SRCBLEND_ZERO) hackoperation = 3; - //if (blendDstBits == GLS_DSTBLEND_ZERO) hackoperation = 3; - } - if (stage->bundle[0].numImageAnimations>0){ - int n, o; - n= stage->bundle[0].numImageAnimations; - for (o=0; obundle[0].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags ); - - if(o == 0) COM_StripExtension( imageNameAnim0, imageName, MAX_QPATH ); - if(o == 1) COM_StripExtension( imageNameAnim1, imageName, MAX_QPATH ); - if(o == 2) COM_StripExtension( imageNameAnim2, imageName, MAX_QPATH ); - if(o == 3) COM_StripExtension( imageNameAnim3, imageName, MAX_QPATH ); - if(o == 4) COM_StripExtension( imageNameAnim4, imageName, MAX_QPATH ); - if(o == 5) COM_StripExtension( imageNameAnim5, imageName, MAX_QPATH ); - if(o == 6) COM_StripExtension( imageNameAnim6, imageName, MAX_QPATH ); - if(o == 7) COM_StripExtension( imageNameAnim7, imageName, MAX_QPATH ); - if(o == 8) COM_StripExtension( imageNameAnim8, imageName, MAX_QPATH ); - stage->bundle[0].image[o] = R_FindImageFile( imageName, itype, iflags ); - - } - } - else - stage->bundle[0].image[0] = R_FindImageFile( imageName, itype, iflags ); - stage->isBlend = hackoperation; - - if (blendSrcBits == GLS_SRCBLEND_SRC_ALPHA && - blendDstBits == GLS_SRCBLEND_ONE) // additive, but blended away by alpha - stage->isBlend = 0; - - } return qtrue; } +extern int hackoperation; +extern int ismaptexture; +int surfaceflagsy; + /* =============== ParseDeform @@ -4802,7 +4109,8 @@ static void VertexLightingCollapse( void ) { if ( shader.lightmapIndex == LIGHTMAP_NONE ) { stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE; } else { - stages[0].rgbGen = CGEN_EXACT_VERTEX; + stages[0].rgbGen = CGEN_VERTEX_LIT;// leilei - dynamic lights in vertex lighting + //stages[0].rgbGen = CGEN_EXACT_VERTEX; } stages[0].alphaGen = AGEN_SKIP; } else { @@ -5444,71 +4752,6 @@ shader_t *R_FindShaderReal( const char *name, int lightmapIndex, qboolean mipRaw // create the default shading commands // - if (r_parseStageSimple->integer){ // leilei - for powervr - hackoperation = 0; - - if ( shader.lightmapIndex == LIGHTMAP_NONE ) { - // dynamic colors at vertexes - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE; - stages[0].stateBits = GLS_DEFAULT; - } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) { - // explicit colors at vertexes - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_EXACT_VERTEX; - stages[0].alphaGen = AGEN_SKIP; - stages[0].stateBits = GLS_DEFAULT; - } else if ( shader.lightmapIndex == LIGHTMAP_2D ) { - // GUI elements - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_VERTEX; - stages[0].alphaGen = AGEN_VERTEX; - stages[0].stateBits = GLS_DEPTHTEST_DISABLE; - stages[0].isBlend = 0; - hackoperation = 0; - } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) { - // fullbright level - stages[1].bundle[0].image[0] = tr.whiteImage; - stages[1].active = qtrue; - stages[1].rgbGen = CGEN_IDENTITY_LIGHTING; - stages[1].stateBits = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_DST_ALPHA; - - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_IDENTITY; - stages[0].stateBits = GLS_DEFAULT; - } else { - - // two pass lightmap - - hackoperation = 0; - stages[0].isBlend = 0; - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_IDENTITY; - stages[0].stateBits = GLS_DEFAULT; - - hackoperation = 4; - stages[1].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; - stages[1].bundle[0].isLightmap = qtrue; - stages[1].active = qtrue; - stages[1].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation - stages[1].isBlend = 1; - // for identitylight - stages[1].stateBits = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_DST_ALPHA; - - - } - - - - } - else // normal - { - if ( shader.lightmapIndex == LIGHTMAP_NONE ) { // dynamic colors at vertexes stages[0].bundle[0].image[0] = image; @@ -5519,7 +4762,8 @@ shader_t *R_FindShaderReal( const char *name, int lightmapIndex, qboolean mipRaw // explicit colors at vertexes stages[0].bundle[0].image[0] = image; stages[0].active = qtrue; - stages[0].rgbGen = CGEN_EXACT_VERTEX; + stages[0].rgbGen = CGEN_VERTEX_LIT;// leilei - dynamic lights in vertex lighting + //stages[0].rgbGen = CGEN_EXACT_VERTEX; stages[0].alphaGen = AGEN_SKIP; stages[0].stateBits = GLS_DEFAULT; } else if ( shader.lightmapIndex == LIGHTMAP_2D ) { @@ -5561,7 +4805,6 @@ shader_t *R_FindShaderReal( const char *name, int lightmapIndex, qboolean mipRaw // detail { int f; - if (r_parseStageSimple->integer) hackoperation = 4; for (f=0;f MAX_SHADER_STAGES) break;// don't exceed limit! @@ -5604,7 +4847,6 @@ shader_t *R_FindShaderReal( const char *name, int lightmapIndex, qboolean mipRaw stages[1].rgbGen = CGEN_IDENTITY; stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; } - } // leilei - handle image height @@ -5729,7 +4971,8 @@ qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_ // explicit colors at vertexes stages[0].bundle[0].image[0] = image; stages[0].active = qtrue; - stages[0].rgbGen = CGEN_EXACT_VERTEX; + stages[0].rgbGen = CGEN_VERTEX_LIT;// leilei - dynamic lights in vertex lighting + //stages[0].rgbGen = CGEN_EXACT_VERTEX; stages[0].alphaGen = AGEN_SKIP; stages[0].stateBits = GLS_DEFAULT; } else if ( shader.lightmapIndex == LIGHTMAP_2D ) { From 79a5732af5b71bde1facc2811a12bc6c84a3a19b Mon Sep 17 00:00:00 2001 From: leilei- Date: Fri, 28 Mar 2025 06:53:25 -0400 Subject: [PATCH 02/20] - r_slowness gone. Use llvmpipe, PCem, or a slow computer instead. --- code/renderer_oa/tr_backend.c | 38 ----------------------------------- code/renderer_oa/tr_init.c | 7 ------- 2 files changed, 45 deletions(-) diff --git a/code/renderer_oa/tr_backend.c b/code/renderer_oa/tr_backend.c index 9e53eee2ee..51e1164221 100644 --- a/code/renderer_oa/tr_backend.c +++ b/code/renderer_oa/tr_backend.c @@ -1456,11 +1456,6 @@ const void *RB_ClearDepth(const void *data) return (const void *)(cmd + 1); } - -extern cvar_t *r_slowness; // leilei - experimental variable slowness -extern cvar_t *r_slowness_cpu; // leilei - experimental variable slowness -extern cvar_t *r_slowness_gpu; // leilei - experimental variable slowness - // leilei - motion blur hack float motiontime; float motion_finished; @@ -1647,12 +1642,6 @@ const void *RB_SwapBuffers( const void *data ) { R_BrightScreen(); // leilei - alternate brightness - do it here so we hit evereything that represents our video buffer - R_RetroAAScreen(); // leilei - then apply 'anti aliasing' (hint: IT'S NOT really antialiasing) - R_PaletteScreen(); // leilei - then we palette our overbrighted antialiased screen. - R_NTSCScreen(); // leilei - then we get it through a DAC, degrading our precious VGA signals - R_TVScreen(); // leilei - tv operation comes last, this is a SCREEN - - cmd = (const swapBuffersCommand_t *)data; // we measure overdraw by reading back the stencil buffer and @@ -1707,33 +1696,6 @@ const void *RB_SwapBuffers( const void *data ) { backEnd.doneFlareTests = qfalse; backEnd.flareTestTime = backEnd.refdef.time + 100.0f; } - - // leilei - artificial slowness (mapper debug) - this might be windows only -#ifdef _WIN32 - - if (r_slowness->integer > 2){ - // Should be roughly equiv to a P2 300 at value 1.0 (target system) - float cpuspeed = r_slowness_cpu->value; - float gpuspeed = r_slowness_gpu->value; - - if (cpuspeed < 1) cpuspeed = 1; - if (gpuspeed < 1) gpuspeed = 1; // avoid div0 - - float slowit = (float)(((float)(backEnd.pc.c_surfaces) / 16) + ((float)backEnd.pc.c_vertexes / 64) + 5400.0f); - slowit /= cpuspeed; // yeah it's the cpu - float blowit = ((float)(backEnd.pc.c_surfaces / 32) + (backEnd.pc.c_indexes / 1324 * (float)(glConfig.vidWidth * glConfig.vidHeight / 1100))); - blowit /= gpuspeed; // yeah it's the gpu - - if (blowit > slowit) slowit = blowit; // GPU bottleneck - else if (slowit > blowit) blowit = slowit; // CPU bottlebeck - - if (slowit > 8500) slowit = 8500; // but not too much? - Sleep(slowit); // FORCE A SLEEP!! HAHAHAHA!!! - - } -#endif - - time_last = backEnd.refdef.time; return (const void *)(cmd + 1); diff --git a/code/renderer_oa/tr_init.c b/code/renderer_oa/tr_init.c index fc3871a6d9..260155ea2e 100644 --- a/code/renderer_oa/tr_init.c +++ b/code/renderer_oa/tr_init.c @@ -225,10 +225,6 @@ cvar_t *r_suggestiveThemes; // leilei - mature content control //cvar_t *r_motionblur; // Leilei - motionblur cvar_t *r_motionblur_fps; // Leilei - motionblur framerated -cvar_t *r_slowness; // Leilei - the cvar that slows everything down. use with caution. -cvar_t *r_slowness_cpu; // Leilei -cvar_t *r_slowness_gpu; // Leilei - cvar_t *r_textureDither; // leilei - Dithered texture cvar_t *r_texdump; // Leilei - debug - texture dump as they load, players should never need to use this! @@ -1346,9 +1342,6 @@ void R_Register( void ) r_leidebug = ri.Cvar_Get( "r_leidebug", "0" , CVAR_CHEAT); r_particles = ri.Cvar_Get( "r_particles", "0" , CVAR_ARCHIVE | CVAR_LATCH); r_leidebugeye = ri.Cvar_Get( "r_leidebugeye", "0" , CVAR_CHEAT); - r_slowness = ri.Cvar_Get( "r_slowness", "0" , CVAR_ARCHIVE); // it's 0 because you want it to be the fastest possible by default. - r_slowness_cpu = ri.Cvar_Get( "r_slowness_cpu", "300" , CVAR_ARCHIVE); // it's 0 because you want it to be the fastest possible by default. - r_slowness_gpu = ri.Cvar_Get( "r_slowness_gpu", "96" , CVAR_ARCHIVE); // it's 0 because you want it to be the fastest possible by default. r_iconmip = ri.Cvar_Get ("r_iconmip", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - icon mip r_iconBits = ri.Cvar_Get ("r_iconBits", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - icon bits From bc431a4b743e08a7fda07a441a15de53a6b1b377 Mon Sep 17 00:00:00 2001 From: leilei- Date: Fri, 28 Mar 2025 08:08:46 -0400 Subject: [PATCH 03/20] Spring cleaning of old deprecated/broken post-process GLSL experiments - r_anime broke in 2015 - r_tvMode - well, shaderglass exists now - r_motionblur - Bad technique, too much memory - t_pslettize - slow, relies on shader's lookup of a vector table - r_film - bad on well-lit maps - r_retroAA - this broke early too. also looked bad. would rather implement FSAA 4x --- code/renderer_oa/tr_backend.c | 166 ------ code/renderer_oa/tr_bloom.c | 935 +--------------------------------- code/renderer_oa/tr_image.c | 6 +- code/renderer_oa/tr_init.c | 87 ---- code/renderer_oa/tr_local.h | 77 +-- code/renderer_oa/tr_shade.c | 10 - code/renderer_oa/tr_shader.c | 19 - code/sdl/sdl_glimp.c | 73 --- 8 files changed, 6 insertions(+), 1367 deletions(-) diff --git a/code/renderer_oa/tr_backend.c b/code/renderer_oa/tr_backend.c index 51e1164221..ff44597509 100644 --- a/code/renderer_oa/tr_backend.c +++ b/code/renderer_oa/tr_backend.c @@ -1062,9 +1062,6 @@ RB_SetGL2D ================ */ -extern int tvWidth; -extern int tvHeight; - extern int vresWidth; extern int vresHeight; @@ -1456,143 +1453,6 @@ const void *RB_ClearDepth(const void *data) return (const void *)(cmd + 1); } -// leilei - motion blur hack -float motiontime; -float motion_finished; -int motionframe; -int motionpasses; -int numofmotionpasses; -int inmotion; - -int mblurred; // tells the renderer if we are rendering to a motion blur accum buffer instead of our drawing buffer -int mpasses; // how many passes of motion blur we should render. - -float motioner; - -void R_TVScreen( void ); -void R_RetroAAScreen( void ); - -void R_MblurScreen( void ); -void R_MblurScreenPost( void ); -void RB_UpdateMotionBlur (void){ - // leilei - motion blur hack - numofmotionpasses = 4; - numofmotionpasses = backEnd.refdef.time - backEnd.refdef.floatTime / 1000.0f; - - motioner = (backEnd.refdef.time - motiontime); - numofmotionpasses = (int)motioner / 3; - - - - // unfortunately doing this with some math just causes it to loop - if (numofmotionpasses == 4) numofmotionpasses = 0; - else if (numofmotionpasses == 3) numofmotionpasses = 1; - else if (numofmotionpasses == 2) numofmotionpasses = 2; - else if (numofmotionpasses == 1) numofmotionpasses = 3; - else if (numofmotionpasses == 0) numofmotionpasses = 4; - //else numofmotionpasses = 0; - - //ri.Printf( PRINT_WARNING, "hah %i\n", numofmotionpasses); - mpasses = floor(numofmotionpasses); - if (mpasses > 4) mpasses = 4; - if (mpasses < 1) return; // JUST DONT!! - motion_finished = (1000.0f / r_motionblur_fps->integer / 5 / mpasses); - - - if (motionpasses > numofmotionpasses){ - motionpasses = 0; - } - - if (motionframe > 5){ - - // do an accumulating post process - motionpasses += 1; - // R_MotionBlur_BackupScreen(10 + motionpasses); - R_MotionBlur_BackupScreen(11); // back it up in there... - motionframe = 1; - //return; - } - - if (backEnd.refdef.time > motiontime){ - R_MotionBlur_BackupScreen(motionframe); // back it up in there... - motionframe += 1; - R_MblurScreen(); - motiontime = backEnd.refdef.time + motion_finished; - inmotion = 1; - - } - else - inmotion = 0; -} - - -float mtime; // motion blur frame time - -// -// leilei - accumulation buffer-based motion blur, a much more legacy technique -// code addapted from MH's "Quake motion blur" thread (which is intended for GLQuake) -// but made to work with our cvars relating to the crappy pixel shader'd motion blur -// i coded on a whim one day. -// - -float mblur_time; -float mblur_timelast; - -float time_now; -float time_last; -float mbluracc; -int mblurredframes; -int mblurredframestotal; -void RB_AccumBlurValue (void) -{ - // calculate how much we need, determined by motion blur fps - mblur_time = time_now - time_last; - mbluracc = (mblur_time) / 32; - mbluracc *= -1; - mbluracc += 1.0f; - mbluracc /= 2; -}; - -void RB_DrawAccumBlur (void) -{ - static int blurstate = 0; - float accblur; - - if (r_tvMode->integer > -1) return; // tvmode causes this to crash - if (!r_motionblur->integer) return; - if (r_motionblur->integer > 1) return; // don't do it for the other motion blur techniques - - RB_AccumBlurValue (); - accblur = mbluracc; - - //ri.Printf( PRINT_WARNING, "accum value %f\n", mbluracc ); -// if (accblur > 1.0f) -// accblur = 0.5f; - - if (accblur <= 0.0f) - { - // reinit if we're not blurring so that the contents of the - // accumulation buffer are valid for the frame - blurstate = 0; - return; - } - - if (!blurstate) - { - // load the scene into the accumulation buffer - qglAccum (GL_LOAD, 1.0f); - } - else - { - qglAccum (GL_LOAD, 1.0f); - qglAccum (GL_MULT, accblur); // scale contents of accumulation buffer - qglAccum (GL_ACCUM, 1.0f - accblur); // add screen contents - qglAccum (GL_RETURN, 1.0f); // read result back - } - - blurstate = 1; -} - /* ============= RB_SwapBuffers @@ -1608,15 +1468,6 @@ const void *RB_SwapBuffers( const void *data ) { RB_EndSurface(); } - if (r_motionblur->integer > 2){ - { - mtime = backEnd.refdef.time + (1000.0f / r_motionblur_fps->integer); - mblurred = 0; - RB_UpdateMotionBlur(); - } - } - - // texture swapping test if ( r_showImages->integer ) { RB_ShowImages(); @@ -1633,13 +1484,6 @@ const void *RB_SwapBuffers( const void *data ) { } - if (r_motionblur->integer == 1){ - RB_DrawAccumBlur (); - - } - - - R_BrightScreen(); // leilei - alternate brightness - do it here so we hit evereything that represents our video buffer cmd = (const swapBuffersCommand_t *)data; @@ -1678,17 +1522,11 @@ const void *RB_SwapBuffers( const void *data ) { backEnd.donewater = qfalse; backEnd.donepostproc = qfalse; backEnd.doneAltBrightness = qfalse; - backEnd.doneFilm = qfalse; backEnd.doneleifx = qfalse; - backEnd.doneanime = qfalse; backEnd.donepalette = qfalse; - backEnd.donemblur = qfalse; backEnd.doneSurfaces = qfalse; backEnd.doneSun = qfalse; backEnd.doneSunFlare = qfalse; - backEnd.donentsc = qfalse; - backEnd.donetv = qfalse; - backEnd.doneraa = qfalse; backEnd.doneParticles = qfalse; // leilei - only reset this every 15hz to keep it fast and synchronized @@ -1697,7 +1535,6 @@ const void *RB_SwapBuffers( const void *data ) { backEnd.flareTestTime = backEnd.refdef.time + 100.0f; } - time_last = backEnd.refdef.time; return (const void *)(cmd + 1); } @@ -1710,7 +1547,6 @@ void RB_ExecuteRenderCommands( const void *data ) { int t1, t2; t1 = ri.Milliseconds (); - time_now = t1; while ( 1 ) { data = PADP(data, sizeof(void *)); @@ -1724,7 +1560,6 @@ void RB_ExecuteRenderCommands( const void *data ) { leifxmode = 0; R_PostprocessScreen(); R_BloomScreen(); - R_FilmScreen(); data = RB_StretchPic( data ); break; case RC_DRAW_SURFS: @@ -1738,7 +1573,6 @@ void RB_ExecuteRenderCommands( const void *data ) { leifxmode = 0; R_PostprocessScreen(); R_BloomScreen(); - R_FilmScreen(); data = RB_SwapBuffers( data ); break; case RC_SCREENSHOT: diff --git a/code/renderer_oa/tr_bloom.c b/code/renderer_oa/tr_bloom.c index e359e90b17..7b2cb1787d 100644 --- a/code/renderer_oa/tr_bloom.c +++ b/code/renderer_oa/tr_bloom.c @@ -67,85 +67,17 @@ static struct { struct { int width, height; } work; - - // leilei - motion blur - struct { - image_t *texture; - int width, height; - float readW, readH; - } motion1; - struct { - image_t *texture; - int width, height; - float readW, readH; - } motion2; - struct { - image_t *texture; - int width, height; - float readW, readH; - } motion3; - struct { - image_t *texture; - int width, height; - float readW, readH; - } motion4; - struct { - image_t *texture; - int width, height; - float readW, readH; - } motion5; - struct { - image_t *texture; - int width, height; - float readW, readH; - } mpass1; - struct { - image_t *texture; - int width, height; - float readW, readH; - } mpass2; - struct { - image_t *texture; - int width, height; - float readW, readH; - } mpass3; - - struct { - image_t *texture; - int width, height; - float readW, readH; - } mpass4; - struct { - image_t *texture; - int width, height; - float readW, readH; - } tv; - struct { - int width, height; - } tvwork; - struct { - image_t *texture; - int width, height; - float readW, readH; - } tveffect; - qboolean started; #endif } postproc; -cvar_t *r_film; extern int force32upload; int leifxmode; int leifxpass; int fakeit = 0; -extern int tvinterlace; -int tvinter= 1; -extern int tvWidth; -extern int tvHeight; -extern float tvAspectW; // aspect correction extern int vresWidth; extern int vresHeight; /* @@ -671,96 +603,6 @@ Restore the temporary framebuffer section we used with the backup texture */ extern int mpasses; -static void ID_INLINE R_Bloom_QuadTV( int width, int height, float texX, float texY, float texWidth, float texHeight, int aa ) -{ - float aspcenter = 0; - float raa = r_retroAA->value; - if (raa < 1) raa = 1; - - float xpix = 1.0f / width / (4 / raa); - float ypix = 1.0f / height / (4 / raa); - float xaa; - float yaa; - int x = 0; - int y = 0; - - - - - if (aa == 0) { - xaa = 0; - yaa = 0; - } - if (aa == 1) { - xaa = -xpix; - yaa = ypix; - } - if (aa == 2) { - xaa = -xpix; - yaa = -ypix; - } - if (aa == 3) { - xaa = xpix; - yaa = -ypix; - } - if (aa == 4) { - xaa = xpix; - yaa = ypix; - } - - - - //y += tvHeight - height; - width += x; - height += y; - - texWidth += texX; - texHeight += texY; - - if (tvAspectW != 1.0) { - aspcenter = tvWidth * ((1.0f - tvAspectW) / 2); - // leilei - also do a quad that is 100% black, hiding our actual rendered viewport - - // qglViewport (0, 0, tvWidth, tvHeight ); - // qglScissor (0, 0, tvWidth, tvHeight ); - qglBegin( GL_QUADS ); - if (r_tvFilter->integer) { // bilinear filter - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - } - else { - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - } - qglColor4f( 0.0, 0.0, 0.0, 1 ); - qglVertex2f(0,0 ); - qglVertex2f(0,height); - qglVertex2f(width,height); - qglVertex2f(width,0); - qglEnd (); - qglColor4f( 1.0, 1.0, 1.0, 1 ); - } - - if (!aa) { - qglViewport(aspcenter, 0, (tvWidth * tvAspectW), tvHeight ); - qglScissor(aspcenter, 0, (tvWidth * tvAspectW), tvHeight ); - } - qglBegin( GL_QUADS ); - //GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - if (aa) - qglColor4f( 0.25, 0.25, 0.25, 1 ); - qglTexCoord2f( texX + xaa, texHeight + yaa); - qglVertex2f( x, y ); - qglTexCoord2f( texX + xaa, texY + yaa ); - qglVertex2f( x, height ); - qglTexCoord2f( texWidth + xaa, texY + yaa ); - qglVertex2f( width, height ); - qglTexCoord2f( texWidth + xaa, texHeight + yaa ); - qglVertex2f( width, y ); - qglEnd (); -} - - static void R_Bloom_RestoreScreen_Postprocessed( void ) { #ifdef GLSL_POSTPROCESSING @@ -778,51 +620,10 @@ static void R_Bloom_RestoreScreen_Postprocessed( void ) if (vertexShaders) R_GLSL_UseProgram(tr.leiFXFilterProgram); program=tr.programs[tr.leiFXFilterProgram]; } - if (leifxmode == 888) { - if (vertexShaders) R_GLSL_UseProgram(tr.animeProgram); - program=tr.programs[tr.animeProgram]; - } - if (leifxmode == 999) { - if (vertexShaders) R_GLSL_UseProgram(tr.animeFilmProgram); - program=tr.programs[tr.animeFilmProgram]; - } - if (leifxmode == 777) { - if (vertexShaders) R_GLSL_UseProgram(tr.motionBlurProgram); - program=tr.programs[tr.motionBlurProgram]; - } - if (leifxmode == 778) { - if (vertexShaders) R_GLSL_UseProgram(tr.motionBlurProgram); - program=tr.programs[tr.motionBlurProgram]; - } - if (leifxmode == 779) { - if (vertexShaders) R_GLSL_UseProgram(tr.motionBlurPostProgram); - program=tr.programs[tr.motionBlurPostProgram]; - } - if (leifxmode == 632) { - if (vertexShaders) R_GLSL_UseProgram(tr.NTSCEncodeProgram); - program=tr.programs[tr.NTSCEncodeProgram]; - } - if (leifxmode == 633) { - if (vertexShaders) R_GLSL_UseProgram(tr.NTSCDecodeProgram); - program=tr.programs[tr.NTSCDecodeProgram]; - } - if (leifxmode == 634) { - if (vertexShaders) R_GLSL_UseProgram(tr.NTSCBleedProgram); - program=tr.programs[tr.NTSCBleedProgram]; - } if (leifxmode == 666) { if (vertexShaders) R_GLSL_UseProgram(tr.BrightnessProgram); program=tr.programs[tr.BrightnessProgram]; } - if (leifxmode == 1236) { - if (vertexShaders) R_GLSL_UseProgram(tr.CRTProgram); - program=tr.programs[tr.CRTProgram]; - } - if (leifxmode == 1997) { - if (vertexShaders) R_GLSL_UseProgram(tr.paletteProgram); - program=tr.programs[tr.paletteProgram]; - } - } else { if (vertexShaders) R_GLSL_UseProgram(tr.postprocessingProgram); @@ -842,10 +643,6 @@ static void R_Bloom_RestoreScreen_Postprocessed( void ) if (program->u_ScreenToNextPixelY > -1) R_GLSL_SetUniform_u_ScreenToNextPixelY(program, (float)1.0/(float)glConfig.vidHeight); - // leilei - for TV shaders - if (program->u_ActualScreenSizeX > -1) R_GLSL_SetUniform_u_ActualScreenSizeX(program, tvWidth); - if (program->u_ActualScreenSizeY > -1) R_GLSL_SetUniform_u_ActualScreenSizeY(program, tvHeight); - //if (program->u_Time > -1) R_GLSL_SetUniform_Time(program, backEnd.refdef.time); if (program->u_Time > -1) R_GLSL_SetUniform_Time(program, ScreenFrameCount); @@ -869,68 +666,12 @@ static void R_Bloom_RestoreScreen_Postprocessed( void ) GL_SelectTexture(7); GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); GL_Bind( postproc.depth.texture ); - - // motion blur crap - if( r_motionblur->integer > 2) { - if (program->u_mpasses > -1) R_GLSL_SetUniform_u_mpasses(program, mpasses); - GL_SelectTexture(2); - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - GL_Bind( postproc.motion1.texture ); - GL_SelectTexture(3); - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - GL_Bind( postproc.motion2.texture ); - GL_SelectTexture(4); - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - GL_Bind( postproc.motion3.texture ); - GL_SelectTexture(5); - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - GL_Bind( postproc.motion4.texture ); - GL_SelectTexture(6); - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - GL_Bind( postproc.motion5.texture ); - GL_SelectTexture(11); - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - GL_Bind( postproc.mpass1.texture ); - GL_SelectTexture(12); - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - GL_Bind( postproc.mpass1.texture ); - GL_SelectTexture(13); - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - GL_Bind( postproc.mpass1.texture ); - GL_SelectTexture(14); - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - GL_Bind( postproc.mpass1.texture ); - } qglColor4f( 1, 1, 1, 1 ); // if (leifxmode == 778) // return; - if (leifxmode == 1234) { - { - R_Bloom_QuadTV( glConfig.vidWidth, glConfig.vidHeight, 0, 0, postproc.screen.readW,postproc.screen.readH, 0 ); - } - } - else if (leifxmode == 1236) { - { - R_Bloom_QuadTV( glConfig.vidWidth, glConfig.vidHeight, 0, 0, postproc.screen.readW,postproc.screen.readH, 0 ); - } - } - else if (leifxmode == 1233) { - - - R_Bloom_QuadTV( glConfig.vidWidth, glConfig.vidHeight, 0, 0, postproc.screen.readW,postproc.screen.readH, 1 ); - GL_SelectTexture(0); - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - GL_Bind( postproc.screen.texture ); - R_Bloom_QuadTV( glConfig.vidWidth, glConfig.vidHeight, 0, 0, postproc.screen.readW,postproc.screen.readH, 2 ); - R_Bloom_QuadTV( glConfig.vidWidth, glConfig.vidHeight, 0, 0, postproc.screen.readW,postproc.screen.readH, 3 ); - R_Bloom_QuadTV( glConfig.vidWidth, glConfig.vidHeight, 0, 0, postproc.screen.readW,postproc.screen.readH, 4 ); - - } - else { - R_Bloom_Quad( glConfig.vidWidth, glConfig.vidHeight, 0, 0, + R_Bloom_Quad( glConfig.vidWidth, glConfig.vidHeight, 0, 0, postproc.screen.readW,postproc.screen.readH ); - } if (vertexShaders) R_GLSL_UseProgram(0); GL_SelectTexture(0); #endif @@ -1122,21 +863,16 @@ static void R_Postprocess_InitTextures( void ) { #ifdef GLSL_POSTPROCESSING byte *data; - int intdiv = 1; force32upload = 1; // find closer power of 2 to screen size for (postproc.screen.width = 1; postproc.screen.width< glConfig.vidWidth; postproc.screen.width *= 2) {} -// if (r_tvMode->integer > 1) // interlaced // for (postproc.screen.height = 1;postproc.screen.height < vidinted;postproc.screen.height *= 2); //else for (postproc.screen.height = 1; postproc.screen.height < glConfig.vidHeight; postproc.screen.height *= 2) {} -// if (r_tvMode->integer > 1) -// intdiv = 2; - postproc.screen.readW = glConfig.vidWidth / (float)postproc.screen.width; postproc.screen.readH = glConfig.vidHeight / (float)postproc.screen.height; @@ -1153,9 +889,6 @@ static void R_Postprocess_InitTextures( void ) postproc.effect.readW = postproc.work.width / (float)postproc.effect.width; postproc.effect.readH = postproc.work.height / (float)postproc.effect.height; -// postproc.screen.readH /= intdiv; // interlacey - - // disable blooms if we can't handle a texture of that size if( postproc.screen.width > glConfig.maxTextureSize || postproc.screen.height > glConfig.maxTextureSize @@ -1172,62 +905,6 @@ static void R_Postprocess_InitTextures( void ) Com_Memset( data, 0, postproc.screen.width * postproc.screen.height * 4 ); postproc.screen.texture = R_CreateImage( "***postproc screen texture***", data, postproc.screen.width, postproc.screen.height, 0, 0, GL_CLAMP_TO_EDGE ); ri.Hunk_FreeTempMemory( data ); - - // leilei - tv output texture - - if (r_tvMode->integer > -1) { - // find closer power of 2 to screen size - for (postproc.tv.width = 1; postproc.tv.width< tvWidth; postproc.tv.width *= 2); - for (postproc.tv.height = 1; postproc.tv.height < tvHeight; postproc.tv.height *= 2); - - //postproc.tv.height /= intdiv; // interlacey - - - postproc.tv.readW = tvWidth / (float)postproc.tv.width; - postproc.tv.readH = tvHeight / (float)postproc.tv.height; - - // find closer power of 2 to effect size - postproc.tvwork.width = r_bloom_sample_size->integer; - postproc.tvwork.height = postproc.tvwork.width * ( tvWidth / tvHeight ); - - // postproc.tvwork.height /= intdiv; // interlacey - - for (postproc.tveffect.width = 1; postproc.tveffect.width < postproc.tvwork.width; postproc.tveffect.width *= 2) {} - if (intdiv > 1) { - for (postproc.tveffect.height = 1; (postproc.tveffect.height/2) < postproc.tvwork.height; postproc.tveffect.height *= 2) {} - } - else { - for (postproc.tveffect.height = 1; postproc.tveffect.height < postproc.tvwork.height; postproc.tveffect.height *= 2) {} - } - - postproc.tveffect.readW = postproc.tvwork.width / (float)postproc.tveffect.width; - postproc.tveffect.readH = postproc.tvwork.height / (float)postproc.tveffect.height; - - - - data = ri.Hunk_AllocateTempMemory( tvWidth * tvHeight * 4 ); - Com_Memset( data, 0, tvWidth * tvHeight * 4 ); - postproc.tv.texture = R_CreateImage( "***tv output screen texture***", data, tvWidth, tvHeight, 0, 0, GL_CLAMP_TO_EDGE ); - ri.Hunk_FreeTempMemory( data ); - } - - // leilei - motion blur textures! - - if (r_motionblur->integer > 2) { - data = ri.Hunk_AllocateTempMemory( postproc.screen.width * postproc.screen.height * 4 ); - Com_Memset( data, 0, postproc.screen.width * postproc.screen.height * 4 ); - postproc.motion1.texture = R_CreateImage( "***motionblur1 texture***", data, postproc.screen.width, postproc.screen.height, 0, 0, GL_CLAMP_TO_EDGE ); - postproc.motion2.texture = R_CreateImage( "***motionblur2 texture***", data, postproc.screen.width, postproc.screen.height, 0, 0, GL_CLAMP_TO_EDGE ); - postproc.motion3.texture = R_CreateImage( "***motionblur3 texture***", data, postproc.screen.width, postproc.screen.height, 0, 0, GL_CLAMP_TO_EDGE ); - postproc.motion4.texture = R_CreateImage( "***motionblur4 texture***", data, postproc.screen.width, postproc.screen.height, 0, 0, GL_CLAMP_TO_EDGE ); - postproc.motion5.texture = R_CreateImage( "***motionblur5 texture***", data, postproc.screen.width, postproc.screen.height, 0, 0, GL_CLAMP_TO_EDGE ); - postproc.mpass1.texture = R_CreateImage( "***motionaccum1 texture***", data, postproc.screen.width, postproc.screen.height, 0, 0, GL_CLAMP_TO_EDGE ); - postproc.mpass2.texture = R_CreateImage( "***motionaccum1 texture***", data, postproc.screen.width, postproc.screen.height, 0, 0, GL_CLAMP_TO_EDGE ); - postproc.mpass3.texture = R_CreateImage( "***motionaccum1 texture***", data, postproc.screen.width, postproc.screen.height, 0, 0, GL_CLAMP_TO_EDGE ); - postproc.mpass4.texture = R_CreateImage( "***motionaccum1 texture***", data, postproc.screen.width, postproc.screen.height, 0, 0, GL_CLAMP_TO_EDGE ); - ri.Hunk_FreeTempMemory( data ); - } - // GLSL Depth Buffer data = ri.Hunk_AllocateTempMemory( postproc.screen.width * postproc.screen.height *4); @@ -1469,119 +1146,6 @@ void R_LeiFXPostprocessFilterScreen( void ) } - -// ================================================================= -// NTSC EFFECTS -// -// Thanks to the libretro team for their gpl ntsc shader code -// -// ================================================================= - - - -void R_NTSCScreen( void ) -{ -#ifdef GLSL_POSTPROCESSING - if( !r_ntsc->integer) - return; - if ( backEnd.donentsc) - return; - if ( !vertexShaders ) - return; // leilei - cards without support for this should not ever activate this -// if ( !backEnd.doneSurfaces ) -// return; - if( !postproc.started ) { - force32upload = 1; - R_Postprocess_InitTextures(); - if( !postproc.started ) - return; - } - - if ( !backEnd.projection2D ) { - RB_SetGL2D(); - } - force32upload = 1; - - int ntsc_bleed = 0; - int ntsc_encode = 0; - int ntsc_decode = 0; - - // TODO: Switch it up - if (r_ntsc->integer == 1) { - ntsc_bleed = 1; - } - else if (r_ntsc->integer == 2) { - ntsc_bleed = 1; - ntsc_encode = 1; - ntsc_decode = 1; - } - else if (r_ntsc->integer == 3) { - ntsc_bleed = 0; - ntsc_encode = 1; - ntsc_decode = 1; - } - else if (r_ntsc->integer == 4) { - ntsc_bleed = 1; - ntsc_encode = 1; - ntsc_decode = 1; - } - else if (r_ntsc->integer > 6) { - ntsc_bleed = 666; - ntsc_encode = 0; - ntsc_decode = 0; - } - else { - ntsc_bleed = 0; - ntsc_encode = 1; - ntsc_decode = 0; - } - - - -// qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); -// qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - - R_LeiFX_Stupid_Hack(); - if (ntsc_encode) { - leifxmode = 632; // Encode to composite - R_Postprocess_BackupScreen(); - R_Bloom_RestoreScreen_Postprocessed(); - } - - - if (ntsc_decode) { - leifxmode = 633; // Decode to RGB - R_Postprocess_BackupScreen(); - R_Bloom_RestoreScreen_Postprocessed(); - } - - if (ntsc_bleed) { - leifxmode = 634; // Encode to YUV and decode to RGB - R_Postprocess_BackupScreen(); - R_Bloom_RestoreScreen_Postprocessed(); - } - - - - if (ntsc_bleed == 666) { - leifxmode = 634; // Encode to YUV and decode to RGB EXCESSIVELY - int passasses = r_ntsc->integer; - int j; - for (j=0; jinteger ) - return; - if ( backEnd.doneFilm ) - return; - if ( !backEnd.projection2D ) - RB_SetGL2D(); - backEnd.doneFilm = qtrue; - - // set up our colors, this is our default - tone[0] = 0.8f; - tone[1] = 0.9f; - tone[2] = 1.0f; - //VectorCopy( backEnd.currentEntity->ambientLight, tone ); - if (backEnd.currentEntity) { - if (backEnd.currentEntity->ambientLight[0] > 0.001f && backEnd.currentEntity->ambientLight[1] > 0.001f && backEnd.currentEntity->ambientLight[2] > 0.001f) { - tone[0] = backEnd.currentEntity->ambientLight[0]; - tone[1] = backEnd.currentEntity->ambientLight[1]; - tone[2] = backEnd.currentEntity->ambientLight[2]; - } - } - - // VectorNormalize(tone); - - tone[0] *= 0.3 + 0.7; - tone[1] *= 0.3 + 0.7; - tone[2] *= 0.3 + 0.7; - - // tone[0] = 1.6f; - // tone[1] = 1.2f; - // tone[2] = 0.7f; - - - // TODO: Get overexposure to flares raising this faking "HDR" - tonecont[0] = 0.0f; - tonecont[1] = 0.0f; - tonecont[2] = 0.0f; - - - // inverted - - toneinv[0] = tone[0] * -1 + 1 + tonecont[0]; - toneinv[1] = tone[1] * -1 + 1 + tonecont[1]; - toneinv[2] = tone[2] * -1 + 1 + tonecont[2]; - - // darken vignette. - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO); - GL_Bind( tr.dlightImage ); - GL_Cull( CT_TWO_SIDED ); - qglColor4f( 0.941177, 0.952941, 0.968628, 1.0f ); - R_Brighter_Quad( glConfig.vidWidth, glConfig.vidHeight, 0.35f, 0.35f, 0.2f, 0.2f ); - - - - // brighten. - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE); - GL_Bind( tr.dlightImage ); - GL_Cull( CT_TWO_SIDED ); - //qglColor4f( 0.941177, 0.952941, 0.968628, 1.0f ); - qglColor4f( (0.9f + (tone[0] * 0.5)), (0.9f + (tone[1] * 0.5)), (0.9f + (tone[2] * 0.5)), 1.0f ); - - R_Brighter_Quad( glConfig.vidWidth, glConfig.vidHeight, 0.25f, 0.25f, 0.48f, 0.48f ); - - // invert. - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE_MINUS_DST_COLOR | GLS_DSTBLEND_ONE_MINUS_SRC_COLOR); - GL_Bind( tr.whiteImage ); - GL_Cull( CT_TWO_SIDED ); - // qglColor4f(0.85098, 0.85098, 0.815686, 1.0f ); - qglColor4f( (0.8f + (toneinv[0] * 0.5)), (0.8f + (toneinv[1] * 0.5)), (0.8f + (toneinv[2] * 0.5)), 1.0f ); - R_Brighter_Quad( glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1, 1 ); - - // brighten. - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_SRC_COLOR); - GL_Bind( tr.whiteImage ); - GL_Cull( CT_TWO_SIDED ); - qglColor4f( 0.615686, 0.615686, 0.615686, 1.0f ); - R_Brighter_Quad( glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1, 1 ); - - - // invoort. - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE_MINUS_DST_COLOR | GLS_DSTBLEND_ONE_MINUS_SRC_COLOR); - GL_Bind( tr.whiteImage ); - GL_Cull( CT_TWO_SIDED ); - qglColor4f(1.0f, 1.0f, 1.0f , 1.0f ); - R_Brighter_Quad( glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1, 1 ); - - // brighten. - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_SRC_COLOR); - GL_Bind( tr.whiteImage ); - GL_Cull( CT_TWO_SIDED ); - // qglColor4f( 0.866667, 0.847059, 0.776471, 1.0f ); - qglColor4f( (0.73f + (toneinv[0] * 0.4)), (0.73f + (toneinv[1] * 0.4)), (0.73f + (toneinv[2] * 0.4)), 1.0f ); - R_Brighter_Quad( glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1, 1 ); } - - -// ================================================================= -// OLD-STYLE ANTIALIASING -// ================================================================= - - - -// leilei - old 2000 console-style antialiasing/antiflickering -void R_RetroAAScreen( void ) -{ - // this should not need glsl either, but -#ifdef GLSL_POSTPROCESSING - if( !r_retroAA->integer) - return; - if ( backEnd.doneraa) - return; - if ( !vertexShaders ) - return; // leilei - cards without support for this should not ever activate this - if( !postproc.started ) { - force32upload = 1; - R_Postprocess_InitTextures(); - if( !postproc.started ) - return; - } - - if ( !backEnd.projection2D ) - RB_SetGL2D(); - force32upload = 1; - - leifxmode = 1233; // just show it through to tvWidth/tvHeight - //R_Postprocess_BackupScreen(); - R_Postprocess_BackupScreen(); - R_Bloom_RestoreScreen_Postprocessed(); - - backEnd.doneraa = qtrue; - - force32upload = 0; - -#endif -} - - - - - - - -// ================================================================= -// !GLSL! -// ANIME SHADERS -// ================================================================= - - - - - -void R_AnimeScreen( void ) -{ -#ifdef GLSL_POSTPROCESSING - if( !r_anime->integer) - return; - if ( backEnd.doneanime) - return; - if ( !backEnd.doneSurfaces ) - return; - if ( !vertexShaders ) - return; // leilei - cards without support for this should not ever activate this - if( !postproc.started ) { - force32upload = 1; - R_Postprocess_InitTextures(); - if( !postproc.started ) - return; - } - - if ( !backEnd.projection2D ) - RB_SetGL2D(); - - force32upload = 1; - - leifxmode = 888; // anime effect - outlines, desat, bloom and other crap to go with it - R_LeiFX_Stupid_Hack(); - R_Postprocess_BackupScreen(); - R_Bloom_RestoreScreen_Postprocessed(); - leifxmode = 999; // film effect - to blur things slightly, and add some grain and chroma stuff - R_LeiFX_Stupid_Hack(); - R_Postprocess_BackupScreen(); - R_Bloom_RestoreScreen_Postprocessed(); - backEnd.doneanime = qtrue; - - force32upload = 0; -#endif - -} - - - - - - - - -// ================================================================= -// !GLSL! -// MOTION BLUR EFFECT -// ================================================================= - - -// leilei - motion blur hack -void R_MotionBlur_BackupScreen(int which) -{ -#ifdef GLSL_POSTPROCESSING - if( r_motionblur->integer < 3) - return; - if (which == 1) { - GL_Bind( postproc.motion1.texture ); // gather thee samples - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - } - if (which == 2) { - GL_Bind( postproc.motion2.texture ); - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - } - if (which == 3) { - GL_Bind( postproc.motion3.texture ); - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - } - if (which == 4) { - GL_Bind( postproc.motion4.texture ); - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - } - if (which == 5) { - GL_Bind( postproc.motion5.texture ); - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - } - if (which == 11) { - GL_Bind( postproc.mpass1.texture ); // to accum - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - } - if (which == 12) { - GL_Bind( postproc.mpass1.texture ); // to accum - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - } - if (which == 13) { - GL_Bind( postproc.mpass1.texture ); // to accum - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - } - if (which == 14) { - GL_Bind( postproc.mpass1.texture ); // to accum - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - } - if (which == 18) { - GL_Bind( postproc.screen.texture ); // to accum - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - } -#endif - -} - - -void R_MblurScreen( void ) -{ -#ifdef GLSL_POSTPROCESSING - if( r_motionblur->integer < 3) - return; - if ( backEnd.donemblur) - return; - if ( !backEnd.doneSurfaces ) - return; - if ( !vertexShaders ) - return; // leilei - cards without support for this should not ever activate this - if( !postproc.started ) { - force32upload = 1; - R_Postprocess_InitTextures(); - if( !postproc.started ) - return; - } - - if ( !backEnd.projection2D ) - RB_SetGL2D(); - - - - - force32upload = 1; - - leifxmode = 777; // accumulate frames for the motion blur buffer - R_LeiFX_Stupid_Hack(); - R_Postprocess_BackupScreen(); - R_Bloom_RestoreScreen_Postprocessed(); - force32upload = 0; -#else - // NO! Use the accumulation buffer instead. -#endif -} - -void R_MblurScreenPost( void ) -{ -#ifdef GLSL_POSTPROCESSING - if( r_motionblur->integer < 3) - return; - if ( !backEnd.doneSurfaces ) - return; - if ( !vertexShaders ) - return; // leilei - cards without support for this should not ever activate this - if( !postproc.started ) { - force32upload = 1; - R_Postprocess_InitTextures(); - if( !postproc.started ) - return; - } - - backEnd.donemblur = qtrue; - - if ( !backEnd.projection2D ) - RB_SetGL2D(); - - force32upload = 1; - - leifxmode = 770; // accumulate frames for the motion blur buffer - R_LeiFX_Stupid_Hack(); -// R_Postprocess_BackupScreen(); - R_Bloom_RestoreScreen_Postprocessed(); - force32upload = 0; -#else - // NO! -#endif -} - - - -// ================================================================= -// TV MODE -// ================================================================= - -static void R_Postprocess_BackupScreenTV( void ) -{ -#ifdef GLSL_POSTPROCESSING - GL_TexEnv( GL_MODULATE ); - qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - qglMatrixMode( GL_PROJECTION ); - qglLoadIdentity (); - qglOrtho( 0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1 ); - qglMatrixMode( GL_MODELVIEW ); - qglLoadIdentity (); - - - GL_Bind( postproc.screen.texture ); - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight); -#endif -} - -static void R_Postprocess_ScaleTV( void ) -{ -#ifdef GLSL_POSTPROCESSING - - GL_TexEnv( GL_MODULATE ); - qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - qglMatrixMode( GL_PROJECTION ); - qglLoadIdentity (); -#endif -} - - - -// tvmode doesn't do any actual postprocessing yet (ntsc, shadow mask etc) - -float tvtime; - -void R_TVScreen( void ) -{ - // leilei - this might not actually need glsl but we're doing this anyway. -#ifdef GLSL_POSTPROCESSING - if( r_tvMode->integer < 0) - return; - if ( backEnd.donetv) - return; - if ( !vertexShaders ) - return; // leilei - cards without support for this should not ever activate this - if( !postproc.started ) { - force32upload = 1; - R_Postprocess_InitTextures(); - if( !postproc.started ) - return; - } - -// if ( !backEnd.projection2D ) -// RB_SetGL2D(); - - - - force32upload = 1; - -// postprocess = 1; - - if (backEnd.refdef.time > tvtime) { - tvinterlace *= -1; - tvtime = backEnd.refdef.time + (1000.0f / 60); // 60hz - } - - tvinter = tvinterlace; - if (tvinter < 0) tvinter = 0; - if (r_tvMode->integer < 100) tvinter = 0; - tvinter = 0; - - leifxmode = 1234; // just show it through to tvWidth/tvHeight - - //if (r_tvMode->integer > 2) - // leifxmode = 1236; // run it through a shader - //R_Postprocess_BackupScreen(); - - if (r_tvMode->integer > 100) { - R_Postprocess_ScaleTV(); - } - else { - R_Postprocess_BackupScreenTV(); - - R_Bloom_RestoreScreen_Postprocessed(); - } - - backEnd.donetv = qtrue; - - force32upload = 0; -#else - // NO! -#endif - -} - - - - - - -// ================================================================= -// PALLETIZING -// -// Processes the screen into having a 8-bit indexed color -// palette to suit a throwback mode better -// -// ================================================================= - - - - -void R_PaletteScreen( void ) -{ -#ifdef GLSL_POSTPROCESSING - if( !r_palletize->integer) - return; - if ( backEnd.donepalette) - return; - if ( !backEnd.doneSurfaces ) - return; - if ( !vertexShaders ) - return; // leilei - cards without support for this should not ever activate this - if( !postproc.started ) { - force32upload = 1; - R_Postprocess_InitTextures(); - if( !postproc.started ) - return; - } - - if ( !backEnd.projection2D ) - RB_SetGL2D(); - - force32upload = 1; - - leifxmode = 1997; // anime effect - outlines, desat, bloom and other crap to go with it - R_LeiFX_Stupid_Hack(); - R_Postprocess_BackupScreen(); - R_Bloom_RestoreScreen_Postprocessed(); - backEnd.donepalette = qtrue; - - force32upload = 0; - -#else - // NO! -#endif -} - - - - // ================================================================= // WATER BUFFER TEST // ================================================================= diff --git a/code/renderer_oa/tr_image.c b/code/renderer_oa/tr_image.c index 4b38d140eb..44cb73678a 100644 --- a/code/renderer_oa/tr_image.c +++ b/code/renderer_oa/tr_image.c @@ -213,18 +213,18 @@ void R_InitPalette( void ) { byte *buff; int i, v; - ri.Printf( PRINT_ALL, "INIT PALETTE......\n"); + ri.Printf( PRINT_ALL, "R_InitPalette: \n"); ri.FS_ReadFile("gfx/palette.lmp", (void **)&buff); if(!buff){ - ri.Printf( PRINT_ALL, "PALLETE FALED :(!\n" ); + ri.Printf( PRINT_ALL, "PALETTE FAILED\n" ); paletteavailable = 0; // Don't have a palette paletteenabled = 0; // Don't do 8-bit textures return; } palettemain = buff; - ri.Printf( PRINT_ALL, "PALETTE LOADDEEEED!!!!!!!!!!!!1\n" ); + ri.Printf( PRINT_ALL, "PALETTE LOADED\n" ); paletteavailable = 1; // Do have a palette if (palettedTextureSupport) { diff --git a/code/renderer_oa/tr_init.c b/code/renderer_oa/tr_init.c index 260155ea2e..8ba236fefc 100644 --- a/code/renderer_oa/tr_init.c +++ b/code/renderer_oa/tr_init.c @@ -196,7 +196,6 @@ cvar_t *r_flareMethod; // method of flare intensity cvar_t *r_flareQuality; // testing quality of the flares. cvar_t *r_flareSun; // type of flare to use for the sun cvar_t *r_flareDelay; // time delay for medium quality flare testing -cvar_t *r_flaresMotionBlur; // Stretch blur cvar_t *r_specMode; //cvar_t *r_waveMode; @@ -212,19 +211,11 @@ cvar_t *r_leifx; // Leilei - leifx nostalgia filter cvar_t *r_modelshader; // Leilei cvar_t *r_particles; // Leilei - particle effects motif -cvar_t *r_ntsc; // Leilei - ntsc / composite signals -//cvar_t *r_tvMode; // Leilei - tv fake mode -cvar_t *r_retroAA; // Leilei - old console AA -cvar_t *r_anime; // Leilei - anime filter -cvar_t *r_palletize; // Leilei - palletization cvar_t *r_leidebug; // Leilei - debug cvar_t *r_leidebugeye; // Leilei - eye debug cvar_t *r_suggestiveThemes; // leilei - mature content control -//cvar_t *r_motionblur; // Leilei - motionblur -cvar_t *r_motionblur_fps; // Leilei - motionblur framerated - cvar_t *r_textureDither; // leilei - Dithered texture cvar_t *r_texdump; // Leilei - debug - texture dump as they load, players should never need to use this! @@ -235,10 +226,6 @@ cvar_t *r_texdump; // Leilei - debug - texture dump as they load, players shoul #ifdef USE_FALLBACK_GLSL -extern const char *fallbackShader_anime_vp; -extern const char *fallbackShader_anime_fp; -extern const char *fallbackShader_anime_film_vp; -extern const char *fallbackShader_anime_film_fp; extern const char *fallbackShader_brightness_vp; extern const char *fallbackShader_brightness_fp; extern const char *fallbackShader_leifx_dither_vp; @@ -249,10 +236,6 @@ extern const char *fallbackShader_leifx_gamma_vp; extern const char *fallbackShader_leifx_gamma_fp; extern const char *fallbackShader_leifx_vgasignal_vp; extern const char *fallbackShader_leifx_vgasignal_fp; -extern const char *fallbackShader_motionblur_accum_vp; -extern const char *fallbackShader_motionblur_accum_fp; -extern const char *fallbackShader_motionblur_post_vp; -extern const char *fallbackShader_motionblur_post_fp; #endif @@ -582,24 +565,12 @@ RB_TakeScreenshotCmd ================== */ -extern int tvWidth; -extern int tvHeight; - const void *RB_TakeScreenshotCmd( const void *data ) { const screenshotCommand_t *cmd; cmd = (const screenshotCommand_t *)data; - // leilei - hack for tvmode - if (r_tvMode->integer > -1) { - - if (cmd->jpeg) - RB_TakeScreenshotJPEG( cmd->x, cmd->y, tvWidth, tvHeight, cmd->fileName); - else - RB_TakeScreenshot( cmd->x, cmd->y, tvWidth, tvHeight, cmd->fileName); - } - if (cmd->jpeg) RB_TakeScreenshotJPEG( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName); else @@ -1317,9 +1288,6 @@ void R_Register( void ) r_flareSun = ri.Cvar_Get( "r_flareSun", "0" , CVAR_ARCHIVE); // it's 0 because mappers expect 0. r_flareDelay = ri.Cvar_Get( "r_flareDelay", "100" , CVAR_CHEAT); // update delay for flare pixel read checking. - r_flaresMotionBlur = ri.Cvar_Get( "r_flaresMotionBlur", "0" , CVAR_ARCHIVE ); // fake motion blur on flares - - r_mockvr = ri.Cvar_Get( "r_mockvr", "0" , CVAR_CHEAT); r_leifx = ri.Cvar_Get( "r_leifx", "0" , CVAR_ARCHIVE | CVAR_LATCH); @@ -1327,18 +1295,8 @@ void R_Register( void ) r_detailTextureScale = ri.Cvar_Get( "r_detailtextureScale", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - adjust scale of detail textures r_detailTextureLayers = ri.Cvar_Get( "r_detailtextureLayers", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - add more detail layers - r_ntsc = ri.Cvar_Get( "r_ntsc", "0" , CVAR_ARCHIVE | CVAR_LATCH); // leilei - ntsc filter - - //r_tvMode = ri.Cvar_Get( "r_tvMode", "0" , CVAR_ARCHIVE | CVAR_LATCH); - r_retroAA = ri.Cvar_Get( "r_retroAA", "0" , CVAR_ARCHIVE | CVAR_LATCH); - r_suggestiveThemes = ri.Cvar_Get( "r_suggestiveThemes", "1" , CVAR_ARCHIVE | CVAR_LATCH); -// r_motionblur = ri.Cvar_Get( "r_motionblur", "0" , CVAR_ARCHIVE | CVAR_LATCH); - r_motionblur_fps = ri.Cvar_Get( "r_motionblur_fps", "60", 0); - - r_anime = ri.Cvar_Get( "r_anime", "0" , CVAR_ARCHIVE | CVAR_LATCH); - r_palletize = ri.Cvar_Get( "r_palletize", "0" , CVAR_ARCHIVE | CVAR_LATCH); r_leidebug = ri.Cvar_Get( "r_leidebug", "0" , CVAR_CHEAT); r_particles = ri.Cvar_Get( "r_particles", "0" , CVAR_ARCHIVE | CVAR_LATCH); r_leidebugeye = ri.Cvar_Get( "r_leidebugeye", "0" , CVAR_CHEAT); @@ -1413,12 +1371,6 @@ static glslProgram_t *R_GLSL_AllocProgram(void) program->u_ViewOrigin = -1; program->u_Normal = -1; - program->u_mpass1 = -1; - program->u_mpass2 = -1; - program->u_mpass3 = -1; - program->u_mpass4 = -1; - - program->rubyTextureSize = -1; program->rubyInputSize = -1; program->rubyOutputSize = -1; @@ -1480,21 +1432,6 @@ void R_GLSL_Init(void) Q_strncpyz(programFragmentObjects[0], "glsl/sky_fp.glsl", sizeof(programFragmentObjects[0])); tr.skyProgram = RE_GLSL_RegisterProgram("sky", (const char *)programVertexObjects, 1, (const char *)programFragmentObjects, 1); - - - Q_strncpyz(programVertexObjects[0], "glsl/anime_vp.glsl", sizeof(programVertexObjects[0])); - Q_strncpyz(programFragmentObjects[0], "glsl/anime_fp.glsl", sizeof(programFragmentObjects[0])); - tr.animeProgram = RE_GLSL_RegisterProgram("anime", (const char *)programVertexObjects, 1, (const char *)programFragmentObjects, 1); - - Q_strncpyz(programVertexObjects[0], "glsl/anime_film_vp.glsl", sizeof(programVertexObjects[0])); - Q_strncpyz(programFragmentObjects[0], "glsl/anime_film_fp.glsl", sizeof(programFragmentObjects[0])); - tr.animeFilmProgram = RE_GLSL_RegisterProgram("anime_film", (const char *)programVertexObjects, 1, (const char *)programFragmentObjects, 1); - - Q_strncpyz(programVertexObjects[0], "glsl/palette_vp.glsl", sizeof(programVertexObjects[0])); - Q_strncpyz(programFragmentObjects[0], "glsl/palette_fp.glsl", sizeof(programFragmentObjects[0])); - tr.paletteProgram = RE_GLSL_RegisterProgram("palette", (const char *)programVertexObjects, 1, (const char *)programFragmentObjects, 1); - - Q_strncpyz(programVertexObjects[0], "glsl/leifx_dither_vp.glsl", sizeof(programVertexObjects[0])); Q_strncpyz(programFragmentObjects[0], "glsl/leifx_dither_fp.glsl", sizeof(programFragmentObjects[0])); tr.leiFXDitherProgram = RE_GLSL_RegisterProgram("leifx_dither", (const char *)programVertexObjects, 1, (const char *)programFragmentObjects, 1); @@ -1510,34 +1447,10 @@ void R_GLSL_Init(void) Q_strncpyz(programFragmentObjects[0], "glsl/leifx_filter_fp.glsl", sizeof(programFragmentObjects[0])); tr.leiFXFilterProgram = RE_GLSL_RegisterProgram("leifx_filter", (const char *)programVertexObjects, 1, (const char *)programFragmentObjects, 1); - Q_strncpyz(programVertexObjects[0], "glsl/motionblur_accum_vp.glsl", sizeof(programVertexObjects[0])); - Q_strncpyz(programFragmentObjects[0], "glsl/motionblur_accum_fp.glsl", sizeof(programFragmentObjects[0])); - tr.motionBlurProgram = RE_GLSL_RegisterProgram("motionblur_accum", (const char *)programVertexObjects, 1, (const char *)programFragmentObjects, 1); - - Q_strncpyz(programVertexObjects[0], "glsl/motionblur_post_vp.glsl", sizeof(programVertexObjects[0])); - Q_strncpyz(programFragmentObjects[0], "glsl/motionblur_post_fp.glsl", sizeof(programFragmentObjects[0])); - tr.motionBlurPostProgram = RE_GLSL_RegisterProgram("motionblur_post", (const char *)programVertexObjects, 1, (const char *)programFragmentObjects, 1); - Q_strncpyz(programVertexObjects[0], "glsl/brightness_vp.glsl", sizeof(programVertexObjects[0])); Q_strncpyz(programFragmentObjects[0], "glsl/brightness_fp.glsl", sizeof(programFragmentObjects[0])); tr.BrightnessProgram = RE_GLSL_RegisterProgram("brightness", (const char *)programVertexObjects, 1, (const char *)programFragmentObjects, 1); - Q_strncpyz(programVertexObjects[0], "glsl/crt_vp.glsl", sizeof(programVertexObjects[0])); - Q_strncpyz(programFragmentObjects[0], "glsl/crt_fp.glsl", sizeof(programFragmentObjects[0])); - tr.CRTProgram = RE_GLSL_RegisterProgram("crt", (const char *)programVertexObjects, 1, (const char *)programFragmentObjects, 1); - - Q_strncpyz(programVertexObjects[0], "glsl/ntsc_encode_vp.glsl", sizeof(programVertexObjects[0])); - Q_strncpyz(programFragmentObjects[0], "glsl/ntsc_encode_fp.glsl", sizeof(programFragmentObjects[0])); - tr.NTSCEncodeProgram = RE_GLSL_RegisterProgram("ntsc_encode", (const char *)programVertexObjects, 1, (const char *)programFragmentObjects, 1); - - Q_strncpyz(programVertexObjects[0], "glsl/ntsc_decode_vp.glsl", sizeof(programVertexObjects[0])); - Q_strncpyz(programFragmentObjects[0], "glsl/ntsc_decode_fp.glsl", sizeof(programFragmentObjects[0])); - tr.NTSCDecodeProgram = RE_GLSL_RegisterProgram("ntsc_decode", (const char *)programVertexObjects, 1, (const char *)programFragmentObjects, 1); - - Q_strncpyz(programVertexObjects[0], "glsl/ntsc_bleed_vp.glsl", sizeof(programVertexObjects[0])); - Q_strncpyz(programFragmentObjects[0], "glsl/ntsc_bleed_fp.glsl", sizeof(programFragmentObjects[0])); - tr.NTSCBleedProgram = RE_GLSL_RegisterProgram("ntsc_bleed", (const char *)programVertexObjects, 1, (const char *)programFragmentObjects, 1); - if (strcmp( (const char *)r_postprocess->string, "none" )) { sprintf(p,"glsl/%s_vp.glsl",r_postprocess->string); Q_strncpyz(programVertexObjects[0], (const char *)&p, sizeof(programVertexObjects[0])); diff --git a/code/renderer_oa/tr_local.h b/code/renderer_oa/tr_local.h index f30505dbc1..930a38b805 100644 --- a/code/renderer_oa/tr_local.h +++ b/code/renderer_oa/tr_local.h @@ -86,8 +86,6 @@ typedef struct { vec3_t axis[3]; // orientation in world vec3_t viewOrigin; // viewParms->or.origin in local coordinates float modelMatrix[16]; - vec3_t viewOriginOld; // leilei - motionBlur - vec3_t viewOriginOlder; // leilei - motionBlur } orientationr_t; //=============================================================================== @@ -931,22 +929,6 @@ typedef struct { GLint u_ActualScreenSizeX; GLint u_ActualScreenSizeY; -// leilei - motion blur vars - - GLfloat u_MotionBlurX;// OBSOLETE - GLfloat u_MotionBlurY;// OBSOLETE - - GLint u_ViewMotion;// OBSOLETE - vec3_t v_ViewMotion;// OBSOLETE - - GLint u_mpass1; // 1-5 - GLint u_mpass2; // 6-10 - GLint u_mpass3; // 11-15 - GLint u_mpass4; // 16-20 - - GLint u_mpasses; // How many passes of Motion do we have anyhow? - - // leilei - 'compatibility' with ruby shader vars (HACK HACK HACK) GLint rubyInputSize; @@ -1121,17 +1103,11 @@ typedef struct { qboolean doneBloom; // done bloom this frame qboolean donepostproc; // done postprocess this frame qboolean doneleifx; // leilei - done leifxing this frame - qboolean doneanime; // leilei - done animeing this frame qboolean doneAltBrightness; // leilei - done alternate brightness this frame - qboolean doneFilm; // leilei - done film filtering this frame qboolean doneSun; // leilei - done drawing a sun qboolean doneSunFlare; // leilei - done drawing a sun flare - qboolean donemblur; // leilei - done motionblur this frame qboolean donewater; // leilei - done water this frame - qboolean donetv; // leilei - tv this frame - qboolean doneraa; // leilei - done aa'ing this frame - qboolean donentsc; // leilei - done ntsc'ing this frame - qboolean donepalette; // leilei - done animeing this frame + qboolean donepalette; // leilei - done paletting this frame qboolean doneSurfaces; // done any 3d surfaces already qboolean doneParticles; // done any particle movement qboolean doneFlareTests; // leilei - done testing flares @@ -1190,16 +1166,7 @@ typedef struct { qhandle_t leiFXDitherProgram; // leilei qhandle_t leiFXGammaProgram; // leilei qhandle_t leiFXFilterProgram; // leilei - qhandle_t animeProgram; // leilei - qhandle_t animeFilmProgram; // leilei - qhandle_t motionBlurProgram; // leilei - qhandle_t motionBlurPostProgram; // leilei qhandle_t BrightnessProgram; // leilei - qhandle_t CRTProgram; // leilei - qhandle_t NTSCEncodeProgram; // leilei - qhandle_t NTSCDecodeProgram; // leilei - qhandle_t NTSCBleedProgram; // leilei - qhandle_t paletteProgram; // leilei int numPrograms; glslProgram_t *programs[MAX_PROGRAMS]; @@ -1418,30 +1385,13 @@ extern cvar_t *r_flaresDlightFade; extern cvar_t *r_flaresDlightOpacity; extern cvar_t *r_flaresDlightScale; -extern cvar_t *r_flaresMotionBlur; -//extern cvar_t *r_flaresSurfradii; - extern cvar_t *r_alternateBrightness; // leilei - alternate brightness extern cvar_t *r_leifx; // Leilei - leifx nostalgia filter extern cvar_t *r_modelshader; // Leilei - new model shading -extern cvar_t *r_ntsc; // Leilei - ntsc - -extern cvar_t *r_tvMode; // Leilei - tv faking mode -extern cvar_t *r_tvModeForceAspect; // Leilei - retain aspect of the tv's mode -extern cvar_t *r_tvFilter; // Leilei - filter to use - - -extern cvar_t *r_retroAA; // Leilei - old console anti aliasing - extern cvar_t *r_suggestiveThemes; // Leilei - mature content -extern cvar_t *r_motionblur; // Leilei - motionblur -extern cvar_t *r_motionblur_fps; // Leilei - motionblur framerated - -extern cvar_t *r_anime; // Leilei - anime filter -extern cvar_t *r_palletize; // Leilei - anime filter extern cvar_t *r_leidebug; // Leilei - debug only! extern cvar_t *r_leidebugeye; // Leilei - debug only! extern cvar_t *r_particles; // Leilei - particles! @@ -1941,14 +1891,6 @@ static ID_INLINE void R_GLSL_SetUniform_u_zFar(glslProgram_t *program, GLfloat v qglUniform1fARB(program->u_zFar, value); } -static ID_INLINE void R_GLSL_SetUniform_u_MotionBlurX(glslProgram_t *program, GLfloat value) { - qglUniform1fARB(program->u_MotionBlurX, value); -} - -static ID_INLINE void R_GLSL_SetUniform_u_MotionBlurY(glslProgram_t *program, GLfloat value) { - qglUniform1fARB(program->u_MotionBlurY, value); -} - static ID_INLINE void R_GLSL_SetUniform_u_CC_Brightness(glslProgram_t *program, GLfloat value) { qglUniform1fARB(program->u_CC_Brightness, value); @@ -1975,10 +1917,6 @@ static ID_INLINE void R_GLSL_SetUniform_u_CC_Overbright(glslProgram_t *program, } -static ID_INLINE void R_GLSL_SetUniform_u_mpasses(glslProgram_t *program, GLint value) { - qglUniform1iARB(program->u_mpasses, value); -} - static ID_INLINE void R_GLSL_SetUniform_u_ActualScreenSizeX(glslProgram_t *program, GLint value) { qglUniform1iARB(program->u_ActualScreenSizeX, value); } @@ -2014,13 +1952,6 @@ static ID_INLINE void R_GLSL_SetUniform_rubyOutputSize(glslProgram_t *program, c // qglUniform3fARB(program->rubyOutputSize, value, valub, 1.0); } - - -static ID_INLINE void R_GLSL_SetUniform_Mpass1(glslProgram_t *program, GLint value) {qglUniform1iARB(program->u_mpass1, value);} -static ID_INLINE void R_GLSL_SetUniform_Mpass2(glslProgram_t *program, GLint value) {qglUniform1iARB(program->u_mpass2, value);} -static ID_INLINE void R_GLSL_SetUniform_Mpass3(glslProgram_t *program, GLint value) {qglUniform1iARB(program->u_mpass3, value);} -static ID_INLINE void R_GLSL_SetUniform_Mpass4(glslProgram_t *program, GLint value) {qglUniform1iARB(program->u_mpass4, value);} - void R_GLSL_Init(void); qhandle_t RE_GLSL_RegisterProgram(const char *name, const char *programVertexObjects, int numVertexObjects, const char *programFragmentObjects, int numFragmentObjects); void R_GLSL_UseProgram(qhandle_t index); @@ -2380,8 +2311,6 @@ void R_BloomInit( void ); void R_WaterInit( void ); void R_BloomScreen( void ); void R_WaterScreen( void ); -void R_AnimeScreen( void ); -void R_NTSCScreen( void ); void R_PaletteScreen( void ); // Postprocessing void R_PostprocessScreen( void ); @@ -2390,14 +2319,10 @@ void R_PostprocessingInit(void); // leilei void R_BrightScreen( void ); void R_AltBrightnessInit( void ); -void R_FilmScreen( void ); // leilei - film effect extern int softwaremode; extern int leifxmode; extern int voodootype; // 0 - none 1 - Voodoo Graphics 2 - Voodoo2, 3 - Voodoo Banshee/3, 4 - Voodoo4/5 -void RB_UpdateMotionBlur (void); -void R_MotionBlur_BackupScreen(int which); - void R_AddParticles (void); void R_RenderParticles (void); void R_ClearParticles (void); diff --git a/code/renderer_oa/tr_shade.c b/code/renderer_oa/tr_shade.c index aa254ba0ff..b111ae6d7b 100644 --- a/code/renderer_oa/tr_shade.c +++ b/code/renderer_oa/tr_shade.c @@ -1481,11 +1481,6 @@ void GLSL_Feeder(shaderStage_t *pStage, shaderCommands_t *input) R_BindAnimatedImage(&pStage->bundle[7]); } - if (program->u_mpass1 > -1 && pStage->bundle[1].image[0]) { GL_SelectTexture(11); qglEnable(GL_TEXTURE_2D); R_BindAnimatedImage(&pStage->bundle[11]);} - if (program->u_mpass2 > -1 && pStage->bundle[1].image[0]) { GL_SelectTexture(12); qglEnable(GL_TEXTURE_2D); R_BindAnimatedImage(&pStage->bundle[12]);} - if (program->u_mpass3 > -1 && pStage->bundle[1].image[0]) { GL_SelectTexture(13); qglEnable(GL_TEXTURE_2D); R_BindAnimatedImage(&pStage->bundle[13]);} - if (program->u_mpass4 > -1 && pStage->bundle[1].image[0]) { GL_SelectTexture(14); qglEnable(GL_TEXTURE_2D); R_BindAnimatedImage(&pStage->bundle[14]);} - /* time */ if (program->u_Time > -1) R_GLSL_SetUniform_Time(program, input->shaderTime); @@ -1501,11 +1496,6 @@ void GLSL_Clean(void) { glslProgram_t *program; program = tr.programs[glState.currentProgram]; - - if (program->u_mpass1 > -1) { GL_SelectTexture(11); qglDisable(GL_TEXTURE_2D); } - if (program->u_mpass2 > -1) { GL_SelectTexture(12); qglDisable(GL_TEXTURE_2D); } - if (program->u_mpass3 > -1) { GL_SelectTexture(13); qglDisable(GL_TEXTURE_2D); } - if (program->u_mpass4 > -1) { GL_SelectTexture(14); qglDisable(GL_TEXTURE_2D); } /* disable texture unit 7 */ if (program->u_Texture7 > -1) diff --git a/code/renderer_oa/tr_shader.c b/code/renderer_oa/tr_shader.c index b99552ab0f..442ab6a087 100644 --- a/code/renderer_oa/tr_shader.c +++ b/code/renderer_oa/tr_shader.c @@ -134,9 +134,6 @@ static glslProgram_t *R_GLSL_AllocProgram(void) { program->u_ScreenToNextPixelX = -1; program->u_ScreenToNextPixelY = -1; program->u_zFar = -1; - program->u_MotionBlurX = -1; - program->u_MotionBlurY = -1; - program->u_mpasses = -1; program->u_CC_Brightness = -1; program->u_CC_Gamma = -1; program->u_CC_Overbright = -1; @@ -194,8 +191,6 @@ static void R_GLSL_ParseProgram(glslProgram_t *program, char *_text) { program->u_ActualScreenSizeX = qglGetUniformLocationARB(program->program, "u_ActualScreenSizeX"); } else if (!Q_stricmp(token, "u_ActualScreenSizeY;")) { program->u_ActualScreenSizeY = qglGetUniformLocationARB(program->program, "u_ActualScreenSizeY"); - } else if (!Q_stricmp(token, "u_mpasses;")) { - program->u_mpasses = qglGetUniformLocationARB(program->program, "u_mpasses"); } else { ri.Printf(PRINT_WARNING, "WARNING: uniform int %s unrecognized in program %s\n", token, program->name); } @@ -213,10 +208,6 @@ static void R_GLSL_ParseProgram(glslProgram_t *program, char *_text) { program->u_ScreenToNextPixelY = qglGetUniformLocationARB(program->program, "u_ScreenToNextPixelY"); } else if (!Q_stricmp(token, "u_zFar;")) { program->u_zFar = qglGetUniformLocationARB(program->program, "u_zFar"); - } else if (!Q_stricmp(token, "u_MotionBlurX;")) { - program->u_MotionBlurX = qglGetUniformLocationARB(program->program, "u_MotionBlurX"); - } else if (!Q_stricmp(token, "u_MotionBlurY;")) { - program->u_MotionBlurY = qglGetUniformLocationARB(program->program, "u_MotionBlurY"); } else if (!Q_stricmp(token, "u_CC_Brightness;")) { program->u_CC_Brightness = qglGetUniformLocationARB(program->program, "u_CC_Brightness"); } else if (!Q_stricmp(token, "u_CC_Overbright;")) { @@ -4867,20 +4858,10 @@ shader_t *R_FindShaderReal( const char *name, int lightmapIndex, qboolean mipRaw return FinishShader(); } -// leilei - rather stupid way to do a cel wrapper to work for all textures shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ) { shader_t *sh; shader_t *ahsh; -/* // Sadly, I have deprecated the old cel hack. I am leaving it here. It breaks 2D textures BTW!!! :( - if (r_anime->integer){ - sh = R_FindShaderReal(va("%s_cel",name), lightmapIndex, mipRawImage); - if ( sh->defaultShader ) - sh = R_FindShaderReal(name, lightmapIndex, mipRawImage); - return sh; - } - else*/ - // load real shader first? sh = R_FindShaderReal(name, lightmapIndex, mipRawImage); if (!Q_strncmp( name, "models/player", 13) ){ // restrict to players; speedup diff --git a/code/sdl/sdl_glimp.c b/code/sdl/sdl_glimp.c index d1c1ae579b..a5d427a5ae 100644 --- a/code/sdl/sdl_glimp.c +++ b/code/sdl/sdl_glimp.c @@ -51,12 +51,6 @@ typedef void *QGLContext; static QGLContext opengl_context; #endif -int tvMode; // leilei - tvmode -int tvWidth; -int tvHeight; -int tvinterlace = 1; // leilei - interlace value for height -float tvAspectW; // leilei - for aspect correction - //int vresWidth; //int vresHeight; @@ -80,11 +74,6 @@ static const SDL_VideoInfo *videoInfo = NULL; #endif cvar_t *r_allowSoftwareGL; // Don't abort out if a hardware visual can't be obtained -cvar_t *r_tvMode; // leilei - tv mode - force 480i rendering, which is then stretched and interlaced -cvar_t *r_tvFilter; // leilei - tv filter -cvar_t *r_tvModeAspect; // leilei - tv mode - to do widescreen and low res tv etc -cvar_t *r_tvModeForceAspect; // leilei - tv mode - to force the screen into its native aspect -cvar_t *r_motionblur; // leilei - moved here to set up accumulation bits cvar_t *r_allowResize; // make window resizable cvar_t *r_conMode; // leilei - console mode - force native resolutions of various consoles cvar_t *r_centerWindow; @@ -280,7 +269,6 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder) int sdlcolorbits; int colorbits, depthbits, stencilbits; int tcolorbits, tdepthbits, tstencilbits; - int accumbits; // leilei - motionblur int samples; int i = 0; SDL_Surface *icon = NULL; @@ -438,12 +426,6 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder) stencilbits = r_stencilbits->value; samples = r_ext_multisample->value; - // leilei - motion blur via accumulation buffer support - if (r_motionblur->integer == 1) - accumbits = 16; - else - accumbits = 0; - for (i = 0; i < 16; i++) { // 0 - default @@ -519,12 +501,6 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder) SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, tdepthbits ); SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, tstencilbits ); - // leilei - accumulation buffer motion blur - SDL_GL_SetAttribute( SDL_GL_ACCUM_RED_SIZE, accumbits ); - SDL_GL_SetAttribute( SDL_GL_ACCUM_GREEN_SIZE, accumbits ); - SDL_GL_SetAttribute( SDL_GL_ACCUM_BLUE_SIZE, accumbits ); - SDL_GL_SetAttribute( SDL_GL_ACCUM_ALPHA_SIZE, accumbits ); - SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, samples ? 1 : 0 ); SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, samples ); @@ -651,12 +627,6 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder) } #endif - // - // leilei - TV MODE - // - tvWidth = glConfig.vidWidth; - tvHeight = glConfig.vidHeight; - vresWidth = glConfig.vidWidth; vresHeight = glConfig.vidHeight; @@ -665,44 +635,10 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder) vresWidth = 640; vresHeight = 480; - //tvAspectW = 1.0; // no change - - if( r_tvMode->integer > -1){ - - - if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, r_tvMode->integer ) ) - { - glConfig.vidWidth = 640; // if we can't do a mode then do this mode - glConfig.vidHeight = 480; - } - - if (glConfig.vidWidth > tvWidth) glConfig.vidWidth = tvWidth; // clamp - if (glConfig.vidHeight > tvHeight) glConfig.vidHeight = tvHeight; // clamp - - - // leilei - make it use an aspect-corrected lower resolution that's always 640 wide for the width, but variable height - // then change the gl port.. - - vresWidth = tvWidth; - vresHeight = tvHeight; - - if( r_tvModeForceAspect->integer ){ - float ttw = (float)glConfig.vidWidth / ((float)tvWidth * (float)((float)glConfig.vidHeight/(float)tvHeight)); // 640 / 853 = 0.75 = ASPECT VALUE - tvAspectW = ttw; // let's try this first to see if we can get it to our renderer - //tvAspectW = 0.75f; // let's try this first to see if we can get it to our renderer - } - } - // leilei - tv mode hack end #if SDL_MAJOR_VERSION != 2 screen = vidscreen; #endif - - if( r_tvModeAspect->integer ) { - float aspe = 640.0f / tvWidth; - glConfig.vidWidth = tvWidth * aspe; - glConfig.vidHeight = tvHeight * aspe; - } // then change the gl port.. glstring = (char *) qglGetString (GL_RENDERER); @@ -967,15 +903,6 @@ void GLimp_Init( void ) r_sdlDriver = ri.Cvar_Get( "r_sdlDriver", "", CVAR_ROM ); r_allowResize = ri.Cvar_Get( "r_allowResize", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_centerWindow = ri.Cvar_Get( "r_centerWindow", "0", CVAR_ARCHIVE | CVAR_LATCH ); -// leilei - tv mode hack - r_tvMode = ri.Cvar_Get( "r_virtualMode", "-1", CVAR_LATCH | CVAR_ARCHIVE ); - r_tvModeAspect = ri.Cvar_Get( "r_tvModeAspect", "0", CVAR_LATCH | CVAR_ARCHIVE ); // yes - r_tvModeForceAspect = ri.Cvar_Get( "r_tvModeForceAspect", "0", CVAR_LATCH | CVAR_ARCHIVE ); // yes - - r_tvFilter = ri.Cvar_Get( "r_tvFilter", "1", CVAR_LATCH | CVAR_ARCHIVE ); - -// leilei - move motionblur cvar here to get it to not upset the other renderers when setting up an accumulation buffer - r_motionblur = ri.Cvar_Get( "r_motionblur", "0", CVAR_LATCH | CVAR_ARCHIVE ); if( ri.Cvar_VariableIntegerValue( "com_abnormalExit" ) ) { From 9dcac5d61049118a276b786a53bf2b61612d8de4 Mon Sep 17 00:00:00 2001 From: leilei- Date: Fri, 28 Mar 2025 08:17:36 -0400 Subject: [PATCH 04/20] test --- code/qcommon/q_shared.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index ff6f1ee0f6..73c2be83d7 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -27,7 +27,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // A user mod should never modify this file #ifdef STANDALONE - #define PRODUCT_NAME "ioq3+oa" + #define PRODUCT_NAME "OpenArena" #define BASEGAME "baseoa" #define CLIENT_WINDOW_TITLE "OpenArena" #define CLIENT_WINDOW_MIN_TITLE "OA" From d06babd6c862093a98910b0aaf52e8bdcc2477fc Mon Sep 17 00:00:00 2001 From: leilei- Date: Sat, 29 Mar 2025 04:29:44 -0400 Subject: [PATCH 05/20] Cool console things - cl_consoleScale : makes the console more 640x480 sized on any higher res. Also affects notify messages, so you can read chat easier - cl_consoleColor also affects the line at the bottom. Also new default colors - If consoleShader can't load (which will happen with some mods), it will fallback to a flat-colored console. - Generic'd the red/blue team names. We will not be having missionpack clans. --- code/client/cl_console.c | 70 ++++++++++++++++++---- code/client/cl_keys.c | 2 +- code/client/cl_main.c | 19 ++++-- code/client/cl_scrn.c | 122 ++++++++++++++++++++++++++++++++------- code/client/client.h | 5 +- 5 files changed, 179 insertions(+), 39 deletions(-) diff --git a/code/client/cl_console.c b/code/client/cl_console.c index 9ea4b19eaf..e1e4ac6028 100644 --- a/code/client/cl_console.c +++ b/code/client/cl_console.c @@ -517,6 +517,8 @@ DRAWING ============================================================================== */ +extern cvar_t *cl_consoleScale; // leilei - scale the console + /* ================ @@ -536,7 +538,7 @@ void Con_DrawInput (void) { re.SetColor( con.color ); - SCR_DrawSmallChar( con.xadjust + 1 * SMALLCHAR_WIDTH, y, ']' ); + SCR_DrawSmallChar( con.xadjust + 1 * SMALLCHAR_WIDTH, y, ']' ,2); Field_Draw( &g_consoleField, con.xadjust + 2 * SMALLCHAR_WIDTH, y, SCREEN_WIDTH - 3 * SMALLCHAR_WIDTH, qtrue, qtrue ); @@ -587,7 +589,7 @@ void Con_DrawNotify (void) currentColor = (text[x]>>8) % NUMBER_OF_COLORS; re.SetColor( g_color_table[currentColor] ); } - SCR_DrawSmallChar( cl_conXOffset->integer + con.xadjust + (x+1)*SMALLCHAR_WIDTH, v, text[x] & 0xff ); + SCR_DrawSmallChar( cl_conXOffset->integer + con.xadjust + (x+1)*SMALLCHAR_WIDTH, v, text[x] & 0xff ,2); } v += SMALLCHAR_HEIGHT; @@ -636,6 +638,17 @@ void Con_DrawSolidConsole( float frac ) { int currentColor; vec4_t color; + if (cl_consoleScale->integer && (cls.glconfig.vidWidth > SCREEN_WIDTH)) + { + lines = SCREEN_HEIGHT * frac; + if (lines <= 0) + return; + + if (lines > SCREEN_HEIGHT ) + lines = SCREEN_HEIGHT; + } + else + { lines = cls.glconfig.vidHeight * frac; if (lines <= 0) return; @@ -646,6 +659,7 @@ void Con_DrawSolidConsole( float frac ) { // on wide screens, we will center the text con.xadjust = 0; SCR_AdjustFrom640( &con.xadjust, NULL, NULL, NULL ); + } // draw the background y = frac * SCREEN_HEIGHT; @@ -667,9 +681,31 @@ void Con_DrawSolidConsole( float frac ) { } } - color[0] = 1; - color[1] = 0; - color[2] = 0; + // leilei - normalize our custom color for the line + //color[0] = 1; + //color[1] = 0; // was 1 pre-1.25 + //color[2] = 0; + + // leilei - normalize from our custom console color and apply it to the line + { + float max; + float rgb[3]; + + rgb[0] = cl_consoleColor[0]->value; + rgb[1] = cl_consoleColor[1]->value; + rgb[2] = cl_consoleColor[2]->value; + + max = rgb[0] + rgb[1] + rgb[2] / 3; + + if (max > 0) + { + color[0] = rgb[0] / max; + color[1] = rgb[1] / max; + color[2] = rgb[2] / max; + } + } + + if( !cl_consoleType->integer ) color[3] = 1; SCR_FillRect( 0, y, SCREEN_WIDTH, 2, color ); @@ -677,16 +713,26 @@ void Con_DrawSolidConsole( float frac ) { // draw the version number - re.SetColor( g_color_table[ColorIndex(COLOR_RED)] ); + re.SetColor( g_color_table[ColorIndex(cl_consoleAccent->integer)] ); i = strlen( Q3_VERSION ); - for (x=0 ; xinteger && (cls.glconfig.vidWidth > SCREEN_WIDTH)){ + for (x=0 ; xinteger)] ); for (x=0 ; x>8) % NUMBER_OF_COLORS; re.SetColor( g_color_table[currentColor] ); } - SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, text[x] & 0xff ); + SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, text[x] & 0xff, 2 ); } } diff --git a/code/client/cl_keys.c b/code/client/cl_keys.c index 1bd9cf9a67..c37f3c6473 100644 --- a/code/client/cl_keys.c +++ b/code/client/cl_keys.c @@ -378,7 +378,7 @@ void Field_VariableSizeDraw( field_t *edit, int x, int y, int width, int size, q i = drawLen - strlen( str ); if ( size == SMALLCHAR_WIDTH ) { - SCR_DrawSmallChar( x + ( edit->cursor - prestep - i ) * size, y, cursorChar ); + SCR_DrawSmallChar( x + ( edit->cursor - prestep - i ) * size, y, cursorChar, 2 ); } else { str[0] = cursorChar; str[1] = 0; diff --git a/code/client/cl_main.c b/code/client/cl_main.c index c9c0785336..96b0909ceb 100644 --- a/code/client/cl_main.c +++ b/code/client/cl_main.c @@ -124,6 +124,8 @@ cvar_t *cl_consoleType; cvar_t *cl_consoleColor[4]; cvar_t *cl_consoleHeight; +cvar_t *cl_consoleAccent; // leilei - change version and line color +cvar_t *cl_consoleScale; // leilei - scale the console clientActive_t cl; clientConnection_t clc; @@ -3115,6 +3117,11 @@ void CL_InitRenderer( void ) { cls.charSetShader = re.RegisterShader( "gfx/2d/bigchars" ); cls.whiteShader = re.RegisterShader( "white" ); cls.consoleShader = re.RegisterShader( "console" ); + if (!cls.consoleShader) // leilei - fallback console type if it fails + { + Cvar_Set("cl_consoleType", "2"); + Com_Printf( "Console shader failed to load, falling back to simple console\n"); + } g_console_field_width = cls.glconfig.vidWidth / SMALLCHAR_WIDTH - 2; g_consoleField.widthInChars = g_console_field_width; } @@ -3552,12 +3559,14 @@ void CL_Init( void ) { cl_consoleKeys = Cvar_Get( "cl_consoleKeys", "~ ` 0x7e 0x60", CVAR_ARCHIVE); cl_consoleType = Cvar_Get( "cl_consoleType", "0", CVAR_ARCHIVE ); - cl_consoleColor[0] = Cvar_Get( "cl_consoleColorRed", "1", CVAR_ARCHIVE ); - cl_consoleColor[1] = Cvar_Get( "cl_consoleColorGreen", "0", CVAR_ARCHIVE ); - cl_consoleColor[2] = Cvar_Get( "cl_consoleColorBlue", "0", CVAR_ARCHIVE ); + cl_consoleColor[0] = Cvar_Get( "cl_consoleColorRed", "0.104", CVAR_ARCHIVE ); + cl_consoleColor[1] = Cvar_Get( "cl_consoleColorGreen", "0.187", CVAR_ARCHIVE ); + cl_consoleColor[2] = Cvar_Get( "cl_consoleColorBlue", "0.312", CVAR_ARCHIVE ); cl_consoleColor[3] = Cvar_Get( "cl_consoleColorAlpha", "0.8", CVAR_ARCHIVE ); cl_consoleHeight = Cvar_Get("cl_consoleHeight", "0.5", CVAR_ARCHIVE); + cl_consoleAccent = Cvar_Get("cl_consoleAccent", "61" , CVAR_ARCHIVE); // leilei - change version and scroll color + cl_consoleScale = Cvar_Get ("cl_consoleScale" , "1" , CVAR_ARCHIVE); // leilei - console/notify text scale // userinfo Cvar_Get ("name", "UnnamedPlayer", CVAR_USERINFO | CVAR_ARCHIVE ); @@ -3567,8 +3576,8 @@ void CL_Init( void ) { Cvar_Get ("headmodel", "sarge", CVAR_USERINFO | CVAR_ARCHIVE ); Cvar_Get ("team_model", "james", CVAR_USERINFO | CVAR_ARCHIVE ); Cvar_Get ("team_headmodel", "*james", CVAR_USERINFO | CVAR_ARCHIVE ); - Cvar_Get ("g_redTeam", "Stroggs", CVAR_SERVERINFO | CVAR_ARCHIVE); - Cvar_Get ("g_blueTeam", "Pagans", CVAR_SERVERINFO | CVAR_ARCHIVE); + Cvar_Get ("g_redTeam", "Red", CVAR_SERVERINFO | CVAR_ARCHIVE); + Cvar_Get ("g_blueTeam", "Blue", CVAR_SERVERINFO | CVAR_ARCHIVE); Cvar_Get ("color1", "4", CVAR_USERINFO | CVAR_ARCHIVE ); Cvar_Get ("color2", "5", CVAR_USERINFO | CVAR_ARCHIVE ); Cvar_Get ("handicap", "100", CVAR_USERINFO | CVAR_ARCHIVE ); diff --git a/code/client/cl_scrn.c b/code/client/cl_scrn.c index 831d5ef7ae..b0feea8d18 100644 --- a/code/client/cl_scrn.c +++ b/code/client/cl_scrn.c @@ -84,6 +84,36 @@ void SCR_AdjustFrom640( float *x, float *y, float *w, float *h ) { } } + +/* +================ +SCR_AdjustFrom480 + +leilei - Adjusted for resolution and screen aspect ratio.... but from vertical only so the aspect is ok +================ +*/ +void SCR_AdjustFrom480( float *x, float *y, float *w, float *h ) { + float xscale; + float yscale; + + // scale for screen sizes + yscale = cls.glconfig.vidHeight / 480.0; + + if ( x ) { + *x *= yscale; + } + if ( y ) { + *y *= yscale; + } + if ( w ) { + *w *= yscale; + } + if ( h ) { + *h *= yscale; + } +} + + /* ================ SCR_FillRect @@ -157,32 +187,84 @@ static void SCR_DrawChar( int x, int y, float size, int ch ) { ** SCR_DrawSmallChar ** small chars are drawn at native screen resolution */ -void SCR_DrawSmallChar( int x, int y, int ch ) { +void SCR_DrawSmallChar( int x, int y, int ch, int scalemode ) { int row, col; float frow, fcol; float size; - ch &= 255; + if ((scalemode) && (cl_consoleScale->integer) && (cls.glconfig.vidWidth > SCREEN_WIDTH)) + { + // leilei - ideally, I want to have the same amount of lines as 640x480 on any higher resolution to keep it readable, + // while horizontally it's also like 640x480 but keeping up a gap to the right so the characters are still 1:2 aspect. + // like idTech 4. + // in 640x480 on a normal pulled down console, there are 12 lines, 6.5 lines on a half pull, and 29 for a full console + int row, col; + float frow, fcol; + float ax, ay, aw, ah; + float size; + float sizeup = 1.0f; + float sizedown = 1.0f; + ch &= 255; + + if (cls.glconfig.vidHeight >= 480) + sizeup = cls.glconfig.vidHeight / 480; + sizedown = (cls.glconfig.vidHeight - 480); - if ( ch == ' ' ) { - return; + if ( ch == ' ' ) { + return; + } + + if ( y < -SMALLCHAR_HEIGHT ) { + return; + } + + ax = x; + ay = y; + aw = SMALLCHAR_WIDTH ; + ah = SMALLCHAR_HEIGHT; + if (scalemode == 2) + SCR_AdjustFrom480( &ax, &ay, &aw, &ah ); + else + SCR_AdjustFrom640( &ax, &ay, &aw, &ah ); + + row = ch>>4; + col = ch&15; + + frow = row*0.0625; + fcol = col*0.0625; + size = 0.0625; + + re.DrawStretchPic( ax, ay, aw, ah, + fcol, frow, + fcol + size, frow + size, + cls.charSetShader ); + + } - - if ( y < -SMALLCHAR_HEIGHT ) { - return; + else + { + ch &= 255; + + if ( ch == ' ' ) { + return; + } + + if ( y < -SMALLCHAR_HEIGHT ) { + return; + } + + row = ch>>4; + col = ch&15; + + frow = row*0.0625; + fcol = col*0.0625; + size = 0.0625; + + re.DrawStretchPic( x, y, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, + fcol, frow, + fcol + size, frow + size, + cls.charSetShader ); } - - row = ch>>4; - col = ch&15; - - frow = row*0.0625; - fcol = col*0.0625; - size = 0.0625; - - re.DrawStretchPic( x, y, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, - fcol, frow, - fcol + size, frow + size, - cls.charSetShader ); } @@ -286,7 +368,7 @@ void SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, continue; } } - SCR_DrawSmallChar( xx, y, *s ); + SCR_DrawSmallChar( xx, y, *s, 2 ); xx += SMALLCHAR_WIDTH; s++; } diff --git a/code/client/client.h b/code/client/client.h index a3a939bc9e..47e073af98 100644 --- a/code/client/client.h +++ b/code/client/client.h @@ -433,6 +433,9 @@ extern cvar_t *cl_consoleKeys; extern cvar_t *cl_consoleType; extern cvar_t *cl_consoleColor[4]; +extern cvar_t *cl_consoleScale; +extern cvar_t *cl_consoleAccent; + extern cvar_t *cl_consoleHeight; #ifdef USE_MUMBLE @@ -582,7 +585,7 @@ void SCR_DrawNamedPic( float x, float y, float width, float height, const char * void SCR_DrawBigString( int x, int y, const char *s, float alpha, qboolean noColorEscape ); // draws a string with embedded color control characters with fade void SCR_DrawBigStringColor( int x, int y, const char *s, vec4_t color, qboolean noColorEscape ); // ignores embedded color control characters void SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor, qboolean noColorEscape ); -void SCR_DrawSmallChar( int x, int y, int ch ); +void SCR_DrawSmallChar( int x, int y, int ch, int scalemode ); // From de7dcf2cc846d9bffbeb511b0502981dc534beeb Mon Sep 17 00:00:00 2001 From: leilei- Date: Sat, 29 Mar 2025 21:46:43 -0400 Subject: [PATCH 06/20] SDL2: Clicking the red X now does something: you can leave!!! If it sucks.... hit da bricks!! real winners quit --- code/sdl/sdl_input.c | 1 + 1 file changed, 1 insertion(+) diff --git a/code/sdl/sdl_input.c b/code/sdl/sdl_input.c index b6d5257d52..2f2a65d1ed 100644 --- a/code/sdl/sdl_input.c +++ b/code/sdl/sdl_input.c @@ -1204,6 +1204,7 @@ static void IN_ProcessEvents( void ) case SDL_WINDOWEVENT_MAXIMIZED: Cvar_SetValue( "com_minimized", 0 ); break; case SDL_WINDOWEVENT_FOCUS_LOST: Cvar_SetValue( "com_unfocused", 1 ); break; case SDL_WINDOWEVENT_FOCUS_GAINED: Cvar_SetValue( "com_unfocused", 0 ); break; + case SDL_WINDOWEVENT_CLOSE: Cbuf_ExecuteText(EXEC_NOW, "quit Closed window\n"); break; } break; #else From fc3524409d22cfafc4430a5da2772d2fa814e570 Mon Sep 17 00:00:00 2001 From: leilei- Date: Sun, 30 Mar 2025 04:43:39 -0400 Subject: [PATCH 07/20] s_xmp_startPattern - makes the tracker song play a different pattern (for use with sub-songs) --- code/client/snd_codec_xmp.c | 41 ++++++++++++++++++++++++++++++++++--- code/client/snd_local.h | 2 ++ code/client/snd_main.c | 3 ++- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/code/client/snd_codec_xmp.c b/code/client/snd_codec_xmp.c index 89db2292d7..7123a76d62 100644 --- a/code/client/snd_codec_xmp.c +++ b/code/client/snd_codec_xmp.c @@ -43,7 +43,10 @@ void sound_deinit(void); - +static float fadey; +extern cvar_t *s_xmp_startPattern; +static int startpat; +static int gopat; extern int samplingrate; // from snd_dma void S_XMP_StartSong ( void ) @@ -58,6 +61,29 @@ void S_XMP_EndSong ( void ) +} + + +// TODO: A callback to set this appropriately from game context (monster sight, level triggers) +void S_XMP_CheckForFade ( void ) +{ + gopat = s_xmp_startPattern->integer; + + if ((gopat != startpat)) + { + fadey -= 0.025f; + // Com_Printf("AHHHFADING TO PATTERN %i!!! %f\n", startpat, fadey); + xmp_set_player(xmpsong, XMP_PLAYER_VOLUME, (fadey * 128)); + } + + if ((startpat != gopat) && (fadey < 0.01)) + { + startpat = gopat; + xmp_set_position(xmpsong, startpat); + xmp_set_player(xmpsong, XMP_PLAYER_VOLUME, 128); + fadey = 1; + } + } int aintistreaming = 0; @@ -79,7 +105,7 @@ S_XMP_CodecOpenStream ================= */ -// FIXME: there's a memory leak here if you start the same song many many many many times. +// FIXME: there's a memory leak here if you start the same song many many many many times? snd_stream_t *S_XMP_CodecOpenStream(const char *filename) { // First let's close whatever song we had.... @@ -130,7 +156,14 @@ snd_stream_t *S_XMP_CodecOpenStream(const char *filename) FS_FCloseFile(file); // unfortunately these do not help with the leak if (itsloaded == 0) - itsloaded = xmp_start_player(xmpsong, xmpspeed, 0); // TODO: do sample rate of the mixer. + { + itsloaded = xmp_start_player(xmpsong, xmpspeed, 0); + startpat=s_xmp_startPattern->integer; + gopat = startpat; + fadey = 1.0; + xmp_set_player(xmpsong, XMP_PLAYER_VOLUME, 128); + xmp_set_position(xmpsong, startpat); + } if (itsloaded == 0) { // Com_Printf("XMP loaded our buffer of the file %s which is %i long \n", filename, thelength); @@ -197,6 +230,8 @@ int S_XMP_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer) return 0; } + S_XMP_CheckForFade(); + return bytes; } diff --git a/code/client/snd_local.h b/code/client/snd_local.h index 42fa7c5844..61325d5195 100644 --- a/code/client/snd_local.h +++ b/code/client/snd_local.h @@ -241,6 +241,8 @@ extern short *sfxScratchBuffer; extern sfx_t *sfxScratchPointer; extern int sfxScratchIndex; +extern cvar_t *s_xmp_startPattern; + qboolean S_Base_Init( soundInterface_t *si ); // OpenAL stuff diff --git a/code/client/snd_main.c b/code/client/snd_main.c index e51ec580fb..b1504b7ba0 100644 --- a/code/client/snd_main.c +++ b/code/client/snd_main.c @@ -35,6 +35,7 @@ cvar_t *s_muteWhenMinimized; cvar_t *s_muteWhenUnfocused; cvar_t *s_interrupts; +cvar_t *s_xmp_startPattern; static soundInterface_t si; @@ -490,7 +491,7 @@ void S_Init( void ) s_interrupts = Cvar_Get( "s_interrupts", "0", CVAR_ARCHIVE ); // leilei - pre-1.25 sound behavior s_muteWhenMinimized = Cvar_Get( "s_muteWhenMinimized", "0", CVAR_ARCHIVE ); s_muteWhenUnfocused = Cvar_Get( "s_muteWhenUnfocused", "0", CVAR_ARCHIVE ); - + s_xmp_startPattern = Cvar_Get( "s_xmp_startPattern", "0", CVAR_CHEAT ); // leilei - starting pattern for song cv = Cvar_Get( "s_initsound", "1", 0 ); if( !cv->integer ) { Com_Printf( "Sound disabled.\n" ); From 354edd5b67d273917016cff56920394f964b09cf Mon Sep 17 00:00:00 2001 From: leilei- Date: Sun, 30 Mar 2025 06:01:18 -0400 Subject: [PATCH 08/20] - fixed xmp playback as xmp explicitly requires a length of the module now. Fixes issue #96 - suppress the warning about non-22khz music, as mods are playing at the mixer's rate always, and this warning regards a much earlier (1999) unstable sound mixer. --- code/client/snd_codec_xmp.c | 2 +- code/client/snd_dma.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/code/client/snd_codec_xmp.c b/code/client/snd_codec_xmp.c index 7123a76d62..b42129aa4d 100644 --- a/code/client/snd_codec_xmp.c +++ b/code/client/snd_codec_xmp.c @@ -149,7 +149,7 @@ snd_stream_t *S_XMP_CodecOpenStream(const char *filename) xmpsong = xmp_create_context(); int itsloaded = 0; - itsloaded = xmp_load_module_from_memory(xmpsong, buffer, 0); + itsloaded = xmp_load_module_from_memory(xmpsong, buffer, thelength); // Free our memory and close the file. Hunk_FreeTempMemory(buffer); diff --git a/code/client/snd_dma.c b/code/client/snd_dma.c index 729cd5305f..ec8596a9a4 100644 --- a/code/client/snd_dma.c +++ b/code/client/snd_dma.c @@ -1432,9 +1432,11 @@ static void S_OpenBackgroundStream( const char *filename ) { return; } - if(s_backgroundStream->info.channels != 2 || s_backgroundStream->info.rate != 22050) { - Com_Printf(S_COLOR_YELLOW "WARNING: music file %s is not 22k stereo\n", filename ); - } +// leilei - commented out, as we have music beyond this rate, and this warning is meant for an older +// iteration of q3's sound engine that couldn't handle other rates. +// if(s_backgroundStream->info.channels != 2 || s_backgroundStream->info.rate != 22050) { +// Com_Printf(S_COLOR_YELLOW "WARNING: music file %s is not 22k stereo\n", filename ); +// } } From 5312d24a4123c49fadc0bda618f1898c7f90ac6b Mon Sep 17 00:00:00 2001 From: leilei- Date: Thu, 10 Apr 2025 06:39:09 -0400 Subject: [PATCH 09/20] - deprecating r_modelshader because the shader got stale, old, buggy, and amd hates it now - r_shadeMethod will be something else (and not shader-based) --- code/renderer_oa/tr_init.c | 4 +-- code/renderer_oa/tr_local.h | 5 +--- code/renderer_oa/tr_shade.c | 12 --------- code/renderer_oa/tr_shade_calc.c | 46 -------------------------------- code/renderer_oa/tr_shader.c | 18 +++---------- 5 files changed, 6 insertions(+), 79 deletions(-) diff --git a/code/renderer_oa/tr_init.c b/code/renderer_oa/tr_init.c index 8ba236fefc..8402a360ff 100644 --- a/code/renderer_oa/tr_init.c +++ b/code/renderer_oa/tr_init.c @@ -208,7 +208,7 @@ cvar_t *r_flaresDlightScale; cvar_t *r_alternateBrightness; // leilei - linux overbright fix cvar_t *r_mockvr; // Leilei - for debugging PVR only! cvar_t *r_leifx; // Leilei - leifx nostalgia filter -cvar_t *r_modelshader; // Leilei +cvar_t *r_shadeMethod; // Leilei cvar_t *r_particles; // Leilei - particle effects motif cvar_t *r_leidebug; // Leilei - debug @@ -1291,7 +1291,7 @@ void R_Register( void ) r_mockvr = ri.Cvar_Get( "r_mockvr", "0" , CVAR_CHEAT); r_leifx = ri.Cvar_Get( "r_leifx", "0" , CVAR_ARCHIVE | CVAR_LATCH); - r_modelshader = ri.Cvar_Get( "r_modelshader", "0" , CVAR_ARCHIVE | CVAR_LATCH); // leilei - load and use special shaders for lightDiffuse models + r_shadeMethod = ri.Cvar_Get( "r_shadeMethod", "0" , CVAR_ARCHIVE | CVAR_LATCH); // leilei - Alternative lightingDiffuse r_detailTextureScale = ri.Cvar_Get( "r_detailtextureScale", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - adjust scale of detail textures r_detailTextureLayers = ri.Cvar_Get( "r_detailtextureLayers", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - add more detail layers diff --git a/code/renderer_oa/tr_local.h b/code/renderer_oa/tr_local.h index 930a38b805..d3d0430e8d 100644 --- a/code/renderer_oa/tr_local.h +++ b/code/renderer_oa/tr_local.h @@ -365,7 +365,6 @@ typedef struct { int isGLSL; int isBlend; // leilei - for leifx - qboolean isLeiShade; // leilei - for the automatic shader qhandle_t program; int imgWidth; @@ -1387,7 +1386,7 @@ extern cvar_t *r_flaresDlightScale; extern cvar_t *r_alternateBrightness; // leilei - alternate brightness extern cvar_t *r_leifx; // Leilei - leifx nostalgia filter -extern cvar_t *r_modelshader; // Leilei - new model shading +extern cvar_t *r_shadeMethod; // Leilei - new model shading methods extern cvar_t *r_suggestiveThemes; // Leilei - mature content @@ -2140,8 +2139,6 @@ void RB_CalcDynamicColor( unsigned char *colors ); void RB_CalcDiffuseColor_Specular( unsigned char *colors ); // leilei - specular hack void RB_CalcFlatAmbient( unsigned char *colors ); // leilei - cel hack void RB_CalcFlatDirect( unsigned char *colors ); // leilei - cel hack -void RB_CalcNormal( unsigned char *colors ); // leilei - normal hack - void RB_CalcGlowBlend( unsigned char *colors, int glowcol, int fx ); // leilei - rgbMod void RB_CalcUVColor( unsigned char *colors, int glowcol, int fx ); // leilei - rgbMod void RB_CalcNormalizeToAlpha( unsigned char *colors); // leilei - rgbMod diff --git a/code/renderer_oa/tr_shade.c b/code/renderer_oa/tr_shade.c index b111ae6d7b..1661746ca1 100644 --- a/code/renderer_oa/tr_shade.c +++ b/code/renderer_oa/tr_shade.c @@ -876,10 +876,6 @@ static void ComputeColors( shaderStage_t *pStage ) Com_Memset( tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 ); break; case CGEN_LIGHTING_DIFFUSE: - if (r_shownormals->integer > 1 || (pStage->isLeiShade)){ - RB_CalcNormal( ( unsigned char * ) tess.svars.colors ); // leilei - debug normals, or use the normals as a color for a lighting shader - break; - } RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors ); if(r_monolightmaps->integer) { @@ -992,10 +988,6 @@ static void ComputeColors( shaderStage_t *pStage ) RB_CalcColorFromOneMinusEntity( ( unsigned char * ) tess.svars.colors ); break; case CGEN_LIGHTING_DIFFUSE_SPECULAR: // leilei - specular hack - if (r_shownormals->integer > 1 || (pStage->isLeiShade)){ - RB_CalcNormal( ( unsigned char * ) tess.svars.colors ); // leilei - debug normals, or use the normals as a color for a lighting shader - break; - } RB_CalcDiffuseColor_Specular( ( unsigned char * ) tess.svars.colors ); if(r_monolightmaps->integer) { @@ -1008,10 +1000,6 @@ static void ComputeColors( shaderStage_t *pStage ) } break; case CGEN_MATERIAL: - if (r_shownormals->integer > 1 || (pStage->isLeiShade)){ - RB_CalcNormal( ( unsigned char * ) tess.svars.colors ); // leilei - debug normals, or use the normals as a color for a lighting shader - break; - } RB_CalcMaterials( ( unsigned char * ) tess.svars.colors, pStage->matAmb, pStage->matDif, pStage->matSpec, pStage->matEmis, pStage->matHard, pStage->matAlpha ); break; } diff --git a/code/renderer_oa/tr_shade_calc.c b/code/renderer_oa/tr_shade_calc.c index e7faafa0a8..a33f0bbda0 100644 --- a/code/renderer_oa/tr_shade_calc.c +++ b/code/renderer_oa/tr_shade_calc.c @@ -1854,52 +1854,6 @@ static void RB_CalcDiffuseColor_scalar( unsigned char *colors ) } } -// leilei - reveal normals to GLSL for light processing. HACK HACK HACK HACK HACK HACK -void RB_CalcNormal( unsigned char *colors ) -{ - float *v; - float *normal = ( float * ) tess.normal; - vec3_t n, m; - int numVertexes; - - v = tess.xyz[0]; - //normal = tess.normal[0]; - - numVertexes = tess.numVertexes; - for (int i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) { - int y; - float mid; - for (y=0;y<3;y++){ - n[y] = normal[y]; - -// colors[i*4+y] = n[y]; - } - //VectorNormalize(n); - - mid = n[1] + n[2]; - if (mid < 0) mid *= -1; - - - // m[0] = 127 - (n[1]*128); - // m[1] = 127 - (n[2]*128); - // m[2] = 255 - (mid*128); - - m[0] = 127 + (n[0]*128); - m[1] = 127 + (n[1]*128); - m[2] = 127 + (n[2]*128); - - - - - colors[i*4+0] = m[0]; - colors[i*4+1] = m[1]; - colors[i*4+2] = m[2]; - colors[i*4+3] = 255; - } -} - - - void RB_CalcDiffuseColor_Specular( unsigned char *colors ) { int i, j; diff --git a/code/renderer_oa/tr_shader.c b/code/renderer_oa/tr_shader.c index 442ab6a087..1a0f7fafed 100644 --- a/code/renderer_oa/tr_shader.c +++ b/code/renderer_oa/tr_shader.c @@ -1392,7 +1392,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) // // map3 // - else if ( !Q_stricmp( token, "map3" ) || (!Q_stricmp( token, "normalmap" ) && r_modelshader->integer)) + else if ( !Q_stricmp( token, "map3" ) || (!Q_stricmp( token, "normalmap" ))) { token = COM_ParseExt( text, qfalse ); if ( !token[0] ) @@ -1440,7 +1440,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) // // map4 // - else if ( !Q_stricmp( token, "map4" ) || (!Q_stricmp( token, "specmap" ) && r_modelshader->integer)) + else if ( !Q_stricmp( token, "map4" ) || (!Q_stricmp( token, "specmap" ))) { token = COM_ParseExt( text, qfalse ); if ( !token[0] ) @@ -1487,7 +1487,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) // // map5 // - else if ( !Q_stricmp( token, "map5" ) || (!Q_stricmp( token, "shadeballmap" ) && r_modelshader->integer)) + else if ( !Q_stricmp( token, "map5" ) || (!Q_stricmp( token, "shadeballmap" ))) { token = COM_ParseExt( text, qfalse ); if ( !token[0] ) @@ -4270,18 +4270,6 @@ static shader_t *FinishShader( void ) { // vertexLightmap = qtrue; //} - -#ifdef GLSL_TEXTURES - - // leilei - force new phong on lightdiffuse and lightdiffusespecular models - // FIXME: Intel HD doesn't like this. - if ((r_modelshader->integer) && (pStage->isGLSL==0) && (r_ext_vertex_shader->integer) && ((pStage->rgbGen == CGEN_LIGHTING_DIFFUSE) || (pStage->rgbGen == CGEN_LIGHTING_DIFFUSE_SPECULAR))) - { - pStage->program = RE_GLSL_RegisterProgram("leishade", "glsl/leishade_vp.glsl", 1, "glsl/leishade_fp.glsl", 1); - pStage->isGLSL=1; - pStage->isLeiShade=1; - } -#endif // // determine sort order and fog color adjustment // From 28e8ff01d9fefd5d8eb71a8f4cbdadabed9021c1 Mon Sep 17 00:00:00 2001 From: leilei- Date: Wed, 16 Apr 2025 05:40:22 -0400 Subject: [PATCH 10/20] - r_lightmapColorNorm : Make normalization of bright luxels an option, default is 1 (q3 behavior). - r_lightmapColorNorm 0 = no normalization, straight clamp, like Nightdive's vision of Quake2 - r_lightmapColorNorm 2 = experiment: normalize, but add some luminance on while maintaining the hue by normalizing again. This tries to restore more range on fully saturated colors - dropped SHADER_MAX_VERTEXES back to 1000 because raising it causes various unexpected issues, so dialing it down for now - raise MAX_IMAGE_ANIMATIONS to 16 because I've got a cool water shader using it and 8 is too choppy --- code/qcommon/qfiles.h | 2 +- code/renderer_oa/tr_bsp.c | 62 +++++++++++++++++++++++++++++++------ code/renderer_oa/tr_init.c | 5 +++ code/renderer_oa/tr_local.h | 3 +- 4 files changed, 61 insertions(+), 11 deletions(-) diff --git a/code/qcommon/qfiles.h b/code/qcommon/qfiles.h index 3333d54e64..9f2b5fb23e 100644 --- a/code/qcommon/qfiles.h +++ b/code/qcommon/qfiles.h @@ -35,7 +35,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #endif // surface geometry should not exceed these limits -#define SHADER_MAX_VERTEXES 4000 +#define SHADER_MAX_VERTEXES 1000 #define SHADER_MAX_INDEXES (6*SHADER_MAX_VERTEXES) diff --git a/code/renderer_oa/tr_bsp.c b/code/renderer_oa/tr_bsp.c index 646eb24d03..394d0b04f8 100644 --- a/code/renderer_oa/tr_bsp.c +++ b/code/renderer_oa/tr_bsp.c @@ -109,15 +109,59 @@ static void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) { g = in[1] << shift; b = in[2] << shift; - // normalize by color instead of saturating to white - if ( ( r | g | b ) > 255 ) { - int max; - - max = r > g ? r : g; - max = max > b ? max : b; - r = r * 255 / max; - g = g * 255 / max; - b = b * 255 / max; + if (r_lightmapColorNorm->integer == 2) // leilei + { + float lum, invader = 0; + // get luma from base color + lum = (0.22126*r + 0.7152*g + 0.0722*b); // thanks wiki + + // normalize by color instead of saturating to white + if ( ( r | g | b ) > 255 ) { + + int max; + int gmr, gmg, gmb; + max = r > g ? r : g; + max = max > b ? max : b; + r = r * 255 / max; + g = g * 255 / max; + b = b * 255 / max; + + + invader = lum - (0.22126*r + 0.7152*g + 0.0722*b); // get the differences from the normalized color + invader *= (invader/255); + + r += invader; + g += invader; + b += invader; + + + // Normalize... again!!! + + max = r > g ? r : g; + max = max > b ? max : b; + r = r * 255 / max; + g = g * 255 / max; + b = b * 255 / max; + } + } + else if (r_lightmapColorNorm->integer) // leilei - made this an option for trying normal clamp + { + // normalize by color instead of saturating to white + if ( ( r | g | b ) > 255 ) { + int max; + + max = r > g ? r : g; + max = max > b ? max : b; + r = r * 255 / max; + g = g * 255 / max; + b = b * 255 / max; + } + } + else + { + if ( r > 255 ) r = 255; + if ( g > 255 ) g = 255; + if ( b > 255 ) b = 255; } out[0] = r; diff --git a/code/renderer_oa/tr_init.c b/code/renderer_oa/tr_init.c index 8402a360ff..4608cb240e 100644 --- a/code/renderer_oa/tr_init.c +++ b/code/renderer_oa/tr_init.c @@ -204,6 +204,9 @@ cvar_t *r_flaresDlightShrink; cvar_t *r_flaresDlightFade; cvar_t *r_flaresDlightOpacity; cvar_t *r_flaresDlightScale; + +cvar_t *r_lightmapColorNorm; + //cvar_t *r_flaresSurfradii; cvar_t *r_alternateBrightness; // leilei - linux overbright fix cvar_t *r_mockvr; // Leilei - for debugging PVR only! @@ -1228,6 +1231,7 @@ void R_Register( void ) r_nocurves = ri.Cvar_Get ("r_nocurves", "0", CVAR_CHEAT ); r_drawworld = ri.Cvar_Get ("r_drawworld", "1", CVAR_CHEAT ); r_lightmap = ri.Cvar_Get ("r_lightmap", "0", 0 ); + r_portalOnly = ri.Cvar_Get ("r_portalOnly", "0", CVAR_CHEAT ); @@ -1305,6 +1309,7 @@ void R_Register( void ) r_iconBits = ri.Cvar_Get ("r_iconBits", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - icon bits r_lightmapBits = ri.Cvar_Get ("r_lightmapBits", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - lightmap color bits + r_lightmapColorNorm = ri.Cvar_Get ("r_lightmapColorNorm", "1", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - lightmap color normalization r_textureDither = ri.Cvar_Get ("r_textureDither", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - dithered textures diff --git a/code/renderer_oa/tr_local.h b/code/renderer_oa/tr_local.h index d3d0430e8d..2b345f3a62 100644 --- a/code/renderer_oa/tr_local.h +++ b/code/renderer_oa/tr_local.h @@ -318,7 +318,7 @@ typedef struct { } texModInfo_t; -#define MAX_IMAGE_ANIMATIONS 8 +#define MAX_IMAGE_ANIMATIONS 16 // leilei - was 8 typedef struct { image_t *image[MAX_IMAGE_ANIMATIONS]; @@ -1399,6 +1399,7 @@ extern cvar_t *r_iconmip; // leilei - icon mip - picmip for 2d icons extern cvar_t *r_iconBits; // leilei - icon color depth for 2d icons extern cvar_t *r_lightmapBits; // leilei - lightmap color depth +extern cvar_t *r_lightmapColorNorm; // leilei - lightmap color normalize extern cvar_t *r_texdump; // leilei - texture dumping From ed16ba35d77caf92932737ea21098e48c0b1dedc Mon Sep 17 00:00:00 2001 From: leilei- Date: Wed, 16 Apr 2025 07:08:47 -0400 Subject: [PATCH 11/20] - Crash fix for older (<=2001) mods by trimming the string shared with ui module, so no overflow for them - jettisoning old proposed mme particle system that was never ever hooked up properly. - other small warning cleanup --- code/client/fx_local.h | 476 ------ code/client/fx_main.c | 1569 -------------------- code/client/fx_parse.c | 2390 ------------------------------ code/client/fx_public.h | 35 - code/client/fx_types.h | 51 - code/renderer_oa/tr_bsp.c | 2 - code/renderer_oa/tr_extensions.c | 6 + code/renderer_oa/tr_init.c | 2 +- code/renderer_oa/tr_local.h | 2 + 9 files changed, 9 insertions(+), 4524 deletions(-) delete mode 100644 code/client/fx_local.h delete mode 100644 code/client/fx_main.c delete mode 100644 code/client/fx_parse.c delete mode 100644 code/client/fx_public.h delete mode 100644 code/client/fx_types.h diff --git a/code/client/fx_local.h b/code/client/fx_local.h deleted file mode 100644 index 04e9351cbe..0000000000 --- a/code/client/fx_local.h +++ /dev/null @@ -1,476 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2006 Sjoerd van der Berg ( harekiet @ gmail.com ) - -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 -=========================================================================== -*/ -// fx_local.h -- private fx definitions - -#define FX_HASH_SHIFT 8 -#define FX_HASH_SIZE ( 1 << FX_HASH_SHIFT ) -#define FX_HASH_MASK (FX_HASH_SIZE - 1) - -#define FX_ACTIVE_HASH_SHIFT 5 -#define FX_ACTIVE_HASH_SIZE ( 1 << FX_ACTIVE_HASH_SHIFT ) -#define FX_ACTIVE_HASH_MASK (FX_ACTIVE_HASH_SIZE - 1) - -#define FX_MAX_SCRIPTS 4096 - -#define FX_MAX_ENTITIES (16*1024) - -#define FX_EMIT_TRACE 0x001 -#define FX_EMIT_SINK 0x002 -#define FX_EMIT_MOVE 0x004 -#define FX_EMIT_PARENT 0x010 -#define FX_EMIT_IMPACT 0x020 - -#define FX_EMIT_MASKSIZE 16 //Probably enough space - -#define FX_ENT_STATIONARY 0x001 -#define FX_ENT_DEAD 0x002 - -#define FX_SCRIPT_PARENT 0x001 -#define FX_STACK_SIZE 128 -#define FX_VECTOR_PARENT 0x10000 - -#define FX_MASK_PARENT 0x00001 -#define FX_MASK_ORIGIN 0x00002 -#define FX_MASK_VELOCITY 0x00004 -#define FX_MASK_SHADER 0x00008 -#define FX_MASK_SIZE 0x00010 -#define FX_MASK_ROTATE 0x00020 -#define FX_MASK_COLOR 0x00040 - -#define FX_MASK_DIR 0x00080 -#define FX_MASK_MODEL 0x00100 -#define FX_MASK_AXIS 0x00200 -#define FX_MASK_ANGLES 0x00400 -#define FX_MASK_WIDTH 0x00800 -#define FX_MASK_T0 0x01000 -#define FX_MASK_T1 0x02000 -#define FX_MASK_T2 0x04000 -#define FX_MASK_T3 0x08000 -#define FX_MASK_V0 0x10000 -#define FX_MASK_V1 0x20000 -#define FX_MASK_V2 0x40000 -#define FX_MASK_V3 0x80000 - - - -struct fxHashEntry_s; -struct fxEntity_s; -struct fxInitScript_s; - -typedef struct fxAtive_s { - struct fxAtive_s *next; - unsigned int key1, key2; - int beenUsed; -} fxActive_t; - -//Making any changes to this order you'll also need to modify the mask/unpacking stuff -typedef struct { - vec3_t origin; - vec3_t velocity; - - float size, rotate; - color4ub_t color; - qhandle_t shader; - - vec3_t dir; - float width; - vec3_t angles; - qhandle_t model; - vec3_t axis[3]; - - float t0, t1, t2, t3; - vec3_t v0, v1, v2, v3; - const fxParent_t *parent; - - float lerp; - float loop; - float life; - - struct fxEntity_s *entity; - int shaderTime; - unsigned int key; - - int stackUsed; - float stackData[FX_STACK_SIZE]; -} fxRun_t; - -const void *fxRunMath( fxRun_t *run, const void *data, float *value ); -typedef const void *(*fxHandler_t)( fxRun_t *run, const void * ); - -static ID_INLINE const float *fxFloatSrc( const fxRun_t *run, int offset ) { - if ( offset & FX_VECTOR_PARENT) - return (float *) (((char *)run->parent) + (offset & ~FX_VECTOR_PARENT) ); - else - return (float *) (((char *)run) + offset ); -} - -static ID_INLINE float *fxFloatDst( const fxRun_t *run, int offset ) { - return (float *) (((char *)run) + offset ); -} - -typedef enum { - fxCmdHalt, - fxCmdSkip, - - fxCmdEmitter, - fxCmdKill, - fxCmdRepeat, - fxCmdOnce, - fxCmdIf, - fxCmdInterval, - fxCmdDistance, - - - fxCmdSprite, - fxCmdBeam, - fxCmdLight, - fxCmdDirModel, - fxCmdAnglesModel, - fxCmdAxisModel, - fxCmdQuad, - fxCmdRings, - fxCmdSpark, - fxCmdDecal, - - fxCmdTrace, - fxCmdScript, - - fxCmdColor, - fxCmdColorList, - fxCmdColorBlend, - fxCmdColorHue, - fxCmdColorScale, - fxCmdColorMath, - fxCmdColorFade, - fxCmdAlphaFade, - - fxCmdShader, - fxCmdShaderList, - fxCmdModel, - fxCmdModelList, - fxCmdSound, - fxCmdSoundList, - fxCmdLoopSound, - fxCmdVibrate, - - fxCmdPush, - fxCmdPop, - fxCmdPushParent, - - fxCmdScale, - fxCmdCopy, - fxCmdAdd, - fxCmdAddScale, - fxCmdSub, - fxCmdSubScale, - fxCmdRotateAround, - fxCmdInverse, - fxCmdNormalize, - fxCmdPerpendicular, - fxCmdRandom, - fxCmdClear, - fxCmdWobble, - fxCmdMakeAngles, - fxCmdValue, -} fxCommand_t; - -typedef struct { - int blockSize; - void *blockData; -} fxRunBlock_t; - -typedef struct fxScript_s { - fxHandle_t handle; - struct fxHashEntry_s *entry; - struct fxScript_s *remap; - unsigned int readMask; - void *data[0]; -} fxScript_t; - -typedef struct { - int renderfx; -} fxRunRender_t; - -typedef struct { - color4ub_t value; -} fxRunColor_t; -typedef struct { - unsigned int count; -} fxRunColorBlend_t; -typedef struct { - unsigned int count; -} fxRunColorList_t; -typedef struct { - float delay, scale; -} fxRunColorFade_t; -typedef struct { - unsigned int index; -} fxRunColorMath_t; -typedef struct { - color4ub_t value; -} fxRunAlpha_t; -typedef struct { - int size; -} fxRunAlphaScale_t; -typedef struct { - float delay, scale; -} fxRunAlphaFade_t; -typedef struct { - int size; -} fxRunRed_t; -typedef struct { - int size; -} fxRunGreen_t; -typedef struct { - int size; -} fxRunBlue_t; - -typedef struct { - unsigned short flags; - unsigned short size; - unsigned short emitRun; - unsigned short impactRun; - unsigned short deathRun; - unsigned short allocSize; - byte mask[FX_EMIT_MASKSIZE]; - float impactSpeed; - float bounceFactor; - float sinkDelay, sinkDepth; - float gravity; -} fxRunEmitter_t; - -typedef struct { - int src; - int dst; -} fxRunScale_t; -typedef struct { - int src; - int dst; -} fxRunWobble_t; -typedef struct { - int src; - int dst; -} fxRunCopy_t; -typedef struct { - int src; - int dst; -} fxRunMakeAngles_t; -typedef struct { - int dst; -} fxRunClear_t; -typedef struct { - int src; - int dst; -} fxRunInverse_t; -typedef struct { - int src; - int dst; -} fxRunNormalize_t; -typedef struct { - int src1; - int src2; - int dst; -} fxRunAdd_t; -typedef struct { - int src1; - int src2; - int dst; -} fxRunSub_t; -typedef struct { - int src; - int scale; - int dst; -} fxRunAddScale_t; -typedef struct { - int src; - int scale; - int dst; -} fxRunSubScale_t; -typedef struct { - int src; - int dir; - int dst; -} fxRunRotateAround_t; -typedef struct { - int src; - int dst; -} fxRunPerpendicular_t; -typedef struct { - int dst; -} fxRunRandom_t; - -typedef struct { - int dst; -} fxRunValue_t; - -typedef struct { - qhandle_t shader; -} fxRunShader_t; -typedef struct { - unsigned int count; -} fxRunShaderList_t; - -typedef struct { - qhandle_t model; -} fxRunModel_t; - -typedef struct { - unsigned int count; - qhandle_t list[0]; -} fxRunModelList_t; - -typedef struct { - int flags; - int life; -} fxRunDecal_t; - -typedef struct { - void *data; -} fxRunScript_t; - -typedef struct { - int count; - int offset; -} fxRunPush_t; - -typedef struct { - int count; - int offset; -} fxRunPushParent_t; - -typedef struct { - int count; - int offset; -} fxRunPop_t; - -typedef struct { - int size; -} fxRunRepeat_t; - -typedef struct { - int size; -} fxRunOnce_t; -typedef struct { - int beenUsed; -} fxActiveOnce_t; - - -typedef struct { - int size; -} fxRunInterval_t; -typedef struct { - int beenUsed; - int nextTime; -} fxActiveInterval_t; - -typedef struct { - int size; -} fxRunSkip_t; -typedef struct { - int testCount; - int elseStep; - int size; -} fxRunIf_t; -typedef struct { - int size; -} fxRunDistance_t; -typedef struct { - int beenUsed; - vec3_t lastOrigin; - float distance; -} fxActiveDistance_t; - -typedef struct { - float strength; -} fxRunVibrate_t; - -typedef struct { - unsigned int count; - sfxHandle_t handle[0]; -} fxRunSoundList_t; - -typedef struct { - sfxHandle_t handle; -} fxRunSound_t; - -typedef struct { - sfxHandle_t handle; -} fxRunLoopSound_t; - -typedef struct fxEntity_s { - struct fxEntity_s *next; - const fxRunEmitter_t *emitter; - - int flags; - int startTime; - float traceTime; - float moveTime, lifeScale; - - vec3_t origin, velocity; -} fxEntity_t; - -/* Just gonna stick with using next for now */ -typedef struct fxHashEntry_s { - const char *name; - const char *text; - fxScript_t *script; - struct fxHashEntry_s *next; -} fxHashEntry_t; - -#define FX_VIBRATE_QUEUE 32 -typedef struct { - fxScript_t *scripts[FX_MAX_SCRIPTS]; - fxHashEntry_t *entryHash[FX_HASH_SIZE]; - fxActive_t *activeHash[FX_ACTIVE_HASH_SIZE]; - - int scriptCount; - int *allocSearch; - int *allocStart; - int allocSize; - int time, oldTime; - float timeFraction; - float deltaTime; - int seed; - fxEntity_t *entityActive; - fxEntity_t *entityNew; - struct { - int entitySize, activeSize; - int entityCount, activeCount; - } last; - struct { - int used, time; - float offset, magnitude; - struct { - vec3_t origin; - float strength; - } queue[FX_VIBRATE_QUEUE]; - } vibrate; - struct { - fxHashEntry_t *entries; - } alloc; -} fxMain_t; - -void fxInitParser( void ); -void fxFreeMemory( void ); - -extern cvar_t *fx_Debug; -extern cvar_t *fx_Override; diff --git a/code/client/fx_main.c b/code/client/fx_main.c deleted file mode 100644 index 593d39c589..0000000000 --- a/code/client/fx_main.c +++ /dev/null @@ -1,1569 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2006 Sjoerd van der Berg ( harekiet @ gmail.com ) - -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 -=========================================================================== -*/ -// fx_main.c Run FX Scripts and provide several commands for them - -#include "client.h" -#include "fx_local.h" - -fxMain_t fx; -cvar_t *fx_Megs; -cvar_t *fx_Vibrate; -cvar_t *fx_Override; -cvar_t *fx_Debug; - -static ID_INLINE void fxMaskInput( const byte *mask, const void *readV, void *writeV ) { - const long *read = (long *)readV; - long *write = (long*)writeV; - - read += mask[0]; - mask++; - while (1) { - int count; - /* Copy blocks */ - if (!mask[0]) - break; - count = mask[0]; - do { - *write++ = *read++; - count--; - } while (count > 0); - /* Skip blocks */ - if (!mask[1]) - break; - read += mask[1]; - mask += 2; - } -} - - -static ID_INLINE void fxMaskOutput( const byte *mask, const void *readV, void *writeV ) { - const long *read = (long *)readV; - long *write = (long*)writeV; - - write += mask[0]; - mask++; - while (1) { - int count; - /* Copy blocks */ - if (!mask[0]) - break; - count = mask[0]; - do { - *write++ = *read++; - count--; - } while (count > 0); - /* Skip blocks */ - if (!mask[1]) - break; - write += mask[1]; - mask += 2; - } -} - - -//Some forward defines -static void *fxGetActive( unsigned int key1, unsigned int key2, int size ); -static const void *fxRun( fxRun_t *run, const void *data ); - -static ID_INLINE int fxRand( void ) { - fx.seed = (69069 * fx.seed + 1); - return fx.seed; -} -static ID_INLINE float fxRandom( void ) { - return (fxRand() & 0xffff) * (1.0f / 0x10000); -} - -/* Very simple allocation function */ -static void *fxAlloc( int size ) { - int *search = fx.allocSearch; - int *searchStart = search; - - size += sizeof( int ); - //TODO make size a multiple of sizeof (void *) - while (1) { - //Used block - if ( search[0] == size ) { - search[0] = -size; - fx.allocSearch = (int*)(((char *)search) + size); - return search + 1; - } else if ( search[0] > size ) { - fx.allocSearch = (int*)(((char *)search) + size); - fx.allocSearch[0] = search[0] - size; - search[0] = -size; - return search + 1; - } else if ( search[0] < 0 ) { - search = (int*)(((char *)search) - search[0]); - //Last block - } else if (!search[0] ) { - search = fx.allocStart; - //Free block but too small, find a free one after it and join - } else { - int *searchNext = (int*)(((char *)search) + search[0]); - /* Is the next one free, if so add it */ - if ( searchNext[0] > 0 ) { - search[0] += searchNext[0]; - /* Added the start one and still not enough room? */ - if ( searchStart == searchNext && search[0] < size ) - break; - continue; - } else { - search = searchNext; - } - } - /* Check if it went a full loop, out of space then */ - if ( search == searchStart) { - break; - } - } - if ( fx_Debug->integer ) { - Com_Printf("FX_Debug:Ran out of allocation space, needed %d\n", size ); - } else { - Com_Error( ERR_DROP, "FX Ran out of allocation space for %d bytes, increase fx_Megs\n", size ); - } - return 0; -} - -static void fxVibrate( const vec3_t position, float strength ) { - if ( fx.vibrate.used < FX_VIBRATE_QUEUE ) { - int i = fx.vibrate.used++; - VectorCopy( position, fx.vibrate.queue[i].origin ); - fx.vibrate.queue[i].strength = strength; - } -} - -static void fxDoVibrate( const vec3_t origin, const vec3_t position, float strength ) { - vec3_t dist; - float magnitude, oldmagnitude; - - VectorSubtract( origin, position, dist ); - - magnitude = 1.0f - VectorLength( dist ) / 1000.0; - if( magnitude <= 0 ) - return; - magnitude = strength * magnitude * magnitude; - - if( fx.vibrate.time ) { - // Adjust for current vibration - int time = fx.time - fx.vibrate.time; - if( time < 20 ) - time = 20; - oldmagnitude = fx.vibrate.magnitude / (time / 20.0f); - } - else { - oldmagnitude = 0; - } - - fx.vibrate.magnitude = magnitude + oldmagnitude; - if( fx.vibrate.magnitude < 0 ) - fx.vibrate.magnitude= 0; - - fx.vibrate.offset = fxRandom() * 360; // Always on the 'up' half - fx.vibrate.time = fx.time; -} - - -void FX_VibrateView( float scale, vec3_t origin, vec3_t angles ) { - int i, time; - float magnitude; - - scale *= fx_Vibrate->value; - if (scale <= 0) { - fx.vibrate.used = 0; - return; - } - for ( i = 0; i < fx.vibrate.used; i++ ) { - fxDoVibrate( origin, fx.vibrate.queue[i].origin, fx.vibrate.queue[i].strength * scale ); - } - fx.vibrate.used = 0; - if( !fx.vibrate.time ) - return; - - time = fx.time - fx.vibrate.time; - if( time < 20 ) - time = 20; - magnitude = ((fx.vibrate.magnitude > 100) ? 100 : fx.vibrate.magnitude) / (time / 20.0f); - if( magnitude <= 3 ) - { - // There's not enough vibration to care about - fx.vibrate.time = 0; - return; - } - - origin[2] += magnitude * 0.3 * sin( 1.4 * (fx.vibrate.offset + SQRTFAST(time)) ); - angles[ROLL] += magnitude * (0.1 * sin( 0.1 * (fx.vibrate.offset + SQRTFAST(time)) ) - 0.05); -} -static int fxSize( void *block ) { - return ((int*)block)[-1]; -} - -static void fxFree( void *block ) { - int *alloc = ((int*)block) - 1; - alloc[0] = -alloc[0]; -} - -static const void *fxRunDecal( const fxRun_t *run, const fxRunDecal_t *decal ) { - int i; - vec4_t color; - - for (i = 0;i<4;i++) - color[i] = run->color[i] * ( 1.0f / 255); - - re.DecalProject( run->shader, run->origin, run->dir, color, run->rotate, run->size, decal->flags, decal->life ); - return decal + 1; -} -static const void* fxRunBeam( const fxRun_t *run, const fxRunRender_t* render ) { - refBeam_t beam; - - VectorCopy( run->origin, beam.start ); - VectorAdd( beam.start, run->dir, beam.end ); - beam.width = run->size; - beam.rotateAngle = run->rotate; - beam.shaderTime = run->shaderTime; - beam.shader = run->shader; - beam.renderfx = render->renderfx; - Byte4Copy( run->color, beam.color ); - re.AddBeamToScene( &beam ); - return render + 1; -} - -static const void* fxRunSpark( const fxRun_t *run, const fxRunRender_t* render ) { - refBeam_t spark; - - VectorNormalize2( run->velocity, spark.end ); - VectorMA( run->origin, -0.5*run->size, spark.end, spark.start ); - VectorMA( run->origin, 0.5*run->size, spark.end, spark.end ); - spark.width = run->width; - spark.rotateAngle = 0; - spark.shaderTime = run->shaderTime; - spark.shader = run->shader; - spark.renderfx = render->renderfx; - Byte4Copy( run->color, spark.color ); - re.AddBeamToScene( &spark ); - return render + 1; -} - -static const void* fxRunRings( const fxRun_t *run, const fxRunRender_t* render ) { - refRings_t rings; - - VectorCopy( run->origin, rings.start ); - VectorAdd( rings.start, run->dir, rings.end ); - rings.radius = run->size; - rings.stepSize = run->width; - rings.shaderTime = run->shaderTime; - rings.shader = run->shader; - rings.renderfx = render->renderfx; - Byte4Copy( run->color, rings.color ); - re.AddRingsToScene( &rings ); - return render + 1; -} -static const void* fxRunSprite( const fxRun_t* run, const fxRunRender_t* render ) { - refSprite_t sprite; - VectorCopy( run->origin, sprite.origin ); - sprite.shader = run->shader; - sprite.radius = run->size; - sprite.rotation = run->rotate; - sprite.shaderTime = run->shaderTime; - Byte4Copy( run->color, sprite.color ); - sprite.renderfx = render->renderfx; - re.AddSpriteToScene( &sprite ); - return render + 1; -} - -static const void* fxRunQuad( const fxRun_t *run, const fxRunRender_t* render ) { - polyVert_t verts[4]; - vec3_t left, up; - - PerpendicularVector( up, run->dir ); - RotatePointAroundVector( left, run->dir, up, run->angles[ROLL] ); - CrossProduct( run->dir, left, up ); - - VectorScale( up, run->size, up ); - VectorScale( left, -run->size, left ); - verts[0].xyz[0] = run->origin[0] + left[0] + up[0]; - verts[0].xyz[1] = run->origin[1] + left[1] + up[1]; - verts[0].xyz[2] = run->origin[2] + left[2] + up[2]; - verts[1].xyz[0] = run->origin[0] - left[0] + up[0]; - verts[1].xyz[1] = run->origin[1] - left[1] + up[1]; - verts[1].xyz[2] = run->origin[2] - left[2] + up[2]; - verts[2].xyz[0] = run->origin[0] - left[0] - up[0]; - verts[2].xyz[1] = run->origin[1] - left[1] - up[1]; - verts[2].xyz[2] = run->origin[2] - left[2] - up[2]; - verts[3].xyz[0] = run->origin[0] + left[0] - up[0]; - verts[3].xyz[1] = run->origin[1] + left[1] - up[1]; - verts[3].xyz[2] = run->origin[2] + left[2] - up[2]; - - Byte4Copy( run->color, verts[0].modulate ); - Byte4Copy( run->color, verts[1].modulate ); - Byte4Copy( run->color, verts[2].modulate ); - Byte4Copy( run->color, verts[3].modulate ); - verts[0].st[0] = 0; verts[0].st[1] = 0; - verts[1].st[0] = 1; verts[1].st[1] = 0; - verts[2].st[0] = 1; verts[2].st[1] = 1; - verts[3].st[0] = 0; verts[3].st[1] = 1; - re.AddPolyToScene( run->shader, 4, verts, 1 ); - return render + 1; -} -static const void* fxRunAnglesModel( const fxRun_t *run, const fxRunRender_t* render ) { - refModel_t model; - - memset( &model, 0, sizeof( model )); - VectorCopy( run->origin, model.origin ); - VectorCopy( run->origin, model.oldorigin ); - - model.hModel = run->model; - model.customShader = run->shader; - model.shaderTime = run->shaderTime; - model.renderfx = render->renderfx; - Byte4Copy( run->color, model.shaderRGBA ); - - // Setup the axis from the angles - AnglesToAxis( run->angles, model.axis ); - if ( run->size > 0 && run->size != 1 ) { - VectorScale( model.axis[0], run->size, model.axis[0] ); - VectorScale( model.axis[1], run->size, model.axis[1] ); - VectorScale( model.axis[2], run->size, model.axis[2] ); - model.nonNormalizedAxes = qtrue; - } - re.AddModelToScene( &model ); - return render + 1; -} -static const void* fxRunDirModel( const fxRun_t *run, const fxRunRender_t* render ) { - refModel_t model; - - memset( &model, 0, sizeof( model )); - VectorCopy( run->origin, model.origin ); - VectorCopy( run->origin, model.oldorigin ); - - model.hModel = run->model; - model.customShader = run->shader; - model.shaderTime = run->shaderTime; - model.renderfx = render->renderfx; - Byte4Copy( run->color, model.shaderRGBA ); - - // Setup the axis from the angles - VectorCopy( run->dir, model.axis[0] ); - RotateAroundDirection( model.axis, run->rotate ); - if ( run->size != 1 ) { - VectorScale( model.axis[0], run->size, model.axis[0] ); - VectorScale( model.axis[1], run->size, model.axis[1] ); - VectorScale( model.axis[2], run->size, model.axis[2] ); - model.nonNormalizedAxes = qtrue; - } - re.AddModelToScene( &model ); - return render + 1; -} -static const void* fxRunAxisModel( const fxRun_t *run, const fxRunRender_t* render ) { - refModel_t model; - - memset( &model, 0, sizeof( model )); - VectorCopy( run->origin, model.origin ); - VectorCopy( run->origin, model.oldorigin ); - - model.hModel = run->model; - model.customShader = run->shader; - model.shaderTime = run->shaderTime; - model.renderfx = render->renderfx; - Byte4Copy( run->color, model.shaderRGBA ); - - // Setup the axis from the angles - if ( run->size != 1 ) { - VectorScale( run->axis[0], run->size, model.axis[0] ); - VectorScale( run->axis[1], run->size, model.axis[1] ); - VectorScale( run->axis[2], run->size, model.axis[2] ); - model.nonNormalizedAxes = qtrue; - } else { - VectorCopy( run->axis[0], model.axis[0] ); - VectorCopy( run->axis[1], model.axis[1] ); - VectorCopy( run->axis[2], model.axis[2] ); - model.nonNormalizedAxes = qfalse; - } - re.AddModelToScene( &model ); - return render + 1; -} -static void fxRunLight( fxRun_t *run ) { - float r = run->color[0] * ( 1 / 255.0f ); - float g = run->color[1] * ( 1 / 255.0f ); - float b = run->color[2] * ( 1 / 255.0f ); - re.AddLightToScene( run->origin, run->size, r, g, b); -} - -static void fxRunTrace( fxRun_t *run ) { - trace_t tr; - vec3_t end; - - VectorMA( run->origin, 8000, run->dir, end ); - CM_BoxTrace( &tr, run->origin, end, 0, 0, 0, CONTENTS_SOLID, qfalse ); - if ( tr.fraction < 1 ) { - VectorCopy( tr.endpos, run->origin ); - VectorCopy( tr.plane.normal, run->dir ); - } -} - -static const void *fxRunShader( fxRun_t *run, const fxRunShader_t *shader ) { - run->shader = shader->shader; - return shader + 1; -} -static const void *fxRunShaderList( fxRun_t *run, const fxRunShaderList_t *shaderList ) { - float i; - qhandle_t *list = (qhandle_t*)fxRunMath( run, shaderList + 1, &i ); - run->shader = list[ (unsigned int)(i * shaderList->count) % shaderList->count ]; - return list + shaderList->count; -} -static const void *fxRunModel( fxRun_t *run, const fxRunModel_t *model ) { - run->model = model->model; - return model + 1; -} -static const void *fxRunModelList( fxRun_t *run, const fxRunModelList_t *modelList ) { - float i; - qhandle_t *list = (qhandle_t*)fxRunMath( run, modelList + 1, &i ); - run->model = list[ (unsigned int)(i * modelList->count) % modelList->count ]; - return list + modelList->count; -} -static const void *fxRunSoundList( const fxRun_t *run, const fxRunSoundList_t *sound ) { - unsigned int index = fxRand() % sound->count; - S_StartSound( run->origin, 0, 0, sound->handle[index] ); - return &sound->handle[ sound->count ]; -} -static const void *fxRunSound( const fxRun_t *run, const fxRunSound_t *sound ) { - S_StartSound( run->origin, 0, 0, sound->handle ); - return sound + 1; -} -static const void *fxRunLoopSound( const fxRun_t *run, const fxRunLoopSound_t *loopSound ) { - S_LoopingSound( (void *)run->key, run->origin, run->velocity, loopSound->handle, 127 ); - return loopSound + 1; -} -static const void *fxRunColor( fxRun_t *run, const fxRunColor_t *color ) { - run->color[0] = color->value[0]; - run->color[1] = color->value[1]; - run->color[2] = color->value[2]; - return color + 1; -} -static const void *fxRunColorList( fxRun_t *run, const fxRunColorList_t *colorList ) { - float i; - color4ub_t *list = (color4ub_t*)fxRunMath( run, colorList + 1, &i ); - byte *newColor; - - newColor = list[(unsigned int)(i * colorList->count) % colorList->count ]; - - run->color[0] = newColor[0]; - run->color[1] = newColor[1]; - run->color[2] = newColor[2]; - return list + colorList->count; -} - -static const void *fxRunColorBlend( fxRun_t *run, const fxRunColorBlend_t *colorBlend ) { - float i; - unsigned int index; - int blend; - color4ub_t *list = (color4ub_t*)fxRunMath( run, colorBlend + 1, &i ); - const byte *start, *end; - - i *= colorBlend->count-1; - index = (int)( i ); - start = list[ index % colorBlend->count ]; - end = list[ (index + 1) % colorBlend->count ]; - blend = Q_ftol(i * 256.0f) & 255; - - run->color[0] = start[0] + ((( end[0] - start[0] ) * blend) >> 8); - run->color[1] = start[1] + ((( end[1] - start[1] ) * blend) >> 8); - run->color[2] = start[2] + ((( end[2] - start[2] ) * blend) >> 8); - return list + colorBlend->count; -} - -static const void *fxRunColorHue( fxRun_t *run, const void *data ) { - float i; - const void *next = fxRunMath( run, data, &i ); - float deg, angle, v; - - deg = (i * 360); - angle = DEG2RAD( fmodf( deg, 120)); - v = ((cos(angle) / cos((M_PI / 3) - angle)) + 1) / 3; - if ( deg <= 120) { - run->color[0] = (v*255); - run->color[1] = ((1-v)*255); - run->color[2] = 0; - } else if ( deg <= 240) { - run->color[0] = 0; - run->color[1] = (v*255); - run->color[2] = ((1-v)*255); - } else { - run->color[0] = ((1-v)*255); - run->color[1] = 0; - run->color[2] = (v*255); - } - return next; -} - -static const void *fxRunColorMath( fxRun_t *run, const fxRunColorMath_t *colorMath ) { - float i; - const void *next = fxRunMath( run, colorMath + 1, &i ); - byte *color = run->color + colorMath->index; - if ( i < 0) - color[0] = 0; - else if ( i > 1.0f) - color[0] = 255; - else - color[0] = Q_ftol( 255 * i ); - return next; -} - -static const void *fxRunColorScale( fxRun_t *run, const void *data ) { - float i; - const void *next = fxRunMath( run, data, &i ); - int s = Q_ftol(255 * i); - run->color[0] = (s * run->color[0]) >> 8; - run->color[1] = (s * run->color[1]) >> 8; - run->color[2] = (s * run->color[2]) >> 8; - return next; -} - -static const void *fxRunColorFade( fxRun_t *run, const fxRunColorFade_t *colorFade ) { - if ( run->lerp > colorFade->delay ) { - int s = 255 - (run->lerp - colorFade->delay) * 255 * (1.0f / (1.0f - colorFade->delay)); - run->color[0] = (s * run->color[0]) >> 8; - run->color[1] = (s * run->color[1]) >> 8; - run->color[2] = (s * run->color[2]) >> 8; - } - return colorFade + 1; -} - -static const void *fxRunAlphaFade( fxRun_t *run, const fxRunAlphaFade_t *alphaFade ) { - if ( run->lerp > alphaFade->delay ) { - unsigned int s = 255 + Q_ftol( (run->lerp - alphaFade->delay) * alphaFade->scale); - run->color[3] = (s * run->color[3]) >> 8; - } - return alphaFade + 1; -} - -static const void *fxRunVibrate( fxRun_t *run, const fxRunVibrate_t *vibrate) { - fxVibrate( run->origin, vibrate->strength ); - return vibrate + 1; -} - -static const void *fxRunScale( fxRun_t *run, const fxRunScale_t *scale) { - const float *src = fxFloatSrc( run, scale->src ); - float *dst = fxFloatDst( run, scale->dst ); - float v; - const void *next; - - next = fxRunMath( run, scale+1, &v ); - VectorScale( src, v, dst ); - return next; -} - -static const void *fxRunValue( fxRun_t *run, const fxRunValue_t *value) { - float *dst = fxFloatDst( run, value->dst ); - return fxRunMath( run, value + 1, dst ); -} - -static const void *fxRunClear( fxRun_t *run, const fxRunClear_t *clear) { - float *dst = fxFloatDst( run, clear->dst ); - VectorClear( dst ); - return clear + 1; -} - -static const void *fxRunAddScale( fxRun_t *run, const fxRunAddScale_t *addScale) { - const float *src = fxFloatSrc( run, addScale->src ); - const float *scale = fxFloatSrc( run, addScale->scale ); - float *dst = fxFloatDst( run, addScale->dst ); - float v; - const void *next; - - next = fxRunMath( run, addScale+1, &v ); - VectorMA( src, v, scale, dst ); - return next; -} - -static const void *fxRunSubScale( fxRun_t *run, const fxRunSubScale_t *subScale) { - const float *src = fxFloatSrc( run, subScale->src ); - const float *scale = fxFloatSrc( run, subScale->scale ); - float *dst = fxFloatDst( run, subScale->dst ); - float v; - const void *next; - - next = fxRunMath( run, subScale+1, &v ); - VectorMA( src, -v, scale, dst ); - return next; -} - - -static const void *fxRunAdd( fxRun_t *run, const fxRunAdd_t *add) { - const float *src1 = fxFloatSrc( run, add->src1 ); - const float *src2 = fxFloatSrc( run, add->src2 ); - float *dst = fxFloatDst( run, add->dst ); - VectorAdd( src1, src2, dst ); - return add + 1; -} - -static const void *fxRunSub( fxRun_t *run, const fxRunSub_t *sub) { - const float *src1 = fxFloatSrc( run, sub->src1 ); - const float *src2 = fxFloatSrc( run, sub->src2 ); - float *dst = fxFloatDst( run, sub->dst ); - VectorSubtract( src1, src2, dst ); - return sub + 1; -} - -static const void *fxRunRotateAround( fxRun_t *run, const fxRunRotateAround_t *rotateAround) { - const float *src = fxFloatSrc( run, rotateAround->src ); - const float *dir = fxFloatSrc( run, rotateAround->dir ); - float *dst = fxFloatDst( run, rotateAround->dst ); - float v; - const void *next; - - next = fxRunMath( run, rotateAround+1, &v ); - RotatePointAroundVector( dst, dir, src, v ); - return next; -} - -static const void *fxRunCopy( fxRun_t *run, const fxRunCopy_t *copy) { - const float *src = fxFloatSrc( run, copy->src ); - float *dst = fxFloatDst( run, copy->dst ); - - VectorCopy( src, dst ); - return copy + 1; -} - -static const void *fxRunInverse( fxRun_t *run, const fxRunInverse_t *inverse ) { - const float *src = fxFloatSrc( run, inverse->src ); - float *dst = fxFloatDst( run, inverse->dst ); - - dst[0] = -src[0]; - dst[1] = -src[1]; - dst[2] = -src[2]; - return inverse+1; -} - -static const void *fxRunNormalize( fxRun_t *run, const fxRunNormalize_t *normalize ) { - const float *src = fxFloatSrc( run, normalize->src ); - float *dst = fxFloatDst( run, normalize->dst ); - - VectorNormalize2( src, dst ); - return normalize+1; -} - -static const void *fxRunPerpendicular( fxRun_t *run, const fxRunPerpendicular_t *perpendicular ) { - const float *src = fxFloatSrc( run, perpendicular->src ); - float *dst = fxFloatDst( run, perpendicular->dst ); - - PerpendicularVector( dst, src ); - return perpendicular+1; -} - -static const void *fxRunWobble( fxRun_t *run, const fxRunWobble_t *wobble ) { - const float *src = fxFloatSrc( run, wobble->src ); - float *dst = fxFloatDst( run, wobble->dst ); - float v; - const void *next; - float angle, s; - vec3_t axis[3]; - - next = fxRunMath( run, wobble+1, &v ); - - /* Check for the unlikely upward/downward vector */ - - VectorCopy( src, axis[0] ); - RotateAroundDirection( axis, fxRandom() * 360 ); - angle = DEG2RAD( v ); - s = cos( angle ); - VectorScale( axis[0], s, dst ); - s = sin( angle ); - VectorMA( dst, s, axis[2], dst ); - return next; -} - -static const void *fxRunMakeAngles( fxRun_t *run, const fxRunMakeAngles_t *makeAngles ) { - const float *src = fxFloatSrc( run, makeAngles->src ); - float *dst = fxFloatDst( run, makeAngles->dst ); - - vectoangles( src, dst ); - return makeAngles + 1; -} - -static const void *fxRunRandom( fxRun_t *run, const fxRunRandom_t *random ) { - float *dst = fxFloatDst( run, random->dst ); - - float yaw = fxRandom() * 2 * M_PI; - float pitch = fxRandom() * 2 * M_PI; - float cp = cos ( pitch ); - float sp = sin ( pitch ); - float cy = cos ( yaw ); - float sy = sin ( yaw ); - - dst[0] = cp*cy; - dst[1] = cp*sy; - dst[2] = -sp; - return random + 1; -} - -static const void *fxRunEmitter( fxRun_t *run, const fxRunEmitter_t *emitter ) { - fxEntity_t *entity; - - entity = fxAlloc( emitter->allocSize ); - if ( entity ) { - float life; - - entity->next = fx.entityNew; - fx.entityNew = entity; - - entity->startTime = fx.time; - fxRunMath( run, emitter + 1, &life ); - entity->lifeScale = 1.0f / (life * 1000); - entity->traceTime = 0; - entity->moveTime = 0; - entity->flags = 0; - VectorCopy( run->origin, entity->origin ); - VectorCopy( run->velocity, entity->velocity ); - entity->emitter = emitter; - fxMaskInput( emitter->mask, run->velocity + 3, entity + 1 ); - } - return ((byte *)emitter) + emitter->size; -} - -const void *fxRunRepeat( fxRun_t *run, const fxRunRepeat_t *repeat ) { - int i, count; - const void *next; - float v, loopScale; - - next = fxRunMath( run, repeat + 1, &v ); - count = Q_ftol(v); - loopScale = 1.0 / count; - for (i = 0; i < count; i++ ) { - run->loop = i * loopScale; - fxRun( run, next ); - } - return ((char *)repeat) + repeat->size; - } - -const void *fxRunIf( fxRun_t *run, const fxRunIf_t *runIf ) { - int i; - const void *next; - float v; - - next = runIf + 1; - for ( i = 0; itestCount;i++) { - int *blockSize; - next = fxRunMath( run, next, &v ); - blockSize = (int *)next; - next = blockSize + 1; - if ( v ) { - fxRun( run, next ); - return ((char *)runIf) + runIf->size; - } else { - /* Skip the block for this if case */ - next = ((char *)(next)) + blockSize[0]; - } - } - if ( runIf->elseStep) { - return next; - } else { - return ((char *)runIf) + runIf->size; - } -} - -static const void *fxRunSkip( fxRun_t *run, const fxRunSkip_t *skip ) { - return ((byte *)skip) + skip->size; -} - -static const void *fxRunDistance( fxRun_t *run, const fxRunDistance_t *distance ) { - fxActiveDistance_t *active; - vec3_t delta, realOrigin; - float lengthScale; - - if ( run->entity && run->entity->flags & FX_ENT_STATIONARY ) - return ((byte *)distance) + distance->size; - active = fxGetActive( run->key, (unsigned int)distance, sizeof( fxActiveDistance_t) ); - if ( !active ) - return ((byte *)distance) + distance->size; - if ( !active->beenUsed ) { - active->beenUsed = qtrue; - VectorCopy( run->origin, active->lastOrigin ); - return ((byte *)distance) + distance->size; - } - VectorSubtract( run->origin, active->lastOrigin, delta ); - lengthScale = VectorNormalize( delta ); - if ( lengthScale + active->distance < 0 ) { - return ((byte *)distance) + distance->size; - } - active->distance += lengthScale; - lengthScale = -active->distance; - VectorCopy( run->origin, realOrigin ); - while ( active->distance >= 0 ) { - float step; - const void *mathEnd = fxRunMath( run, distance + 1, &step ); - VectorMA( active->lastOrigin, lengthScale, delta, run->origin ); - lengthScale += step; - active->distance -= step; - fxRun( run, mathEnd ); - } - VectorCopy( realOrigin, active->lastOrigin ); - VectorCopy( realOrigin, run->origin ); - return ((byte *)distance) + distance->size; -} - -static const void *fxRunInterval( fxRun_t *run, const fxRunInterval_t *interval ) { - float i; - fxActiveInterval_t *active; - const void *mathNext; - - active = fxGetActive( run->key, (unsigned int)interval, sizeof( fxActiveInterval_t) ); - if ( !active->beenUsed ) { - mathNext = fxRunMath( run, interval + 1, &i ); - if ( i <= 0) - goto returnIt; - active->beenUsed = qtrue; - fxRun( run, mathNext); - active->nextTime = fx.time + i * 1000; - } else while( active->nextTime <= fx.time ) { - mathNext = fxRunMath( run, interval + 1, &i ); - if ( i <= 0) - break; - fxRun( run, mathNext); - active->nextTime += i * 1000; - } -returnIt: - return ((byte *)interval) + interval->size; - } - -static const void *fxRunOnce( fxRun_t *run, const fxRunOnce_t *once ) { - fxActiveOnce_t *active; - - active = fxGetActive( run->key, (unsigned int)once, sizeof( fxActiveOnce_t) ); - if ( !active->beenUsed ) { - active->beenUsed = qtrue; - fxRun( run, once + 1); - } - return ((byte *)once) + once->size; - } - -static const void *fxRunPushParent( fxRun_t *run, const fxRunPushParent_t *push ) { - int i; - float *input = ( float *)(((char *)(run->parent)) + push->offset); - if ( run->stackUsed + push->count > FX_STACK_SIZE ) { - Com_Printf( "Overflowing run stack\n" ); - return push + 1; - } - for (i = push->count; i > 0; i--) { - run->stackData[run->stackUsed++] = *input++; - } - return push + 1; -} - -static const void *fxRunPush( fxRun_t *run, const fxRunPush_t *push ) { - int i; - float *input = ( float *)(((char *)run) + push->offset); - if ( run->stackUsed + push->count > FX_STACK_SIZE ) { - Com_Printf( "Overflowing run stack\n" ); - return push + 1; - } - for (i = push->count; i > 0; i--) { - run->stackData[run->stackUsed++] = *input++; - } - return push + 1; -} - -static const void *fxRunPop( fxRun_t *run, const fxRunPop_t *pop ) { - int i; - float *output = ( float *)(((char *)run) + pop->offset); - if ( run->stackUsed - pop->count < 0) { - Com_Printf( "underflowing run stack\n" ); - return pop + 1; - } - for (i = pop->count; i > 0; i--) { - output[i-1] = run->stackData[--run->stackUsed]; - } - return pop + 1; -} - -static const void *fxRun( fxRun_t *run, const void *data ); - -static const void *fxRunScript( fxRun_t *run, const fxRunScript_t *script ) { - fxRun( run, script->data ); - return script + 1; -} - -static const void *fxRun( fxRun_t *run, const void *data ) { - while ( 1 ) { - const int *cmdList = (int *)data; - int cmd = cmdList[0]; - data = cmdList + 1; - switch ( cmd ) { - case fxCmdHalt: - return data; - default: - Com_Error( ERR_DROP, "FX:Unknown command %d\n", cmd ); - break; - case fxCmdSkip: - data = fxRunSkip( run, (fxRunSkip_t*)data); - break; - case fxCmdKill: - if ( run->entity ) - run->entity->flags |= FX_ENT_DEAD; - return data; - case fxCmdEmitter: - data = fxRunEmitter( run, (fxRunEmitter_t*)data); - break; - case fxCmdRepeat: - data = fxRunRepeat( run, (fxRunRepeat_t*)data); - break; - case fxCmdDistance: - data = fxRunDistance( run, (fxRunDistance_t*)data); - break; - case fxCmdInterval: - data = fxRunInterval( run, (fxRunInterval_t*)data); - break; - case fxCmdIf: - data = fxRunIf( run, (fxRunIf_t*)data); - break; - case fxCmdOnce: - data = fxRunOnce( run, (fxRunOnce_t*)data); - break; - - case fxCmdLight: - fxRunLight( run ); - break; - case fxCmdSprite: - data = fxRunSprite( run, (fxRunRender_t*)data ); - break; - case fxCmdQuad: - data = fxRunQuad( run, (fxRunRender_t*)data ); - break; - case fxCmdSpark: - data = fxRunSpark( run, (fxRunRender_t*)data ); - break; - case fxCmdBeam: - data = fxRunBeam( run, (fxRunRender_t*)data ); - break; - case fxCmdRings: - data = fxRunRings( run, (fxRunRender_t*)data ); - break; - case fxCmdAxisModel: - data = fxRunAxisModel( run, (fxRunRender_t*)data ); - break; - case fxCmdAnglesModel: - data = fxRunAnglesModel( run, (fxRunRender_t*)data ); - break; - case fxCmdDirModel: - data = fxRunDirModel( run, (fxRunRender_t*)data ); - break; - case fxCmdDecal: - data = fxRunDecal( run, (fxRunDecal_t*)data ); - break; - - case fxCmdTrace: - fxRunTrace( run ); - break; - - case fxCmdScript: - data = fxRunScript( run, (fxRunScript_t*)data ); - break; - case fxCmdColor: - data = fxRunColor( run, (fxRunColor_t*)data); - break; - case fxCmdColorList: - data = fxRunColorList( run, (fxRunColorList_t*)data); - break; - case fxCmdColorBlend: - data = fxRunColorBlend( run, (fxRunColorBlend_t*)data); - break; - case fxCmdColorMath: - data = fxRunColorMath( run, (fxRunColorMath_t*)data); - break; - case fxCmdColorScale: - data = fxRunColorScale( run, data); - break; - case fxCmdColorHue: - data = fxRunColorHue( run, data); - break; - case fxCmdShader: - data = fxRunShader( run, (fxRunShader_t*)data); - break; - case fxCmdShaderList: - data = fxRunShaderList( run, (fxRunShaderList_t*)data); - break; - case fxCmdModel: - data = fxRunModel( run, (fxRunModel_t*)data); - break; - case fxCmdModelList: - data = fxRunModelList( run, (fxRunModelList_t*)data); - break; - case fxCmdSound: - data = fxRunSound( run, (fxRunSound_t*)data); - break; - case fxCmdSoundList: - data = fxRunSoundList( run, (fxRunSoundList_t*)data); - break; - case fxCmdLoopSound: - data = fxRunLoopSound( run, (fxRunLoopSound_t*)data); - break; - case fxCmdVibrate: - data = fxRunVibrate( run, (fxRunVibrate_t*)data); - break; - - case fxCmdAlphaFade: - data = fxRunAlphaFade( run, (fxRunAlphaFade_t*)data); - break; - case fxCmdColorFade: - data = fxRunColorFade( run, (fxRunColorFade_t*)data); - break; - case fxCmdPush: - data = fxRunPush( run, (fxRunPush_t*)data); - break; - case fxCmdPop: - data = fxRunPop( run, (fxRunPop_t*)data); - break; - case fxCmdPushParent: - data = fxRunPushParent( run, (fxRunPushParent_t*)data); - break; - - case fxCmdAdd: - data = fxRunAdd( run, (fxRunAdd_t*)data); - break; - case fxCmdSub: - data = fxRunSub( run, (fxRunSub_t*)data); - break; - case fxCmdAddScale: - data = fxRunAddScale( run, (fxRunAddScale_t*)data); - break; - case fxCmdSubScale: - data = fxRunSubScale( run, (fxRunSubScale_t*)data); - break; - case fxCmdRotateAround: - data = fxRunRotateAround( run, (fxRunRotateAround_t*)data); - break; - case fxCmdScale: - data = fxRunScale( run, (fxRunScale_t*)data); - break; - case fxCmdCopy: - data = fxRunCopy( run, (fxRunCopy_t*)data); - break; - case fxCmdRandom: - data = fxRunRandom( run, (fxRunRandom_t*)data); - break; - case fxCmdWobble: - data = fxRunWobble( run, (fxRunWobble_t*)data); - break; - case fxCmdNormalize: - data = fxRunNormalize( run, (fxRunNormalize_t*)data); - break; - case fxCmdPerpendicular: - data = fxRunPerpendicular( run, (fxRunPerpendicular_t*)data); - break; - case fxCmdInverse: - data = fxRunInverse( run, (fxRunInverse_t*)data); - break; - case fxCmdClear: - data = fxRunClear( run, (fxRunClear_t*)data); - break; - case fxCmdValue: - data = fxRunValue( run, (fxRunValue_t*)data ); - break; - } - } - return data; -} - -static fxEntity_t *fxRunEntities( fxEntity_t **nextEntity ) { - fxEntity_t *lastEntity; - fxRun_t run; - - lastEntity = 0; - for (; nextEntity[0]; nextEntity = &nextEntity[0]->next ) { - float deltaTime; - float moveTime; - int movePasses; - const fxRunEmitter_t *emitter; -killSkip: - run.entity = nextEntity[0]; - - fx.last.entityCount++; - fx.last.entitySize += fxSize( run.entity ); - - deltaTime = (fx.time - run.entity->startTime) + fx.timeFraction; - run.lerp = deltaTime * run.entity->lifeScale; - if ( run.lerp >= 1.0f ) { - run.entity->flags |= FX_ENT_DEAD; - } else if ( deltaTime < 0 ) { - lastEntity = run.entity; - continue; - } - run.shaderTime = run.entity->startTime; - run.life = deltaTime * 0.001; - run.key = (unsigned int)run.entity; - emitter = run.entity->emitter; - run.stackUsed = 0; - - if ( !(emitter->flags & FX_EMIT_MOVE ) ) { - VectorCopy( run.entity->origin, run.origin ); - VectorCopy( run.entity->velocity, run.velocity ); - goto runEntity; - } else if ( !(emitter->flags & FX_EMIT_TRACE ) ) { - VectorMA( run.entity->origin, run.life, run.entity->velocity, run.origin ); - VectorCopy( run.entity->velocity, run.velocity ); - - run.velocity[2] -= 2 * run.life * emitter->gravity; - run.origin[2] -= run.life * run.life * emitter->gravity; - goto runEntity; - } else if ( run.entity->flags & FX_ENT_STATIONARY ) { - VectorCopy( run.entity->origin, run.origin ); - if ( emitter->flags & FX_EMIT_SINK && run.lerp > emitter->sinkDelay ) { - run.origin[2] -= emitter->sinkDepth * ( run.lerp - emitter->sinkDelay ); - } - VectorClear( run.velocity ); - goto runEntity; - } - - moveTime = run.life - run.entity->moveTime; - //Still within the valid trace range just move it directly - if( !moveTime || (moveTime < run.entity->traceTime )) { -traceOkay: - VectorMA( run.entity->origin, moveTime, run.entity->velocity, run.origin ); - run.origin[2] -= moveTime * moveTime * emitter->gravity; - VectorCopy( run.entity->velocity, run.velocity ); - run.velocity[2] -= 2 * moveTime * emitter->gravity; - goto runEntity; - } - - //movepasses will go down fast incase stuff fails - for( movePasses = 2; movePasses >= 0; movePasses-- ) { - trace_t tr; - vec3_t oldOrigin, oldVelocity, newOrigin; - vec3_t traceMin, traceMax; - float addTime; - - //Tracetime holds the time since the last update to the origin/velocity - //Calculate the previous trace end position - VectorMA( run.entity->origin, run.entity->traceTime, run.entity->velocity, oldOrigin ); - oldOrigin[2] -= run.entity->traceTime * run.entity->traceTime * emitter->gravity; - VectorCopy( run.entity->velocity, oldVelocity ); - oldVelocity[2] -= 2 * run.entity->traceTime * emitter->gravity; - - //Predict how far we can go from this position if there's any time left in the particle's life anyway - addTime = 0.001 * movePasses * ( 30 + (rand() & 15 ) ); - - //If the entity is still moving upwards check when upward speed will hit 0 if that takes longer that 2 milliseconds - if ( oldVelocity[2] > 0 ) { - float left = oldVelocity[2] / ( 2 * emitter->gravity ); - if ( left < addTime ) { - addTime = left; - } - traceMin[2] = 0; - traceMax[2] = addTime * addTime * emitter->gravity; - } else { - traceMin[2] = -addTime * addTime * emitter->gravity; - traceMax[2] = 0; - } - traceMin[0] = traceMin[1] = -0.1f; - traceMin[2] -= 0.1f; - traceMax[0] = traceMax[1] = 0.1f; - traceMax[2] += 0.1f; - //Check the end position of the trace without the last piece of gravity - VectorMA( oldOrigin, addTime, oldVelocity, newOrigin ); - - CM_BoxTrace( &tr, oldOrigin, newOrigin, traceMin, traceMax, 0, CONTENTS_SOLID, qfalse ); - if ( tr.allsolid || tr.fraction == 0 ) - break; - if ( tr.fraction < 1 ) { - addTime *= tr.fraction * 0.99; - } - run.entity->traceTime += addTime; - //Have we moved into safe territory for now - if ( run.entity->traceTime >= moveTime ) { - goto traceOkay; - } - //Did we only add a very small piece go into regular trace mode -// if ( addTime > 0.001f ) -// break; - } - - //Can do a few passes if the particle bounces between a few surfaces - for( movePasses = 2; movePasses >= 0; movePasses-- ) { - vec3_t oldOrigin; - trace_t tr; - - VectorMA( run.entity->origin, run.entity->traceTime, run.entity->velocity, oldOrigin ); - oldOrigin[2] -= run.entity->traceTime * run.entity->traceTime * emitter->gravity; - - VectorCopy( run.entity->origin, run.origin ); - VectorMA( run.entity->origin, moveTime, run.entity->velocity, run.origin ); - run.origin[2] -= moveTime * moveTime * emitter->gravity; - - VectorCopy( run.entity->velocity, run.velocity ); - run.velocity[2] -= 2 * moveTime * emitter->gravity; - - //Determine how far we can still go before we hit something - CM_BoxTrace( &tr, oldOrigin, run.origin, vec3_origin, vec3_origin, 0, CONTENTS_SOLID, qtrue ); - if ( tr.allsolid || (tr.surfaceFlags & SURF_NOIMPACT) ) { - /* Special case just don't do anything */ - goto killEntity; - //Full trace succeeded - } else if ( tr.fraction == 1 ) { - goto runEntity; - } else { - if ( emitter->flags & FX_EMIT_IMPACT ) { - run.entity->flags |= FX_ENT_DEAD; - goto runEntity; - } - if ( emitter->impactRun && (VectorLengthSquared( run.velocity ) > emitter->impactSpeed ) ) { - /* Run the optional code for the impact handler */ - VectorCopy( tr.endpos, run.origin ); - VectorCopy( tr.plane.normal, run.dir ); - fxRun( &run, ((char *)emitter) + emitter->impactRun ); - } - if ( emitter->bounceFactor > 0 ) { - float bounceTime; - float reflect; - float fractionTime = ( moveTime - run.entity->traceTime ) * tr.fraction; - - bounceTime = run.entity->traceTime + fractionTime; - if ( tr.fraction ) { - //Add back the velocity till the impact time - run.velocity[2] += 2 * fractionTime * emitter->gravity; - reflect = -2 * DotProduct( tr.plane.normal, run.velocity ); - VectorMA( run.velocity, reflect, tr.plane.normal, run.velocity ); - VectorScale( run.velocity, emitter->bounceFactor, run.velocity ); - VectorCopy( run.velocity, run.entity->velocity ); - } - VectorCopy( tr.endpos, run.entity->origin ); - - //Stop moving if it's on a vertical slope and speed is low */ - if ( ( tr.plane.normal[2] > 0 && VectorLengthSquared( run.velocity ) < 40 ) ) { - run.entity->flags |= FX_ENT_STATIONARY; - VectorClear( run.entity->velocity ); - goto runEntity; - } - //Move slightly back in time to prevent negative offsets - run.entity->moveTime += bounceTime; - moveTime = run.life - run.entity->moveTime; - run.entity->traceTime = 0; - continue; - } - } - } -runEntity: - fxMaskOutput( emitter->mask, run.entity + 1, run.velocity + 3 ); - if ( run.entity->flags & FX_ENT_DEAD ) { - if ( emitter->deathRun ) - fxRun( &run, ((char *)emitter) + emitter->deathRun ); - goto killEntity; - } else { - fxRun( &run, ((char *)emitter) + emitter->emitRun ); - } - lastEntity = run.entity; - continue; -killEntity: - nextEntity[0] = run.entity->next; - fxFree( run.entity ); - if ( !nextEntity[0] ) - break; - goto killSkip; - } - return lastEntity; -} - -static void *fxGetActive( unsigned int key1, unsigned int key2, int size ) { - fxActive_t *active; - unsigned int index; - - index = ((key1 ^ key2) >> FX_ACTIVE_HASH_SHIFT) ^ key1 ^ key2; - index &= FX_ACTIVE_HASH_MASK; - active = fx.activeHash[ index ]; - while (1) { - if (!active) { - active = fxAlloc( sizeof( fxActive_t ) + size ); - if (!active) - return 0; - active->next = fx.activeHash[ index ]; - fx.activeHash[ index ] = active; - - active->key1 = key1; - active->key2 = key2; - memset( active + 1, 0, size ); - fx.last.activeCount++; - fx.last.activeSize += fxSize( active ); - break; - } else if (active->key1 == key1 && active->key2 == key2) { - fx.last.activeCount++; - fx.last.activeSize += fxSize( active ); - break; - } - active = active->next; - } - active->beenUsed = qtrue; - return active + 1; -} - - -static void fxDebugDrawString( int x, int y, const char *line ) { - int i; - for (i = 0; i<40;i++) { - if (!line[i]) - break; - SCR_DrawSmallChar( x, y, line[i] ); - x += SMALLCHAR_WIDTH; - } -} - -static void fxDebugDraw( void ) { - char buf[512]; - int x = cls.glconfig.vidWidth * 3 / 4; - int y = cls.glconfig.vidHeight - SMALLCHAR_HEIGHT * 10 * 1.5; - - re.SetColor( colorWhite ); - - Com_sprintf( buf, sizeof( buf ), "Entities %d, mem %dkb", fx.last.entityCount, fx.last.entitySize / -1024 ); - fxDebugDrawString( x, y, buf ); - y += SMALLCHAR_HEIGHT * 1.5; - Com_sprintf( buf, sizeof( buf ), "Active %d, mem %dkb", fx.last.activeCount, fx.last.activeSize / -1024 ); - fxDebugDrawString( x, y, buf ); - y += SMALLCHAR_HEIGHT * 1.5; - - re.SetColor( NULL ); -} - -void FX_Debug( void ) { - if ( fx_Debug->integer ) - fxDebugDraw(); -} - -void FX_Reset( void ) { - int *lastAlloc; - - memset( fx.activeHash, 0, sizeof( fx.activeHash )); - fx.entityActive = 0; - fx.entityNew = 0; - fx.vibrate.time = 0; - fx.vibrate.used = 0; - /* Create the terminator block */ - fx.allocStart[0] = fx.allocSize - sizeof( int ); - fx.allocSearch = fx.allocStart; - lastAlloc = (int *)(((char *)fx.allocStart) + fx.allocSize - sizeof( int )); - lastAlloc[0] = 0; -} - -void FX_Begin( int time, float timeFraction ) { - fx.deltaTime = fx.time - fx.oldTime; - fx.oldTime = fx.time; - fx.time = time; - fx.timeFraction = timeFraction; - if ( fx.deltaTime < 0 || fx.deltaTime > 50) { - fx.oldTime = fx.time; - fx.deltaTime = 0; - } - fx.seed = time; - /* Clear some stats */ - fx.last.activeCount = 0; - fx.last.entityCount = 0; - fx.last.entitySize = 0; - fx.last.activeSize = 0; - /* Run the currently active entities */ - fxRunEntities( &fx.entityActive ); -} - -void FX_End( void ) { - int i; - int loops = 5; - /* Run all the new entities and loop a few times for recursive entities */ - while ( loops>0 && fx.entityNew ) { - fxEntity_t *newEntities, *lastEntity; - newEntities = fx.entityNew; - fx.entityNew = 0; - lastEntity = fxRunEntities( &newEntities ); - if ( lastEntity ) { - lastEntity->next = fx.entityActive; - fx.entityActive = newEntities; - } - loops --; - } - /* Go through the active list and set all to false */ - for( i = 0; i < FX_ACTIVE_HASH_SIZE; i++) { - fxActive_t **activeList = &fx.activeHash[i]; - while ( activeList[0] ) { - fxActive_t *active = activeList[0]; - if ( active->beenUsed ) { - active->beenUsed = qfalse; - if (!active->next) - break; - activeList = &active->next; - continue; - } - activeList[0] = active->next; - fxFree( active ); - } - } -} - -void FX_Run( fxHandle_t handle, const fxParent_t *parent, unsigned int key ) { - fxRun_t run; - const fxScript_t *script; - - if (handle <= 0 || handle > fx.scriptCount || !parent ) - return; - script = fx.scripts[handle]; - - //Check for illegal readmasks for undefined values - if ( fx_Debug->integer ) { - int debug = fx_Debug->integer; - char warning[256]; - warning[0] = 0; - if ( (script->readMask & FX_MASK_ORIGIN) && !(parent->flags & FXP_ORIGIN ) ) { - Q_strcat( warning, sizeof( warning ), "origin, " ); - } - if ( (script->readMask & FX_MASK_VELOCITY) && !(parent->flags & FXP_VELOCITY ) ) { - Q_strcat( warning, sizeof( warning ), "velocity, " ); - } - if ( (script->readMask & FX_MASK_DIR) && !(parent->flags & FXP_DIR ) ) { - Q_strcat( warning, sizeof( warning ), "dir, " ); - } - if ( (script->readMask & FX_MASK_ANGLES) && !(parent->flags & FXP_ANGLES ) ) { - Q_strcat( warning, sizeof( warning ), "angles, " ); - } - if ( debug > 1 && (script->readMask & FX_MASK_SIZE) && !(parent->flags & FXP_SIZE ) ) { - Q_strcat( warning, sizeof( warning ), "size, " ); - } - if ( (script->readMask & FX_MASK_WIDTH) && !(parent->flags & FXP_WIDTH ) ) { - Q_strcat( warning, sizeof( warning ), "width, " ); - } - if ( debug > 1 && (script->readMask & FX_MASK_SHADER) && !(parent->flags & FXP_SHADER ) ) { - Q_strcat( warning, sizeof( warning ), "shader, " ); - } - if ( (script->readMask & FX_MASK_MODEL) && !(parent->flags & FXP_MODEL ) ) { - Q_strcat( warning, sizeof( warning ), "model, " ); - } - if ( (script->readMask & FX_MASK_AXIS) && !(parent->flags & FXP_AXIS ) ) { - Q_strcat( warning, sizeof( warning ), "axis, " ); - } - if ( warning[0] ) { - Com_Printf("FX_Debug:script '%s' requires %s which aren't supplied by caller\n", script->entry->name, warning ); - } - } - VectorCopy( parent->origin, run.origin ); - if ( parent->flags & FXP_VELOCITY) - VectorCopy( parent->velocity, run.velocity ); - else - VectorClear( run.velocity ); - if ( parent->flags & FXP_DIR ) - VectorCopy( parent->dir, run.dir ); - if ( parent->flags & FXP_ANGLES ) { - VectorCopy( parent->angles, run.angles ); - run.rotate = run.angles[ROLL]; - } else { - VectorClear( run.angles ); - run.rotate = 0; - } - if ( parent->flags & FXP_AXIS ) - AxisCopy( parent->axis, run.axis ); - - *(int *)run.color = ( parent->flags & FXP_COLOR ) ? *(int *)parent->color : 0xffffffff; - run.shader = ( parent->flags & FXP_SHADER ) ? parent->shader : 0; - run.model = ( parent->flags & FXP_MODEL ) ? parent->model : 0; - run.size = ( parent->flags & FXP_SIZE ) ? parent->size : 1.0f; - run.width = ( parent->flags & FXP_WIDTH ) ? parent->width : 1.0f; - - run.parent = parent; - run.shaderTime = 0; - run.key = key; - run.stackUsed = 0; - run.entity = 0; - fxRun( &run, script->data ); -} - - -static void fxList( void ) { - const fxScript_t *script; - int i; - - if ( fx.scriptCount <= 1) { - Com_Printf("No fx scripts loaded\n"); - return; - } - Com_Printf ( "-----------------------\n" ); - for ( i = 1; ientry->name ); - if ( script->remap ) { - Com_Printf( " remap to %s", script->remap->entry->name ); - } - Com_Printf( "\n"); - } - Com_Printf( "%d Total scripts\n", fx.scriptCount - 1); - Com_Printf ( "-----------------------\n" ); -} - -static void fxStats( void ) { - int *alloc = fx.allocStart; - int allocSize, allocBlocks; - int freeSize, freeBlocks; - - allocSize = allocBlocks = 0; - freeSize = freeBlocks = 0; - - while ( 1 ) { - int size = alloc[0]; - if ( size < 0 ) { - size = -size; - allocSize += size; - allocBlocks++; - } else if ( size > 0 ) { - freeSize += size; - freeBlocks++; - } else - break; - alloc = (int*)(((char *)alloc) + size); - } - - Com_Printf( "FX Stats:\n" ); - Com_Printf( "Free %d in %d blocks\n", freeSize, freeBlocks ); - Com_Printf( "Allocated %d in %d blocks\n", allocSize, allocBlocks ); -} - -void FX_Init( void ) { - Com_Memset( &fx, 0, sizeof( fx )); - - fx_Megs = Cvar_Get( "fx_Megs", "2", CVAR_ARCHIVE | CVAR_LATCH ); - fx_Vibrate = Cvar_Get( "fx_Vibrate", "1", CVAR_ARCHIVE ); - fx_Override = Cvar_Get( "fx_Override", "", CVAR_ARCHIVE ); - fx_Debug = Cvar_Get( "fx_Debug", "0", CVAR_CHEAT ); - fx.allocSize = fx_Megs->integer; - if ( fx.allocSize < 1) - fx.allocSize = 1; - else if (fx.allocSize > 8) { - fx.allocSize = 8; - } - fx.allocSize *= 1024*1024; - fx.allocStart = Hunk_Alloc( fx.allocSize, h_low ); - FX_Reset( ); - Cmd_AddCommand( "fxStats", fxStats ); - Cmd_AddCommand( "fxList", fxList ); - Cmd_AddCommand( "fxReset", FX_Reset ); - - fxInitParser(); -} - -void FX_Shutdown( void ) { - Cmd_RemoveCommand( "fxStats" ); - Cmd_RemoveCommand( "fxReset" ); - Cmd_RemoveCommand( "fxRemap" ); - Cmd_RemoveCommand( "fxMath" ); - Cmd_RemoveCommand( "fxReload" ); - if ( fx.alloc.entries ) - fxFreeMemory(); -} \ No newline at end of file diff --git a/code/client/fx_parse.c b/code/client/fx_parse.c deleted file mode 100644 index 23993034c7..0000000000 --- a/code/client/fx_parse.c +++ /dev/null @@ -1,2390 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2006 Sjoerd van der Berg ( harekiet @ gmail.com ) - -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 -=========================================================================== -*/ - -// fx_parse.c -- Parse and load FX Scripts and handle the fx related math - -#include "client.h" -#include "fx_local.h" - -fxMain_t fx; - -#define parentOfs(m) ((size_t)&((((fxParent_t*)0)->m))) -#define parentSize(m) (sizeof((((fxParent_t*)0)->m)) / sizeof(float)) -#define runOfs(m) ((size_t)&((((fxRun_t*)0)->m))) -#define runSize(m) (sizeof((((fxRun_t*)0)->m)) / sizeof(float)) - -static fxScript_t *fxFindScript( const char *name ); - -static unsigned int fxGenerateHash( const char *name ) { - unsigned int hash = 0; - while (*name) { - char c = tolower(name[0]); - hash = (hash << 5 ) ^ (hash >> 27) ^ c; - name++; - } - return (hash ^ (hash >> FX_HASH_SHIFT) ^ (hash >> (FX_HASH_SHIFT*2))) & FX_HASH_MASK; -} - -typedef enum { - fxParentScript, - fxParentEmitter, -} fxParseParent_t; - -typedef struct { - const char *last, *text, *name, *line; - int lineCount; - char token[1024]; - fxParseParent_t parent; - fxRunEmitter_t *emitter; - int loopDepth; - unsigned int readMask, writeMask, vectorMask; -} fxParse_t; - -typedef struct { - int size, used; - byte *data; -} fxParseOut_t; - - -static ID_INLINE void fxParseWrite( fxParse_t *parse, unsigned int mask ) { - parse->writeMask |= mask; -} - -static ID_INLINE void fxParseRead( fxParse_t *parse, unsigned int mask ) { - mask &= ~parse->writeMask; - parse->readMask |= mask; -} - -qboolean fxParseError( fxParse_t *parse, const char *fmt, ... ) { - va_list argptr; - char msg[512]; - char line[512]; - int i = 0; - - if ( parse->line ) { - while (i < sizeof( line ) - 1) { - if ( !parse->line[i] ) - break; - if ( parse->line[i] == '\n' ) - break; - if ( parse->line[i] == '\r' ) - break; - line[i] = parse->line[i]; - i++; - } - } - line[i] = 0; - - va_start (argptr,fmt); - Q_vsnprintf (msg, sizeof(msg), fmt, argptr); - va_end (argptr); - - Com_Printf( S_COLOR_YELLOW "fxError:'%s' in line '%s' in script '%s'\n", msg ,line, parse->name ); - return qfalse; -} - -qboolean fxParseErrorIllegal( fxParse_t *parse ) { - return fxParseError( parse, "Illegal token %s", parse->token ); -} - -static void *fxParseAlloc( int size ) { - return Z_TagMalloc( size, TAG_FX ); -} -static void fxParseFree( void *free ) { - Z_Free( free ); -} - -static qboolean fxParseCreateMask( fxParse_t *parse, byte *table, int tableLen, unsigned short *allocAdd ) { - byte modMask[ runOfs( stackUsed ) / 4 ]; - unsigned int mask = parse->readMask; - int modeCount, maskIndex, maskLast, tableIndex = 0; - int totalCount; - byte checkVal; - - memset( modMask, 0, sizeof( modMask )); -#define MODSET( m ) memset( modMask + (runOfs( m ) / 4), 1, runSize( m ) ); -#if 0 - if ( mask & FX_MASK_ORIGIN ) MODSET( origin ); - if ( mask & FX_MASK_VELOCITY ) MODSET( velocity ); -#endif - if ( mask & FX_MASK_SHADER ) MODSET( shader ); - if ( mask & FX_MASK_SIZE ) MODSET( size ); - if ( mask & FX_MASK_ROTATE ) MODSET( rotate ); - if ( mask & FX_MASK_COLOR ) MODSET( color ); - - if ( mask & FX_MASK_PARENT ) MODSET( parent ); - if ( mask & FX_MASK_DIR ) MODSET( dir ); - if ( mask & FX_MASK_MODEL ) MODSET( model ); - if ( mask & FX_MASK_AXIS ) MODSET( axis ); - if ( mask & FX_MASK_ANGLES ) MODSET( angles ); - if ( mask & FX_MASK_WIDTH ) MODSET( width ); - if ( mask & FX_MASK_T0 ) MODSET( t0 ); - if ( mask & FX_MASK_T1 ) MODSET( t1 ); - if ( mask & FX_MASK_T2 ) MODSET( t2 ); - if ( mask & FX_MASK_T3 ) MODSET( t3 ); - if ( mask & FX_MASK_V0 ) MODSET( v0 ); - if ( mask & FX_MASK_V1 ) MODSET( v1 ); - if ( mask & FX_MASK_V2 ) MODSET( v2 ); - if ( mask & FX_MASK_V3 ) MODSET( v3 ); -#undef MODSET - - //This is all somewhat hacky, but seems to work - maskIndex = 3 + runOfs( velocity ) / 4; - maskLast = runOfs( parent ) / 4 + runSize( parent ); - modeCount = 0; - totalCount = 0; - checkVal = 0; - - while ( maskIndex < maskLast ) { - if ( checkVal == modMask[maskIndex] ) { - maskIndex++; - modeCount++; - totalCount += checkVal; - } else { - if ( tableIndex >= tableLen ) - return fxParseError( parse, "Ran out of write mask space" ); - checkVal ^= 1; - table[tableIndex++] = modeCount; - modeCount = 0; - } - } - if ( tableIndex >= tableLen ) - return fxParseError( parse, "Ran out of write mask space" ); - table[tableIndex++] = modeCount; - if (modeCount) { - if ( tableIndex >= tableLen ) - return fxParseError( parse, "Ran out of write mask space" ); - table[tableIndex++] = 0; - } - *allocAdd += totalCount * 4; - return qtrue; -} - -#define SEPERATOR(_T_) ((_T_ == ' ') || (_T_ == '\n') || (_T_ == '\t') || (_T_ == '\r')) - -static qboolean fxParseToken( fxParse_t *parse, qboolean skipLine ) { - const char *p = parse->text; - char *token = parse->token; - qboolean haveQuote = qfalse; - int tokenLength = 0; - - if (!parse->line) - parse->line = p; - - parse->last = p; - while (1) { - if ( tokenLength >= sizeof( parse->token )) { - parse->token[ sizeof( parse->token ) -1 ] = 0; - return fxParseError( parse, "token %s too long", parse->token ); - } - if ( haveQuote ) { - if (*p == '\n' || *p == '\r' || *p == 0) { - return fxParseError( parse, "token missing end quote" ); - } - if ( *p == '\"' ) { - if (!SEPERATOR(p[1]) && !p[1]) - return fxParseError( parse, "token quote followed by a character" ); - haveQuote = qfalse; - p++; - break; - } - token[tokenLength++] = p[0]; - } else if ( tokenLength ) { - if (SEPERATOR(p[0]) || !p[0]) - break; - token[tokenLength++] = p[0]; - } else if (!p[0]) { - break; - } else if (p[0] == '"' ) { - haveQuote = qtrue; - } else if (SEPERATOR(p[0])) { - if ( p[0] == '\n' || p[0] == '\r' ) { - if ( !skipLine ) - break; - parse->line = p+1; - parse->last = 0; - } - } else { - token[tokenLength++] = p[0]; - } - p++; - } - parse->text = p; - token[tokenLength] = 0; - if (!tokenLength ) - return qfalse; - return qtrue; -} - -static qboolean fxParseReverse( fxParse_t *parse ) { - if (!parse->last) - return fxParseError( parse, "Can't reverse a token" ); - parse->text = parse->last; - return qtrue; -} - -static qboolean fxParseWord( fxParse_t *parse, const char *type ) { - if (!fxParseToken( parse, qfalse )) { - if ( !type ) - type = "word"; - return fxParseError( parse, "Missing %s" ); - } - return qtrue; -} - -static qboolean fxParseCompare( fxParse_t *parse, const char *compare ) { - if (!fxParseWord( parse, compare )) { - return qfalse; - } - if (Q_stricmp( parse->token, compare )) - return fxParseError( parse, "%s doesn't match %s", parse->token, compare ); - return qtrue; -} - -typedef qboolean (*fxListMatch_t)( fxParse_t *, void * ); - -static qboolean fxParseList( fxParse_t *parse, const char *list, fxListMatch_t match, int dataSize, void *data, int countMax, unsigned int *count ) { - const char *token = parse->token; - - if (!fxParseCompare( parse, "{")) - return qfalse; - *count = 0; - while ( 1 ) { - if (!fxParseToken( parse, qtrue )) { - return fxParseError( parse, "Expected %s entry", list ); - } - if (!Q_stricmp( token, "}")) - break; - if (!match( parse, ((char *)data) + *count * dataSize )) - return qfalse; - (*count)++; - if ( *count >= countMax ) - return fxParseError( parse, "Too many entries for %s (max %d)", list, countMax ); - } - if (!*count) - return fxParseError( parse, "%s is empty", list ); - return qtrue; -} - -static qboolean fxMatchValidFloat( fxParse_t *parse ) { - int doneNumber = 0; - int donePoint = 0; - - char *token = parse->token; - for ( ;1;token++) { - switch (*token) { - case 0: - if (!doneNumber) - return fxParseError( parse, "empty float", parse->token ); - return qtrue; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - doneNumber++; - continue; - case '.': - if ( donePoint ) - return fxParseError( parse, "invalid float %s", parse->token ); - donePoint++; - continue; - default: - return fxParseError( parse, "illegal char %c in float %s", *token, parse->token ); - } - } - return qfalse; -} - -static qboolean fxParseFloat( fxParse_t *parse, float *data ) { - if (!fxParseToken( parse, qfalse )) { - return fxParseError( parse, "Expected float" ); - } - if (!fxMatchValidFloat( parse )) - return qfalse; - //TODO check for valid float? - *data = atof( parse->token ); - return qtrue; -} - -/* Bit of a hack to parse the second 2 values */ -static qboolean fxMatchColor( fxParse_t *parse, byte *data ) { - int i; - for (i = 0;i<3;i++) { - float f; - if (!i) { - if (!fxMatchValidFloat( parse )) - return qfalse; - f = atof( parse->token ); - } else if (!fxParseFloat( parse, &f)) { - return qfalse; - } - if ( f < 0 ) - f = 0; - else if ( f > 1) - f = 1; - data[i] = f * 255; - } - return qtrue; -} - -static qboolean fxMatchShader( fxParse_t *parse, qhandle_t *data ) { - data[0] = re.RegisterShader( parse->token ); - if (!data[0]) - return fxParseError( parse, "shader %s not found", parse->token ); - return qtrue; -} - -static qboolean fxMatchModel( fxParse_t *parse, qhandle_t *data ) { - data[0] = re.RegisterModel( parse->token ); - if (!data[0]) - return fxParseError( parse, "model %s not found", parse->token ); - return qtrue; -} - -static qboolean fxMatchSound( fxParse_t *parse, sfxHandle_t *data ) { - data[0] = S_RegisterSound( parse->token, qfalse ); - if (!data[0]) - return fxParseError( parse, "Sound %s not found", parse->token ); - return qtrue; -} - -static qboolean fxParseColor( fxParse_t *parse, byte *data ) { - int i; - for (i = 0;i<3;i++) { - float f; - if (!fxParseFloat( parse, &f )) { - return qfalse; - } - if ( f < 0 ) - f = 0; - else if ( f > 1) - f = 1; - data[i] = f * 255; - } - return qtrue; -} - -static qboolean fxParseRenderFX( fxParse_t *parse, int *renderFX ) { - *renderFX = RF_NOSHADOW; - while (fxParseToken( parse, qfalse ) ) { - const char *token = parse->token; - if (!Q_stricmp(token, "firstPerson")) { - *renderFX |= RF_FIRST_PERSON; - } else if (!Q_stricmp(token, "thirdPerson")) { - *renderFX |= RF_THIRD_PERSON; - } else if (!Q_stricmp(token, "shadow")) { - *renderFX &= ~RF_NOSHADOW; - } else if (!Q_stricmp(token, "cullNear") || !Q_stricmp(token, "cullRadius" ) ) { - *renderFX |= RF_CULLRADIUS; - } else if (!Q_stricmp(token, "depthHack")) { - *renderFX |= RF_DEPTHHACK; - } else if (!Q_stricmp(token, "stencil")) { - *renderFX |= RF_STENCIL; - } else { - return fxParseError( parse, "Illegal render keyword %s", token ); - } - } - return qtrue; -} - - -static qboolean fxParseOut( fxParse_t *parse, fxParseOut_t *out, const void *data, int size ) { - if ( out->used + size + sizeof( void *) > out->size ) { - fxParseError( parse, "Overflowing output buffer" ); - return qfalse; - } - memcpy( out->data + out->used, data, size ); - out->used += size; - return qtrue; -} - -static qboolean fxParseOutCmd( fxParse_t *parse, fxParseOut_t *out, int cmd, const void *data, int size ) { - if (!fxParseOut( parse, out, &cmd, sizeof( cmd ) )) - return qfalse; - if (!fxParseOut( parse, out, data, size )) - return qfalse; - return qtrue; -} - -typedef struct { - fxRun_t *run; - const int *data; -} fxMathInfo_t; - -typedef float (*fxMathHandler)( fxMathInfo_t *info ); - -static float ID_INLINE fxMath( fxMathInfo_t *info ) { - fxMathHandler * handler = ( fxMathHandler *)info->data; - info->data++; - return (*handler)( info ); -} - -const void *fxRunMath( fxRun_t *run, const void *data, float *value ) { - fxMathInfo_t info; - info.run = run; - info.data = data; - - *value = fxMath( &info ); - return info.data; -} -static float fxMathNeg( fxMathInfo_t *info ) { - return -fxMath( info ); -} -static float fxMathMul( fxMathInfo_t *info ) { - float v1 = fxMath( info ); - float v2 = fxMath( info ); - return v1 * v2; -} -static float fxMathDiv( fxMathInfo_t *info ) { - float v1 = fxMath( info ); - float v2 = fxMath( info ); - return v1 / v2; -} -static float fxMathAdd( fxMathInfo_t *info ) { - float v1 = fxMath( info ); - float v2 = fxMath( info ); - return v1 + v2; -} -static float fxMathSub( fxMathInfo_t *info ) { - float v1 = fxMath( info ); - float v2 = fxMath( info ); - return v1 - v2; -} - -static float fxMathEqual( fxMathInfo_t *info ) { - float v1 = fxMath( info ); - float v2 = fxMath( info ); - return ((v1 != 0) == (v2 != 0)) ? 1 : 0; -} -static float fxMathNotEqual( fxMathInfo_t *info ) { - float v1 = fxMath( info ); - float v2 = fxMath( info ); - return ((v1 != 0) != (v2 != 0)) ? 1 : 0; -} - -static float fxMathTE( fxMathInfo_t *info ) { - float v1 = fxMath( info ); - float v2 = fxMath( info ); - return ( v1 == v2 ) ? 1 : 0; -} -static float fxMathTNE( fxMathInfo_t *info ) { - float v1 = fxMath( info ); - float v2 = fxMath( info ); - return ( v1 != v2 ) ? 1 : 0; -} -static float fxMathTG( fxMathInfo_t *info ) { - float v1 = fxMath( info ); - float v2 = fxMath( info ); - return (v1 > v2) ? 1 : 0; -} -static float fxMathTGE( fxMathInfo_t *info ) { - float v1 = fxMath( info ); - float v2 = fxMath( info ); - return (v1 >= v2) ? 1 : 0; -} -static float fxMathTS( fxMathInfo_t *info ) { - float v1 = fxMath( info ); - float v2 = fxMath( info ); - return (v1 < v2) ? 1 : 0; -} -static float fxMathTSE( fxMathInfo_t *info ) { - float v1 = fxMath( info ); - float v2 = fxMath( info ); - return (v1 <= v2) ? 1 : 0; -} - -static float fxMathAND( fxMathInfo_t *info ) { - float v1 = fxMath( info ); - float v2 = fxMath( info ); - return (v1 && v2) ? 1 : 0; -} - -static float fxMathOR( fxMathInfo_t *info ) { - float v1 = fxMath( info ); - float v2 = fxMath( info ); - return (v1 || v2) ? 1 : 0; -} - -static float fxMathSin( fxMathInfo_t *info ) { - return sinf( DEG2RAD( fxMath( info ))); -} -static float fxMathCos( fxMathInfo_t *info ) { - return cosf( DEG2RAD( fxMath( info ))); -} -static float fxMathWave( fxMathInfo_t *info ) { - return sinf( fxMath( info ) * 2 * M_PI ); -} -static float fxMathSqrt( fxMathInfo_t *info ) { - return sqrtf( fxMath( info )); -} -static float fxMathCeil( fxMathInfo_t *info ) { - return ceilf( fxMath( info )); -} -static float fxMathFloor( fxMathInfo_t *info ) { - return floorf( fxMath( info )); -} -static float fxMathClip( fxMathInfo_t *info) { - float v = fxMath( info ); - if ( v < 0.0f) - return 0.0f; - if ( v > 1.0f ) - return 1.0f; - return v; -} -static float fxMathZero( fxMathInfo_t *info ) { - return 0; -} -static float fxMathPi( fxMathInfo_t *info ) { - return M_PI; -} -static float fxMathRed( fxMathInfo_t *info ) { - return info->run->color[0] * (1.0f/255); -} -static float fxMathGreen( fxMathInfo_t *info ) { - return info->run->color[1] * (1.0f/255); -} -static float fxMathBlue( fxMathInfo_t *info ) { - return info->run->color[2] * (1.0f/255); -} -static float fxMathAlpha( fxMathInfo_t *info ) { - return info->run->color[3] * (1.0f/255); -} -static float fxMathValue( fxMathInfo_t *info ) { - int ofs = info->data[0]; - float *v = (float *)(((char *)info->run) + ofs); - info->data++; - return v[0]; -} -static float fxMathLength( fxMathInfo_t *info ) { - int ofs = info->data[0]; - const float *v = fxFloatSrc( info->run, ofs ); - info->data++; - return VectorLength( v ); -} -static float fxMathParent( fxMathInfo_t *info ) { - int ofs = info->data[0]; - float *v = (float *)(((char *)info->run->parent) + ofs); - info->data++; - return v[0]; -} -static float fxMathConst( fxMathInfo_t *info) { - float v1 = ((float *)info->data)[0]; - info->data++; - return v1; -} -static float fxMathTime( fxMathInfo_t *info) { - return fx.time * 0.001f; -} -static float fxMathRand( fxMathInfo_t *info) { - fx.seed = fx.seed * 16091 + 1; - return (fx.seed & 0xffff) * (1.0f / 0x10000); -} -static float fxMathCrand( fxMathInfo_t *info) { - fx.seed = fx.seed * 16091 + 1; - return 1.0f - (2.0f / 0x10000) * (fx.seed & 0xffff); -} -static float fxMathCvar( fxMathInfo_t *info ) { - cvar_t *cvar; - memcpy( &cvar, info->data, sizeof( cvar_t *)); - info->data += sizeof( cvar_t *) / sizeof( int ); - return cvar->value; -} - -static qboolean fxParseParentValue( const char *val, int *ofs ) { - if (0) { - } else if (!Q_stricmp( val, "parentorigin0")) { - *ofs = parentOfs( origin[0] ); - } else if (!Q_stricmp( val, "parentorigin1")) { - *ofs = parentOfs( origin[1] ); - } else if (!Q_stricmp( val, "parentorigin2")) { - *ofs = parentOfs( origin[2] ); - } else if (!Q_stricmp( val, "parentvelocity0")) { - *ofs = parentOfs( velocity[0] ); - } else if (!Q_stricmp( val, "parentvelocity1")) { - *ofs = parentOfs( velocity[1] ); - } else if (!Q_stricmp( val, "parentvelocity2")) { - *ofs = parentOfs( velocity[2] ); - } else if (!Q_stricmp( val, "parentangles0")) { - *ofs = parentOfs( angles[0] ); - } else if (!Q_stricmp( val, "parentangles1")) { - *ofs = parentOfs( angles[1] ); - } else if (!Q_stricmp( val, "parentangles2")) { - *ofs = parentOfs( angles[2] ); - } else if (!Q_stricmp( val, "parentyaw")) { - *ofs = parentOfs( angles[YAW] ); - } else if (!Q_stricmp( val, "parentpitch")) { - *ofs = parentOfs( angles[PITCH] ); - } else if (!Q_stricmp( val, "parentroll")) { - *ofs = parentOfs( angles[ROLL] ); - } else if (!Q_stricmp( val, "parentangle")) { - *ofs = parentOfs( angles[ROLL] ); - } else if (!Q_stricmp( val, "parentsize")) { - *ofs = parentOfs( size ); - } else { - return qfalse; - } - return qtrue; -} - - -#define PARSE_RUN_VECTOR_ENTRY( _VEC, _MASK, _NUM ) \ - if (!Q_stricmp( val, #_VEC #_NUM)) { \ - *ofs = runOfs( _VEC[_NUM] ); \ - *mask = _MASK; \ - } - - -#define PARSE_RUN_VECTOR( _VEC, _MASK ) \ - PARSE_RUN_VECTOR_ENTRY( _VEC, _MASK, 0 ) \ - else \ - PARSE_RUN_VECTOR_ENTRY( _VEC, _MASK, 1 ) \ - else \ - PARSE_RUN_VECTOR_ENTRY( _VEC, _MASK, 2 ) - - -static qboolean fxMatchFloat( const char *val, int *ofs, unsigned int *mask ) { - PARSE_RUN_VECTOR( origin, FX_MASK_ORIGIN ) - else PARSE_RUN_VECTOR( velocity, FX_MASK_VELOCITY ) - else PARSE_RUN_VECTOR( angles, FX_MASK_ANGLES ) - else PARSE_RUN_VECTOR( dir, FX_MASK_DIR ) - else PARSE_RUN_VECTOR( v0, FX_MASK_V0 ) - else PARSE_RUN_VECTOR( v1, FX_MASK_V1 ) - else PARSE_RUN_VECTOR( v2, FX_MASK_V2 ) - else PARSE_RUN_VECTOR( v3, FX_MASK_V3 ) - else if (!Q_stricmp( val, "rotate") || !Q_stricmp( val, "angle")) { - *ofs = runOfs( rotate ); - *mask = FX_MASK_ROTATE; - } else if (!Q_stricmp( val, "size")) { - *ofs = runOfs( size ); - *mask = FX_MASK_SIZE; - } else if (!Q_stricmp( val, "width")) { - *ofs = runOfs( width ); - *mask = FX_MASK_WIDTH; - } else if (!Q_stricmp( val, "yaw")) { - *ofs = runOfs( angles[YAW] ); - *mask = FX_MASK_ANGLES; - } else if (!Q_stricmp( val, "pitch")) { - *ofs = runOfs( angles[PITCH] ); - *mask = FX_MASK_ANGLES; - } else if (!Q_stricmp( val, "roll")) { - *ofs = runOfs( angles[ROLL] ); - *mask = FX_MASK_ANGLES; - } else if (!Q_stricmp( val, "t0")) { - *ofs = runOfs( t0 ); - *mask = FX_MASK_T0; - } else if (!Q_stricmp( val, "t1")) { - *ofs = runOfs( t1 ); - *mask = FX_MASK_T1; - } else if (!Q_stricmp( val, "t2")) { - *ofs = runOfs( t2 ); - *mask = FX_MASK_T2; - } else if (!Q_stricmp( val, "t3")) { - *ofs = runOfs( t3 ); - *mask = FX_MASK_T3; - } else { - return qfalse; - } - return qtrue; -} - -static qboolean fxMatchVector( const char *val, int *ofs, unsigned int *mask ) { - if (!Q_stricmp( val, "origin")) { - *ofs = runOfs( origin ); - *mask = FX_MASK_ORIGIN; - } else if (!Q_stricmp( val, "velocity")) { - *ofs = runOfs( velocity ); - *mask = FX_MASK_VELOCITY; - } else if (!Q_stricmp( val, "angles")) { - *ofs = runOfs( angles ); - *mask = FX_MASK_ANGLES; - } else if (!Q_stricmp( val, "dir")) { - *ofs = runOfs( dir ); - *mask = FX_MASK_DIR; - } else if (!Q_stricmp( val, "v0")) { - *ofs = runOfs( v0 ); - *mask = FX_MASK_V0; - } else if (!Q_stricmp( val, "v1")) { - *ofs = runOfs( v1 ); - *mask = FX_MASK_V1; - } else if (!Q_stricmp( val, "v2")) { - *ofs = runOfs( v2 ); - *mask = FX_MASK_V2; - } else if (!Q_stricmp( val, "v3")) { - *ofs = runOfs( v3 ); - *mask = FX_MASK_V3; - } else if (!Q_stricmp( val, "parentOrigin" )) { - *ofs = parentOfs( origin ) | FX_VECTOR_PARENT; - *mask = FX_MASK_PARENT; - } else if (!Q_stricmp( val, "parentVelocity" )) { - *ofs = parentOfs( velocity ) | FX_VECTOR_PARENT; - *mask = FX_MASK_PARENT; - } else if (!Q_stricmp( val, "parentAngles" )) { - *ofs = parentOfs( angles ) | FX_VECTOR_PARENT; - *mask = FX_MASK_PARENT; - } else if (!Q_stricmp( val, "parentDir" )) { - *ofs = parentOfs( dir ) | FX_VECTOR_PARENT; - *mask = FX_MASK_PARENT; - } else { - return qfalse; - } - return qtrue; -} - -static qboolean fxParseVectorOptional( fxParse_t *parse, int *ofs ) { - unsigned int mask; - - if (!fxParseToken( parse, qfalse )) { - mask = parse->vectorMask; - } else if (!fxMatchVector( parse->token, ofs, &mask ) ) { - mask = parse->vectorMask; - if (!fxParseReverse( parse )) - return qfalse; - } - if ( mask & FX_MASK_PARENT ) { - return fxParseError( parse, "Can't write to a parent vector" ); - } - fxParseWrite( parse, mask ); - return qtrue; -} - -static qboolean fxParseVectorRead( fxParse_t *parse, int *ofs ) { - unsigned int mask; - if (!fxParseToken( parse, qfalse )) { - return fxParseError( parse, "Expected read vector name" ); - } - if ( !fxMatchVector( parse->token, ofs, &mask ) ) { - return fxParseError( parse, "Unknown read vector name %s", parse->token ); - } - parse->vectorMask = mask; - fxParseRead( parse, mask ); - return qtrue; -} - -static qboolean fxParseVectorWrite( fxParse_t *parse, int *ofs ) { - unsigned int mask; - if (!fxParseToken( parse, qfalse )) { - return fxParseError( parse, "Expected write vector name" ); - } - if ( !fxMatchVector( parse->token, ofs, &mask ) ) { - return fxParseError( parse, "Unknown write vector name %s", parse->token ); - } - if ( mask & FX_MASK_PARENT ) { - return fxParseError( parse, "Can't write to a parent vector" ); - } - fxParseWrite( parse, mask ); - return qtrue; -} - -typedef enum { - mathParseLine, - mathParseSingle, - mathParseMul, -} mathParseType_t; - -typedef struct { - byte data[1024]; - int used; -} fxMathOut_t; - - -static qboolean fxMathAppend( fxParse_t *parse, fxMathOut_t *out, const void *data, int size ) { - if ( size + out->used > sizeof( out->data )) - return fxParseError( parse, "Overflowing math parser" ); - if ( !size || !data) - return fxParseError( parse, "math adding 0 sized data" ); - memcpy( out->data + out->used, data, size ); - out->used += size; - return qtrue; -} - -static qboolean fxMathAppendOut( fxParse_t *parse, fxMathOut_t *out, const fxMathOut_t *add ) { - return fxMathAppend( parse, out, add->data, add->used ); -} - -static qboolean fxMathAppendInt( fxParse_t *parse, fxMathOut_t *out, int val ) { - return fxMathAppend( parse, out, &val, sizeof( int )); -} - -static qboolean fxMathAppendHandler( fxParse_t *parse, fxMathOut_t *out, fxMathHandler handler ) { - //TODO for 64bit platforms use a relative 32bit offset - return fxMathAppend( parse, out, &handler, sizeof( handler )); -} - -static qboolean fxMathParse( fxParse_t *parse, mathParseType_t parseType, char **line, const fxMathOut_t *in, fxMathOut_t *out ); - -static qboolean fxMathParseHandler( fxParse_t *parse, char **line, fxMathOut_t *out, fxMathHandler handler ) { - if (!fxMathAppendHandler( parse, out, handler)) - return qfalse; - return fxMathParse( parse, mathParseSingle, line, 0, out ); -} - - -static qboolean fxMathParse( fxParse_t *parse, mathParseType_t parseType, char **line, const fxMathOut_t *in, fxMathOut_t *out ) { - char buf[64]; - int wordSize; - fxMathOut_t val; - fxMathHandler tempHandler; - - wordSize = 0; - val.used = 0; - - if ( parseType == mathParseLine && !in ) { - if (!fxMathParse( parse, mathParseMul, line, 0, &val )) - return qfalse; - return fxMathParse( parse, mathParseLine, line, &val, out ); - } - - while ( 1 ) { - char c = line[0][0]; - - if ( wordSize ) { - int i; - qboolean isNumber; - - if ( !c || c == ')' || c == '(' || c == ' ' - || c == '-' || c =='+' || c == '*' || c == '/' - || c == '!' || c == '<' || c == '>' || c == '=' || - c == '&' || c == '|' ) { - /* Easier to just parse the value first incase of trouble */ - buf[wordSize] = 0; - - if ( val.used ) - return fxParseError( parse, "math double value %s", buf ); - - isNumber = qtrue; - for ( i = 0; i < wordSize;i++) { - if (!(buf[i] == '.' || (buf[i] >= '0' && buf[i] <= '9'))) { - isNumber = qfalse; - break; - } - } - - if ( isNumber ) { - float value = atof( buf ); - if (!fxMathAppendHandler( parse, &val, fxMathConst )) - return qfalse; - if (!fxMathAppend( parse, &val, &value, sizeof( value ))) - return qfalse; - } else if (!Q_stricmp( buf, "sin")) { - if (!fxMathParseHandler( parse, line, &val, &fxMathSin )) - return qfalse; - } else if (!Q_stricmp( buf, "cos")) { - if (!fxMathParseHandler( parse, line, &val, &fxMathCos )) - return qfalse; - } else if (!Q_stricmp( buf, "wave")) { - if (!fxMathParseHandler( parse, line, &val, &fxMathWave)) - return qfalse; - } else if (!Q_stricmp( buf, "sqrt")) { - if (!fxMathParseHandler( parse, line, &val, &fxMathSqrt )) - return qfalse; - } else if (!Q_stricmp( buf, "ceil")) { - if (!fxMathParseHandler( parse, line, &val, &fxMathCeil )) - return qfalse; - } else if (!Q_stricmp( buf, "floor")) { - if (!fxMathParseHandler( parse, line, &val, &fxMathFloor )) - return qfalse; - } else if (!Q_stricmp( buf, "clip")) { - if (!fxMathParseHandler( parse, line, &val, &fxMathClip )) - return qfalse; - } else if (!Q_stricmp( buf, "rand") || !Q_stricmp( buf, "rnd")) { - if (!fxMathAppendHandler( parse, &val, &fxMathRand)) - return qfalse; - } else if (!Q_stricmp( buf, "time")) { - if (!fxMathAppendHandler( parse, &val, &fxMathTime)) - return qfalse; - } else if (!Q_stricmp( buf, "crand")) { - if (!fxMathAppendHandler( parse, &val, &fxMathCrand)) - return qfalse; - } else if (!Q_stricmp( buf, "pi")) { - if (!fxMathAppendHandler( parse, &val, &fxMathPi)) - return qfalse; - } else if (!Q_stricmp( buf, "red")) { - if (!fxMathAppendHandler( parse, &val, &fxMathRed)) - return qfalse; - fxParseRead( parse, FX_MASK_COLOR); - } else if (!Q_stricmp( buf, "green")) { - if (!fxMathAppendHandler( parse, &val, &fxMathGreen)) - return qfalse; - fxParseRead( parse, FX_MASK_COLOR); - } else if (!Q_stricmp( buf, "blue")) { - if (!fxMathAppendHandler( parse, &val, &fxMathBlue)) - return qfalse; - fxParseRead( parse, FX_MASK_COLOR); - } else if (!Q_stricmp( buf, "alpha")) { - if (!fxMathAppendHandler( parse, &val, &fxMathAlpha)) - return qfalse; - fxParseRead( parse, FX_MASK_COLOR); - } else if (!Q_stricmp( buf, "life")) { - if ( !parse->emitter ) - return fxParseError( parse, "Can't access life outside of emitter" ); - if (!fxMathAppendHandler( parse, &val, &fxMathValue)) - return qfalse; - if (!fxMathAppendInt( parse, &val, runOfs( life ))) - return qfalse; - } else if (!Q_stricmp( buf, "lerp")) { - if ( !parse->emitter ) - return fxParseError( parse, "Can't access lerp outside of emitter" ); - if (!fxMathAppendHandler( parse, &val, &fxMathValue)) - return qfalse; - if (!fxMathAppendInt( parse, &val, runOfs( lerp ))) - return qfalse; - } else if (!Q_stricmp( buf, "loop")) { - if ( parse->loopDepth <= 0 ) - return fxParseError( parse, "Can't access loop outside of a loop" ); - if (!fxMathAppendHandler( parse, &val, &fxMathValue)) - return qfalse; - if (!fxMathAppendInt( parse, &val, runOfs( loop ))) - return qfalse; - } else { - int ofs; - unsigned int mask; - cvar_t *cv; - if (fxMatchFloat( buf, &ofs, &mask)) { - parse->readMask |= mask; - if (!fxMathAppendHandler( parse, &val, fxMathValue)) - return qfalse; - if (!fxMathAppendInt( parse, &val, ofs )) - return qfalse; - } else if (fxMatchVector( buf, &ofs, &mask)) { - parse->readMask |= mask; - if (!fxMathAppendHandler( parse, &val, fxMathLength)) - return qfalse; - if (!fxMathAppendInt( parse, &val, ofs )) - return qfalse; - } else if (fxParseParentValue( buf, &ofs)) { - parse->readMask |= FX_MASK_PARENT; - if (!fxMathAppendHandler( parse, &val, fxMathParent)) - return qfalse; - if (!fxMathAppendInt( parse, &val, ofs )) - return qfalse; - } else if ( (cv = Cvar_FindVar( buf )) ) { - if (!fxMathAppendHandler( parse, &val, &fxMathCvar)) - return qfalse; - if (!fxMathAppend( parse, &val, &cv, sizeof( cv ))) - return qfalse; - } else { - return fxParseError( parse, "math unknown word %s", buf ); - } - } - wordSize = 0; - } else { - if (wordSize >= sizeof( buf ) - 1) - return fxParseError( parse, "math too long word %s", buf ); - buf[wordSize++] = c; - line[0]++; - } - continue; - } - - switch (c) { - case '+': - case '-': - if ( parseType != mathParseLine ) { - if ( val.used ) - return fxMathAppendOut( parse, out, &val ); - if ( c == '-' && !fxMathAppendHandler( parse, out, fxMathNeg )) - return qfalse; - line[0]++; - return fxMathParse( parse, mathParseMul, line, 0, out ); - } - line[0]++; - if (!fxMathAppendHandler( parse, &val, c == '+' ? fxMathAdd : fxMathSub )) - return qfalse; - if (!fxMathAppendOut( parse, &val, in )) - return qfalse; - if (!fxMathParse( parse, mathParseMul, line, 0, &val )) - return qfalse; - return fxMathParse( parse, mathParseLine, line, &val, out ); - case '!': - case '<': - case '>': - case '=': - case '&': - case '|': - if ( parseType != mathParseLine ) { - if (!val.used ) - return fxParseError( parse, "Expected value before %c", c ); - return fxMathAppendOut( parse, out, &val ); - } - switch (c) { - case '&': - if ( line[0][1] == '&' ) - line[0]++; - tempHandler = fxMathAND; - break; - case '|': - if ( line[0][1] == '|' ) - line[0]++; - tempHandler = fxMathOR; - break; - case '<': - if ( line[0][1] == '=' ) { - line[0]++; - tempHandler = fxMathTSE; - } else { - tempHandler = fxMathTS; - } - break; - case '>': - if ( line[0][1] == '=' ) { - line[0]++; - tempHandler = fxMathTGE; - } else { - tempHandler = fxMathTG; - } - break; - case '!': - if ( line[0][1] == '=' ) { - line[0]++; - tempHandler = fxMathNotEqual; - } else { - tempHandler = fxMathTNE; - } - break; - case '=': - if ( line[0][1] == '=' ) { - line[0]++; - tempHandler = fxMathEqual; - } else { - tempHandler = fxMathTE; - } - break; - default: - return fxParseError( parse, "math unknown char '%c'", c ); - } - line[0]++; - if (!fxMathAppendHandler( parse, out, tempHandler )) - return qfalse; - if (!fxMathAppendOut( parse, out, in )) - return qfalse; - return fxMathParse( parse, mathParseLine, line, 0, out ); - case '*': - case '/': - if (!val.used) { - return fxParseError( parse, "math unexpected %c", c ); - } - if ( parseType != mathParseMul ) - return fxMathAppendOut( parse, out, &val ); - line[0]++; - if (!fxMathAppendHandler( parse, out, c == '*' ? fxMathMul : fxMathDiv )) - return qfalse; - if (!fxMathAppendOut( parse, out, &val )) - return qfalse; - return fxMathParse( parse, mathParseMul, line, 0, out ); - case '(': - if ( val.used || parseType == mathParseLine) - return fxParseError( parse, "math unexpected (" ); - line[0]++; - if (!fxMathParse( parse, mathParseLine, line, 0, &val )) - return qfalse; - if (line[0][0] != ')' ) - return fxParseError( parse, "math expected )" ); - line[0]++; - continue; - case ')': - if ( parseType == mathParseLine ) { - if (!in || !in->used ) - return fxParseError( parse, "math:unexpected )"); - return fxMathAppendOut( parse, out, in ); - } - return fxMathAppendOut( parse, out, &val ); - case 0: - if ( parseType == mathParseLine ) { - if (!in ) - return fxParseError( parse, "math empty line?" ); - return fxMathAppendOut( parse, out, in ); - } - if ( !val.used ) - return fxParseError( parse, "math expected some value" ); - return fxMathAppendOut( parse, out, &val ); - case ' ': - line[0]++; - continue; - default: - if ( val.used ) - return fxParseError( parse, "math unexpected char %c", c ); - buf[wordSize++] = c; - line[0]++; - continue; - } - //Final break that only reaches when we end this parse - break; - } - return qfalse; -} - -static qboolean fxParseMath( fxParse_t *parse, fxParseOut_t *out ) { - char buf[1024]; - int i; - const char *p; - char *line; - fxMathOut_t mathOut; - - p = parse->text; - parse->last = p; - i = 0; - - for( ;; p++ ) { - switch (*p) { - case '\n': - case '\r': - case '{': - case 0: - break; - case '"': - continue; - default: - if ( i > sizeof( buf) - 2) - break; - buf[i++] = *p; - continue; - } - break; - } - parse->text = p; - buf[i] = 0; - - line = buf; - mathOut.used = 0; - if (!fxMathParse( parse, mathParseLine, &line, 0, &mathOut )) - return qfalse; - if ( out->used + mathOut.used > out->size ) - return fxParseError( parse, "Overflowing output buffer" ); - memcpy( out->data + out->used, mathOut.data, mathOut.used ); - out->used += mathOut.used; - return qtrue; -} - -static qboolean fxParseStackName( fxParse_t *parse, int *ofs, int *count, unsigned int *mask ) { - - const char *token = parse->token; - if (!fxParseWord( parse , "stack name" )) - return qfalse; - - if ( fxMatchFloat( token, ofs, mask )) { - *count = 1; - return qtrue; - } else if ( fxMatchVector( token, ofs, mask )) { - if ( *mask & FX_MASK_PARENT ) - return fxParseError( parse, "Can't access parent value %s", token ); - *count = 3; - return qtrue; - } else if (!Q_stricmp( token, "color")) { - *ofs = runOfs( color ); - *count = runSize( color ); - *mask = FX_MASK_COLOR; - } else if (!Q_stricmp( token, "model")) { - *ofs = runOfs( model ); - *count = runSize( model ); - *mask = FX_MASK_MODEL; - } else if (!Q_stricmp( token, "shader")) { - *ofs = runOfs( shader ); - *count = runSize( shader ); - *mask = FX_MASK_SHADER; - } else { - return fxParseError( parse, "Unknown stack tag %s", token ); - } - return qtrue; -} - -static qboolean fxParseParentName( fxParse_t *parse, int *ofs, int *count ) { - const char *token = parse->token; - if (!fxParseWord( parse, "parentname" )) - return qfalse; - if (!Q_stricmp( token, "origin")) { - *ofs = parentOfs( origin ); - *count = parentSize( origin ); - } else if (!Q_stricmp( token, "velocity")) { - *ofs = parentOfs( velocity ); - *count = parentSize( velocity ); - } else if (!Q_stricmp( token, "dir")) { - *ofs = parentOfs( dir ); - *count = parentSize( dir ); - } else if (!Q_stricmp( token, "angles")) { - *ofs = parentOfs( angles ); - *count = parentSize( angles ); - } else if (!Q_stricmp( token, "shader")) { - *ofs = parentOfs( shader ); - *count = parentSize( shader ); - } else if (!Q_stricmp( token, "model")) { - *ofs = parentOfs( model ); - *count = parentSize( model ); - } else if (!Q_stricmp( token, "size")) { - *ofs = parentOfs( size ); - *count = parentSize( size ); - } else if (!Q_stricmp( token, "width")) { - *ofs = parentOfs( width ); - *count = parentSize( width ); - } else if (!Q_stricmp( token, "yaw")) { - *ofs = parentOfs( angles[YAW] ); - *count = parentSize( angles[YAW] ); - } else if (!Q_stricmp( token, "pitch")) { - *ofs = parentOfs( angles[PITCH] ); - *count = parentSize( angles[PITCH] ); - } else if (!Q_stricmp( token, "roll")) { - *ofs = parentOfs( angles[ROLL] ); - *count = parentSize( angles[ROLL] ); - } else if (!Q_stricmp( token, "angle")) { - *ofs = parentOfs( angles[ROLL] ); - *count = parentSize( angles[ROLL] ); - } else if (!Q_stricmp( token, "color")) { - *ofs = parentOfs( color ); - *count = parentSize( color ); - } else if (!Q_stricmp( token, "color2")) { - *ofs = parentOfs( color2 ); - *count = parentSize( color2 ); - } else { - return fxParseError( parse, "Unknown parent tag %s", token ); - } - return qtrue; -} - -static qboolean fxParseColorMathOut( fxParse_t *parse, fxParseOut_t *out, unsigned int index ) { - fxRunColorMath_t colorMath; - colorMath.index = index; - if (!fxParseOutCmd( parse, out, fxCmdColorMath, &colorMath, sizeof( colorMath ))) - return qfalse; - if (!fxParseMath( parse, out )) - return qfalse; - fxParseWrite( parse, FX_MASK_COLOR ); - return qtrue; -} - -static qboolean fxParseBlock( fxParse_t *parse, fxParseOut_t *out ); - -static qboolean fxParseIfBlock( fxParse_t *parse, fxParseOut_t *out ) { - int *blockSize = (int *)(out->data + out->used); - /* Store an int to contain the block size */ - if (!fxParseOut( parse, out, blockSize, sizeof( int ))) - return qfalse; - blockSize[0] = out->used; - if (!fxParseBlock( parse, out )) - return qfalse; - /* Store the blocksize in front of the block */ - blockSize[0] = out->used - blockSize[0]; - return qtrue; -} - -/* This is started up with a parsed token alread in the parse */ -static qboolean fxParseBlock( fxParse_t *parse, fxParseOut_t *out ) { - byte temp[1024]; - const char *token = parse->token; - - if (!fxParseToken( parse, qtrue )) { - return fxParseError( parse, "missing opening paranthesis" ); - } - if (Q_stricmp( token, "{" )) - return fxParseError( parse, "no opening paranthesis, got %s", token ); - - while ( 1 ) { - if (!fxParseToken( parse, qtrue )) { - return fxParseError( parse, "missing closing paranthesis" ); - } - if ( parse->emitter ) { - fxRunEmitter_t *emitter = parse->emitter; - if (!Q_stricmp( token, "moveGravity" ) ) { - if (!fxParseFloat( parse, &emitter->gravity )) - return qfalse; - emitter->flags |= FX_EMIT_MOVE; - continue; - } else if (!Q_stricmp( token, "moveBounce" ) ) { - if (!fxParseFloat( parse, &emitter->gravity )) - return qfalse; - if (!fxParseFloat( parse, &emitter->bounceFactor )) - return qfalse; - emitter->flags |= FX_EMIT_MOVE | FX_EMIT_TRACE; - continue; - } else if (!Q_stricmp( token, "impactDeath" ) ) { - if (!fxParseFloat( parse, &emitter->gravity )) - return qfalse; - emitter->flags |= FX_EMIT_MOVE | FX_EMIT_TRACE | FX_EMIT_IMPACT; - continue; - } else if (!Q_stricmp( token, "sink" ) ) { - if (!fxParseFloat( parse, &emitter->sinkDelay )) - return qfalse; - if (!fxParseFloat( parse, &emitter->sinkDepth )) - return qfalse; - //Scale the sinkdepth up for easy multiplying later - emitter->sinkDepth *= 1.0f / ( 1.0f - emitter->sinkDelay ); - emitter->flags |= FX_EMIT_MOVE | FX_EMIT_SINK; - continue; - } else if (!Q_stricmp( token, "impact" ) ) { - fxParseOut_t impactOut; - fxRunSkip_t *skip = (fxRunSkip_t *)temp; - - if (!fxParseFloat( parse, &emitter->impactSpeed )) - return qfalse; - - emitter->impactSpeed *= emitter->impactSpeed; - emitter->flags |= FX_EMIT_MOVE | FX_EMIT_TRACE; - - impactOut.data = temp; - impactOut.size = sizeof( temp ); - impactOut.used = sizeof( fxRunSkip_t ); - if (!fxParseBlock( parse, &impactOut )) - return qfalse; - skip->size = impactOut.used; - - emitter->impactRun = out->used + sizeof( void *) + sizeof( fxRunSkip_t ); - if (!fxParseOutCmd( parse, out, fxCmdSkip, skip, skip->size )) - return qfalse; - continue; - } else if (!Q_stricmp( token, "death" ) ) { - fxParseOut_t deathOut; - fxRunSkip_t *skip = (fxRunSkip_t *)temp; - - deathOut.data = temp; - deathOut.size = sizeof( temp ); - deathOut.used = sizeof( fxRunSkip_t ); - if (!fxParseBlock( parse, &deathOut )) - return qfalse; - skip->size = deathOut.used; - - emitter->deathRun = out->used + sizeof( void *) + sizeof( fxRunSkip_t ); - if (!fxParseOutCmd( parse, out, fxCmdSkip, skip, skip->size )) - return qfalse; - continue; - } - } - if (0) { - } else if (!Q_stricmp( token, "shaderClear" ) ) { - fxRunShader_t shader; - shader.shader = 0; - if (!fxParseOutCmd( parse, out, fxCmdShader, &shader, sizeof( shader ))) - return qfalse; - fxParseWrite( parse, FX_MASK_SHADER ); - } else if (!Q_stricmp( token, "shader" ) ) { - fxRunShader_t shader; - if (!fxParseWord( parse, "shadername" )) - return qfalse; - if (!fxMatchShader( parse, &shader.shader )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdShader, &shader, sizeof( shader ))) - return qfalse; - fxParseWrite( parse, FX_MASK_SHADER ); - } else if (!Q_stricmp( token, "model" ) ) { - fxRunModel_t model; - if (!fxParseWord( parse, "modelname" )) - return qfalse; - if (!fxMatchModel( parse, &model.model )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdModel, &model, sizeof( model ))) - return qfalse; - fxParseWrite( parse, FX_MASK_MODEL ); - } else if (!Q_stricmp( token, "sound" ) ) { - fxRunSound_t sound; - if (!fxParseWord( parse, "soundname" )) - return qfalse; - if (!fxMatchSound( parse, &sound.handle )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdSound, &sound, sizeof( sound ))) - return qfalse; - fxParseRead( parse, FX_MASK_ORIGIN ); - } else if (!Q_stricmp( token, "shaderList" ) ) { - fxRunShaderList_t *shaderList = (fxRunShaderList_t *)&temp; - fxParseOut_t shaderListOut; - - shaderListOut.data = temp; - shaderListOut.size = sizeof( temp ); - shaderListOut.used = sizeof( fxRunShaderList_t ); - if (!fxParseMath( parse, &shaderListOut )) - return qfalse; - if (!fxParseList( parse, "shaderList", fxMatchShader, sizeof (qhandle_t ), - temp + shaderListOut.used, - ( shaderListOut.size - shaderListOut.used ) / sizeof (qhandle_t ), - &shaderList->count )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdShaderList, temp, shaderListOut.used + shaderList->count * sizeof( qhandle_t ) )) - return qfalse; - fxParseWrite( parse, FX_MASK_SHADER ); - } else if (!Q_stricmp( token, "modelList" ) ) { - fxRunModelList_t *modelList = (fxRunModelList_t *)&temp; - fxParseOut_t modelListOut; - - modelListOut.data = temp; - modelListOut.size = sizeof( temp ); - modelListOut.used = sizeof( fxRunModelList_t ); - if (!fxParseMath( parse, &modelListOut )) - return qfalse; - if (!fxParseList( parse, "modelList", fxMatchModel, sizeof (qhandle_t ), - temp + modelListOut.used, - ( modelListOut.size - modelListOut.used ) / sizeof (qhandle_t ), - &modelList->count )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdModelList, temp, modelListOut.used + modelList->count * sizeof( qhandle_t ) )) - return qfalse; - fxParseWrite( parse, FX_MASK_MODEL ); - } else if (!Q_stricmp( token, "colorList" ) ) { - fxRunColorList_t *colorList = (fxRunColorList_t *)&temp; - fxParseOut_t colorListOut; - - colorListOut.data = temp; - colorListOut.size = sizeof( temp ); - colorListOut.used = sizeof( fxRunColorList_t ); - if (!fxParseMath( parse, &colorListOut )) - return qfalse; - if (!fxParseList( parse, "colorList", fxMatchColor, sizeof( color4ub_t ), - temp + colorListOut.used, - ( colorListOut.size - colorListOut.used ) / sizeof( color4ub_t ), - &colorList->count )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdColorList, temp, colorListOut.used + colorList->count * sizeof( color4ub_t ) )) - return qfalse; - fxParseWrite( parse, FX_MASK_COLOR ); - } else if (!Q_stricmp( token, "colorBlend" ) ) { - fxRunColorBlend_t *colorBlend = (fxRunColorBlend_t *)&temp; - fxParseOut_t colorBlendOut; - - colorBlendOut.data = temp; - colorBlendOut.size = sizeof( temp ); - colorBlendOut.used = sizeof( fxRunColorBlend_t ); - if (!fxParseMath( parse, &colorBlendOut )) - return qfalse; - if (!fxParseList( parse, "colorBlend", fxMatchColor, sizeof( color4ub_t ), - temp + colorBlendOut.used, - ( colorBlendOut.size - colorBlendOut.used ) / sizeof( color4ub_t ), - &colorBlend->count )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdColorBlend, temp, colorBlendOut.used + colorBlend->count * sizeof( color4ub_t ) )) - return qfalse; - fxParseWrite( parse, FX_MASK_COLOR ); - } else if (!Q_stricmp( token, "soundList" ) ) { - fxRunSoundList_t *soundList = (fxRunSoundList_t *)&temp; - if (!fxParseList( parse, "SoundList", fxMatchSound, sizeof( sfxHandle_t ), - soundList + 1, - (sizeof(temp) - sizeof( *soundList)) / sizeof( sfxHandle_t ), - &soundList->count )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdSoundList, temp, sizeof(soundList) + soundList->count * sizeof( sfxHandle_t ) )) - return qfalse; - fxParseRead( parse, FX_MASK_ORIGIN ); - } else if (!Q_stricmp( token, "loopSound" ) ) { - fxRunLoopSound_t loopSound; - if (!fxParseWord( parse, "Soundname" )) { - return qfalse; - } - loopSound.handle = S_RegisterSound( token, qfalse ); - if (!fxParseOutCmd( parse, out, fxCmdLoopSound, &loopSound, sizeof( loopSound ))) - return qfalse; - fxParseRead( parse, FX_MASK_ORIGIN | FX_MASK_VELOCITY ); - } else if (!Q_stricmp( token, "Sprite" ) ) { - fxRunRender_t runRender; - if (!fxParseRenderFX( parse, &runRender.renderfx )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdSprite, &runRender, sizeof( runRender ))) - return qfalse; - fxParseRead( parse, FX_MASK_ORIGIN | FX_MASK_COLOR | FX_MASK_ROTATE | FX_MASK_SHADER | FX_MASK_SIZE ); - } else if (!Q_stricmp( token, "Spark" ) ) { - fxRunRender_t runRender; - if (!fxParseRenderFX( parse, &runRender.renderfx )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdSpark, &runRender, sizeof( runRender ))) - return qfalse; - fxParseRead( parse, FX_MASK_ORIGIN | FX_MASK_VELOCITY | FX_MASK_COLOR | FX_MASK_SHADER | FX_MASK_SIZE | FX_MASK_WIDTH ); - } else if (!Q_stricmp( token, "Quad" ) ) { - fxRunRender_t runRender; - if (!fxParseRenderFX( parse, &runRender.renderfx )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdQuad, &runRender, sizeof( runRender ))) - return qfalse; - fxParseRead( parse, FX_MASK_ORIGIN | FX_MASK_COLOR | FX_MASK_ROTATE | FX_MASK_SHADER | FX_MASK_SIZE | FX_MASK_DIR ); - } else if (!Q_stricmp( token, "Beam" ) ) { - fxRunRender_t runRender; - if (!fxParseRenderFX( parse, &runRender.renderfx )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdBeam, &runRender, sizeof( runRender ))) - return qfalse; - fxParseRead( parse, FX_MASK_ORIGIN | FX_MASK_COLOR | FX_MASK_ROTATE | FX_MASK_SHADER | FX_MASK_SIZE | FX_MASK_DIR ); - } else if (!Q_stricmp( token, "Rings" ) ) { - fxRunRender_t runRender; - if (!fxParseRenderFX( parse, &runRender.renderfx )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdRings, &runRender, sizeof( runRender ))) - return qfalse; - fxParseRead( parse, FX_MASK_ORIGIN | FX_MASK_COLOR | FX_MASK_ROTATE | FX_MASK_SHADER | FX_MASK_SIZE | FX_MASK_WIDTH | FX_MASK_DIR ); - } else if (!Q_stricmp( token, "anglesModel" ) ) { - fxRunRender_t runRender; - if (!fxParseRenderFX( parse, &runRender.renderfx )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdAnglesModel, &runRender, sizeof( runRender ))) - return qfalse; - fxParseRead( parse, FX_MASK_ORIGIN | FX_MASK_COLOR | FX_MASK_SHADER | FX_MASK_SIZE | FX_MASK_ANGLES | FX_MASK_MODEL ); - } else if (!Q_stricmp( token, "axisModel" ) ) { - fxRunRender_t runRender; - if (!fxParseRenderFX( parse, &runRender.renderfx )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdAxisModel, &runRender, sizeof( runRender ))) - return qfalse; - fxParseRead( parse, FX_MASK_ORIGIN | FX_MASK_COLOR | FX_MASK_SHADER | FX_MASK_SIZE | FX_MASK_AXIS | FX_MASK_MODEL ); - } else if (!Q_stricmp( token, "dirModel" ) ) { - fxRunRender_t runRender; - if (!fxParseRenderFX( parse, &runRender.renderfx )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdDirModel, &runRender, sizeof( runRender ))) - return qfalse; - fxParseRead( parse, FX_MASK_ORIGIN | FX_MASK_COLOR | FX_MASK_SHADER | FX_MASK_SIZE | FX_MASK_DIR | FX_MASK_MODEL | FX_MASK_ROTATE ); - } else if (!Q_stricmp( token, "Light" ) ) { - if (!fxParseOutCmd( parse, out, fxCmdLight, 0, 0 )) - return qfalse; - fxParseRead( parse, FX_MASK_ORIGIN | FX_MASK_COLOR | FX_MASK_SIZE ); - } else if (!Q_stricmp( token, "Decal" ) ) { - fxRunDecal_t decal; - decal.flags = 0; - decal.life = 10000; - - while (fxParseToken( parse, qfalse ) ) { - if (!Q_stricmp(token, "temp")) { - decal.flags |= DECAL_TEMP; - } else if (!Q_stricmp(token, "alpha")) { - decal.flags |= DECAL_ALPHA; - } else if (!Q_stricmp(token, "energy")) { - decal.flags |= DECAL_ENERGY; - //Last one has to be a float life - } else { - if (!fxMatchValidFloat( parse )) - return qfalse; - decal.life = atof( token ) * 1000; - } - } - if ( decal.life <= 0 ) { - decal.life = 10000; - } - if (!fxParseOutCmd( parse, out, fxCmdDecal, &decal, sizeof( decal ))) - return qfalse; - fxParseRead( parse, FX_MASK_ORIGIN | FX_MASK_COLOR | FX_MASK_SIZE | FX_MASK_DIR ); - } else if (!Q_stricmp( token, "Trace" ) ) { - if (!fxParseOutCmd( parse, out, fxCmdTrace, 0, 0)) - return qfalse; - fxParseRead( parse, FX_MASK_ORIGIN | FX_MASK_DIR ); - fxParseWrite( parse, FX_MASK_ORIGIN | FX_MASK_DIR ); - } else if (!Q_stricmp( token, "vibrate" ) ) { - fxRunVibrate_t vibrate; - if (!fxParseFloat( parse, &vibrate.strength )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdVibrate, &vibrate, sizeof( vibrate ))) - return qfalse; - fxParseRead( parse, FX_MASK_ORIGIN ); - } else if (!Q_stricmp( token, "alphaFade" ) ) { - fxRunAlphaFade_t alphaFade; - if (!fxParseFloat( parse, &alphaFade.delay )) - return qfalse; - if ( alphaFade.delay < 0 || alphaFade.delay >= 1.0f ) - return fxParseError( parse, "Fade value %f illegal", alphaFade.delay ); - alphaFade.scale = -255.0f / (1.0f - alphaFade.delay ); - if (!fxParseOutCmd( parse, out, fxCmdAlphaFade, &alphaFade, sizeof( alphaFade ))) - return qfalse; - fxParseRead( parse, FX_MASK_COLOR ); - fxParseWrite( parse, FX_MASK_COLOR ); - } else if (!Q_stricmp( token, "color" ) ) { - fxRunColor_t color; - if (!fxParseColor( parse, color.value )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdColor, &color, sizeof( color ))) - return qfalse; - fxParseWrite( parse, FX_MASK_COLOR ); - } else if (!Q_stricmp( token, "colorFade" ) ) { - fxRunColorFade_t colorFade; - if (!fxParseFloat( parse, &colorFade.delay )) - return qfalse; - if ( colorFade.delay < 0 || colorFade.delay >= 1.0f ) - return fxParseError( parse, "Fade value %f illegal", colorFade.delay ); - colorFade.scale = -255.0f / (1.0f - colorFade.delay ); - if (!fxParseOutCmd( parse, out, fxCmdColorFade, &colorFade, sizeof( colorFade ))) - return qfalse; - fxParseRead( parse, FX_MASK_COLOR ); - fxParseWrite( parse, FX_MASK_COLOR ); - } else if (!Q_stricmp( token, "colorScale" ) ) { - if (!fxParseOutCmd( parse, out, fxCmdColorScale, 0, 0 )) - return qfalse; - if (!fxParseMath( parse, out )) - return qfalse; - fxParseRead( parse, FX_MASK_COLOR ); - fxParseWrite( parse, FX_MASK_COLOR ); - } else if (!Q_stricmp( token, "colorHue" ) ) { - if (!fxParseOutCmd( parse, out, fxCmdColorHue, 0, 0)) - return qfalse; - if (!fxParseMath( parse, out )) - return qfalse; - fxParseWrite( parse, FX_MASK_COLOR ); - } else if (!Q_stricmp( token, "red" ) ) { - if (!fxParseColorMathOut( parse, out, 0 )) - return qfalse; - } else if (!Q_stricmp( token, "green" ) ) { - if (!fxParseColorMathOut( parse, out, 1 )) - return qfalse; - } else if (!Q_stricmp( token, "blue" ) ) { - if (!fxParseColorMathOut( parse, out, 2 )) - return qfalse; - } else if (!Q_stricmp( token, "alpha" ) ) { - if (!fxParseColorMathOut( parse, out, 3 )) - return qfalse; - } else if (!Q_stricmp( token, "wobble" ) ) { - fxRunWobble_t wobble; - - if (!fxParseVectorRead( parse, &wobble.src )) - return qfalse; - if (!fxParseVectorWrite( parse, &wobble.dst )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdWobble, &wobble, sizeof( wobble ))) - return qfalse; - if (!fxParseMath( parse, out )) - return qfalse; - } else if (!Q_stricmp( token, "makeAngles" ) ) { - fxRunMakeAngles_t makeAngles; - - if (!fxParseVectorRead( parse, &makeAngles.src )) - return qfalse; - makeAngles.dst = makeAngles.src; - if (!fxParseVectorOptional( parse, &makeAngles.dst )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdMakeAngles, &makeAngles, sizeof( makeAngles ))) - return qfalse; - } else if (!Q_stricmp( token, "inverse" ) ) { - fxRunInverse_t inverse; - - if (!fxParseVectorRead( parse, &inverse.src )) - return qfalse; - inverse.dst = inverse.src; - fxParseVectorOptional( parse, &inverse.dst ); - if (!fxParseOutCmd( parse, out, fxCmdInverse, &inverse, sizeof( inverse ))) - return qfalse; - } else if (!Q_stricmp( token, "normalize" ) ) { - fxRunNormalize_t normalize; - - if (!fxParseVectorRead( parse, &normalize.src )) - return qfalse; - normalize.dst = normalize.src; - fxParseVectorOptional( parse, &normalize.dst ); - if (!fxParseOutCmd( parse, out, fxCmdNormalize, &normalize, sizeof( normalize ))) - return qfalse; - } else if (!Q_stricmp( token, "perpendicular" ) ) { - fxRunPerpendicular_t perpendicular; - - if (!fxParseVectorRead( parse, &perpendicular.src )) - return qfalse; - perpendicular.dst = perpendicular.src; - fxParseVectorOptional( parse, &perpendicular.dst ); - if (!fxParseOutCmd( parse, out, fxCmdPerpendicular, &perpendicular, sizeof( perpendicular ))) - return qfalse; - } else if (!Q_stricmp( token, "clear" ) ) { - fxRunClear_t clear; - if (!fxParseVectorWrite( parse, &clear.dst )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdClear, &clear, sizeof( clear ))) - return qfalse; - } else if (!Q_stricmp( token, "copy" ) ) { - fxRunCopy_t copy; - if (!fxParseVectorRead( parse, ©.src )) - return qfalse; - if (!fxParseVectorWrite( parse, ©.dst )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdCopy, ©, sizeof( copy ))) - return qfalse; - } else if (!Q_stricmp( token, "scale" ) ) { - fxRunScale_t scale; - - if (!fxParseVectorRead( parse, &scale.src )) - return qfalse; -// scale.dst = scale.src; - if (!fxParseVectorWrite( parse, &scale.dst )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdScale, &scale, sizeof( scale ))) - return qfalse; - if (!fxParseMath( parse, out )) - return qfalse; - } else if (!Q_stricmp( token, "add" ) ) { - fxRunAdd_t add; - - if (!fxParseVectorRead( parse, &add.src1 )) - return qfalse; - if (!fxParseVectorRead( parse, &add.src2 )) - return qfalse; - if (!fxParseVectorWrite( parse, &add.dst )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdAdd, &add, sizeof( add ))) - return qfalse; - } else if (!Q_stricmp( token, "sub" ) ) { - fxRunSub_t sub; - - if (!fxParseVectorRead( parse, &sub.src1 )) - return qfalse; - if (!fxParseVectorRead( parse, &sub.src2 )) - return qfalse; - if (!fxParseVectorWrite( parse, &sub.dst )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdSub, &sub, sizeof( sub ))) - return qfalse; - } else if (!Q_stricmp( token, "addScale" ) ) { - fxRunAddScale_t addScale; - - if (!fxParseVectorRead( parse, &addScale.src )) - return qfalse; - if (!fxParseVectorRead( parse, &addScale.scale )) - return qfalse; - if (!fxParseVectorWrite( parse, &addScale.dst )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdAddScale, &addScale, sizeof( addScale ))) - return qfalse; - if (!fxParseMath( parse, out )) - return qfalse; - } else if (!Q_stricmp( token, "subScale" ) ) { - fxRunSubScale_t subScale; - - if (!fxParseVectorRead( parse, &subScale.src )) - return qfalse; - if (!fxParseVectorRead( parse, &subScale.scale )) - return qfalse; - if (!fxParseVectorWrite( parse, &subScale.dst )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdSubScale, &subScale, sizeof( subScale ))) - return qfalse; - if (!fxParseMath( parse, out )) - return qfalse; - } else if (!Q_stricmp( token, "rotateAround" ) ) { - fxRunRotateAround_t rotateAround; - - if (!fxParseVectorRead( parse, &rotateAround.src )) - return qfalse; - if (!fxParseVectorRead( parse, &rotateAround.dir )) - return qfalse; - if (!fxParseVectorWrite( parse, &rotateAround.dst )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdRotateAround, &rotateAround, sizeof( rotateAround ))) - return qfalse; - if (!fxParseMath( parse, out )) - return qfalse; - } else if (!Q_stricmp( token, "random" ) ) { - fxRunRandom_t random; - if (!fxParseVectorWrite( parse, &random.dst )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdRandom, &random, sizeof( random ))) - return qfalse; - } else if (!Q_stricmp( token, "kill" ) ) { - if (!fxParseOutCmd( parse, out, fxCmdKill, 0, 0 )) - return qfalse; - } else if (!Q_stricmp( token, "emitter" ) || !Q_stricmp( token, "entity" )) { - fxRunEmitter_t *oldEmitter; - fxRunEmitter_t *newEmitter = (fxRunEmitter_t *)temp; - fxParseOut_t emitterOut; - unsigned oldReadMask, oldWriteMask, newReadMask; - int oldLoopDepth; - - memset( newEmitter, 0, sizeof( fxRunEmitter_t ) ); - - emitterOut.data = temp; - emitterOut.size = sizeof( temp ); - emitterOut.used = sizeof( fxRunEmitter_t ); - if (!fxParseMath( parse, &emitterOut )) - return qfalse; - newEmitter->emitRun = emitterOut.used; - oldEmitter = parse->emitter; - oldReadMask = parse->readMask; - oldWriteMask = parse->writeMask; - oldLoopDepth = parse->loopDepth; - - parse->emitter = newEmitter; - parse->loopDepth = 0; - parse->readMask = 0; - parse->writeMask = 0; - if (!fxParseBlock( parse, &emitterOut )) - return qfalse; - //Create copy table and extra size requirements - if (!fxParseCreateMask( parse, newEmitter->mask, sizeof( newEmitter->mask ), &newEmitter->allocSize )) - return qfalse; - newEmitter->allocSize += sizeof( fxEntity_t ); - newEmitter->size = emitterOut.used; - //Emitters only read, restore the rest of the previous version - newReadMask = parse->readMask; - parse->readMask = oldReadMask; - parse->writeMask = oldWriteMask; - parse->loopDepth = oldLoopDepth; - //forward readmask to caller - fxParseRead( parse, newReadMask ); - parse->emitter = oldEmitter; - if (!fxParseOutCmd( parse, out, fxCmdEmitter, newEmitter, emitterOut.used )) - return qfalse; - - } else if (!Q_stricmp( token, "interval" ) ) { - fxRunInterval_t *Interval = (fxRunInterval_t *)temp; - fxParseOut_t intervalOut; - - parse->loopDepth++; - intervalOut.data = temp; - intervalOut.size = sizeof( temp ); - intervalOut.used = sizeof( fxRunInterval_t ); - if (!fxParseMath( parse, &intervalOut )) - return qfalse; - if (!fxParseBlock( parse, &intervalOut )) - return qfalse; - Interval->size = intervalOut.used; - if (!fxParseOutCmd( parse, out, fxCmdInterval, Interval, intervalOut.used )) - return qfalse; - parse->loopDepth--; - - } else if (!Q_stricmp( token, "repeat" ) ) { - fxRunRepeat_t *repeat = (fxRunRepeat_t *)temp; - fxParseOut_t repeatOut; - - repeatOut.data = temp; - repeatOut.size = sizeof( temp ); - repeatOut.used = sizeof( fxRunRepeat_t ); - parse->loopDepth++; - if (!fxParseMath( parse, &repeatOut )) - return qfalse; - if (!fxParseBlock( parse, &repeatOut )) - return qfalse; - repeat->size = repeatOut.used; - if (!fxParseOutCmd( parse, out, fxCmdRepeat, repeat, repeatOut.used )) - return qfalse; - parse->loopDepth--; - } else if (!Q_stricmp( token, "distance" ) ) { - fxRunDistance_t *distance = (fxRunDistance_t *)temp; - fxParseOut_t distanceOut; - - parse->loopDepth++; - distanceOut.data = temp; - distanceOut.size = sizeof( temp ); - distanceOut.used = sizeof( fxRunDistance_t ); - if (!fxParseMath( parse, &distanceOut )) - return qfalse; - if (!fxParseBlock( parse, &distanceOut )) - return qfalse; - distance->size = distanceOut.used; - if (!fxParseOutCmd( parse, out, fxCmdDistance, distance, distanceOut.used )) - return qfalse; - parse->loopDepth--; - fxParseRead( parse, FX_MASK_ORIGIN ); - } else if (!Q_stricmp( token, "if" ) ) { - fxRunIf_t *doIf = (fxRunIf_t *)temp; - fxParseOut_t ifOut; - - doIf->testCount = 1; - doIf->elseStep = 0; - ifOut.data = temp; - ifOut.size = sizeof( temp ); - ifOut.used = sizeof( fxRunIf_t ); - if (!fxParseMath( parse, &ifOut )) - return qfalse; - if (!fxParseIfBlock( parse, &ifOut )) - return qfalse; - while (1) { - if (!fxParseToken( parse, qfalse )) - break; - if (!Q_stricmp( token, "elif")) { - doIf->testCount += 1; - if (!fxParseMath( parse, &ifOut )) - return qfalse; - if (!fxParseIfBlock( parse, &ifOut )) - return qfalse; - } else if (!Q_stricmp( token, "else" )) { - doIf->elseStep = qtrue; - if (!fxParseBlock( parse, &ifOut )) - return qfalse; - break; - } - } - /* Calculate the total size for the final exit */ - doIf->size = ifOut.used; - if (!fxParseOutCmd( parse, out, fxCmdIf, doIf, ifOut.used )) - return qfalse; - } else if (!Q_stricmp( token, "once" ) ) { - fxRunOnce_t *once = (fxRunOnce_t *)temp; - fxParseOut_t onceOut; - - onceOut.data = temp; - onceOut.size = sizeof( temp ); - onceOut.used = sizeof( fxRunOnce_t ); - if (!fxParseBlock( parse, &onceOut )) - return qfalse; - once->size = onceOut.used; - if (!fxParseOutCmd( parse, out, fxCmdOnce, once, onceOut.used )) - return qfalse; - } else if (!Q_stricmp( token, "pushParent" ) ) { - fxRunPushParent_t push; - if (!fxParseParentName( parse, &push.offset, &push.count )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdPushParent, &push, sizeof( push ))) - return qfalse; - fxParseRead( parse, FX_MASK_PARENT ); - } else if (!Q_stricmp( token, "push" ) ) { - int mask; - fxRunPush_t push; - if (!fxParseStackName( parse, &push.offset, &push.count, &mask )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdPush, &push, sizeof( push ))) - return qfalse; - fxParseRead( parse, mask ); - } else if (!Q_stricmp( token, "pop" ) ) { - int mask; - fxRunPop_t pop; - - if (!fxParseStackName( parse, &pop.offset, &pop.count, &mask )) - return qfalse; - if (!fxParseOutCmd( parse, out, fxCmdPop, &pop, sizeof( pop ))) - return qfalse; - fxParseWrite( parse, mask ); - } else if (!Q_stricmp( token, "script" ) ) { - fxRunScript_t script; - fxScript_t *loadScript; - - if (!fxParseWord( parse, "scriptname" )) - return qfalse; - loadScript = fxFindScript( token ); - if (!loadScript ) - return fxParseError( parse, "Can't load script %s", token ); - script.data = loadScript->data; - fxParseRead( parse, loadScript->readMask ); - if (!fxParseOutCmd( parse, out, fxCmdScript, &script, sizeof( script ))) - return qfalse; - } else if (!Q_stricmp( token, "}" ) ) { - if (!fxParseOutCmd( parse, out, 0, 0, 0 )) - return qfalse; - return qtrue; - } else { - unsigned int mask; - fxRunValue_t value; - if (fxMatchFloat( token, &value.dst, &mask)) { - if (!fxParseOutCmd( parse, out, fxCmdValue, &value, sizeof( value ) )) - return qfalse; - if (!fxParseMath( parse, out )) - return qfalse; - fxParseWrite( parse, mask ); - } else { - return fxParseError( parse, "Unknown token %s", parse->token ); - } - } - } - return qfalse; -} - -static fxScript_t *fxParseScript( fxHashEntry_t *entry ) { - fxParse_t parse; - fxParseOut_t parseOut; - fxScript_t *script; - char parseData[ 32*1024]; - byte *allocBuf; - int allocSize; - - /* Check if this one has already been loaded */ - if ( entry->script ) - return entry->script; - - if ( fx.scriptCount >= FX_MAX_SCRIPTS ) { - Com_Printf( "fx script limit reached" ); - return 0; - } - - /* Prepare variables for parsing the text */ - memset( &parse, 0, sizeof( parse )); - parse.text = entry->text; - parse.name = entry->name; - - parseOut.data = parseData; - parseOut.used = 0; - parseOut.size = sizeof( parseData ); - - if (!fxParseBlock( &parse, &parseOut )) - return 0; - - /* Allocate the script struct and set it up */ - allocSize = parseOut.used + sizeof( fxScript_t ); - allocBuf = fxParseAlloc( allocSize ); - script = (fxScript_t *) allocBuf; - script->remap = 0; - script->readMask = parse.readMask; - Com_Memcpy( &script->data, parseOut.data, parseOut.used ); - entry->script = script; - script->entry = entry; - /* Register script in table an increase scriptcount */ - fx.scripts[ fx.scriptCount ] = script; - script->handle = fx.scriptCount; - fx.scriptCount++; - return script; -} - - -#define SCAN_ENTRIES 256 -typedef struct fxScanBlock_s { - fxHashEntry_t entries[SCAN_ENTRIES]; - int entriesUsed; - struct fxScanBlock_s *next; -} fxScanBlock_t; - -static char *scanSkipSpaces( char *p ) { - for (;*p;p++) - if ((*p != ' ') && (*p != '\t') && (*p != '\n')) - break; - return p; -} -/* This will modify the original string */ -static char *scanMakeWord( char **input ) { - char *ret; - char *p = *input; - - p = scanSkipSpaces( p ); - ret = p; - for (;*p;p++) { - if (*p == ' ' || *p == '\t' || *p == '\n') { - *p++ = 0; - break; - } - } - *input = p; - return ret; -} - -static char *scanMakeSection( char **input ) { - char *ret; - char *p = *input; - int braceDepth = 1; - - p = scanSkipSpaces( p ); - if ( p[0] != '{') - return 0; - ret = p; - p++; - for (;*p;p++) { - if ( p[0] == '{') { - braceDepth++; - } else if ( p[0] == '}') { - braceDepth--; - if (!braceDepth) { - if (p[1]) { - p[1] = 0; - p+=2; - } else { - p += 1; - } - break; - } - } - } - if ( braceDepth ) - return 0; - *input = p; - return ret; -} - -static int scanCopyString( char *dst, const char *src, int left ) { - int done = 0; - if ( left <= 0) - return 0; - while (left > 1 && src[done]) { - dst[done] = src[done]; - done++; - left--; - } - dst[done] = 0; - done++; - return done; -} - -static void fxScanDir( const char *dirName, void **buffers, int *numFiles) { - int i, dirFiles; - char **fxFiles; - - fxFiles = FS_ListFiles( "scripts", ".fx", &dirFiles ); - - // load the files first time - for ( i = 0; i < dirFiles; i++ ) { - char filename[MAX_QPATH]; - if (*numFiles >= FX_MAX_SCRIPTS) { - Com_Error( ERR_DROP, "Too many .fx files" ); - } - Com_sprintf( filename, sizeof( filename ), "%s/%s", dirName, fxFiles[i] ); - FS_ReadFile( filename, &buffers[numFiles[0]] ); - numFiles[0]++; - } - FS_FreeFileList( fxFiles ); -} - -static void *emptyScript[2]; -static void fxScanFiles( void ) { - char *buffers[FX_MAX_SCRIPTS]; - int numFiles; - int allocSize; - int i; - fxHashEntry_t *entryWrite; - int entrySize, nameSize, textSize; - char *allocBuf, *nameWrite, *textWrite; - fxScanBlock_t *scanBlock = 0; - fxHashEntry_t *tempHash[FX_HASH_SIZE]; - - /* Clear some stuff just to be safe */ - fx.alloc.entries = 0; - memset( fx.scripts, 0, sizeof( fx.scripts )); - memset( fx.entryHash, 0, sizeof( fx.entryHash )); - /* Init the default handle for an invalid/empty script*/ - fx.scripts[0] = (fxScript_t *)emptyScript; - fx.scriptCount = 1; - // scan for FX files - Com_Memset( tempHash, 0, sizeof( tempHash )); - numFiles = 0; - fxScanDir( "scripts", buffers, &numFiles ); - if ( fx_Override->string[0] ) { - int i; - Cmd_TokenizeString( fx_Override->string ); - for( i=0; inext ) { - if ( Q_stricmp( entry->name, name )) - continue; - /* Override the current entry */ - entry->name = name; - entry->text = section; - break; - } - /* Didn't find an entry, add a new one */ - if (!entry) { - /* Get an entry from the block */ - if ( !scanBlock || scanBlock->entriesUsed == SCAN_ENTRIES) { - fxScanBlock_t *newBlock = Hunk_AllocateTempMemory( sizeof( fxScanBlock_t )); - newBlock->entriesUsed = 0; - newBlock->next = scanBlock; - scanBlock = newBlock; - } - entry = &scanBlock->entries[scanBlock->entriesUsed++]; - entry->name = name; - entry->text = section; - entry->next = tempHash[hashIndex]; - tempHash[hashIndex] = entry; - } - } - } - /* Scan through our hash and determine allocation sizes */ - nameSize = 0; textSize = 0; entrySize = 0; - allocSize = 0; - for ( i = 0; i < FX_HASH_SIZE; i++) { - fxHashEntry_t *entry; - for (entry = tempHash[i]; entry; entry = entry->next ) { - entrySize += sizeof( fxHashEntry_t ); - nameSize += strlen( entry->name ) + 1; - textSize += strlen( entry->text ) + 1; - } - } - /* List of entries in front, then all the names, then all the text */ - allocBuf = (char*) fxParseAlloc( entrySize + nameSize + textSize ); - fx.alloc.entries = (fxHashEntry_t*)allocBuf; - entryWrite = fx.alloc.entries; - nameWrite = allocBuf + entrySize; - textWrite = allocBuf + entrySize + nameSize; - /* Silly overkill to ensure that names are read linearly, oh well */ - for ( i = 0; i < FX_HASH_SIZE; i++) { - fxHashEntry_t *entry, *newEntry, *startEntry; - newEntry = 0; - startEntry = entryWrite; - for (entry = tempHash[i]; entry; entry = entry->next ) { - int len; - newEntry = entryWrite++; - - memset( newEntry, 0, sizeof (*newEntry)); - newEntry->next = entryWrite; - - newEntry->name = nameWrite; - len = scanCopyString( nameWrite, entry->name, nameSize ); - nameSize -= len; nameWrite += len; - - newEntry->text = textWrite; - len = scanCopyString( textWrite, entry->text, textSize ); - textSize -= len; textWrite += len; - } - if ( newEntry ) { - fx.entryHash[i] = startEntry; - newEntry->next = 0; - } - } - /* Free all allocated memory in the good order hopefully */ - while (scanBlock) { - fxScanBlock_t *next = scanBlock->next; - Hunk_FreeTempMemory( scanBlock ); - scanBlock = next; - } - for ( i = numFiles-1; i >=0; i-- ) - FS_FreeFile( buffers[i] ); -} - -static fxScript_t *fxFindScript( const char *name ) { - unsigned int hashIndex; - fxHashEntry_t *entry; - if (!name) - return 0; - - hashIndex = fxGenerateHash( name ); - for ( entry = fx.entryHash[ hashIndex ]; entry; entry = entry->next ) { - if (!Q_stricmp( entry->name, name )) { - return fxParseScript( entry ); - } - } - return 0; -} - -fxHandle_t FX_Register( const char *name ) { - const fxScript_t *script; - script = fxFindScript( name ); - if ( fx_Debug->integer ) { - Com_Printf( "FX_Debug:Registering script %s, %s\n", name, script ? "success" : "failed" ); - } - if ( script ) - return script->handle; - return 0; -} - -static void fxRemap( void ) { - const char *map1, *map2; - fxScript_t *script1, *script2; - - if ( Cmd_Argc() < 1 ) { - Com_Printf("fxRemap oldScript newScript, will replace oldscript with new one\n" ); - Com_Printf("fxRemap oldScript, will reset the remap\n" ); - return; - } - map1 = Cmd_Argv( 1 ); - script1 = fxFindScript( map1 ); - if (!script1) { - Com_Printf( "fxScript %s not found\n", map1 ); - return; - } - if ( Cmd_Argc() > 2) { - map2 = Cmd_Argv( 2 ); - script2 = fxFindScript( map2 ); - if (!script2) { - Com_Printf( "fxScript %s not found\n", map2 ); - return; - } - script1->remap = script2; - Com_Printf("Remapped %s to %s", script1->entry->name, script2->entry->name ); - } else { - Com_Printf("Cleared remapping on script %s", script1->entry->name ); - script1->remap = 0; - } -} - -static void fxReload( void ) { - fxScript_t *scripts[FX_MAX_SCRIPTS]; - fxHashEntry_t *entries = fx.alloc.entries; - fxHashEntry_t *entryHash[FX_HASH_SIZE]; - int scriptCount; - int i; - - FX_Reset(); - - scriptCount = fx.scriptCount; - for ( i = 1; i < scriptCount;i++ ) { - scripts[i] = fx.scripts[i]; - fx.scripts[i] = 0; - } - for ( i = 0; i < FX_HASH_SIZE;i++ ) { - entryHash[i] = fx.entryHash[i]; - fx.entryHash[i] = 0; - } - fx.alloc.entries = 0; - /* Rescan all the files */ - fxScanFiles(); - /* Reload all the scripts in the same order */ - for (i = 1; i < scriptCount;i++ ) { - int c; - const char *name = scripts[i]->entry->name; - fxScript_t *load = fxFindScript( name ); - if ( load && load->handle == i ) - continue; - if (!load) - Com_Printf( "Failed to reload scripts %s\n", name ); - else - Com_Printf( "Script %s doesn't reload in the right handle\n", name ); - - /* Restore the old stuff and free the new stuff */ - for ( c = 1; c < fx.scriptCount; c++ ) - fxParseFree( fx.scripts[c] ); - fxParseFree( fx.alloc.entries ); - fx.scriptCount = scriptCount; - for ( c = 1; c < scriptCount; c++ ) - fx.scripts[c] = scripts[c]; - for ( c = 0; c< FX_HASH_SIZE; c++ ) - fx.entryHash[c] = entryHash[c]; - fx.alloc.entries = entries; - return; - } - /* Free the old stuff */ - for ( i = 1; i < scriptCount; i++ ) - fxParseFree( scripts[i] ); - fxParseFree( entries ); -} - - -static void fxMathTest( void ) { - char line[1024]; - char *lineP = line; - fxMathOut_t mathOut; - fxParse_t parse; - fxRun_t run; - - memset( &parse, 0, sizeof( parse )); - memset( &mathOut, 0, sizeof( mathOut )); - memset( &run, 0, sizeof( run )); - - Q_strncpyz( line, Cmd_ArgsFrom( 1 ), sizeof( line ) ); - if ( fxMathParse( &parse, mathParseLine, &lineP, 0, &mathOut ) ) { - fxMathInfo_t info; - info.data = (int *)mathOut.data; - info.run = &run; - Com_Printf( "result %f\n", fxMath( &info) ); - } -} - -void fxFreeMemory( void ) { - int i; - for ( i = 1; i < fx.scriptCount; i++ ) { - fxParseFree( fx.scripts[i] ); - fx.scripts[i] = 0; - } - fx.scriptCount = 0; - if ( fx.alloc.entries ) - fxParseFree( fx.alloc.entries ); - fx.alloc.entries = 0; -} - -void fxInitParser( void ) { - fxScanFiles(); - Cmd_AddCommand( "fxReload", fxReload ); - Cmd_AddCommand( "fxRemap", fxRemap ); - Cmd_AddCommand( "fxMath", fxMathTest ); -} - diff --git a/code/client/fx_public.h b/code/client/fx_public.h deleted file mode 100644 index 01bdce17df..0000000000 --- a/code/client/fx_public.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2006 Sjoerd van der Berg ( harekiet @ gmail.com ) - -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 -=========================================================================== -*/ -// fx_public.h -- public fx definitions - -#include "fx_types.h" - -void FX_Init( void ); -void FX_Shutdown( void ); -fxHandle_t FX_Register( const char *name ); - -void FX_Debug( void ); -void FX_Reset( void ); -void FX_Begin( int time, float fraction ); -void FX_End( void ); -void FX_Run( fxHandle_t handle, const fxParent_t *parent, unsigned int key ); -void FX_VibrateView( float scale, vec3_t origin, vec3_t angles ); diff --git a/code/client/fx_types.h b/code/client/fx_types.h deleted file mode 100644 index 92547cd70a..0000000000 --- a/code/client/fx_types.h +++ /dev/null @@ -1,51 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2006 Sjoerd van der Berg ( harekiet @ gmail.com ) - -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 -=========================================================================== -*/ -// fx_types.h -- shared fx types -typedef int fxHandle_t; - -#define FXP_ORIGIN 0x0001 -#define FXP_VELOCITY 0x0002 -#define FXP_DIR 0x0004 -#define FXP_ANGLES 0x0008 -#define FXP_SIZE 0x0010 -#define FXP_WIDTH 0x0020 -#define FXP_COLOR 0x0040 -#define FXP_SHADER 0x0080 -#define FXP_MODEL 0x0100 -#define FXP_AXIS 0x0200 -#define FXP_LIFE 0x0400 - -typedef struct { - int flags; - vec3_t origin; - vec3_t velocity; - vec3_t dir; - color4ub_t color; - qhandle_t shader; - float life; - float size; - float width; - qhandle_t model; - vec3_t angles; - vec3_t axis[3]; - color4ub_t color2; -} fxParent_t; diff --git a/code/renderer_oa/tr_bsp.c b/code/renderer_oa/tr_bsp.c index 394d0b04f8..224cfc4fb5 100644 --- a/code/renderer_oa/tr_bsp.c +++ b/code/renderer_oa/tr_bsp.c @@ -119,7 +119,6 @@ static void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) { if ( ( r | g | b ) > 255 ) { int max; - int gmr, gmg, gmb; max = r > g ? r : g; max = max > b ? max : b; r = r * 255 / max; @@ -134,7 +133,6 @@ static void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) { g += invader; b += invader; - // Normalize... again!!! max = r > g ? r : g; diff --git a/code/renderer_oa/tr_extensions.c b/code/renderer_oa/tr_extensions.c index a63bc0a3b7..150d660909 100644 --- a/code/renderer_oa/tr_extensions.c +++ b/code/renderer_oa/tr_extensions.c @@ -126,6 +126,7 @@ typedef enum { int softwaremode; // leilei - detect for software mode int voodootype; // leilei - detect for voodoo revision +char extensions_string_full [BIG_INFO_STRING]; // leilei - gl extensions crash workaround /** From renderer_opengl2 (v28) */ static qboolean GLimp_HaveExtension(const char *ext) @@ -331,6 +332,11 @@ void GLimp_InitExtraExtensions() Q_strncpyz( buf, glConfig.renderer_string, sizeof(buf) ); Q_strlwr( buf ); + // leilei - we are done with our extensions string, if it's too long we can just trim it so we won't hardlock old qvms with an overflow. + Q_strncpyz( extensions_string_full, (char *) qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) ); // copy to a global for gfxinfo + char butt[640]; + Q_strncpyz( glConfig.extensions_string, (char *) qglGetString (GL_EXTENSIONS), sizeof( butt ) ); + // // this is where hardware specific workarounds that should be diff --git a/code/renderer_oa/tr_init.c b/code/renderer_oa/tr_init.c index 4608cb240e..66493b08ee 100644 --- a/code/renderer_oa/tr_init.c +++ b/code/renderer_oa/tr_init.c @@ -1013,7 +1013,7 @@ void GfxInfo_f( void ) ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glConfig.renderer_string ); ri.Printf( PRINT_ALL, "GL_VERSION: %s\n", glConfig.version_string ); ri.Printf( PRINT_ALL, "GL_EXTENSIONS: " ); - R_PrintLongString( glConfig.extensions_string ); + R_PrintLongString( extensions_string_full );//R_PrintLongString( glConfig.extensions_string ); // leilei - gl extensions crash workaround ri.Printf( PRINT_ALL, "\n" ); ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_SIZE: %d\n", glConfig.maxTextureSize ); ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_UNITS_ARB: %d\n", glConfig.numTextureUnits ); diff --git a/code/renderer_oa/tr_local.h b/code/renderer_oa/tr_local.h index 2b345f3a62..f1c883d487 100644 --- a/code/renderer_oa/tr_local.h +++ b/code/renderer_oa/tr_local.h @@ -2337,5 +2337,7 @@ void R_LFX_Blood (const vec3_t org, const vec3_t dir, float pressure) ; void LFX_ShaderInit(void); void LFX_ParticleEffect (int effect, const vec3_t org, const vec3_t dir); +extern char extensions_string_full [BIG_INFO_STRING]; // leilei - gl extensions crash workaround + #endif //TR_LOCAL_H From 7749e7dcaeda444c43ee48485575f9403c511e6c Mon Sep 17 00:00:00 2001 From: leilei- Date: Thu, 17 Apr 2025 22:34:40 -0400 Subject: [PATCH 12/20] Some renderer refactor and cleanup - r_shadeMethod : 0/1 = q3 behavior, 2 = ue1-ish behavior, 3 = mix of 1 and 2, -1 = one uniform color, 150-666 = a lod range to change between the 3 - r_monolightmaps : refactor - goes to the light data instead of the calculations and images - removed r_greyscale because this is a data-modifying novelty that would complicate support for loading compressed texture formats. This is better off as a post-process shader - environment mapping refactor, rewrite and cleanup - removed a lot of deprecated rgbGens - removed r_texdump (it never worked) - remove a few leftover broken postprocess things --- code/client/cl_scrn.c | 7 - code/renderer_oa/tr_bloom.c | 55 --- code/renderer_oa/tr_bsp.c | 12 +- code/renderer_oa/tr_image.c | 251 +---------- code/renderer_oa/tr_init.c | 14 +- code/renderer_oa/tr_local.h | 31 +- code/renderer_oa/tr_mesh.c | 2 +- code/renderer_oa/tr_scene.c | 14 + code/renderer_oa/tr_shade.c | 147 +------ code/renderer_oa/tr_shade_calc.c | 695 ++++++++----------------------- code/renderer_oa/tr_shader.c | 31 +- code/server/sv_init.c | 3 +- 12 files changed, 232 insertions(+), 1030 deletions(-) diff --git a/code/client/cl_scrn.c b/code/client/cl_scrn.c index b0feea8d18..f81e2236db 100644 --- a/code/client/cl_scrn.c +++ b/code/client/cl_scrn.c @@ -93,7 +93,6 @@ leilei - Adjusted for resolution and screen aspect ratio.... but from vertical o ================ */ void SCR_AdjustFrom480( float *x, float *y, float *w, float *h ) { - float xscale; float yscale; // scale for screen sizes @@ -202,14 +201,8 @@ void SCR_DrawSmallChar( int x, int y, int ch, int scalemode ) { float frow, fcol; float ax, ay, aw, ah; float size; - float sizeup = 1.0f; - float sizedown = 1.0f; ch &= 255; - if (cls.glconfig.vidHeight >= 480) - sizeup = cls.glconfig.vidHeight / 480; - sizedown = (cls.glconfig.vidHeight - 480); - if ( ch == ' ' ) { return; } diff --git a/code/renderer_oa/tr_bloom.c b/code/renderer_oa/tr_bloom.c index 7b2cb1787d..46068da654 100644 --- a/code/renderer_oa/tr_bloom.c +++ b/code/renderer_oa/tr_bloom.c @@ -1277,58 +1277,3 @@ void R_AltBrightnessInit( void ) r_alternateBrightness = ri.Cvar_Get( "r_alternateBrightness", "0", CVAR_ARCHIVE | CVAR_LATCH); } - - -// ================================================================= -// WATER BUFFER TEST -// ================================================================= - -#if 0 -static struct { - // NO! -} water; - -// leilei - experimental water effect -static void R_Water_InitTextures( void ) -{ - // NO! -} -#endif - - - -void R_InitWaterTextures( void ) -{ - // NO! -} - - -#if 0 -static void R_Water_BackupScreen( void ) -{ - // NO! -} - -static void R_WaterWorks( void ) -{ - // NO! -} - - -static void R_Water_RestoreScreen( void ) -{ - // NO! -} -#endif - -void R_WaterInit( void ) -{ - // NO! -} - - -void R_WaterScreen( void ) -{ - // NO! -} - diff --git a/code/renderer_oa/tr_bsp.c b/code/renderer_oa/tr_bsp.c index 224cfc4fb5..d995c55625 100644 --- a/code/renderer_oa/tr_bsp.c +++ b/code/renderer_oa/tr_bsp.c @@ -108,6 +108,17 @@ static void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) { r = in[0] << shift; g = in[1] << shift; b = in[2] << shift; + + // leilei - handle light desaturation here instead, so we can also mono the lightgrid and have one less redundant clamp + if( r_monolightmaps->value > 0) + { + float saturated = (r * 0.22126) + (g * 0.7152) + (b * 0.0722); + float ml = r_monolightmaps->value; // sanitize + if (ml>1) ml=1; if (ml<0) ml=0; + r = saturated + (r - saturated) * ( 1-ml ); + g = saturated + (g - saturated) * ( 1-ml ); + b = saturated + (b - saturated) * ( 1-ml ); + } if (r_lightmapColorNorm->integer == 2) // leilei { @@ -341,7 +352,6 @@ static shader_t *ShaderForShaderNum( int shaderNum, int lightmapNum ) { // leilei - placeholder hack if (tr.placeholderTextureAvail == 1 && !Q_strncmp( dsh->shader, "textures", 8 )) { - // return tr.placeholderTextureShader; shader = R_FindShader( "placeholder_texture", lightmapNum, qtrue ); return shader; } diff --git a/code/renderer_oa/tr_image.c b/code/renderer_oa/tr_image.c index 44cb73678a..898e0a8ce0 100644 --- a/code/renderer_oa/tr_image.c +++ b/code/renderer_oa/tr_image.c @@ -1033,79 +1033,6 @@ int hqresample = 0; // leilei - high quality texture resampling // Currently 0 as there is an alignment issue I haven't fixed. int isicon; // leilei - for determining if it's an icon. -char dumpname[ MAX_QPATH ]; // leilei - name for texture dumping - -static void DumpTex( unsigned *data, - int width, int height ) -{ - -// leilei - Do crazy dumping crap - byte *scan; - byte *baffer, *alffer, *flipper; - scan = ((byte *)data); - int padlen = 0; - int be, ber; - int scrale = width * height; - int hasalf = 0; - float countw = 0; -#if 0 - int scravg = width + height / 2; - int quality = 85; // estimate quality from total size - if (scravg > 511) quality = 42; // huge textures - else if (scravg > 255) quality = 62; // large textures - else if (scravg > 127) quality = 72; // large textures - else if (scravg < 127) quality = 95; // tiny textures -#endif - baffer = ri.Hunk_AllocateTempMemory( width * height * 3 ); - flipper = ri.Hunk_AllocateTempMemory( width * height * 3 ); - alffer = ri.Hunk_AllocateTempMemory( width * height * 3 ); - // TODO: Save alpha separately - // I'm gonna flip...... - int alfcnt = 0; - - - - for (be=0; be width) - countw = 0; - else - countw++; - ber = scrale - be - 1; - bib = be; - if (bib < 0) bib = 0; - if (bib > scrale) bib = 0; - baffer[bib*3] = scan[ber*4]; - baffer[bib*3+1] = scan[ber*4+1]; - baffer[bib*3+2] = scan[ber*4+2]; - alffer[bib*3] = scan[ber*4+3]; - alffer[bib*3+1] = scan[ber*4+3]; - alffer[bib*3+2] = scan[ber*4+3]; - if (scan[ber*4+3] > 1){ hasalf = 1;} - if (scan[ber*4+3] == 255){ alfcnt += 1; } - } - - - // NOW FIX IT - - - //memcount = (width * 3 + padlen) * height; - if ((width > 16) && (height > 16)){ - RE_SaveJPG( va("dump/%s.jpg", dumpname), 85,width, height, baffer, padlen); - if (hasalf) { - RE_SaveJPG( va("dump/%s_alpha.jpg", dumpname), 85,width, height, alffer, padlen); - } - } - ri.Printf( PRINT_ALL, "TEXDUMP: %s \n", dumpname ); - -// if ( baffer != 0 ) - ri.Hunk_FreeTempMemory( baffer ); -// if ( alffer != 0 ) - ri.Hunk_FreeTempMemory( alffer ); - ri.Hunk_FreeTempMemory( flipper ); -} - static void Upload32( unsigned *data, int width, int height, @@ -1205,12 +1132,8 @@ static void Upload32( unsigned *data, // if ( isicon ){ - if (r_iconmip->integer){ - - // Auto-determine from resolution division - if (r_iconmip->integer == 1){ int wadth, haght, dev = 0; @@ -1263,8 +1186,6 @@ static void Upload32( unsigned *data, scaled_height = 1; } - - // // clamp to the current upper OpenGL limit // scale both axis down equally so we don't have to @@ -1298,7 +1219,6 @@ static void Upload32( unsigned *data, int r, g, b; vec3_t rgb; byte alfa = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]); - //byte alfa = (scan[i*4]+ scan[i*4 + 1]+ scan[i*4 + 2]) / 3; r = scan[i*4 + 0]; g = scan[i*4 + 1]; @@ -1406,152 +1326,11 @@ static void Upload32( unsigned *data, } - - if(r_textureDither->integer) // possibly the stupidest texture dithering ever - { -#ifdef DONTEVENTHINKABOUTTHIS - int passes = r_textureDither->integer; - int that; - /* LEIFX FILTER C PORT PROTOTYPE SCRATCH AREA - No vectors, only ints ints ints Obviously can be refactored with SSE */ -#define FILTCAP (0.075 * 255) -#define FILTCAPG (FILTCAP / 2) - for (that=0;that FILTCAP ) rd = FILTCAP; - if (gd > FILTCAPG) gd = FILTCAPG; - if (bd > FILTCAP ) bd = FILTCAP; - - if (rd < -FILTCAP ) rd = -FILTCAP; - if (gd < -FILTCAPG) gd = -FILTCAPG; - if (bd < -FILTCAP ) bd = -FILTCAP; - - /* Add our Differences */ - - r1 += (rd/3); - g1 += (gd/3); - b1 += (bd/3); - - /* Obligatory clamping part */ - if (r1 < 0) r1 = 0; - if (g1 < 0) g1 = 0; - if (b1 < 0) b1 = 0; - - if (r1 > 255) r1 = 255; - if (g1 > 255) g1 = 255; - if (b1 > 255) b1 = 255; - - if (r2 < 0) r2 = 0; - if (g2 < 0) g2 = 0; - if (b2 < 0) b2 = 0; - - if (r2 > 255) r2 = 255; - if (g2 > 255) g2 = 255; - if (b2 > 255) b2 = 255; - - - - /* Put processed image back into the buffer */ - scan[i*4] = r1; - scan[i*4 + 1] = g1; - scan[i*4 + 2] = b1; - - } - - } -#endif - - for ( i = 0; i < c; i++ ) - { - int ren = (crandom() * 4); - int rg,gg,bb; - rg = scan[i*4]; - gg = scan[i*4+1]; - bb = scan[i*4+2]; - - //if ((rg / 64) != ceil(rg / 64)) - rg = scan[i*4] + ren; - //if ((gg / 32) != ceil(gg / 32)) - gg = scan[i*4 + 1] + (ren / 2); - //if ((bb / 64) != ceil(bb / 64)) - bb = scan[i*4 + 2] + ren; - - if (rg < 0) rg = 0; - if (gg < 0) gg = 0; - if (bb < 0) bb = 0; - - if (rg > 255) rg = 255; - if (gg > 255) gg = 255; - if (bb > 255) bb = 255; - - scan[i*4] = rg; - scan[i*4 + 1] = gg; - scan[i*4 + 2] = bb; - } - - } - - - - - if( r_greyscale->value ) - { - // leilei - replaced with saturation processing - for ( i = 0; i < c; i++ ) - { - float saturated = (scan[i*4] * 0.333) + (scan[i*4 + 1] * 0.333) + (scan[i*4 + 2] * 0.333); - scan[i*4] = saturated + (scan[i*4] - saturated) * (1-r_greyscale->value); - scan[i*4 + 1] = saturated + (scan[i*4 + 1] - saturated) * (1-r_greyscale->value); - scan[i*4 + 2] = saturated + (scan[i*4 + 2] - saturated) * (1-r_greyscale->value); + // texturdither was here, will return properly someday. - if (scan[i*4] > 255) scan[i*4] = 255; - if (scan[i*4 + 1] > 255) scan[i*4 + 1] = 255; - if (scan[i*4 + 2] > 255) scan[i*4 + 2] = 255; - } - } - if(lightMap) { - if( r_monolightmaps->value ) - { - for ( i = 0; i < c; i++ ) - { - float saturated = (scan[i*4] * 0.333) + (scan[i*4 + 1] * 0.333) + (scan[i*4 + 2] * 0.333); - scan[i*4] = saturated + (scan[i*4] - saturated) * (1-r_monolightmaps->value); - scan[i*4 + 1] = saturated + (scan[i*4 + 1] - saturated) * (1-r_monolightmaps->value ); - scan[i*4 + 2] = saturated + (scan[i*4 + 2] - saturated) * (1-r_monolightmaps->value ); - - if (scan[i*4] > 255) scan[i*4] = 255; - if (scan[i*4 + 1] > 255) scan[i*4 + 1] = 255; - if (scan[i*4 + 2] > 255) scan[i*4 + 2] = 255; - } - } - - if(r_greyscale->integer) - internalFormat = GL_LUMINANCE; - else if(r_monolightmaps->integer) + if(r_monolightmaps->integer) internalFormat = GL_LUMINANCE; else internalFormat = GL_RGB; @@ -1614,16 +1393,6 @@ static void Upload32( unsigned *data, // select proper internal format if ( samples == 3 ) { - if(r_greyscale->integer) - { - if(r_texturebits->integer == 16 || forceBits == 16) - internalFormat = GL_LUMINANCE8; - else if(r_texturebits->integer == 32 || forceBits == 32) - internalFormat = GL_LUMINANCE16; - else - internalFormat = GL_LUMINANCE; - } - else { if ( glConfig.textureCompression == TC_S3TC_ARB ) { @@ -1664,16 +1433,6 @@ static void Upload32( unsigned *data, } else if ( samples == 4 ) { - if(r_greyscale->integer) - { - if(r_texturebits->integer == 16 || forceBits == 16) - internalFormat = GL_LUMINANCE8_ALPHA8; - else if(r_texturebits->integer == 32 || forceBits == 32) - internalFormat = GL_LUMINANCE16_ALPHA16; - else - internalFormat = GL_LUMINANCE_ALPHA; - } - else { if ( glConfig.textureCompression == TC_S3TC_ARB ) { @@ -2215,12 +1974,6 @@ image_t *R_CreateImage( const char *name, byte *pic, int width, int height, GL_Bind(image); - // leilei - texture dumping - if (r_texdump->integer) { - COM_StripExtension( name, dumpname, MAX_QPATH ); // leilei - transfer name for texdump - DumpTex( (unsigned *)pic, image->width, image->height); - } - if (paletteavailable && r_texturebits->integer == 8 && !isLightmap && !depthimage && !force32upload) { Upload8( (unsigned *)pic, image->width, image->height, image->flags & IMGFLAG_MIPMAP, diff --git a/code/renderer_oa/tr_init.c b/code/renderer_oa/tr_init.c index 66493b08ee..d3e04b78e1 100644 --- a/code/renderer_oa/tr_init.c +++ b/code/renderer_oa/tr_init.c @@ -71,7 +71,6 @@ cvar_t *r_skipBackEnd; cvar_t *r_stereoEnabled; cvar_t *r_anaglyphMode; -cvar_t *r_greyscale; cvar_t *r_monolightmaps; cvar_t *r_ignorehwgamma; @@ -221,8 +220,6 @@ cvar_t *r_suggestiveThemes; // leilei - mature content control cvar_t *r_textureDither; // leilei - Dithered texture -cvar_t *r_texdump; // Leilei - debug - texture dump as they load, players should never need to use this! - // leilei - fallback shader hack @@ -998,6 +995,7 @@ void R_PrintLongString(const char *string) GfxInfo_f ================ */ +extern char extensions_string_full [BIG_INFO_STRING]; // leilei - gl extensions crash workaround void GfxInfo_f( void ) { const char *enablestrings[] = { @@ -1171,10 +1169,9 @@ void R_Register( void ) r_subdivisions = ri.Cvar_Get ("r_subdivisions", "4", CVAR_ARCHIVE | CVAR_LATCH); r_stereoEnabled = ri.Cvar_Get( "r_stereoEnabled", "0", CVAR_ARCHIVE | CVAR_LATCH); r_ignoreFastPath = ri.Cvar_Get( "r_ignoreFastPath", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_greyscale = ri.Cvar_Get("r_greyscale", "0", CVAR_ARCHIVE | CVAR_LATCH); - ri.Cvar_CheckRange(r_greyscale, 0, 1, qfalse); - r_monolightmaps = ri.Cvar_Get("r_monolightmaps", "0", CVAR_ARCHIVE | CVAR_LATCH); + ri.Cvar_CheckRange(r_monolightmaps, 0, 1, qfalse); + // // temporary latched variables that can only change over a restart @@ -1295,7 +1292,7 @@ void R_Register( void ) r_mockvr = ri.Cvar_Get( "r_mockvr", "0" , CVAR_CHEAT); r_leifx = ri.Cvar_Get( "r_leifx", "0" , CVAR_ARCHIVE | CVAR_LATCH); - r_shadeMethod = ri.Cvar_Get( "r_shadeMethod", "0" , CVAR_ARCHIVE | CVAR_LATCH); // leilei - Alternative lightingDiffuse + r_shadeMethod = ri.Cvar_Get( "r_shadeMethod", "0" , CVAR_ARCHIVE); // leilei - Alternative lightingDiffuse r_detailTextureScale = ri.Cvar_Get( "r_detailtextureScale", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - adjust scale of detail textures r_detailTextureLayers = ri.Cvar_Get( "r_detailtextureLayers", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - add more detail layers @@ -1313,8 +1310,6 @@ void R_Register( void ) r_textureDither = ri.Cvar_Get ("r_textureDither", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - dithered textures - r_texdump = ri.Cvar_Get( "r_texdump", "0", CVAR_CHEAT ); // leilei - debug - texture dumping - // make sure all the commands added here are also // removed in R_Shutdown ri.Cmd_AddCommand( "imagelist", R_ImageList_f ); @@ -1530,7 +1525,6 @@ void R_Init( void ) R_BloomInit(); R_PostprocessingInit(); R_AltBrightnessInit(); // leilei - alternate brightness - R_WaterInit(); // leilei - water test max_polys = r_maxpolys->integer; if (max_polys < MAX_POLYS) max_polys = MAX_POLYS; diff --git a/code/renderer_oa/tr_local.h b/code/renderer_oa/tr_local.h index f1c883d487..89ab892f08 100644 --- a/code/renderer_oa/tr_local.h +++ b/code/renderer_oa/tr_local.h @@ -195,8 +195,6 @@ typedef enum { TCGEN_LIGHTMAP, TCGEN_TEXTURE, TCGEN_ENVIRONMENT_MAPPED, - TCGEN_ENVIRONMENT_CELSHADE_MAPPED, - TCGEN_ENVIRONMENT_CELSHADE_LEILEI, // leilei - cel hack TCGEN_ENVIRONMENT_MAPPED_WATER, // leilei - fake water reflection TCGEN_EYE_LEFT, // eyes TCGEN_EYE_RIGHT, // eyes @@ -878,7 +876,7 @@ typedef struct { unsigned v_FogColor; GLint u_Greyscale; - int v_Greyscale; + int v_Greyscale; GLint u_IdentityLight; float v_IdentityLight; @@ -1351,8 +1349,6 @@ extern cvar_t *r_skipBackEnd; extern cvar_t *r_anaglyphMode; -extern cvar_t *r_greyscale; - extern cvar_t *r_monolightmaps; extern cvar_t *r_ignoreGLErrors; @@ -1401,8 +1397,6 @@ extern cvar_t *r_iconBits; // leilei - icon color depth for 2d icons extern cvar_t *r_lightmapBits; // leilei - lightmap color depth extern cvar_t *r_lightmapColorNorm; // leilei - lightmap color normalize -extern cvar_t *r_texdump; // leilei - texture dumping - extern cvar_t *r_detailTextureScale; // leilei - scale tweak the detail textures, 0 doesn't tweak at all. extern cvar_t *r_detailTextureLayers; // leilei - add in more smaller detail texture layers, expensive! @@ -2107,13 +2101,10 @@ void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t void RB_DeformTessGeometry( void ); void RB_CalcEnvironmentTexCoords( float *dstTexCoords ); -void RB_CalcCelTexCoords( float *dstTexCoords ); // leilei - cel hack -void RB_CalcEnvironmentTexCoordsJO( float *dstTexCoords ); // leilei -void RB_CalcEnvironmentTexCoordsR( float *dstTexCoords ); // leilei +void RB_CalcEnvironmentTexCoordsEx( float *st, int xx, int yy, int mode ); // leilei - extra envmapping + void RB_CalcEyes( float *st, qboolean theothereye); // leilei - eyes -void RB_CalcEnvironmentCelShadeTexCoords( float *dstTexCoords ); -void RB_CalcEnvironmentTexCoordsNew( float *dstTexCoords ); -void RB_CalcEnvironmentTexCoordsHW(void); + void RB_CalcFogTexCoords( float *dstTexCoords ); void RB_CalcScrollTexCoords( const float scroll[2], float *dstTexCoords ); void RB_CalcRotateTexCoords( float rotSpeed, float *dstTexCoords ); @@ -2128,22 +2119,15 @@ void RB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors ); void RB_CalcAlphaFromEntity( unsigned char *dstColors ); void RB_CalcAlphaFromOneMinusEntity( unsigned char *dstColors ); void RB_CalcStretchTexCoords( const waveForm_t *wf, float *texCoords ); -void RB_CalcLightscaleTexCoords( float *texCoords ); void RB_CalcAtlasTexCoords( const atlas_t *at, float *st ); void RB_CalcColorFromEntity( unsigned char *dstColors ); void RB_CalcColorFromOneMinusEntity( unsigned char *dstColors ); void RB_CalcSpecularAlpha( unsigned char *alphas ); void RB_CalcSpecularAlphaNew( unsigned char *alphas ); -void RB_CalcDiffuseColor( unsigned char *colors ); -void RB_CalcUniformColor( unsigned char *colors ); -void RB_CalcDynamicColor( unsigned char *colors ); -void RB_CalcDiffuseColor_Specular( unsigned char *colors ); // leilei - specular hack -void RB_CalcFlatAmbient( unsigned char *colors ); // leilei - cel hack -void RB_CalcFlatDirect( unsigned char *colors ); // leilei - cel hack void RB_CalcGlowBlend( unsigned char *colors, int glowcol, int fx ); // leilei - rgbMod void RB_CalcUVColor( unsigned char *colors, int glowcol, int fx ); // leilei - rgbMod void RB_CalcNormalizeToAlpha( unsigned char *colors); // leilei - rgbMod - +void RB_CalcDiffuseColor( unsigned char *colors ); void RB_CalcMaterials( unsigned char *colors, int ambient, int diffuse, int specular, int emissive, int spechard, int alpha ); // leilei - materials void RB_CalcVertLights( unsigned char *colors ); // leilei - dynamic vertex lights @@ -2306,10 +2290,7 @@ void RE_TakeVideoFrame( int width, int height, //Bloom Stuff void R_BloomInit( void ); -void R_WaterInit( void ); void R_BloomScreen( void ); -void R_WaterScreen( void ); -void R_PaletteScreen( void ); // Postprocessing void R_PostprocessScreen( void ); void R_PostprocessingInit(void); @@ -2337,7 +2318,5 @@ void R_LFX_Blood (const vec3_t org, const vec3_t dir, float pressure) ; void LFX_ShaderInit(void); void LFX_ParticleEffect (int effect, const vec3_t org, const vec3_t dir); -extern char extensions_string_full [BIG_INFO_STRING]; // leilei - gl extensions crash workaround - #endif //TR_LOCAL_H diff --git a/code/renderer_oa/tr_mesh.c b/code/renderer_oa/tr_mesh.c index d0be29bc2e..4b63b11054 100644 --- a/code/renderer_oa/tr_mesh.c +++ b/code/renderer_oa/tr_mesh.c @@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "tr_local.h" -static float ProjectRadius( float r, vec3_t location ) +float ProjectRadius( float r, vec3_t location ) { float pr; float dist; diff --git a/code/renderer_oa/tr_scene.c b/code/renderer_oa/tr_scene.c index c1259048d2..fa1773e13c 100644 --- a/code/renderer_oa/tr_scene.c +++ b/code/renderer_oa/tr_scene.c @@ -245,7 +245,21 @@ void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, floa if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) { return; } + dl = &backEndData->dlights[r_numdlights++]; + + // leilei - r_monolightmaps also desaturate vertex dynamic lights + float ml = r_monolightmaps->value; // sanitize + if (ml>1) ml=1; if (ml<0) ml=0; + + if( ml ) + { + float saturated = (r * 0.22126) + (g * 0.7152) + (b * 0.0722); + r = saturated + (r - saturated) * ( 1-ml ); + g = saturated + (g - saturated) * ( 1-ml ); + b = saturated + (b - saturated) * ( 1-ml ); + } + VectorCopy (org, dl->origin); dl->radius = intensity; dl->color[0] = r; diff --git a/code/renderer_oa/tr_shade.c b/code/renderer_oa/tr_shade.c index 1661746ca1..88d6f0bd75 100644 --- a/code/renderer_oa/tr_shade.c +++ b/code/renderer_oa/tr_shade.c @@ -502,31 +502,6 @@ static void ProjectDlightTexture_altivec( void ) { origin2 = dl->transformed[2]; radius = dl->radius; scale = 1.0f / radius; - - if(r_greyscale->integer) - { - float luminance; - - luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; - floatColor[0] = floatColor[1] = floatColor[2] = luminance; - } - else if(r_monolightmaps->integer) - { - float luminance; - - luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; - floatColor[0] = floatColor[1] = floatColor[2] = luminance; - } - else if(r_greyscale->value) - { - float luminance; - - luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; - floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value); - floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value); - floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value); - } - else { floatColor[0] = dl->color[0] * 255.0f; floatColor[1] = dl->color[1] * 255.0f; @@ -673,35 +648,9 @@ static void ProjectDlightTexture_scalar( void ) { radius = dl->radius; scale = 1.0f / radius; - if(r_greyscale->integer) - { - float luminance; - - luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; - floatColor[0] = floatColor[1] = floatColor[2] = luminance; - } - else if(r_monolightmaps->integer) - { - float luminance; - - luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; - floatColor[0] = floatColor[1] = floatColor[2] = luminance; - } - else if(r_greyscale->value) - { - float luminance; - - luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; - floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value); - floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value); - floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value); - } - else - { - floatColor[0] = dl->color[0] * 255.0f; - floatColor[1] = dl->color[1] * 255.0f; - floatColor[2] = dl->color[2] * 255.0f; - } + floatColor[0] = dl->color[0] * 255.0f; + floatColor[1] = dl->color[1] * 255.0f; + floatColor[2] = dl->color[2] * 255.0f; for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) { int clip = 0; @@ -877,44 +826,18 @@ static void ComputeColors( shaderStage_t *pStage ) break; case CGEN_LIGHTING_DIFFUSE: RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors ); - if(r_monolightmaps->integer) - { - int scale; - for(i = 0; i < tess.numVertexes; i++) - { - scale = LUMA(tess.svars.colors[i][0], tess.svars.colors[i][1], tess.svars.colors[i][2]); - tess.svars.colors[i][0] = tess.svars.colors[i][1] = tess.svars.colors[i][2] = scale; - } - } break; case CGEN_LIGHTING_UNIFORM: - RB_CalcUniformColor( ( unsigned char * ) tess.svars.colors ); - break; - case CGEN_LIGHTING_DYNAMIC: - RB_CalcDynamicColor( ( unsigned char * ) tess.svars.colors ); + RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors ); break; case CGEN_LIGHTING_FLAT_AMBIENT: - RB_CalcFlatAmbient( ( unsigned char * ) tess.svars.colors ); - if(r_monolightmaps->integer) - { - int scale; - for(i = 0; i < tess.numVertexes; i++) - { - scale = LUMA(tess.svars.colors[i][0], tess.svars.colors[i][1], tess.svars.colors[i][2]); - tess.svars.colors[i][0] = tess.svars.colors[i][1] = tess.svars.colors[i][2] = scale; - } + for ( i = 0; i < tess.numVertexes; i++ ) { + *(int *)tess.svars.colors[i] = *(int *)pStage->constantColor; } break; case CGEN_LIGHTING_FLAT_DIRECT: - RB_CalcFlatDirect( ( unsigned char * ) tess.svars.colors ); - if(r_monolightmaps->integer) - { - int scale; - for(i = 0; i < tess.numVertexes; i++) - { - scale = LUMA(tess.svars.colors[i][0], tess.svars.colors[i][1], tess.svars.colors[i][2]); - tess.svars.colors[i][0] = tess.svars.colors[i][1] = tess.svars.colors[i][2] = scale; - } + for ( i = 0; i < tess.numVertexes; i++ ) { + *(int *)tess.svars.colors[i] = *(int *)pStage->constantColor; } break; case CGEN_EXACT_VERTEX: @@ -987,18 +910,6 @@ static void ComputeColors( shaderStage_t *pStage ) case CGEN_ONE_MINUS_ENTITY: RB_CalcColorFromOneMinusEntity( ( unsigned char * ) tess.svars.colors ); break; - case CGEN_LIGHTING_DIFFUSE_SPECULAR: // leilei - specular hack - RB_CalcDiffuseColor_Specular( ( unsigned char * ) tess.svars.colors ); - if(r_monolightmaps->integer) - { - int scale; - for(i = 0; i < tess.numVertexes; i++) - { - scale = LUMA(tess.svars.colors[i][0], tess.svars.colors[i][1], tess.svars.colors[i][2]); - tess.svars.colors[i][0] = tess.svars.colors[i][1] = tess.svars.colors[i][2] = scale; - } - } - break; case CGEN_MATERIAL: RB_CalcMaterials( ( unsigned char * ) tess.svars.colors, pStage->matAmb, pStage->matDif, pStage->matSpec, pStage->matEmis, pStage->matHard, pStage->matAlpha ); break; @@ -1138,28 +1049,6 @@ static void ComputeColors( shaderStage_t *pStage ) } } - // if in greyscale rendering mode turn all color values into greyscale. - if(r_greyscale->integer) - { - int scale; - for(i = 0; i < tess.numVertexes; i++) - { - scale = LUMA(tess.svars.colors[i][0], tess.svars.colors[i][1], tess.svars.colors[i][2]); - tess.svars.colors[i][0] = tess.svars.colors[i][1] = tess.svars.colors[i][2] = scale; - } - } - else if(r_greyscale->value) - { - float scale; - - for(i = 0; i < tess.numVertexes; i++) - { - scale = LUMA(tess.svars.colors[i][0], tess.svars.colors[i][1], tess.svars.colors[i][2]); - tess.svars.colors[i][0] = LERP(tess.svars.colors[i][0], scale, r_greyscale->value); - tess.svars.colors[i][1] = LERP(tess.svars.colors[i][1], scale, r_greyscale->value); - tess.svars.colors[i][2] = LERP(tess.svars.colors[i][2], scale, r_greyscale->value); - } - } } @@ -1170,9 +1059,7 @@ ComputeUVColors */ static void ComputeUVColors( shaderStage_t *pStage ) { - int i; - - // + // // rgbMod // switch ( pStage->rgbMod ) @@ -1244,13 +1131,7 @@ static void ComputeTexCoords( shaderStage_t *pStage ) { RB_CalcEnvironmentTexCoords( ( float * ) tess.svars.texcoords[b] ); break; case TCGEN_ENVIRONMENT_MAPPED_WATER: - RB_CalcEnvironmentTexCoordsJO( ( float * ) tess.svars.texcoords[b] ); - break; - case TCGEN_ENVIRONMENT_CELSHADE_MAPPED: - RB_CalcEnvironmentCelShadeTexCoords( ( float * ) tess.svars.texcoords[b] ); - break; - case TCGEN_ENVIRONMENT_CELSHADE_LEILEI: - RB_CalcCelTexCoords( ( float * ) tess.svars.texcoords[b] ); + RB_CalcEnvironmentTexCoordsEx( ( float * ) tess.svars.texcoords[b], 0, 1, 1 ); break; case TCGEN_EYE_LEFT: RB_CalcEyes( ( float * ) tess.svars.texcoords[b], 1); @@ -1302,10 +1183,6 @@ static void ComputeTexCoords( shaderStage_t *pStage ) { ( float * ) tess.svars.texcoords[b] ); break; - case TMOD_LIGHTSCALE: - RB_CalcLightscaleTexCoords( ( float * ) tess.svars.texcoords[b] ); - break; - case TMOD_TRANSFORM: RB_CalcTransformTexCoords( &pStage->bundle[b].texMods[tm], ( float * ) tess.svars.texcoords[b] ); @@ -1374,10 +1251,6 @@ void GLSL_Feeder(shaderStage_t *pStage, shaderCommands_t *input) if (program->u_FogColor > -1 && tess.fogNum) R_GLSL_SetUniform_FogColor(program, (tr.world->fogs + tess.fogNum)->colorInt); - /* greyscale */ - if (program->u_Greyscale > -1) - R_GLSL_SetUniform_Greyscale(program, r_greyscale->integer); - /* identity light */ if (program->u_IdentityLight > -1) R_GLSL_SetUniform_IdentityLight(program, tr.identityLight); diff --git a/code/renderer_oa/tr_shade_calc.c b/code/renderer_oa/tr_shade_calc.c index a33f0bbda0..7d3018fc78 100644 --- a/code/renderer_oa/tr_shade_calc.c +++ b/code/renderer_oa/tr_shade_calc.c @@ -108,43 +108,6 @@ void RB_CalcStretchTexCoords( const waveForm_t *wf, float *st ) RB_CalcTransformTexCoords( &tmi, st ); } - -// leilei - this is for celshading -void RB_CalcLightscaleTexCoords(float *st ) -{ - float p; - texModInfo_t tmi; - float light = 1.0f; -#if 0 - vec3_t lightDir; - vec3_t ambientLight; - VectorCopy( backEnd.currentEntity->ambientLight, ambientLight ); - VectorCopy( backEnd.currentEntity->lightDir, lightDir ); -#endif - vec3_t directedLight; - VectorCopy( backEnd.currentEntity->directedLight, directedLight ); - //light = DotProduct (directedLight, lightDir); - light = ((directedLight[0] + directedLight[1] + directedLight[2]) * 0.333) / 255; - if (light > 1) - light = 1.0f; - - p = 1.0f - (light * 0.7f); - - tmi.matrix[0][0] = p; - tmi.matrix[1][0] = 0; - tmi.translate[0] = 0.5f - 0.5f * p; - - tmi.matrix[0][1] = 0; - tmi.matrix[1][1] = p; - tmi.translate[1] = 0.5f - 0.5f * p; - - RB_CalcTransformTexCoords( &tmi, st ); -} - - - - - /* ==================================================================== @@ -1082,194 +1045,125 @@ void RB_CalcEnvironmentTexCoordsNew( float *st ) /* -** RB_CalcEnvironmentTexCoordsHW - - Hardware-native cubemapping (or sphere mapping if the former is unsupported) - - adapted from this tremulous patch by Odin - - NOTE: THIS BREAKS OTHER TCMODS IN A STAGE -*/ -void RB_CalcEnvironmentTexCoordsHW() -{ - qglTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); - qglTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); - qglTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); - qglEnable(GL_TEXTURE_GEN_S); - qglEnable(GL_TEXTURE_GEN_T); - qglEnable(GL_TEXTURE_GEN_R); -} - - -/* -** RB_CalcEnvironmentTexCoordsJO - from JediOutcast source +** RB_CalcEnvironmentTexCoordsEx + + leilei - extended environment texcoords (to replace redundancy), to: + + - specify which axis are used + - imitate raven behavior + - allow reflection from local lights (i.e. for celshading, or weapon glimmer) + + mode 1 = raven mode (including weapon shine). + note: this ISN'T from JediOutcast but rather clean-room experiments for VitaVoyager + mode 2 = weapon shine + mode 3 = all models shine + mode 4? = sun shine (water)? + mode 5 - view space (i.e. buffer reflections/refractions) */ -void RB_CalcEnvironmentTexCoordsJO( float *st ) +void RB_CalcEnvironmentTexCoordsEx( float *st, int xx, int yy, int mode ) { int i; float *v, *normal; - vec3_t viewer; + vec3_t viewer, reflected; float d; v = tess.xyz[0]; normal = tess.normal[0]; - if (backEnd.currentEntity && backEnd.currentEntity->e.renderfx&RF_FIRST_PERSON) //this is a view model so we must use world lights instead of vieworg + // clamp these + if (xx > 2) xx = 2; if (yy > 2) yy = 2; + if (xx < 0) xx = 0; if (yy < 0) yy = 0; + + if (mode == 1) // raven { - for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 ) + if (backEnd.currentEntity->e.renderfx & RF_FIRST_PERSON) // Weapons { - d = DotProduct (normal, backEnd.currentEntity->lightDir); - st[0] = normal[0]*d - backEnd.currentEntity->lightDir[0]; - st[1] = normal[1]*d - backEnd.currentEntity->lightDir[1]; + for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 ) + { + VectorCopy (backEnd.currentEntity->lightDir, viewer); + VectorNormalizeFast (viewer); + + d = DotProduct (normal, viewer); + + reflected[xx] = normal[xx]*2*d - viewer[xx]; + reflected[yy] = normal[yy]*2*d - viewer[yy]; + + st[0] = reflected[xx] * 0.5; + st[1] = reflected[yy] * 0.5; + } } - } else { //the normal way - for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 ) + else // World { - VectorSubtract (backEnd.or.viewOrigin, v, viewer); - VectorNormalizeFast (viewer); - - d = DotProduct (normal, viewer); - st[0] = normal[0]*d - 0.5*viewer[0]; - st[1] = normal[1]*d - 0.5*viewer[1]; + for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 ) + { + VectorSubtract (backEnd.or.viewOrigin, v, viewer); + VectorNormalizeFast (viewer); + + d = DotProduct (normal, viewer); + + reflected[xx] = normal[xx]*2*d - viewer[xx]; + reflected[yy] = normal[yy]*2*d - viewer[yy]; + + st[0] = reflected[xx] * 0.5; + st[1] = reflected[yy] * 0.5; + } } } -} - -/* -** RB_CalcEnvironmentTexCoordsR - Inpsired by Revolution, reflect from the sun light position instead -*/ - -void RB_CalcEnvironmentTexCoordsR( float *st ) -{ - int i; - float *v, *normal; - vec3_t viewer, reflected, sunned; - float d; - vec3_t sundy; - float size; - float dist; - vec3_t vec1, vec2; - - v = tess.xyz[0]; - normal = tess.normal[0]; - - dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) - size = dist * 0.4; - - VectorScale( tr.sunDirection, dist, sundy); - PerpendicularVector( vec1, tr.sunDirection ); - CrossProduct( tr.sunDirection, vec1, vec2 ); - - VectorScale( vec1, size, vec1 ); - VectorScale( vec2, size, vec2 ); - - - v = tess.xyz[0]; - normal = tess.normal[0]; - - for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 ) + else if (mode == 5) // view space { - VectorSubtract (backEnd.or.viewOrigin, v, viewer); - VectorNormalizeFast (viewer); - - VectorSubtract (sundy, v, sunned); - VectorNormalizeFast (sunned); + { + for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 ) + { + vec3_t deflected; + vec4_t deflecteder; + VectorSubtract (backEnd.or.viewOrigin, v, viewer); + VectorNormalizeFast (viewer); + - d = DotProduct (normal, viewer) + DotProduct (viewer, sunned); + R_TransformModelToClip(v, backEnd.or.modelMatrix, backEnd.viewParms.projectionMatrix, deflected, deflecteder ); - reflected[0] = normal[0]*2*d - viewer[0]; - reflected[1] = normal[1]*2*d - viewer[1]; - reflected[2] = normal[2]*2*d - viewer[2]; + VectorNormalizeFast(deflecteder); - st[0] = 0.5 + reflected[1] * 0.5; - st[1] = 0.5 - reflected[2] * 0.5; + st[0] = 0.5 + deflecteder[0] * 0.5; + st[1] = 0.5 + deflecteder[1] * 0.5; + } + } } -} - -/* -** RB_CalcCelTexCoords - Butchered from JediOutcast source, note that this is not the same method as ZEQ2. -*/ -void RB_CalcCelTexCoords( float *st ) -{ - int i; - float *v, *normal; - vec3_t viewer, reflected, lightdir, directedLight; - float d, l, p; - - - v = tess.xyz[0]; - normal = tess.normal[0]; - - VectorCopy(backEnd.currentEntity->lightDir, lightdir); - VectorCopy(backEnd.currentEntity->directedLight, directedLight); - float light = (directedLight[0] + directedLight[1] + directedLight[2] / 3); - p = 1.0f - (light / 255); - for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 ) + else { - VectorSubtract (backEnd.or.viewOrigin, v, viewer); - VectorNormalizeFast (viewer); - - d = DotProduct (normal, viewer); - - l = DotProduct (normal, backEnd.currentEntity->lightDir); - - if (d < 0)d = 0; - if (l < 0)l = 0; - - if (d < p)d = p; - if (l < p)l = p; - - reflected[0] = normal[0]*1*(d+l) - (viewer[0] + lightdir[0] ); - reflected[1] = normal[1]*1*(d+l) - (viewer[1] + lightdir[1] ); - reflected[2] = normal[2]*1*(d+l) - (viewer[2] + lightdir[2] ); - - st[0] = 0.5 + reflected[1] * 0.5; - st[1] = 0.5 - reflected[2] * 0.5; - + if ((backEnd.currentEntity->e.renderfx & RF_FIRST_PERSON && mode == 2) || ( ( backEnd.currentEntity != &tr.worldEntity ) && mode == 3)) // local light sine + { + for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 ) + { + VectorCopy (backEnd.currentEntity->lightDir, viewer); + VectorNormalizeFast (viewer); + + d = DotProduct (normal, viewer); + + reflected[xx] = normal[xx]*2*d - viewer[xx]; + reflected[yy] = normal[yy]*2*d - viewer[yy]; + + st[0] = 0.5 + reflected[xx] * 0.5; + st[1] = 0.5 - reflected[yy] * 0.5; + } + } + for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 ) + { + VectorSubtract (backEnd.or.viewOrigin, v, viewer); + VectorNormalizeFast (viewer); + + d = DotProduct (normal, viewer); + + reflected[xx] = normal[xx]*2*d - viewer[xx]; + reflected[yy] = normal[yy]*2*d - viewer[yy]; + + st[0] = 0.5 + reflected[xx] * 0.5; + st[1] = 0.5 - reflected[yy] * 0.5; + } } } - - -/* -** RB_CalcEnvironmentCelShadeTexCoords -** -** RiO; celshade 1D environment map -*/ - - - - -void RB_CalcEnvironmentCelShadeTexCoords( float *st ) -{ - int i; - float *v, *normal; - vec3_t lightDir; - float d; - - normal = tess.normal[0]; - v = tess.xyz[0]; - - // Calculate only once -// VectorCopy( backEnd.currentEntity->lightDir, lightDir ); -// if ( backEnd.currentEntity == &tr.worldEntity ) -// VectorSubtract( lightOrigin, v, lightDir ); -// else - VectorCopy( backEnd.currentEntity->lightDir, lightDir ); - VectorNormalizeFast( lightDir ); - - for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 ) { - d= DotProduct( normal, lightDir ); - - st[0] = 0.5 + d * 0.5; - st[1] = 0.5; - } -} - /* ** RB_CalcTurbulentTexCoords */ @@ -1734,6 +1628,52 @@ static void RB_UVColor( unsigned char *colors, int glowcol, int fx ) ** ** The basic vertex lighting calc */ + +// leilei - with some extra modes (flat, high, rim) + +// fastest possible path - but shouldn't be very bright. +static void RB_CalcDiffuseColor_flat( unsigned char *colors ) +{ + int i; + float *v, *normal; + trRefEntity_t *ent; + vec3_t ambientLight; + vec3_t directedLight; + int numVertexes; + ent = backEnd.currentEntity; + VectorCopy( ent->ambientLight, ambientLight ); + VectorCopy( ent->directedLight, directedLight ); + + v = tess.xyz[0]; + normal = tess.normal[0]; + numVertexes = tess.numVertexes; + + int r = ri.ftol(ambientLight[0] + directedLight[0]); + int g = ri.ftol(ambientLight[1] + directedLight[1]); + int b = ri.ftol(ambientLight[2] + directedLight[2]); + + r = (ambientLight[0] + r) / 2; + g = (ambientLight[1] + g) / 2; + b = (ambientLight[2] + b) / 2; + + if (r < ambientLight[0]) r = ambientLight[0]; + if (g < ambientLight[1]) g = ambientLight[1]; + if (b < ambientLight[2]) b = ambientLight[2]; + + if ( r > 255 ) r = 255; + if ( g > 255 ) g = 255; + if ( b > 255 ) b = 255; + + for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) { + colors[i*4+0] = r; + colors[i*4+1] = g; + colors[i*4+2] = b; + colors[i*4+3] = 255; + } +} + + + #if idppc_altivec static void RB_CalcDiffuseColor_altivec( unsigned char *colors ) { @@ -1854,146 +1794,7 @@ static void RB_CalcDiffuseColor_scalar( unsigned char *colors ) } } -void RB_CalcDiffuseColor_Specular( unsigned char *colors ) -{ - int i, j; - float spec; - float *v, *normal; - float incoming; - trRefEntity_t *ent; - int ambientLightInt; - vec3_t ambientLight; - vec3_t lightDir; - vec3_t directedLight; - vec3_t specularLight; - int numVertexes; - int shadecap = 200; // was 127 - ent = backEnd.currentEntity; - ambientLightInt = ent->ambientLightInt; - VectorCopy( ent->ambientLight, ambientLight ); - VectorCopy( ent->directedLight, directedLight ); - - VectorCopy( ent->directedLight, specularLight ); - VectorAdd( ent->ambientLight, directedLight, directedLight ); - VectorCopy( ent->lightDir, lightDir ); - - // averaging colors test -/* - { - int rf; - for (rf=0;rf<3;rf++){ - //directedLight[rf] = ambientLight[rf] + directedLight[rf] / 2; - //ambientLight[rf] = pow((ambientLight[rf] / 255), (directedLight[rf] / 255)) * 255; - specularLight[rf] -= ambientLight[rf]; - ambientLight[rf] = ambientLight[rf] + ambientLight[rf] + (directedLight[rf] / 512); - - - //shadecap += directedLight[rf]; - if (specularLight[rf] < 0) specularLight[rf] = 0; - if (ambientLight[rf] > 255) ambientLight[rf] = 255; - - } - //shadecap /= 3; - - ambientLightInt *= 1.5; - - } -*/ - v = tess.xyz[0]; - normal = tess.normal[0]; - - numVertexes = tess.numVertexes; - for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) { - incoming = DotProduct (normal, lightDir); - - if ( incoming <= 0 ) { - *(int *)&colors[i*4] = ambientLightInt; - continue; - } - - - // Specular - - { - float ilength; - vec3_t viewer, reflected; - - VectorCopy( backEnd.currentEntity->lightDir, lightDir ); - VectorNormalizeFast( lightDir ); - - // calculate the specular color - float d = DotProduct (normal, lightDir); - - // we don't optimize for the d < 0 case since this tends to - // cause visual artifacts such as faceted "snapping" - reflected[0] = normal[0]*2*d - lightDir[0]; - reflected[1] = normal[1]*2*d - lightDir[1]; - reflected[2] = normal[2]*2*d - lightDir[2]; - - VectorSubtract (backEnd.or.viewOrigin, v, viewer); - ilength = Q_rsqrt( DotProduct( viewer, viewer ) ); - float l = DotProduct (reflected, viewer); - l *= ilength; - - if (l < 0) { - spec = 0; - } else { - l = l*l; - l = l*l; - spec = l * 2.2f; - if (spec > 1) spec = 1; - } - // specularLight[0] += spec; - // specularLight[1] += spec; - // specularLight[2] += spec; - - // if (specularLight[0] < shadecap) specularLight[0] = 0; - // if (specularLight[1] < shadecap) specularLight[1] = 0; - // if (specularLight[2] < shadecap) specularLight[2] = 0; - - // if (specularLight[0]) specularLight[0] = 255; - // if (specularLight[1]) specularLight[1] = 255; - // if (specularLight[2]) specularLight[2] = 255; - } - - j = ri.ftol(ambientLight[0] + incoming * directedLight[0]); - if ( j > shadecap ) { - j = shadecap; - j += ri.ftol(spec * specularLight[0]); - } - - // j += specularLight[0]; - if ( j > 255) j = 255; - colors[i*4+0] = j; - - j = ri.ftol(ambientLight[1] + incoming * directedLight[1]); - if ( j > shadecap ) { - j = shadecap; - j += ri.ftol(spec * specularLight[1]); - } - - // j += specularLight[1]; - if ( j > 255) j = 255; - - - colors[i*4+1] = j; - - j = ri.ftol(ambientLight[2] + incoming * directedLight[2]); - if ( j > shadecap ) { - j = shadecap; - j += ri.ftol(spec * specularLight[2]); - } - - // j += specularLight[2]; - if ( j > 255) j = 255; - colors[i*4+2] = j; - - colors[i*4+3] = 255; - } -} - - - +extern float ProjectRadius( float r, vec3_t location ); void RB_CalcDiffuseColor( unsigned char *colors ) { #if idppc_altivec @@ -2005,82 +1806,47 @@ void RB_CalcDiffuseColor( unsigned char *colors ) #endif - // leilei - reduced it to just this, r_shadeMode deprecated. :( - RB_CalcDiffuseColor_scalar( colors ); - - -} - - -/* -** RB_CalcUniformColor -** -** RiO; Uniform vertex color lighting for cel shading -*/ -void RB_CalcUniformColor( unsigned char *colors ) -{ - - int i; - trRefEntity_t *ent; - vec3_t ambientLight; - //vec3_t directedLight; - vec4_t uniformLight; - int numVertexes; - float normalize; - - ent = backEnd.currentEntity; - - VectorCopy( ent->ambientLight, ambientLight ); - //VectorCopy( ent->directedLight, directedLight ); - - VectorAdd( ambientLight, ambientLight/*directedLight*/, uniformLight ); - - normalize = NormalizeColor( uniformLight, uniformLight ); - if ( normalize > 255 ) normalize = 255; - VectorScale( uniformLight, normalize, uniformLight ); - uniformLight[3] = 255; - - numVertexes = tess.numVertexes; - for (i = 0 ; i < numVertexes ; i++ ) { - colors[i*4+0] = uniformLight[0]; - colors[i*4+1] = uniformLight[1]; - colors[i*4+2] = uniformLight[2]; - colors[i*4+3] = uniformLight[3]; + if (r_shadeMethod->integer == -1) // Fastest + { + RB_CalcDiffuseColor_flat( colors ); } -} - -/* -** RB_CalcDynamicColor -** -** MDave; Vertex color dynamic lighting for cel shading -*/ -void RB_CalcDynamicColor( unsigned char *colors ) -{ - int i; - trRefEntity_t *ent; - vec4_t dynamic; - int numVertexes; - float normalize; - - ent = backEnd.currentEntity; - - VectorCopy( ent->dynamicLight, dynamic ); - - normalize = NormalizeColor( dynamic, dynamic ); - if ( normalize > 255 ) normalize = 255; - VectorScale( dynamic, normalize, dynamic ); - dynamic[3] = 255; + else if (r_shadeMethod->integer == 2) // mimic UE1 style + { + RB_CalcMaterials( colors, 0xFFFFFF, 0x000000, 0xFFFFFF, 0x000000, 128, 255 ); + } + else if (r_shadeMethod->integer == 3) // have a little both diffuse and specular for a balanced look + { + RB_CalcMaterials( colors, 0xFFFFFF, 0x808080, 0x808080, 0x000000, 128, 255 ); + } + else if ((r_shadeMethod->integer > 150) && (r_shadeMethod->integer < 667)) // values in a certain range is an adaptive LOD selection of -1, 0 and 3 + { + float projectedRadius, fsh, shadescale, radius; + trRefEntity_t *ent = backEnd.currentEntity; + fsh = 1; + radius = 1; + if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 ) + { + shadescale = r_shadeMethod->value*-0.2; + if (shadescale > 666) shadescale = 666; + fsh = 1.0f - projectedRadius * shadescale; + } + if (fsh > 5) + RB_CalcMaterials( colors, 0xFFFFFF, 0x808080, 0x808080, 0x000000, 128, 255 ); + else if (fsh > 2.5) + RB_CalcDiffuseColor_scalar( colors ); + else + RB_CalcDiffuseColor_flat( colors ); - numVertexes = tess.numVertexes; - for (i = 0 ; i < numVertexes ; i++ ) { - colors[i*4+0] = dynamic[0]; - colors[i*4+1] = dynamic[1]; - colors[i*4+2] = dynamic[2]; - colors[i*4+3] = dynamic[3]; } + else // standard idtech3 shading + { + RB_CalcDiffuseColor_scalar( colors ); + } + } + void RB_CalcGlowBlend( unsigned char *colors, int glowcol, int fx ) { RB_GlowBlend( colors, glowcol, fx ); @@ -2156,9 +1922,10 @@ static void RB_VertLightsPerVert( unsigned char *colors ) for (f=0 ; fcolor[0]; g = l->color[1]; b = l->color[2]; + if (l->radius >= 1) // if light is good, mark the map { // calc the light against the world verts @@ -2169,9 +1936,9 @@ static void RB_VertLightsPerVert( unsigned char *colors ) if (power < 0) power = 0; // add the color of the light - cl[0] += (l->color[0] * power); - cl[1] += (l->color[1] * power); - cl[2] += (l->color[2] * power); + cl[0] += (r * power); + cl[1] += (g * power); + cl[2] += (b * power); // clamp stuff // normalize by color instead of saturating to white @@ -2187,10 +1954,6 @@ static void RB_VertLightsPerVert( unsigned char *colors ) if (cl[0] < 0) cl[0] = 0; if (cl[1] < 0) cl[1] = 0; if (cl[2] < 0) cl[2] = 0; - - // if (cl[0] > 255) cl[0] = 255; - // if (cl[1] > 255) cl[1] = 255; - // if (cl[2] > 255) cl[2] = 255; } } } @@ -2208,100 +1971,6 @@ void RB_CalcVertLights( unsigned char *colors ) RB_VertLightsPerVert( colors ); } - - - -// leilei celsperiment - - -void RB_CalcFlatAmbient( unsigned char *colors ) -{ - int i, j; - float *v, *normal; - trRefEntity_t *ent; - vec3_t ambientLight; - int numVertexes; - ent = backEnd.currentEntity; - VectorCopy( ent->ambientLight, ambientLight ); - - v = tess.xyz[0]; - normal = tess.normal[0]; - - numVertexes = tess.numVertexes; - for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) { - j = ri.ftol(ambientLight[0]); - if ( j > 255 ) { - j = 255; - } - colors[i*4+0] = j; - - j = ri.ftol(ambientLight[1]); - if ( j > 255 ) { - j = 255; - } - colors[i*4+1] = j; - - j = ri.ftol(ambientLight[2]); - if ( j > 255 ) { - j = 255; - } - colors[i*4+2] = j; - colors[i*4+3] = 255; - } -} - - -void RB_CalcFlatDirect( unsigned char *colors ) -{ - int i, j; - float *v, *normal; - trRefEntity_t *ent; - vec3_t ambientLight; - vec3_t directedLight; - int numVertexes; - ent = backEnd.currentEntity; - VectorCopy( ent->ambientLight, ambientLight ); - VectorCopy( ent->directedLight, directedLight ); - - - - directedLight[0] -= ambientLight[0]; - directedLight[1] -= ambientLight[1]; - directedLight[2] -= ambientLight[2]; - - if (directedLight[0] < 0) directedLight[0] = 0; - if (directedLight[1] < 0) directedLight[1] = 0; - if (directedLight[2] < 0) directedLight[2] = 0; - - v = tess.xyz[0]; - normal = tess.normal[0]; - - numVertexes = tess.numVertexes; - for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) { - j = ri.ftol(directedLight[0]); - if ( j > 255 ) { - j = 255; - } - colors[i*4+0] = j; - - j = ri.ftol(directedLight[1]); - if ( j > 255 ) { - j = 255; - } - colors[i*4+1] = j; - - j = ri.ftol(directedLight[2]); - if ( j > 255 ) { - j = 255; - } - colors[i*4+2] = j; - colors[i*4+3] = 255; - } -} - - - - #define MAXFRESLIGHTS 512 /* diff --git a/code/renderer_oa/tr_shader.c b/code/renderer_oa/tr_shader.c index 1a0f7fafed..690f82d42f 100644 --- a/code/renderer_oa/tr_shader.c +++ b/code/renderer_oa/tr_shader.c @@ -996,13 +996,6 @@ static void ParseTexMod( char *_text, shaderStage_t *stage ) tmi->type = TMOD_ATLAS; } - else if ( !Q_stricmp( token, "lightscale" ) ) - { - token = COM_ParseExt( text, qfalse ); - - tmi->type = TMOD_LIGHTSCALE; - } - // // transform // @@ -2665,30 +2658,10 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) { stage->rgbGen = CGEN_LIGHTING_DIFFUSE; } - else if ( !Q_stricmp( token, "lightingUniform" ) ) - { - stage->rgbGen = CGEN_LIGHTING_UNIFORM; - } - else if ( !Q_stricmp( token, "lightingDynamic" ) ) - { - stage->rgbGen = CGEN_LIGHTING_DYNAMIC; - } - else if ( !Q_stricmp( token, "flatAmbient" ) ) - { - stage->rgbGen = CGEN_LIGHTING_FLAT_AMBIENT; - } - else if ( !Q_stricmp( token, "flatDirect" ) ) - { - stage->rgbGen = CGEN_LIGHTING_FLAT_DIRECT; - } else if ( !Q_stricmp( token, "oneMinusVertex" ) ) { stage->rgbGen = CGEN_ONE_MINUS_VERTEX; } - else if ( !Q_stricmp( token, "lightingSpecularDiffuse" ) ) // leilei - deprecated - { - stage->rgbGen = CGEN_LIGHTING_DIFFUSE; - } else if ( !Q_stricmp( token, "material" ) ) // leilei - material system { token = COM_ParseExt( text, qfalse ); @@ -2909,11 +2882,11 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) } else if ( !Q_stricmp( token, "cel" ) ) { - stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_CELSHADE_MAPPED; + stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED; } else if ( !Q_stricmp( token, "celshading" ) ) // leilei - my technique is different { - stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_CELSHADE_LEILEI; + stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED; } else if ( !Q_stricmp( token, "eyeleft" ) ) // leilei - eye tracking { diff --git a/code/server/sv_init.c b/code/server/sv_init.c index fe07472fd4..0b819c5add 100644 --- a/code/server/sv_init.c +++ b/code/server/sv_init.c @@ -677,8 +677,7 @@ void SV_Init (void) Cvar_Get ("sv_dlURL", "", CVAR_SERVERINFO | CVAR_ARCHIVE); sv_master[0] = Cvar_Get("sv_master1", MASTER_SERVER_NAME, 0); - sv_master[1] = Cvar_Get("sv_master2", "master.ioquake3.org", 0); - for(index = 2; index < MAX_MASTER_SERVERS; index++) + for(index = 1; index < MAX_MASTER_SERVERS; index++) sv_master[index] = Cvar_Get(va("sv_master%d", index + 1), "", CVAR_ARCHIVE); sv_reconnectlimit = Cvar_Get ("sv_reconnectlimit", "3", 0); From 8b7378a4be6c338a0c1ec579c4d7b7f32aeb99a4 Mon Sep 17 00:00:00 2001 From: leilei- Date: Sat, 17 May 2025 05:03:54 -0400 Subject: [PATCH 13/20] - Internal GLSL brightness shader, so gamma control can work without the glsl/brightness_fp.glsl file when r_ext_vertex_shader is 1 and r_alternateBrightness is 2. - r_skyTess - an attempt to make the complexity of skydomes an option so it could use less polygons. Has no effect on skyboxes --- code/renderer_oa/tr_init.c | 56 ++++++++++- code/renderer_oa/tr_local.h | 3 + code/renderer_oa/tr_shader.c | 190 +++++++++++++++++++++++++++++++++++ code/renderer_oa/tr_sky.c | 149 +++++++++++++++------------ 4 files changed, 332 insertions(+), 66 deletions(-) diff --git a/code/renderer_oa/tr_init.c b/code/renderer_oa/tr_init.c index d3e04b78e1..a148083089 100644 --- a/code/renderer_oa/tr_init.c +++ b/code/renderer_oa/tr_init.c @@ -213,6 +213,8 @@ cvar_t *r_leifx; // Leilei - leifx nostalgia filter cvar_t *r_shadeMethod; // Leilei cvar_t *r_particles; // Leilei - particle effects motif +cvar_t *r_skytess; // leilei - lower detail of skies + cvar_t *r_leidebug; // Leilei - debug cvar_t *r_leidebugeye; // Leilei - eye debug @@ -1293,6 +1295,9 @@ void R_Register( void ) r_mockvr = ri.Cvar_Get( "r_mockvr", "0" , CVAR_CHEAT); r_leifx = ri.Cvar_Get( "r_leifx", "0" , CVAR_ARCHIVE | CVAR_LATCH); r_shadeMethod = ri.Cvar_Get( "r_shadeMethod", "0" , CVAR_ARCHIVE); // leilei - Alternative lightingDiffuse + + r_skytess = ri.Cvar_Get( "r_skyTess", "8", CVAR_ARCHIVE ); // leilei - sky detail adjustment + r_detailTextureScale = ri.Cvar_Get( "r_detailtextureScale", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - adjust scale of detail textures r_detailTextureLayers = ri.Cvar_Get( "r_detailtextureLayers", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - add more detail layers @@ -1449,7 +1454,56 @@ void R_GLSL_Init(void) Q_strncpyz(programVertexObjects[0], "glsl/brightness_vp.glsl", sizeof(programVertexObjects[0])); Q_strncpyz(programFragmentObjects[0], "glsl/brightness_fp.glsl", sizeof(programFragmentObjects[0])); - tr.BrightnessProgram = RE_GLSL_RegisterProgram("brightness", (const char *)programVertexObjects, 1, (const char *)programFragmentObjects, 1); + if (!(tr.BrightnessProgram = RE_GLSL_RegisterProgram("brightness", (const char *)programVertexObjects, 1, (const char *)programFragmentObjects, 1))) + { + // load it through this code + ri.Printf( PRINT_ALL, "----- Trying to load Brightness Shader internally!!! \n" ); + + const GLchar *brightnessfp = \ + "#version 120 \n" + "uniform sampler2D u_Texture0; \n" + "varying vec2 texture_coordinate;\n" + "uniform float u_CC_Overbright; \n" + "uniform float u_CC_Gamma; \n" + "void main()\n" + "{\n" + "gl_FragColor = texture2D(u_Texture0, texture_coordinate); \n" + "vec3 color;\n" + "vec3 colord;\n" + "int coloredr;\n" + "int coloredg;\n" + "int coloredb;\n" + "color.r = 1;\n" + "color.g = 1;\n" + "color.b = 1;\n" + "int yeh = 0;\n" + "float ohyes;\n" + "// Overbrights\n" + "gl_FragColor *= (u_CC_Overbright + 1);\n" + "// Gamma Correction\n" + "float gamma = u_CC_Gamma;\n" + "gl_FragColor.r = pow(gl_FragColor.r, 1.0 / gamma);\n" + "gl_FragColor.g = pow(gl_FragColor.g, 1.0 / gamma);\n" + "gl_FragColor.b = pow(gl_FragColor.b, 1.0 / gamma);\n" + "}\n"; + + const GLchar *brightnessvp = \ + "varying vec2 texture_coordinate;\n" + "varying vec2 texture_coordinate2;\n" + "varying vec2 texture_coordinate3;\n" + "varying vec2 texture_coordinate4;\n" + "varying vec2 texture_coordinate5;\n" + "varying float scale;\n" + "uniform float u_CC_Overbright;\n" + "uniform float u_CC_Gamma;\n" + "void main()\n" + "{\n" + "gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n" + "texture_coordinate = vec2(gl_MultiTexCoord0); \n" + "}\n"; + + tr.BrightnessProgram = RE_GLSL_RegisterProgramRaw("brightnessInternal", (const char *)brightnessvp, 1, (const char *)brightnessfp, 1); + } if (strcmp( (const char *)r_postprocess->string, "none" )) { sprintf(p,"glsl/%s_vp.glsl",r_postprocess->string); diff --git a/code/renderer_oa/tr_local.h b/code/renderer_oa/tr_local.h index 89ab892f08..d524c1e68f 100644 --- a/code/renderer_oa/tr_local.h +++ b/code/renderer_oa/tr_local.h @@ -1402,6 +1402,8 @@ extern cvar_t *r_detailTextureLayers; // leilei - add in more smaller detail t extern cvar_t *r_textureDither; // leilei - apply dithering for lower texture bits +extern cvar_t *r_skytess; // leilei - adjusts the subdivisions of the sky (max 8, min 1) + //==================================================================== void R_SwapBuffers( int ); @@ -1948,6 +1950,7 @@ static ID_INLINE void R_GLSL_SetUniform_rubyOutputSize(glslProgram_t *program, c void R_GLSL_Init(void); qhandle_t RE_GLSL_RegisterProgram(const char *name, const char *programVertexObjects, int numVertexObjects, const char *programFragmentObjects, int numFragmentObjects); +qhandle_t RE_GLSL_RegisterProgramRaw(const char *name, const char *programVertexObjects, int numVertexObjects, const char *programFragmentObjects, int numFragmentObjects); void R_GLSL_UseProgram(qhandle_t index); void RB_GLSL_StageIteratorGeneric(void); void RB_GLSL_StageIteratorVertexLitTexture(void); diff --git a/code/renderer_oa/tr_shader.c b/code/renderer_oa/tr_shader.c index 690f82d42f..a279e1ebbd 100644 --- a/code/renderer_oa/tr_shader.c +++ b/code/renderer_oa/tr_shader.c @@ -456,6 +456,137 @@ static qboolean R_GLSL_LoadProgram(glslProgram_t *program, const char *name, con #endif } +static qboolean R_GLSL_LoadProgramRaw(glslProgram_t *program, const char *name, const char *programVertexObjects, int numVertexObjects, const char *programFragmentObjects, int numFragmentObjects) { +#ifdef GLSL_BACKEND + GLcharARB *buffer_vp[MAX_PROGRAM_OBJECTS]; + GLcharARB *buffer_fp[MAX_PROGRAM_OBJECTS]; + GLcharARB *buffer; + GLhandleARB shader_vp; + GLhandleARB shader_fp; + GLint status; + char *str; + int size = 0; + int i; + + + /* create program */ + program->program = qglCreateProgramObjectARB(); + + /* vertex program */ + for (i = 0, str = (const char *)programVertexObjects; i < numVertexObjects; i++, str += MAX_QPATH) { + buffer_vp[i] = str; + size += sizeof(str)*32; + if (!buffer_vp[i]) { + ri.Printf( PRINT_WARNING, "Couldn't load %s", str); + return qfalse; + } + + /* compile vertex shader */ + shader_vp = qglCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); + qglShaderSourceARB(shader_vp, 1, (const GLcharARB **)&buffer_vp, NULL); + qglCompileShaderARB(shader_vp); + + /* check for errors in vertex shader */ + qglGetObjectParameterivARB(shader_vp, GL_OBJECT_COMPILE_STATUS_ARB, &status); + if (!status) { + int length; + char *msg; + + /* print glsl error message */ + qglGetObjectParameterivARB(shader_vp, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); + msg = ri.Hunk_AllocateTempMemory(length); + qglGetInfoLogARB(shader_vp, length, &length, msg); + ri.Printf(PRINT_ALL, "Error:\n%s\n", msg); + ri.Hunk_FreeTempMemory(msg); + + /* exit */ + ri.Printf( PRINT_WARNING, "Couldn't compile vertex shader for program %s", name); + return qfalse; + } + + /* attach vertex shader to program */ + qglAttachObjectARB(program->program, shader_vp); + qglDeleteObjectARB(shader_vp); + } + + /* fragment program */ + for (i = 0, str = (const char *)programFragmentObjects; i < numFragmentObjects; i++, str += MAX_QPATH) { + buffer_fp[i] = str; + size += sizeof(str)*32; + if (!buffer_fp[i]) { + ri.Printf( PRINT_WARNING, "Couldn't load %s", str); + return qfalse; + } + + /* compile fragment shader */ + shader_fp = qglCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); + qglShaderSourceARB(shader_fp, 1, (const GLcharARB **)&buffer_fp[i], NULL); + qglCompileShaderARB(shader_fp); + + /* check for errors in fragment shader */ + qglGetObjectParameterivARB(shader_fp, GL_OBJECT_COMPILE_STATUS_ARB, &status); + if (!status) { + int length; + char *msg; + + /* print glsl error message */ + + qglGetObjectParameterivARB(shader_fp, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); + msg = ri.Hunk_AllocateTempMemory(length); + qglGetInfoLogARB(shader_fp, length, &length, msg); + ri.Printf(PRINT_ALL, "Error:\n%s\n", msg); + ri.Hunk_FreeTempMemory(msg); + ri.Printf(PRINT_DEVELOPER, "oops\n"); + /* exit */ + ri.Printf( PRINT_WARNING, "Couldn't compile fragment shader for program %s", name); + return qfalse; + } + + /* attach fragment shader to program */ + qglAttachObjectARB(program->program, shader_fp); + qglDeleteObjectARB(shader_fp); + } + + /* link complete program */ + qglLinkProgramARB(program->program); + /* check for linking errors */ + qglGetObjectParameterivARB(program->program, GL_OBJECT_LINK_STATUS_ARB, &status); + if (!status) { + int length; + char *msg; + /* print glsl error message */ + qglGetObjectParameterivARB(program->program, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); + msg = ri.Hunk_AllocateTempMemory(length); + qglGetInfoLogARB(program->program, length, &length, msg); + ri.Printf(PRINT_ALL, "Error:\n%s\n", msg); + ri.Hunk_FreeTempMemory(msg); + + /* exit */ + ri.Printf( PRINT_WARNING, "Couldn't link shaders for program %s", name); + return qfalse; + } + /* build single large program file for parsing */ + buffer = ri.Hunk_AllocateTempMemory(++size); + + Q_strncpyz(buffer, buffer_vp[0], size); + + for (i = 1; i < numVertexObjects; i++) + strncat(buffer, buffer_vp[i], size); + for (i = 0; i < numFragmentObjects; i++) + strncat(buffer, buffer_fp[i], size); + /* get uniform locations */ + qglUseProgramObjectARB(program->program); + R_GLSL_ParseProgram(program, buffer); + qglUseProgramObjectARB(0); + /* clean up */ + ri.Hunk_FreeTempMemory(buffer); + + return qtrue; +#endif +} + + + /* * RE_GLSL_RegisterProgram * Loads in a program of given name @@ -514,6 +645,65 @@ qhandle_t RE_GLSL_RegisterProgram(const char *name, const char *programVertexObj } +/* + * RE_GLSL_RegisterProgram + * Loads in a program of given name + */ +qhandle_t RE_GLSL_RegisterProgramRaw(const char *name, const char *programVertexObjects, int numVertexObjects, const char *programFragmentObjects, int numFragmentObjects) { +#ifdef GLSL_BACKEND + glslProgram_t *program; + qhandle_t hProgram; + + if (!vertexShaders) + return 0; + + if (!name || !name[0]) { + ri.Printf(PRINT_ALL, "RE_GLSL_RegisterProgram: NULL name\n"); + return 0; + } + + if (strlen(name) >= MAX_QPATH) { + Com_Printf("Program name exceeds MAX_QPATH\n"); + return 0; + } + + /* search the currently loaded programs */ + for (hProgram = 0; hProgram < tr.numPrograms; hProgram++) { + program = tr.programs[hProgram]; + if (!strcmp(program->name, name)) { + if (!program->valid) + return 0; + + return hProgram; + } + } + + /* allocate a new glslProgram_t */ + if ((program = R_GLSL_AllocProgram()) == NULL) { + ri.Printf(PRINT_WARNING, "RE_GLSL_RegisterProgram: R_GLSL_AllocProgram() failed for '%s'\n", name); + return 0; + } + + /* only set the name after the program has successfully loaded */ + Q_strncpyz(program->name, name, sizeof(program->name)); + + R_IssuePendingRenderCommands(); + + /* load the files */ + if (!R_GLSL_LoadProgramRaw(program, name, (const char*)programVertexObjects, numVertexObjects, (const char*)programFragmentObjects, numFragmentObjects)) { + qglDeleteObjectARB(program->program); + program->valid = qfalse; + //vertexShaders=0; //If program in error disable the glsl feature altogether + return 0; + } + + program->valid = qtrue; + return program->index; +#endif +} + + + void R_RemapShader(const char *shaderName, const char *newShaderName, const char *timeOffset) { char strippedName[MAX_QPATH]; int hash; diff --git a/code/renderer_oa/tr_sky.c b/code/renderer_oa/tr_sky.c index b955230bb6..f09d69c641 100644 --- a/code/renderer_oa/tr_sky.c +++ b/code/renderer_oa/tr_sky.c @@ -25,6 +25,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define SKY_SUBDIVISIONS 8 #define HALF_SKY_SUBDIVISIONS (SKY_SUBDIVISIONS/2) +// leilei - optimizing sky +static int SkySub = 8; +static int HalfSkySub = 4; + static float s_cloudTexCoords[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2]; static float s_cloudTexP[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1]; @@ -309,6 +313,7 @@ static void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXY float boxSize; boxSize = backEnd.viewParms.zFar / 1.75; // div sqrt(3) + b[0] = s*boxSize; b[1] = t*boxSize; b[2] = boxSize; @@ -367,11 +372,11 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max GL_Bind( image ); - for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) + for ( t = mins[1]+HalfSkySub; t < maxs[1]+HalfSkySub; t++ ) { qglBegin( GL_TRIANGLE_STRIP ); - for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) + for ( s = mins[0]+HalfSkySub; s <= maxs[0]+HalfSkySub; s++ ) { qglTexCoord2fv( s_skyTexCoords[t][s] ); qglVertex3fv( s_skyPoints[t][s] ); @@ -398,10 +403,10 @@ static void DrawSkyBox( shader_t *shader ) int sky_mins_subd[2], sky_maxs_subd[2]; int s, t; - sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; + sky_mins[0][i] = floor( sky_mins[0][i] * HalfSkySub ) / HalfSkySub; + sky_mins[1][i] = floor( sky_mins[1][i] * HalfSkySub ) / HalfSkySub; + sky_maxs[0][i] = ceil( sky_maxs[0][i] * HalfSkySub ) / HalfSkySub; + sky_maxs[1][i] = ceil( sky_maxs[1][i] * HalfSkySub ) / HalfSkySub; if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) || ( sky_mins[1][i] >= sky_maxs[1][i] ) ) @@ -409,38 +414,38 @@ static void DrawSkyBox( shader_t *shader ) continue; } - sky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS; - sky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS; - sky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS; - sky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS; - - if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS; - if ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS; - - if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS; - if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS; + sky_mins_subd[0] = sky_mins[0][i] * HalfSkySub; + sky_mins_subd[1] = sky_mins[1][i] * HalfSkySub; + sky_maxs_subd[0] = sky_maxs[0][i] * HalfSkySub; + sky_maxs_subd[1] = sky_maxs[1][i] * HalfSkySub; + + if ( sky_mins_subd[0] < -HalfSkySub ) + sky_mins_subd[0] = -HalfSkySub; + else if ( sky_mins_subd[0] > HalfSkySub ) + sky_mins_subd[0] = HalfSkySub; + if ( sky_mins_subd[1] < -HalfSkySub ) + sky_mins_subd[1] = -HalfSkySub; + else if ( sky_mins_subd[1] > HalfSkySub ) + sky_mins_subd[1] = HalfSkySub; + + if ( sky_maxs_subd[0] < -HalfSkySub ) + sky_maxs_subd[0] = -HalfSkySub; + else if ( sky_maxs_subd[0] > HalfSkySub ) + sky_maxs_subd[0] = HalfSkySub; + if ( sky_maxs_subd[1] < -HalfSkySub ) + sky_maxs_subd[1] = -HalfSkySub; + else if ( sky_maxs_subd[1] > HalfSkySub ) + sky_maxs_subd[1] = HalfSkySub; // // iterate through the subdivisions // - for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ ) + for ( t = sky_mins_subd[1]+HalfSkySub; t <= sky_maxs_subd[1]+HalfSkySub; t++ ) { - for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ ) + for ( s = sky_mins_subd[0]+HalfSkySub; s <= sky_maxs_subd[0]+HalfSkySub; s++ ) { - MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, + MakeSkyVec( ( s - HalfSkySub ) / ( float ) HalfSkySub, + ( t - HalfSkySub ) / ( float ) HalfSkySub, i, s_skyTexCoords[t][s], s_skyPoints[t][s] ); @@ -463,9 +468,9 @@ static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean ad tHeight = maxs[1] - mins[1] + 1; sWidth = maxs[0] - mins[0] + 1; - for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) + for ( t = mins[1]+HalfSkySub; t <= maxs[1]+HalfSkySub; t++ ) { - for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) + for ( s = mins[0]+HalfSkySub; s <= maxs[0]+HalfSkySub; s++ ) { VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0]; @@ -516,7 +521,7 @@ static void FillCloudBox( const shader_t *shader, int stage ) if ( 1 ) // FIXME? shader->sky.fullClouds ) { - MIN_T = -HALF_SKY_SUBDIVISIONS; + MIN_T = -HalfSkySub; // still don't want to draw the bottom, even if fullClouds if ( i == 5 ) @@ -537,15 +542,15 @@ static void FillCloudBox( const shader_t *shader, int stage ) continue; case 4: // top default: - MIN_T = -HALF_SKY_SUBDIVISIONS; + MIN_T = -HalfSkySub; break; } } - sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; + sky_mins[0][i] = floor( sky_mins[0][i] * HalfSkySub ) / HalfSkySub; + sky_mins[1][i] = floor( sky_mins[1][i] * HalfSkySub ) / HalfSkySub; + sky_maxs[0][i] = ceil( sky_maxs[0][i] * HalfSkySub ) / HalfSkySub; + sky_maxs[1][i] = ceil( sky_maxs[1][i] * HalfSkySub ) / HalfSkySub; if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) || ( sky_mins[1][i] >= sky_maxs[1][i] ) ) @@ -553,38 +558,38 @@ static void FillCloudBox( const shader_t *shader, int stage ) continue; } - sky_mins_subd[0] = ri.ftol(sky_mins[0][i] * HALF_SKY_SUBDIVISIONS); - sky_mins_subd[1] = ri.ftol(sky_mins[1][i] * HALF_SKY_SUBDIVISIONS); - sky_maxs_subd[0] = ri.ftol(sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS); - sky_maxs_subd[1] = ri.ftol(sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS); + sky_mins_subd[0] = ri.ftol(sky_mins[0][i] * HalfSkySub); + sky_mins_subd[1] = ri.ftol(sky_mins[1][i] * HalfSkySub); + sky_maxs_subd[0] = ri.ftol(sky_maxs[0][i] * HalfSkySub); + sky_maxs_subd[1] = ri.ftol(sky_maxs[1][i] * HalfSkySub); - if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS; + if ( sky_mins_subd[0] < -HalfSkySub ) + sky_mins_subd[0] = -HalfSkySub; + else if ( sky_mins_subd[0] > HalfSkySub ) + sky_mins_subd[0] = HalfSkySub; if ( sky_mins_subd[1] < MIN_T ) sky_mins_subd[1] = MIN_T; - else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS; + else if ( sky_mins_subd[1] > HalfSkySub ) + sky_mins_subd[1] = HalfSkySub; - if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS; + if ( sky_maxs_subd[0] < -HalfSkySub ) + sky_maxs_subd[0] = -HalfSkySub; + else if ( sky_maxs_subd[0] > HalfSkySub ) + sky_maxs_subd[0] = HalfSkySub; if ( sky_maxs_subd[1] < MIN_T ) sky_maxs_subd[1] = MIN_T; - else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS; + else if ( sky_maxs_subd[1] > HalfSkySub ) + sky_maxs_subd[1] = HalfSkySub; // // iterate through the subdivisions // - for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ ) + for ( t = sky_mins_subd[1]+HalfSkySub; t <= sky_maxs_subd[1]+HalfSkySub; t++ ) { - for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ ) + for ( s = sky_mins_subd[0]+HalfSkySub; s <= sky_maxs_subd[0]+HalfSkySub; s++ ) { - MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, + MakeSkyVec( ( s - HalfSkySub ) / ( float ) HalfSkySub, + ( t - HalfSkySub ) / ( float ) HalfSkySub, i, NULL, s_skyPoints[t][s] ); @@ -644,19 +649,30 @@ void R_InitSkyTexCoords( float heightCloud ) vec3_t skyVec; vec3_t v; + + // leilei - sky optimizations + SkySub = r_skytess->integer; + HalfSkySub = r_skytess->integer / 2; + + if (SkySub < 2) SkySub = 2; + if (SkySub > 8) SkySub = 8; + if (HalfSkySub < 1) HalfSkySub = 1; + if (HalfSkySub > 4) HalfSkySub = 4; + + // init zfar so MakeSkyVec works even though // a world hasn't been bounded backEnd.viewParms.zFar = 1024; for ( i = 0; i < 6; i++ ) { - for ( t = 0; t <= SKY_SUBDIVISIONS; t++ ) + for ( t = 0; t <= SkySub; t++ ) { - for ( s = 0; s <= SKY_SUBDIVISIONS; s++ ) + for ( s = 0; s <= SkySub; s++ ) { // compute vector from view origin to sky side integral point - MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, + MakeSkyVec( ( s - HalfSkySub ) / ( float ) HalfSkySub, + ( t - HalfSkySub ) / ( float ) HalfSkySub, i, NULL, skyVec ); @@ -705,6 +721,7 @@ void RB_DrawSun( void ) { if ( !backEnd.skyRenderedThisView ) { return; } + // TODO: Add a sun check for sky shaders explicitly requesting for the sun, to keep compatibility with sun-less skies. if ( !r_drawSun->integer ) { return; } @@ -838,7 +855,9 @@ void RB_StageIteratorSky( void ) { // r_showsky will let all the sky blocks be drawn in // front of everything to allow developers to see how // much sky is getting sucked in - if ( r_showsky->integer ) { + if ( r_showsky->integer == 2) { + qglDepthRange( 0.0, 1.0 ); // leilei - pvr1 imitation + } else if ( r_showsky->integer ) { qglDepthRange( 0.0, 0.0 ); } else { qglDepthRange( 1.0, 1.0 ); From bd458c0fd1d95c1630c0c30fa608dd4726072c31 Mon Sep 17 00:00:00 2001 From: leilei- Date: Sat, 24 May 2025 21:45:25 -0400 Subject: [PATCH 14/20] - More r_dynamiclight options: r_dynamiclight 2 = Slightly additive dynamic light projections, modeled after the PS2 port r_dynamiclight 3 = disables dynamic light projections but substitutes them with flashblends (ala GLQuake). If r_monolightmaps are enabled, the flashblends are orange. Viewblends are left out as the sudden duration of the dynamic lights when firing would be harmful. - Because of these changes, Riva 128 and Permedia 2 owners should be allowed to enjoy dynamic lights - option to use ReactOS's wspiapi.h header (file not included) - some makefile changes to allow an option for more Win 4 (95/NT4) compatiblity easier. Compiling with WINFOUR disables curl, uses SDL1, and has some additional workarounds to get it working on Windows 95 (winsock2 still required though) --- Makefile | 25 +++++++++- Makefile.OpenArena | 16 ++++++- code/qcommon/net_ip.c | 6 +++ code/reactos/readme.md | 2 + code/renderer_oa/tr_backend.c | 90 +++++++++++++++++++++++++++++++++++ code/renderer_oa/tr_local.h | 2 + code/renderer_oa/tr_scene.c | 29 ++++++++--- code/renderer_oa/tr_shade.c | 6 +++ code/renderer_oa/tr_shader.c | 9 ++++ code/sys/sys_main.c | 6 +++ code/sys/sys_win32.c | 6 ++- 11 files changed, 186 insertions(+), 11 deletions(-) create mode 100644 code/reactos/readme.md diff --git a/Makefile b/Makefile index ee2700ae7c..4cb402553e 100644 --- a/Makefile +++ b/Makefile @@ -228,6 +228,14 @@ ifndef USE_LOCAL_HEADERS USE_LOCAL_HEADERS=1 endif +ifndef WINFOUR +WINFOUR=0 +endif + +ifndef USE_REACTOS_WINSOCK_HEADER +USE_REACTOS_WINSOCK_HEADER=0 +endif + ifndef USE_RENDERER_DLOPEN USE_RENDERER_DLOPEN=1 endif @@ -244,6 +252,15 @@ ifndef SDL_VERSION SDL_VERSION=2 endif +ifeq ($(WINFOUR),1) + BASE_CFLAGS += -DWINFOUR + BASE_CFLAGS += -DUSE_REACTOS_WINSOCK_HEADER + BASE_CFLAGS += -DUSE_INTERNAL_JPEG + SDL_VERSION=1 + USE_CURL=0 + CLIENTBIN=oa95 +endif + ############################################################################# BD=$(BUILD_DIR)/debug-$(PLATFORM)-$(ARCH) @@ -1141,6 +1158,10 @@ ifeq ($(USE_LOCAL_HEADERS),1) BASE_CFLAGS += -DUSE_LOCAL_HEADERS endif +ifeq ($(USE_REACTOS_WINSOCK_HEADER),1) + BASE_CFLAGS += -DUSE_REACTOS_WINSOCK_HEADER +endif + ifeq ($(BUILD_STANDALONE),1) BASE_CFLAGS += -DSTANDALONE endif @@ -3020,8 +3041,8 @@ else @$(MAKE) VERSION=$(VERSION) -C $(LOKISETUPDIR) V=$(V) endif -dist: - git archive --format zip --output $(CLIENTBIN)-$(VERSION).zip HEAD +# dist: +# git archive --format zip --output $(CLIENTBIN)-$(VERSION).zip HEAD ############################################################################# # DEPENDENCIES diff --git a/Makefile.OpenArena b/Makefile.OpenArena index 7657f96c3a..7beee1636c 100644 --- a/Makefile.OpenArena +++ b/Makefile.OpenArena @@ -10,11 +10,13 @@ BUILD_CLIENT=1 BUILD_SERVER=1 BUILD_GAME_SO=0 BUILD_GAME_QVM=0 +USE_GIT=0 BUILD_BASEGAME=0 BUILD_MISSIONPACK=0 BASEGAME=baseoa # VERSION=1.36+0.8.8 -VERSION=3.0.0a +VERSION=TEST + # OpenArena doesn't use opus yet USE_CODEC_VORBIS=1 @@ -24,13 +26,17 @@ ifndef USE_CODEC_XMP USE_CODEC_XMP=1 endif +USE_CURL=1 + # FLTO Test OPTIMIZE += -flto -# This doesn't work with OpenArena yet +# Not supported BUILD_RENDERER_OPENGL2=0 # You can disable the renderer libraries and build in the OA renderer by default +# This is disabled because we have some client builtins used (trace etc) and +# we are scaling back some modularization for security and support reasons. USE_RENDERER_DLOPEN=0 # Choose version 1 or 2 @@ -58,6 +64,12 @@ CLIENTBIN=openarena SERVERBIN=oa_ded COPYDIR=/usr/local/games/openarena +# Use the Winsock2 headers from ReactOS, which doesn't give errors in Win9x +# USE_REACTOS_WINSOCK_HEADER=1 + +# Enable changes to allow Windows 95 and NT4 to work +# (Overrides enabling libraries above that don't work well, and outputs to oa95.exe) +WINFOUR=0 # DEBUG_CFLAGS=-ggdb -O0 diff --git a/code/qcommon/net_ip.c b/code/qcommon/net_ip.c index 4ef3e3453c..71920137a4 100644 --- a/code/qcommon/net_ip.c +++ b/code/qcommon/net_ip.c @@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # include # include # if WINVER < 0x501 + # ifdef __MINGW32__ // wspiapi.h isn't available on MinGW, so if it's // present it's because the end user has added it @@ -37,6 +38,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # endif # else # include +# endif + + // leilei - addition to fix win9x +# ifdef USE_REACTOS_WINSOCK_HEADER +# include "../reactos/wspiapi.h" # endif typedef int socklen_t; diff --git a/code/reactos/readme.md b/code/reactos/readme.md new file mode 100644 index 0000000000..dbc123d0ad --- /dev/null +++ b/code/reactos/readme.md @@ -0,0 +1,2 @@ +Place ReactOS' wspiapi.h file here. + diff --git a/code/renderer_oa/tr_backend.c b/code/renderer_oa/tr_backend.c index ff44597509..32cf2f7cc6 100644 --- a/code/renderer_oa/tr_backend.c +++ b/code/renderer_oa/tr_backend.c @@ -849,6 +849,95 @@ void RB_BeginDrawingView (void) { #define MAC_EVENT_PUMP_MSEC 5 + +/* +=================== +R_RenderFlashblend + +leilei - GLQuake RenderDlights +Renders the classic GLQuake flashblend cone to subsitute dynamic lights. May be +a little redundant with r_flaresDlight +=================== +*/ +static void R_RenderFlashblend (dlight_t *light) +{ + int i, j; + float a; + vec3_t v, vv; + float rad; + vec3_t vup, vpn, vright; + vec3_t point; + float ofs = 1; + + if ( (backEnd.refdef.rdflags & RDF_NOWORLDMODEL)) return; // leilei - don't draw flashblends in the UI + + VectorCopy( backEnd.refdef.viewaxis[0], vpn ); + VectorCopy( backEnd.refdef.viewaxis[1], vright ); + VectorCopy( backEnd.refdef.viewaxis[2], vup ); + + + rad = light->radius * 0.35f; + + for (int qj=0 ; qj<3 ; qj++) + v[qj] = light->origin[qj]; + + VectorSubtract (light->origin, backEnd.or.viewOrigin, vv); + + RB_BeginSurface( tr.coneShader, tess.fogNum ); + + for (i=0 ; i<3 ; i++) + tess.xyz[tess.numVertexes][i] = light->origin[i] - (vpn[i]*(rad*(ofs*.75))); + tess.vertexColors[tess.numVertexes][0] = light->color[0] * 64; + tess.vertexColors[tess.numVertexes][1] = light->color[1] * 64; + tess.vertexColors[tess.numVertexes][2] = light->color[2] * 64; + + // glquake's colors kick in if monolightmaps + if (r_monolightmaps->integer){ + tess.vertexColors[tess.numVertexes][0] = 0.3 * 255; + tess.vertexColors[tess.numVertexes][1] = 0.2 * 255; + tess.vertexColors[tess.numVertexes][2] = 0.0 * 255; + } + tess.vertexColors[tess.numVertexes][3] = 255; + tess.numVertexes++; + + for (int qi=0 ; qi<(17) ; qi++) + { + a = qi/(float)(16) * M_PI*2; + for (int qj=0 ; qj<3 ; qj++) + point[qj] = v[qj] + vright[qj]*cos(a)*rad + vup[qj]*sin(a)*rad; + VectorCopy (point, tess.xyz[tess.numVertexes] ); + tess.vertexColors[tess.numVertexes][0] = 0; + tess.vertexColors[tess.numVertexes][1] = 0; + tess.vertexColors[tess.numVertexes][2] = 0; + tess.vertexColors[tess.numVertexes][3] = 0; + tess.indexes[tess.numIndexes++] = 0; + tess.indexes[tess.numIndexes++] = qi; + tess.indexes[tess.numIndexes++] = qi+1; + tess.numVertexes++; + } + RB_EndSurface(); + +} + + +// leilei - go through the active dlights, and then draw them +static void RB_RenderFlashblends() { + int l; + int i; + if ( !backEnd.refdef.num_dlights ) { + return; + } + l = backEnd.refdef.dlights; + + for (i=0 ; iadditive == 2) + R_RenderFlashblend(dl); // this is definitely flashblend. + } + +}; + /* ================== RB_RenderDrawSurfList @@ -1038,6 +1127,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { // add the particles //R_AddParticles (); R_RenderParticles (); + RB_RenderFlashblends(); // add light flares on lights that aren't obscured RB_RenderFlares(); diff --git a/code/renderer_oa/tr_local.h b/code/renderer_oa/tr_local.h index d524c1e68f..0bd8c51782 100644 --- a/code/renderer_oa/tr_local.h +++ b/code/renderer_oa/tr_local.h @@ -1153,6 +1153,8 @@ typedef struct { shader_t *flareShaderAtlas; // leilei - lens reflections shader_t *sunShader; + shader_t *coneShader; // leilei - flashblends + qhandle_t skipProgram; qhandle_t defaultProgram; qhandle_t vertexLitProgram; diff --git a/code/renderer_oa/tr_scene.c b/code/renderer_oa/tr_scene.c index fa1773e13c..0db0c65b5f 100644 --- a/code/renderer_oa/tr_scene.c +++ b/code/renderer_oa/tr_scene.c @@ -241,10 +241,6 @@ void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, floa if ( intensity <= 0 ) { return; } - // these cards don't have the correct blend mode - if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) { - return; - } dl = &backEndData->dlights[r_numdlights++]; @@ -266,6 +262,26 @@ void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, floa dl->color[1] = g; dl->color[2] = b; dl->additive = additive; + + // leilei - q3r/alice mode + if ( r_dynamiclight->integer == 2){ + + dl->color[0] = r * 0.1; + dl->color[1] = g * 0.1; + dl->color[2] = b * 0.1; + dl->additive = 1; + } + + // these cards don't have the correct blend mode + // leilei - so force additive and keep going + if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) { + dl->additive = 1; + } + + // leilei - glquake mode - 2 shuts off the light projection to make room for flashblend + if ( r_dynamiclight->integer == 3) + dl->additive = 2; + } /* @@ -374,9 +390,10 @@ void RE_RenderScene( const refdef_t *fd ) { // turn off dynamic lighting globally by clearing all the // dlights if it needs to be disabled or if vertex lighting is enabled - if ( r_dynamiclight->integer == 0 || + if ( r_dynamiclight->integer == 0 // || // r_vertexLight->integer == 1 || // leilei - commented this out, as we can now do dynamic lights with vertex light - glConfig.hardwareType == GLHW_PERMEDIA2 ) { + // glConfig.hardwareType == GLHW_PERMEDIA2 // leilei - commented this out, as permedia should play with flashblend/verts + ) { tr.refdef.num_dlights = 0; } diff --git a/code/renderer_oa/tr_shade.c b/code/renderer_oa/tr_shade.c index 88d6f0bd75..afe021f3f3 100644 --- a/code/renderer_oa/tr_shade.c +++ b/code/renderer_oa/tr_shade.c @@ -644,6 +644,12 @@ static void ProjectDlightTexture_scalar( void ) { colors = colorArray[0]; dl = &backEnd.refdef.dlights[l]; + + if ( dl->additive == 2) // leilei - glquake flashblend mode + { + return; + } + VectorCopy( dl->transformed, origin ); radius = dl->radius; scale = 1.0f / radius; diff --git a/code/renderer_oa/tr_shader.c b/code/renderer_oa/tr_shader.c index a279e1ebbd..6c5779090e 100644 --- a/code/renderer_oa/tr_shader.c +++ b/code/renderer_oa/tr_shader.c @@ -5521,6 +5521,15 @@ static void CreateInternalShaders( void ) { Q_strncpyz( shader.name, "", sizeof( shader.name ) ); shader.sort = SS_STENCIL_SHADOW; tr.shadowShader = FinishShader(); + + // leilei - cone shader for flashblend + Q_strncpyz( shader.name, "", sizeof( shader.name ) ); + stages[0].bundle[0].image[0] = tr.whiteImage; + stages[0].active = qtrue; + stages[0].rgbGen = CGEN_VERTEX; + stages[0].alphaGen = AGEN_VERTEX; + stages[0].stateBits = GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE; + tr.coneShader = FinishShader(); } static void CreateExternalShaders( void ) { diff --git a/code/sys/sys_main.c b/code/sys/sys_main.c index ea3cf21e59..8e08ecbc2d 100644 --- a/code/sys/sys_main.c +++ b/code/sys/sys_main.c @@ -161,6 +161,12 @@ qboolean Sys_WritePIDFile( void ) FILE *f; qboolean stale = qfalse; +#ifdef WINFOUR + // leilei - workaround to avoid crashes on WinNT4/W9X + if ( pidFiles ) + return qfalse; +#endif + if( pidFile == NULL ) return qfalse; diff --git a/code/sys/sys_win32.c b/code/sys/sys_win32.c index 3288105fe0..5cb3bea9f7 100644 --- a/code/sys/sys_win32.c +++ b/code/sys/sys_win32.c @@ -170,7 +170,10 @@ Sys_RandomBytes qboolean Sys_RandomBytes( byte *string, int len ) { HCRYPTPROV prov; - + // leilei - NT 3.51 doesn't have this in ADVAPI32, so leave this out of WINFOUR +#ifdef WINFOUR + return qfalse; +#else if( !CryptAcquireContext( &prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) ) { @@ -183,6 +186,7 @@ qboolean Sys_RandomBytes( byte *string, int len ) } CryptReleaseContext( prov, 0 ); return qtrue; +#endif } /* From 16ae6f4fdded916783eeb6524eab76a0ed5d1539 Mon Sep 17 00:00:00 2001 From: leilei- Date: Fri, 30 May 2025 06:19:20 -0400 Subject: [PATCH 15/20] - fixed a fog modulation regression stemming from a rgbMod case returning and not breaking. whoops - little warning cleanup wrt flashblend --- code/renderer_oa/tr_backend.c | 22 +++++++++------------- code/renderer_oa/tr_shade.c | 2 +- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/code/renderer_oa/tr_backend.c b/code/renderer_oa/tr_backend.c index 32cf2f7cc6..e33cf4d7e8 100644 --- a/code/renderer_oa/tr_backend.c +++ b/code/renderer_oa/tr_backend.c @@ -861,9 +861,9 @@ a little redundant with r_flaresDlight */ static void R_RenderFlashblend (dlight_t *light) { - int i, j; + int i; float a; - vec3_t v, vv; + vec3_t v; float rad; vec3_t vup, vpn, vright; vec3_t point; @@ -881,8 +881,6 @@ static void R_RenderFlashblend (dlight_t *light) for (int qj=0 ; qj<3 ; qj++) v[qj] = light->origin[qj]; - VectorSubtract (light->origin, backEnd.or.viewOrigin, vv); - RB_BeginSurface( tr.coneShader, tess.fogNum ); for (i=0 ; i<3 ; i++) @@ -921,15 +919,13 @@ static void R_RenderFlashblend (dlight_t *light) // leilei - go through the active dlights, and then draw them -static void RB_RenderFlashblends() { - int l; +static void RB_RenderFlashblends(void) { int i; if ( !backEnd.refdef.num_dlights ) { return; } - l = backEnd.refdef.dlights; - for (i=0 ; iadditive == 2) @@ -945,13 +941,13 @@ RB_RenderDrawSurfList */ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader, *oldShader; - int fogNum, oldFogNum; - int entityNum, oldEntityNum; - int dlighted, oldDlighted; + int fogNum, oldFogNum; + int entityNum, oldEntityNum; + int dlighted, oldDlighted; qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair; - int i; + int i; drawSurf_t *drawSurf; - int oldSort; + int oldSort; float originalTime; // save original time for entity shader offsets diff --git a/code/renderer_oa/tr_shade.c b/code/renderer_oa/tr_shade.c index afe021f3f3..9e1b2bb784 100644 --- a/code/renderer_oa/tr_shade.c +++ b/code/renderer_oa/tr_shade.c @@ -1031,7 +1031,7 @@ static void ComputeColors( shaderStage_t *pStage ) // TODO break; case CMOD_BAD: - return; + break; } // From d825d6f6aa398aef9f6db44d37da650992c5953f Mon Sep 17 00:00:00 2001 From: leilei- Date: Sat, 28 Jun 2025 23:43:00 -0400 Subject: [PATCH 16/20] Sun stuff - r_drawSun is now default 1 (was 0), because... - sunShader key - allows sky shaders to explicitly define a shader to use for the sun. In addition to that, a flare type number and a size multiplier number can follow for a little more customization. Partially inspired by RTCW's sunshader key, which only dealt with the image (and never finished their lens flare reflections) - Suns with a portal on screen won't cancel out the sun or its flare - If no sun flare is specified, don't draw a sun flare at all. should be one less unnecessary depth read - r_drawSun 2 is the old 'always show sun' behavior - sun shader now correctly orientated - drawing the sun uses a quadstamp - some 'low end video' alternative shader loading that current does not work. May revert - ifdefing out shademethod LOD for fixing later --- code/renderer_oa/tr_bsp.c | 9 +++ code/renderer_oa/tr_flares.c | 20 +++++++ code/renderer_oa/tr_init.c | 9 ++- code/renderer_oa/tr_local.h | 17 ++++-- code/renderer_oa/tr_shade_calc.c | 2 + code/renderer_oa/tr_shader.c | 95 ++++++++++++++++++++++++++++---- code/renderer_oa/tr_sky.c | 81 +++++++++------------------ 7 files changed, 162 insertions(+), 71 deletions(-) diff --git a/code/renderer_oa/tr_bsp.c b/code/renderer_oa/tr_bsp.c index d995c55625..19ac5c7a98 100644 --- a/code/renderer_oa/tr_bsp.c +++ b/code/renderer_oa/tr_bsp.c @@ -1878,6 +1878,9 @@ void RE_LoadWorldMap( const char *name ) { tr.sunDirection[0] = 0.45f; tr.sunDirection[1] = 0.3f; tr.sunDirection[2] = 0.9f; + + // leilei - deactivate sun and flare if it ain't there + tr.sunOn = 0; tr.sunFlare = 0; tr.sunShaderCustom = 0; VectorNormalize( tr.sunDirection ); @@ -1929,6 +1932,12 @@ void RE_LoadWorldMap( const char *name ) { R_LoadEntities( &header->lumps[LUMP_ENTITIES] ); R_LoadLightGrid( &header->lumps[LUMP_LIGHTGRID] ); + // leilei - load our specific custom sun here + if (tr.sunShaderCustom) + tr.sunShader = R_FindShader( tr.sunShaderCustom, LIGHTMAP_NONE, qtrue ); + else + tr.sunShader = R_FindShader( "sun", LIGHTMAP_NONE, qtrue ); + s_worldData.dataSize = (byte *)ri.Hunk_Alloc(0, h_low) - startMarker; // only set tr.world now that we know the entire level has loaded properly diff --git a/code/renderer_oa/tr_flares.c b/code/renderer_oa/tr_flares.c index b8a6b06590..495d6a5991 100644 --- a/code/renderer_oa/tr_flares.c +++ b/code/renderer_oa/tr_flares.c @@ -1330,11 +1330,31 @@ void RB_DrawSunFlare( void ) return; } + // leilei - don't draw the flare if we ain't got the sun + if ( !r_drawSun->integer ) { + return; + } + + // don't draw the flare if we don't define the sun + if ( r_drawSun->integer == 1 && (!tr.sunOn) ) { + return; + } + if ( backEnd.doneSunFlare) // leilei - only do sun once return; + if (backEnd.viewParms.isPortal) // leilei - do sun only not in the portal (keeps sun from disappearing when portal is onscreen) + return; + fetype = r_flareSun->integer; + // if we specified a flare type for sunshader in the sky, then we use it. + if (tr.sunOn && (r_drawSun->integer == 1)) { + fetype = tr.sunFlare; + } + // but, if we don't want the sunflare (type is 0 - either on the r_drawSun 2 override or the shader) then we just forget it + if (fetype == 0) return; + qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); diff --git a/code/renderer_oa/tr_init.c b/code/renderer_oa/tr_init.c index a148083089..b5e20e25e4 100644 --- a/code/renderer_oa/tr_init.c +++ b/code/renderer_oa/tr_init.c @@ -222,6 +222,9 @@ cvar_t *r_suggestiveThemes; // leilei - mature content control cvar_t *r_textureDither; // leilei - Dithered texture +cvar_t *r_lerpbias; // Leilei - lerping bias + +cvar_t *r_lowEndVideo; // leilei - load .low shaders // leilei - fallback shader hack @@ -1196,7 +1199,7 @@ void R_Register( void ) r_ignoreGLErrors = ri.Cvar_Get( "r_ignoreGLErrors", "1", CVAR_ARCHIVE ); r_fastsky = ri.Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE ); r_inGameVideo = ri.Cvar_Get( "r_inGameVideo", "1", CVAR_ARCHIVE ); - r_drawSun = ri.Cvar_Get( "r_drawSun", "0", CVAR_ARCHIVE ); + r_drawSun = ri.Cvar_Get( "r_drawSun", "1", CVAR_ARCHIVE ); // leilei - default 1 for allowing sky shaders to define a sun. r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE ); r_dlightBacks = ri.Cvar_Get( "r_dlightBacks", "1", CVAR_ARCHIVE ); r_finish = ri.Cvar_Get ("r_finish", "0", CVAR_ARCHIVE); @@ -1307,12 +1310,16 @@ void R_Register( void ) r_particles = ri.Cvar_Get( "r_particles", "0" , CVAR_ARCHIVE | CVAR_LATCH); r_leidebugeye = ri.Cvar_Get( "r_leidebugeye", "0" , CVAR_CHEAT); + r_lerpbias = ri.Cvar_Get( "r_lerpbias", "-2" , CVAR_ARCHIVE); + r_iconmip = ri.Cvar_Get ("r_iconmip", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - icon mip r_iconBits = ri.Cvar_Get ("r_iconBits", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - icon bits r_lightmapBits = ri.Cvar_Get ("r_lightmapBits", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - lightmap color bits r_lightmapColorNorm = ri.Cvar_Get ("r_lightmapColorNorm", "1", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - lightmap color normalization + r_lowEndVideo = ri.Cvar_Get( "r_lowEndVideo", "0", CVAR_ARCHIVE | CVAR_LATCH ); + r_textureDither = ri.Cvar_Get ("r_textureDither", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - dithered textures // make sure all the commands added here are also diff --git a/code/renderer_oa/tr_local.h b/code/renderer_oa/tr_local.h index 0bd8c51782..d4af6e248b 100644 --- a/code/renderer_oa/tr_local.h +++ b/code/renderer_oa/tr_local.h @@ -1152,6 +1152,7 @@ typedef struct { shader_t *flareShader; shader_t *flareShaderAtlas; // leilei - lens reflections shader_t *sunShader; + char *sunShaderCustom; // leilei - sunShader override shader_t *coneShader; // leilei - flashblends @@ -1193,6 +1194,8 @@ typedef struct { vec3_t sunLight; // from the sky shader for this level vec3_t sunDirection; + int sunFlare; // leilei - sun flare type + float sunOn; // leilei - allow the sun to be drawn, if a sunShader is specified by a sky shader. This is a float so we can multiply the size of the sun in the shader frontEndCounters_t pc; int frontEndMsec; // not in pc due to clearing issue @@ -1255,7 +1258,7 @@ extern glstate_t glState; // outside of TR since it shouldn't be cleared during extern qboolean vertexShaders; extern qboolean postprocess; extern int leifxmode; // leilei - leifx -extern char depthimage; +extern char depthimage; // // cvars @@ -1396,6 +1399,8 @@ extern cvar_t *r_particles; // Leilei - particles! extern cvar_t *r_iconmip; // leilei - icon mip - picmip for 2d icons extern cvar_t *r_iconBits; // leilei - icon color depth for 2d icons +extern cvar_t *r_lerpbias; // Leilei - lerping bias + extern cvar_t *r_lightmapBits; // leilei - lightmap color depth extern cvar_t *r_lightmapColorNorm; // leilei - lightmap color normalize @@ -1406,6 +1411,8 @@ extern cvar_t *r_textureDither; // leilei - apply dithering for lower texture extern cvar_t *r_skytess; // leilei - adjusts the subdivisions of the sky (max 8, min 1) +extern cvar_t *r_lowEndVideo; // leilei - load .low shaders + //==================================================================== void R_SwapBuffers( int ); @@ -1567,12 +1574,12 @@ typedef struct shaderCommands_s shader_t *shader; float shaderTime; - int fogNum; + int fogNum; - int dlightBits; // or together of all vertexDlightBits + int dlightBits; // or together of all vertexDlightBits - int numIndexes; - int numVertexes; + int numIndexes; + int numVertexes; // info extracted from current shader int numPasses; diff --git a/code/renderer_oa/tr_shade_calc.c b/code/renderer_oa/tr_shade_calc.c index 7d3018fc78..0e78798283 100644 --- a/code/renderer_oa/tr_shade_calc.c +++ b/code/renderer_oa/tr_shade_calc.c @@ -1818,6 +1818,7 @@ void RB_CalcDiffuseColor( unsigned char *colors ) { RB_CalcMaterials( colors, 0xFFFFFF, 0x808080, 0x808080, 0x000000, 128, 255 ); } +#if BROKEN // leilei: FIXME this does not work as intended else if ((r_shadeMethod->integer > 150) && (r_shadeMethod->integer < 667)) // values in a certain range is an adaptive LOD selection of -1, 0 and 3 { float projectedRadius, fsh, shadescale, radius; @@ -1838,6 +1839,7 @@ void RB_CalcDiffuseColor( unsigned char *colors ) RB_CalcDiffuseColor_flat( colors ); } +#endif // BROKEN else // standard idtech3 shading { RB_CalcDiffuseColor_scalar( colors ); diff --git a/code/renderer_oa/tr_shader.c b/code/renderer_oa/tr_shader.c index 6c5779090e..ac1f1eafaf 100644 --- a/code/renderer_oa/tr_shader.c +++ b/code/renderer_oa/tr_shader.c @@ -3604,6 +3604,38 @@ static qboolean ParseShader( char **text ) SkipRestOfLine( text ); continue; } + + // leilei - Parse a shader for the sun, and a type of flare for the number after it. + // Inspired by ET's sunShader (my own implementation) + else if ( !Q_stricmp( token, "sunShader" ) ) { + // load a sun shader to override our default shader + token = COM_ParseExt( text, qfalse ); + + tr.sunShaderCustom = CopyString(token); // leilei - copy the shader's name so we can load it properly elsewhere (doing it here would make a broken sun) + tr.sunOn = 1; // activate sun to be rendered for r_drawSun 1. + + // the next one is the flare type. + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + tr.sunFlare = 0; // dont flare if we dont specify + continue; + } + tr.sunFlare = atoi( token ); + + // the next one is a size multiplier. + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + tr.sunOn = 1; // sun is always normal size if we don't specify + continue; + } + if (atof( token )>1) + tr.sunOn = atof( token ); + + continue; + } + // sun parms else if ( !Q_stricmp( token, "q3map_sun" ) ) { float a, b; @@ -5346,18 +5378,41 @@ a single large text block that can be scanned for shader names ===================== */ #define MAX_SHADER_FILES 4096 + +static int Shader_AddFileToList( char *name, char *list[0x1000], int nfiles ) { + int i; + + if ( nfiles == 0x1000 - 1 ) { + return nfiles; + } + for ( i = 0 ; i < nfiles ; i++ ) { + if ( !Q_stricmp( name, list[i] ) ) { + return nfiles; // allready in list + } + } + list[nfiles] = CopyString( name ); + nfiles++; + + return nfiles; +} + + static void ScanAndLoadShaderFiles( void ) { char **shaderFiles; + char *buffers[MAX_SHADER_FILES]; char *p; int numShaderFiles; - int i; + int i, j; char *oldp, *token, *hashMem, *textEnd; int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size; char shaderName[MAX_QPATH]; int shaderLine; + char **lowShaderFiles; + int numLowShaderFiles; + long sum = 0, summand; // scan for shader files shaderFiles = ri.FS_ListFiles( "scripts", ".shader", &numShaderFiles ); @@ -5368,10 +5423,6 @@ static void ScanAndLoadShaderFiles( void ) return; } - if ( numShaderFiles > MAX_SHADER_FILES ) { - numShaderFiles = MAX_SHADER_FILES; - } - // load and parse shader files for ( i = 0; i < numShaderFiles; i++ ) { @@ -5383,7 +5434,7 @@ static void ScanAndLoadShaderFiles( void ) if ( !buffers[i] ) ri.Error( ERR_DROP, "Couldn't load %s", filename ); - + // Do a simple check on the shader structure in that file to make sure one bad shader file cannot fuck up all other shaders. p = buffers[i]; COM_BeginParseSession(filename); @@ -5427,8 +5478,35 @@ static void ScanAndLoadShaderFiles( void ) sum += summand; } + // leilei - low end video + if (r_lowEndVideo->integer) + { + + + lowShaderFiles = ri.FS_ListFiles( "scripts", ".low", &numLowShaderFiles ); + // shaderFiles += lowShaderFiles; + // numShaderFiles += numLowShaderFiles; + + // leilei - append in low shader files + if (numLowShaderFiles) + for ( i = 0; i < numLowShaderFiles; i++ ) + { + ri.Printf( PRINT_WARNING, "USING LOW END SHADER: %s\n", lowShaderFiles[i]); + // Shader_AddFileToList (lowShaderFiles[i], shaderFiles, numShaderFiles); + // shaderFiles[numShaderFiles+1] = lowShaderFiles[i];CopyString( lowShaderFiles[i] ); + // numShaderFiles++; + // shaderFiles[numShaderFiles+1] = lowShaderFiles[i]; + + } + } + + + if ( numShaderFiles > MAX_SHADER_FILES ) { + numShaderFiles = MAX_SHADER_FILES; + } + // build single large buffer - s_shaderText = ri.Hunk_Alloc( sum + numShaderFiles*2, h_low ); + s_shaderText = ri.Hunk_Alloc( sum + (numShaderFiles*2) + (numLowShaderFiles*2), h_low ); s_shaderText[ 0 ] = '\0'; textEnd = s_shaderText; @@ -5576,9 +5654,6 @@ static void CreateExternalShaders( void ) { } } - - tr.sunShader = R_FindShader( "sun", LIGHTMAP_NONE, qtrue ); - // leilei - placeholder shaders tr.placeholderTextureShader = R_FindShader( "placeholder_texture", LIGHTMAP_NONE, qtrue ); tr.placeholderModelShader = R_FindShader( "placeholder_model", LIGHTMAP_NONE, qtrue ); diff --git a/code/renderer_oa/tr_sky.c b/code/renderer_oa/tr_sky.c index f09d69c641..edc3072d42 100644 --- a/code/renderer_oa/tr_sky.c +++ b/code/renderer_oa/tr_sky.c @@ -716,7 +716,6 @@ void RB_DrawSun( void ) { float size; float dist; vec3_t origin, vec1, vec2; - vec3_t temp; if ( !backEnd.skyRenderedThisView ) { return; @@ -726,15 +725,33 @@ void RB_DrawSun( void ) { return; } + // leilei - do the actual sun check, for our default behavior + if ( r_drawSun->integer == 1 && !tr.sunOn ) { + return; + } + + if ( (backEnd.refdef.rdflags & RDF_NOWORLDMODEL)) return; // leilei - don't bother with sun if we don't world. Possible crash prevention to an uninitialized sun + + if ( !tr.sunShader ) // leilei - if we somehow, did not load a sun shader at all for some reason, don't try + return; + if ( backEnd.doneSun) // leilei - only do sun once return; + if (backEnd.viewParms.isPortal) // leilei - do sun only not in the portal (keeps sun from disappearing when portal is onscreen) + return; + qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) size = dist * 0.4; + // leilei - allow the size of the sun to be changed + if (tr.sunOn) + size *= tr.sunOn; + + size *= -1; // inverse to fix flip // leilei - SUN color vec3_t coll; @@ -766,62 +783,16 @@ void RB_DrawSun( void ) { // farthest depth range qglDepthRange( 1.0, 1.0 ); - - - - // FIXME: use quad stamp RB_BeginSurface( tr.sunShader, tess.fogNum ); - VectorCopy( origin, temp ); - VectorSubtract( temp, vec1, temp ); - VectorSubtract( temp, vec2, temp ); - VectorCopy( temp, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = 255; - tess.vertexColors[tess.numVertexes][1] = 255; - tess.vertexColors[tess.numVertexes][2] = 255; - tess.numVertexes++; - - VectorCopy( origin, temp ); - VectorAdd( temp, vec1, temp ); - VectorSubtract( temp, vec2, temp ); - VectorCopy( temp, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = 255; - tess.vertexColors[tess.numVertexes][1] = 255; - tess.vertexColors[tess.numVertexes][2] = 255; - tess.numVertexes++; - - VectorCopy( origin, temp ); - VectorAdd( temp, vec1, temp ); - VectorAdd( temp, vec2, temp ); - VectorCopy( temp, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 1; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = 255; - tess.vertexColors[tess.numVertexes][1] = 255; - tess.vertexColors[tess.numVertexes][2] = 255; - tess.numVertexes++; - - VectorCopy( origin, temp ); - VectorSubtract( temp, vec1, temp ); - VectorAdd( temp, vec2, temp ); - VectorCopy( temp, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 1; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = 255; - tess.vertexColors[tess.numVertexes][1] = 255; - tess.vertexColors[tess.numVertexes][2] = 255; - tess.numVertexes++; - - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 1; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 3; + // leilei - for quadstamp + byte colb[4]; + colb[0] = coll[0] * 255; + colb[1] = coll[1] * 255; + colb[2] = coll[2] * 255; + colb[3] = 255; + + RB_AddQuadStamp( origin, vec1, vec2, colb ); RB_EndSurface(); // back to normal depth range From 3827ec0073c704551dac52357b295a51fb443f78 Mon Sep 17 00:00:00 2001 From: leilei- Date: Tue, 1 Jul 2025 06:11:55 -0400 Subject: [PATCH 17/20] - GetViewPosition builtin for cgame to allow stuff like text drawn over entities - MDR physics: allows MDR bones to move independently of model by a defined file on bone numbers, their type, etc. (like hair and flags), but broken (currently ifdef'd out) - ifdef'd out IQM support as that's broken, we aren't using it, and only other whole games are using it - Removed attempt at r_lowEndVideo --- code/cgame/cg_public.h | 3 +- code/cgame/cg_syscalls.asm | 1 + code/client/cl_cgame.c | 4 +- code/qcommon/qcommon.h | 5 + code/qcommon/qfiles.h | 16 ++ code/renderer_oa/tr_animation.c | 286 +++++++++++++++++++++++++++++++ code/renderer_oa/tr_init.c | 10 +- code/renderer_oa/tr_local.h | 87 +++++++++- code/renderer_oa/tr_main.c | 2 + code/renderer_oa/tr_model.c | 167 +++++++++++++++++- code/renderer_oa/tr_model_iqm.c | 4 +- code/renderer_oa/tr_shade.c | 46 +++++ code/renderer_oa/tr_shade_calc.c | 2 +- code/renderer_oa/tr_shader.c | 49 +----- code/renderer_oa/tr_surface.c | 20 +++ code/renderercommon/tr_public.h | 1 + 16 files changed, 635 insertions(+), 68 deletions(-) diff --git a/code/cgame/cg_public.h b/code/cgame/cg_public.h index caefff0ac7..2592ab8015 100644 --- a/code/cgame/cg_public.h +++ b/code/cgame/cg_public.h @@ -183,7 +183,8 @@ typedef enum { CG_TESTPRINTINT, CG_TESTPRINTFLOAT, CG_ACOS, - CG_R_LFX_PARTICLEEFFECT // leilei - particle effects + CG_R_LFX_PARTICLEEFFECT, // leilei - particle effects + CG_R_VIEWPOSITION // leilei - view position } cgameImport_t; diff --git a/code/cgame/cg_syscalls.asm b/code/cgame/cg_syscalls.asm index f6f8d9efa7..fdbced3b72 100644 --- a/code/cgame/cg_syscalls.asm +++ b/code/cgame/cg_syscalls.asm @@ -104,3 +104,4 @@ equ testPrintInt -110 equ testPrintFloat -111 equ acos -112 equ trap_R_LFX_ParticleEffect -113 +equ trap_R_GetViewPosition -114 diff --git a/code/client/cl_cgame.c b/code/client/cl_cgame.c index 31a6a4d981..9d86e97176 100644 --- a/code/client/cl_cgame.c +++ b/code/client/cl_cgame.c @@ -637,7 +637,9 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) { case CG_R_LFX_PARTICLEEFFECT: re.LFX_ParticleEffect( args[1], VMA(2), VMA(3)); return 0; - + case CG_R_VIEWPOSITION: + re.GetViewPosition( VMA(1) ); + return VMA(1); case CG_PC_ADD_GLOBAL_DEFINE: return botlib_export->PC_AddGlobalDefine( VMA(1) ); case CG_PC_LOAD_SOURCE: diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index f219f572d4..b631e13b6f 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -34,6 +34,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA //#define PRE_RELEASE_DEMO +// leilei - broken things + +//#define BROKEN_MDRPHYS // MDR physics are not serialized! +//#define BROKEN_IQM // crashes (and we don't plan to use the format anyway. IQM users are other games) + //============================================================================ // diff --git a/code/qcommon/qfiles.h b/code/qcommon/qfiles.h index 9f2b5fb23e..b3beb19b85 100644 --- a/code/qcommon/qfiles.h +++ b/code/qcommon/qfiles.h @@ -300,6 +300,22 @@ typedef struct { int ofsEnd; // end of file } mdrHeader_t; +#ifdef BROKEN_MDRPHYS +// leilei - bone deformery +// MDR loading also checks for a text file that can set these properties so the "MDP" code can get to work with them. +// and working from the cliententity. +typedef struct { + + vec3_t ofs[MDR_MAX_BONES]; + vec3_t wgt[MDR_MAX_BONES]; + float jiggle[MDR_MAX_BONES]; + +} mdrClBoneDeformSet_t; + +typedef struct { + mdrClBoneDeformSet_t def[4]; // up to 4 can alter bones +} mdrDeformity_t; +#endif /* ============================================================================== diff --git a/code/renderer_oa/tr_animation.c b/code/renderer_oa/tr_animation.c index 7bcc5bdf69..182a98d836 100644 --- a/code/renderer_oa/tr_animation.c +++ b/code/renderer_oa/tr_animation.c @@ -177,6 +177,9 @@ R_MDRAddAnimSurfaces */ // much stuff in there is just copied from R_AddMd3Surfaces in tr_mesh.c +#ifdef BROKEN_MDRPHYS +int TheRealMDL; // leilei HACK - tr.currentModel->index returns an incorrect index at this point, so we must set this from tr_main. +#endif void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { mdrHeader_t *header; @@ -217,6 +220,11 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { ent->e.oldframe = 0; } +#ifdef BROKEN_MDRPHYS + TheRealMDL = tr.currentModel->index; +#endif + + // // cull the entire model if merged bounding box of both frames // is outside the view frustum. @@ -302,6 +310,7 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd ); } } +extern float ProjectRadius( float r, vec3_t location ); /* ============== @@ -337,6 +346,21 @@ void RB_MDRSurfaceAnim( mdrSurface_t *surface ) frontlerp = 1.0f - backlerp; } + if (r_lerpbias->integer) + { + float projectedRadius, fsh, lerpscale, radius; + trRefEntity_t *ent = backEnd.currentEntity; + fsh = 1; + radius = 1; + lerpscale = r_lerpbias->value*-0.2; + if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 ) + { + fsh = 1.0f - projectedRadius * lerpscale; + } + if (fsh > 1) + backlerp = 0; + } + header = (mdrHeader_t *)((byte *)surface + surface->ofsHeader); frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); @@ -519,3 +543,265 @@ void MC_UnCompress(float mat[3][4],const unsigned char * comp) val-=1<<(MC_BITS_VECT-1); mat[2][2]=((float)(val))*MC_SCALE_VECT; } + +#ifdef BROKEN_MDRPHYS + +/* +============== +RB_ClientDeformedMDRSurfaceAnim + +leilei - This is for supporting the eventual creation of player customization on special 'generic' player models + where sliders determine the body types. + + tl;dr: jiggle bones and body sliders. +============== +*/ + +vec3_t oldorg; +vec3_t neworg; +vec3_t oofs; +int thme; +int thmend; + +void RB_MDRP_Spring ( mdrBone_t bone, mdrPhysics_t phys, int bindex, vec3_t ofs, vec3_t ofs3, vec3_t ofs4, vec3_t bm1, vec3_t bm2, vec3_t bm3 ) +{ + vec3_t lfrom, lto, bold,bnew; + int i; + mdrPhysLocal_t *pl; + // Get our position + VectorCopy(ofs, lfrom); + + // Take in some of our animation's changes, exaggerate a bit + lto[0] = DotProduct( ofs, bm1 ) * 5; + lto[1] = DotProduct( ofs, bm2 ) * 5; + lto[2] = DotProduct( ofs, bm3 ) * 5; + + // Transform from the world + lfrom[0] = DotProduct( lto, backEnd.currentEntity->e.axis[0] ); + lfrom[1] = DotProduct( lto, backEnd.currentEntity->e.axis[1] ); + lfrom[2] = DotProduct( lto, backEnd.currentEntity->e.axis[2] ); + VectorAdd(lfrom,backEnd.currentEntity->e.origin, lfrom); + + pl = &backEnd.currentEntity->pl; + + if (tr.refdef.time > (pl->time[bindex] + 100)) + { + // it's either been too long since the last physics rendering, or the framerate is too low + // so reset the stuff + VectorCopy(lfrom, bold); + VectorCopy(lfrom, bnew); + VectorClear(pl->vel[bindex]); + pl->time[bindex] = tr.refdef.time + 16.667f; // 60fps + return; + } + + else if (tr.refdef.time > pl->time[bindex]) + { + int k; + VectorCopy(pl->neworg[bindex], bnew); + VectorCopy(pl->oldorg[bindex], bold); + for(k=0;k<3;k++) + { + float res = 0; + bnew[k] = (bnew[k] + bnew[k] + bold[k] + bnew[k]) / 4; + bold[k] = (bold[k] + lfrom[k] + lfrom[k] + bold[k]) / (4+res); + bold[k] += (pl->vel[bindex][k] * -phys.spring); // and a bit of spring + bold[k] += (pl->vel[bindex][k] * (-phys.spring * 0.5f)); // and a bit of spring + pl->vel[bindex][k]= (bnew[k] - bold[k]) * phys.limitl[k]; + } + VectorCopy(bnew, pl->neworg[bindex]); + VectorCopy(bold, pl->oldorg[bindex]); + pl->time[bindex] = tr.refdef.time + 16.667f; // 60fps + } + + ofs3[0] = DotProduct( pl->vel[bindex], backEnd.currentEntity->e.axis[0] ); + ofs3[1] = DotProduct( pl->vel[bindex], backEnd.currentEntity->e.axis[1] ); + ofs3[2] = DotProduct( pl->vel[bindex], backEnd.currentEntity->e.axis[2] ); + + for(i=0;i<3;i++) + { + ofs3[i] *= (phys.spring); + ofs4[i] = ofs3[i] * phys.limitr[i]; + ofs3[i] *= (phys.limitl[i]); + if (ofs3[i] > (phys.limitl[i]*4)) pl->vel[bindex][i] -= (pl->vel[bindex][i]*0.8); // there's a limit + } + + +} + +void RB_ClientDeformedMDRSurfaceAnim( mdrSurface_t *surface ) +{ + int i, j, k; + float frontlerp, backlerp; + int *triangles; + int indexes; + int baseIndex, baseVertex; + int numVerts; + int skipPhys = 0; + mdrVertex_t *v; + mdrHeader_t *header; + mdrFrame_t *frame; + mdrFrame_t *oldFrame; + mdrBone_t bones[MDR_MAX_BONES], *bonePtr, *bone; + model_t *mdl; + mdl = R_GetModelByHandle( backEnd.currentEntity->e.hModel ); + TheRealMDL = mdl->index; + + int frameSize; + + if (skipPhys || !r_mdrPhysics->integer) + { + RB_MDRSurfaceAnim( surface ); + return; + } + + //ri.Printf( PRINT_DEVELOPER, "DEFORMED! %i aka %s.......OR IS IT %i aka %s ?!??\n", tr.currentModel->index, tr.currentModel->name, TheRealMDL, tr.models[TheRealMDL]->name); + //ri.Printf(PRINT_WARNING,"MDP Rendered model index is %i\n", tr.currentModel->index); + // don't lerp if lerping off, or this is the only frame, or the last frame... + // + if (backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame) + { + backlerp = 0; // if backlerp is 0, lerping is off and frontlerp is never used + frontlerp = 1; + } + else + { + backlerp = backEnd.currentEntity->e.backlerp; + frontlerp = 1.0f - backlerp; + } +// if (!r_lerpModels->integer) backlerp = 0; + + + header = (mdrHeader_t *)((byte *)surface + surface->ofsHeader); + + frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); + + frame = (mdrFrame_t *)((byte *)header + header->ofsFrames + + backEnd.currentEntity->e.frame * frameSize ); + oldFrame = (mdrFrame_t *)((byte *)header + header->ofsFrames + + backEnd.currentEntity->e.oldframe * frameSize ); + + RB_CheckOverflow( surface->numVerts, surface->numTriangles ); + + triangles = (int *) ((byte *)surface + surface->ofsTriangles); + indexes = surface->numTriangles * 3; + baseIndex = tess.numIndexes; + baseVertex = tess.numVertexes; + + // Set up all triangles. + for (j = 0 ; j < indexes ; j++) + { + tess.indexes[baseIndex + j] = baseVertex + triangles[j]; + } + tess.numIndexes += indexes; + + // + // lerp all the needed bones + // + if ( !backlerp ) + { + // no lerping needed + bonePtr = frame->bones; + } + + else + { + bonePtr = bones; + + for ( i = 0 ; i < header->numBones*12 ; i++ ) + { + ((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i] + backlerp * ((float *)oldFrame->bones)[i]; + } + + } + + // + // deform the vertexes by the lerped bones + // + numVerts = surface->numVerts; + v = (mdrVertex_t *) ((byte *)surface + surface->ofsVerts); + for ( j = 0; j < numVerts; j++ ) + { + + vec3_t tempVert, tempNormal; + mdrWeight_t *w; + + VectorClear( tempVert ); + VectorClear( tempNormal ); + w = v->weights; + + for ( k = 0 ; k < v->numWeights ; k++, w++ ) + { + vec3_t bmx[3]; + int p = 0; + // Set up the bones + bone = bonePtr + w->boneIndex; + + vec3_t ofs, ofs2, ofs3, ofs4; + + // Leilei - Iterate physics + + float tblend; + + tblend = 1.0; + VectorCopy(bone->matrix[0], bmx[0]); + VectorCopy(bone->matrix[1], bmx[1]); + VectorCopy(bone->matrix[2], bmx[2]); + + VectorCopy(w->offset, ofs); // Local offset to modify + VectorCopy(w->offset, ofs2); // Final offset to push to the rendering + if (tblend > 1) tblend = 1.0f; + if (tblend < 0) tblend = 0.0f; + + float wt21 = w->boneWeight; + float wt22 = w->boneWeight; + float wt23 = w->boneWeight; + + // Go through the known physics properties for the model + for(p=0;pphys.p[p].targbone == w->boneIndex) + { + if (mdl->phys.p[p].type == MDP_SPRING) + { + + RB_MDRP_Spring ( *bone, mdl->phys.p[p], w->boneIndex, ofs, ofs3, ofs4, bmx[0], bmx[1], bmx[2] ); + bmx[2][2] += (ofs4[2]); // rotate + + ofs2[0] += ofs3[0]; + ofs2[1] += ofs3[1]; + ofs2[2] += ofs3[2]; + + } + } + } + + + tempVert[0] += wt21 * ( DotProduct( bmx[0], ofs2 ) + bone->matrix[0][3] ); + tempVert[1] += wt22 * ( DotProduct( bmx[1], ofs2 ) + bone->matrix[1][3] ); + tempVert[2] += wt23 * ( DotProduct( bmx[2], ofs2 ) + bone->matrix[2][3] ); + + tempNormal[0] += wt21 * DotProduct( bmx[0], v->normal ); + tempNormal[1] += wt22 * DotProduct( bmx[1], v->normal ); + tempNormal[2] += wt23 * DotProduct( bmx[2], v->normal ); + + } + + tess.xyz[baseVertex + j][0] = tempVert[0]; + tess.xyz[baseVertex + j][1] = tempVert[1]; + tess.xyz[baseVertex + j][2] = tempVert[2]; + + tess.normal[baseVertex + j][0] = tempNormal[0]; + tess.normal[baseVertex + j][1] = tempNormal[1]; + tess.normal[baseVertex + j][2] = tempNormal[2]; + + tess.texCoords[baseVertex + j][0][0] = v->texCoords[0]; + tess.texCoords[baseVertex + j][0][1] = v->texCoords[1]; + + v = (mdrVertex_t *)&v->weights[v->numWeights]; + } + tess.numVertexes += surface->numVerts; +} + +#endif \ No newline at end of file diff --git a/code/renderer_oa/tr_init.c b/code/renderer_oa/tr_init.c index b5e20e25e4..0ae00118dc 100644 --- a/code/renderer_oa/tr_init.c +++ b/code/renderer_oa/tr_init.c @@ -212,6 +212,9 @@ cvar_t *r_mockvr; // Leilei - for debugging PVR only! cvar_t *r_leifx; // Leilei - leifx nostalgia filter cvar_t *r_shadeMethod; // Leilei cvar_t *r_particles; // Leilei - particle effects motif +#ifdef BROKEN_MDRPHYS +cvar_t *r_mdrPhysics; // Leilei - mdr physics +#endif cvar_t *r_skytess; // leilei - lower detail of skies @@ -224,7 +227,6 @@ cvar_t *r_textureDither; // leilei - Dithered texture cvar_t *r_lerpbias; // Leilei - lerping bias -cvar_t *r_lowEndVideo; // leilei - load .low shaders // leilei - fallback shader hack @@ -1308,6 +1310,9 @@ void R_Register( void ) r_leidebug = ri.Cvar_Get( "r_leidebug", "0" , CVAR_CHEAT); r_particles = ri.Cvar_Get( "r_particles", "0" , CVAR_ARCHIVE | CVAR_LATCH); +#ifdef BROKEN_MDRPHYS + r_mdrPhysics = ri.Cvar_Get( "r_mdrPhysics", "0" , CVAR_ARCHIVE); +#endif r_leidebugeye = ri.Cvar_Get( "r_leidebugeye", "0" , CVAR_CHEAT); r_lerpbias = ri.Cvar_Get( "r_lerpbias", "-2" , CVAR_ARCHIVE); @@ -1318,8 +1323,6 @@ void R_Register( void ) r_lightmapBits = ri.Cvar_Get ("r_lightmapBits", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - lightmap color bits r_lightmapColorNorm = ri.Cvar_Get ("r_lightmapColorNorm", "1", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - lightmap color normalization - r_lowEndVideo = ri.Cvar_Get( "r_lowEndVideo", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_textureDither = ri.Cvar_Get ("r_textureDither", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - dithered textures // make sure all the commands added here are also @@ -1732,6 +1735,7 @@ refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) re.AddRefEntityToScene = RE_AddRefEntityToScene; re.AddPolyToScene = RE_AddPolyToScene; re.LFX_ParticleEffect = LFX_ParticleEffect; + re.GetViewPosition = RE_GetViewPosition; re.LightForPoint = R_LightForPoint; re.AddLightToScene = RE_AddLightToScene; re.AddAdditiveLightToScene = RE_AddAdditiveLightToScene; diff --git a/code/renderer_oa/tr_local.h b/code/renderer_oa/tr_local.h index d4af6e248b..501a818c8c 100644 --- a/code/renderer_oa/tr_local.h +++ b/code/renderer_oa/tr_local.h @@ -30,7 +30,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../renderercommon/tr_public.h" #include "../renderercommon/tr_common.h" +#ifdef BROKEN_IQM #include "../renderercommon/iqm.h" +#endif #include "../renderercommon/qgl.h" #define GL_INDEX_TYPE GL_UNSIGNED_INT @@ -59,6 +61,53 @@ typedef struct dlight_s { } dlight_t; +// leilei - crazy MDR physics bones +#define MAX_MDR_PHYSICS 32 + +#define MDP_SPRING 1 +#define MDP_JIGGLE 2 +#define MDP_HAIR 3 +#define MDP_SCALESET 4 +#define MDP_LINK 5 // points targbone to targbone2 +#define MDP_INHERIT 6 // takes origin/angle change from targbone to targbone2 +#define MDP_DEBUG 7 + +#ifdef BROKEN_MDRPHYS +typedef struct mdrPhysics_s { + int targbone; // Bone to target + int type; // type of physic + float spring; + vec3_t limitl; // length limit for spring + vec3_t limitr; // rotateable limit for spring + int scaleset; // which set of scale to use + vec3_t scale1; // For scaleset + vec3_t scale2; // For scaleset + int suggestive; // user disableable +} mdrPhysics_t; + +// For Model_t's to track their properties of each physic and the bone they modify +typedef struct mdrPhys_s { + mdrPhysics_t p[MAX_MDR_PHYSICS]; + int maxphs; + int modelindex; + //model_t *mod; + int mdln; + int inited; +} mdrPhys_t; + +// For RefEntity_t's to track their bones that are being moved +typedef struct mdrPhysLocal_s +{ + vec3_t oldorg[MDR_MAX_BONES]; + vec3_t neworg[MDR_MAX_BONES]; + vec3_t oldmorg[MDR_MAX_BONES]; + vec3_t newmorg[MDR_MAX_BONES]; + vec3_t vel[MDR_MAX_BONES]; + int time[MDR_MAX_BONES]; // when to iterate physics + int modindex; // hack to verify if it's the same model getting physics? +} mdrPhysLocal_t; + +#endif // a trRefEntity_t has all the information passed in by // the client game, as well as some locally derived info @@ -76,8 +125,14 @@ typedef struct { vec3_t dynamicLight; float lightDistance; - // leilei - eyes - vec3_t eyepos[2]; // looking from +#ifdef BROKEN_MDRPHYS + // leilei - local mdr physics for this ent + vec3_t bonfs; + vec3_t olorg; + vec3_t nuorg; + mdrPhys_t *phy; + mdrPhysLocal_t pl; +#endif } trRefEntity_t; @@ -584,7 +639,12 @@ typedef enum { SF_POLY, SF_MD3, SF_MDR, +#ifdef BROKEN_MDRPHYS + SF_MDP, +#endif +#ifdef BROKEN_IQM SF_IQM, +#endif SF_FLARE, SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity SF_DISPLAY_LIST, @@ -692,6 +752,7 @@ typedef struct { drawVert_t *verts; } srfTriangles_t; +#ifdef BROKEN_IQM // inter-quake-model typedef struct { int num_vertexes; @@ -736,6 +797,7 @@ typedef struct srfIQModel_s { int first_triangle, num_triangles; } srfIQModel_t; +#endif extern void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])(void *); @@ -967,9 +1029,10 @@ typedef enum { MOD_BAD, MOD_BRUSH, MOD_MESH, - MOD_MDR, - MOD_MDO, - MOD_IQM + MOD_MDR +#ifdef BROKEN_IQM + ,MOD_IQM +#endif } modtype_t; typedef struct model_s { @@ -981,6 +1044,11 @@ typedef struct model_s { bmodel_t *bmodel; // only if type == MOD_BRUSH md3Header_t *md3[MD3_MAX_LODS]; // only if type == MOD_MESH void *modelData; // only if type == (MOD_MDR | MOD_IQM) +#ifdef BROKEN_MDRPHYS + mdrPhys_t phys; // leilei - MDR model physics + int mdln; + int hasphysics; // leilei - mdr physics +#endif int numLods; } model_t; @@ -1395,6 +1463,9 @@ extern cvar_t *r_suggestiveThemes; // Leilei - mature content extern cvar_t *r_leidebug; // Leilei - debug only! extern cvar_t *r_leidebugeye; // Leilei - debug only! extern cvar_t *r_particles; // Leilei - particles! +#ifdef BROKEN_MDRPHYS +extern cvar_t *r_mdrPhysics; // Leilei - MDR Physics +#endif extern cvar_t *r_iconmip; // leilei - icon mip - picmip for 2d icons extern cvar_t *r_iconBits; // leilei - icon color depth for 2d icons @@ -1411,8 +1482,6 @@ extern cvar_t *r_textureDither; // leilei - apply dithering for lower texture extern cvar_t *r_skytess; // leilei - adjusts the subdivisions of the sky (max 8, min 1) -extern cvar_t *r_lowEndVideo; // leilei - load .low shaders - //==================================================================== void R_SwapBuffers( int ); @@ -2081,13 +2150,14 @@ ANIMATED MODELS void R_MDRAddAnimSurfaces( trRefEntity_t *ent ); void RB_MDRSurfaceAnim( mdrSurface_t *surface ); +#ifdef BROKEN_IQM qboolean R_LoadIQM (model_t *mod, void *buffer, int filesize, const char *name ); void R_AddIQMSurfaces( trRefEntity_t *ent ); void RB_IQMSurfaceAnim( surfaceType_t *surface ); int R_IQMLerpTag( orientation_t *tag, iqmData_t *data, int startFrame, int endFrame, float frac, const char *tagName ); - +#endif /* ============================================================= @@ -2329,6 +2399,7 @@ void R_QarticleExplosion(const vec3_t org); void R_LFX_Blood (const vec3_t org, const vec3_t dir, float pressure) ; void LFX_ShaderInit(void); void LFX_ParticleEffect (int effect, const vec3_t org, const vec3_t dir); +void RE_GetViewPosition(vec3_t point); #endif //TR_LOCAL_H diff --git a/code/renderer_oa/tr_main.c b/code/renderer_oa/tr_main.c index 4585582cb8..04135859af 100644 --- a/code/renderer_oa/tr_main.c +++ b/code/renderer_oa/tr_main.c @@ -1249,9 +1249,11 @@ void R_AddEntitySurfaces (void) { case MOD_MDR: R_MDRAddAnimSurfaces( ent ); break; +#ifdef BROKEN_IQM case MOD_IQM: R_AddIQMSurfaces( ent ); break; +#endif case MOD_BRUSH: R_AddBrushModelSurfaces( ent ); break; diff --git a/code/renderer_oa/tr_model.c b/code/renderer_oa/tr_model.c index d473883f34..a684b4b567 100644 --- a/code/renderer_oa/tr_model.c +++ b/code/renderer_oa/tr_model.c @@ -24,7 +24,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "tr_local.h" #define LL(x) x=LittleLong(x) - +#ifdef BROKEN_MDRPHYS +static int isMDP; // leilei - for MDRs with deformed bone properties +#endif static qboolean R_LoadMD3(model_t *mod, int lod, void *buffer, const char *name ); static qboolean R_LoadMDR(model_t *mod, void *buffer, int filesize, const char *name ); extern int ismaptexture; // leilei - for listing map textures @@ -129,7 +131,9 @@ qhandle_t R_RegisterMDR(const char *name, model_t *mod) mod->type = MOD_BAD; return 0; } - +#ifdef BROKEN_MDRPHYS + isMDP = 0; +#endif ident = LittleLong(*(unsigned *)buf.u); if(ident == MDR_IDENT) loaded = R_LoadMDR(mod, buf.u, filesize, name); @@ -146,6 +150,142 @@ qhandle_t R_RegisterMDR(const char *name, model_t *mod) return mod->index; } +#ifdef BROKEN_MDRPHYS + +/* +==================== +R_RegisterMDP + +leilei - MDR with additional defined properties for secondary physics +==================== +*/ +qhandle_t R_RegisterMDP(const char *name, model_t *mod) +{ + union { + unsigned *u; + void *v; + } buf; + int ident; + qboolean loaded = qfalse; + int filesize; + isMDP = 1; + filesize = ri.FS_ReadFile(name, (void **) &buf.v); + if(!buf.u) + { + mod->type = MOD_BAD; + return 0; + } + // leilei - find a config.... + { + int stop = 0; + char cfgName[ MAX_QPATH ]; + char *text_p; + int len; + int i; + char *token; + char text[16384]; + fileHandle_t f; + + // Find our Physics definition file + COM_StripExtension( name, cfgName, MAX_QPATH ); + sprintf(cfgName,"%s.phy",cfgName); + + len = FS_FOpenFileRead(cfgName, &f, qtrue); + if (len <= 0) { + ri.Printf(PRINT_WARNING,"R_RegisterMDP: Couldn't find the %s file, will continue without physics\n", cfgName); + stop=1; + } + if (len >= sizeof ( text) - 1) { + //ri.Printf(PRINT_WARNING,"R_RegisterMDP: Physics file %s is too long\n", cfgName); + FS_FCloseFile (f); + stop=1; + } + if (!stop){ + FS_Read(text, len, f); + text[len] = 0; + FS_FCloseFile(f); + + // parse the text + text_p = text; + + ri.Printf(PRINT_WARNING,"MDP - this is model index %i", mod->index); + ri.Printf(PRINT_WARNING,"R_RegisterMDP: Physics reading.....\n"); + int thep = 0; + + isMDP = 1; // yep, there's physics here + + while (1) { + + token = COM_Parse(&text_p); + if ( !token[0] ) { + break; + } + //token = COM_Parse(&text_p); + if (!Q_stricmp(token, "suggestive")){ // allow user to turn off the physics after this mark + if (r_suggestiveThemes->integer < 1) break; + + else + { + token = COM_Parse(&text_p); + } + } + if (!Q_stricmp(token, "spring")) { + token = COM_Parse(&text_p); + ri.Printf(PRINT_WARNING,"R_RegisterMDP: Physic %i: spring\n",thep); + mod->phys.p[thep].type= MDP_SPRING; + + + //token = COM_Parse(&text_p); + ri.Printf(PRINT_WARNING,"Spring parameters: %i bonenumber", atoi(token)); + mod->phys.p[thep].targbone=atoi(token); + // default parms + mod->phys.p[thep].spring = 0.30f; + mod->phys.p[thep].limitl[0] = 0.3f; + mod->phys.p[thep].limitl[1] = 0.3f; + mod->phys.p[thep].limitl[2] = 0.9f; + mod->phys.p[thep].limitr[0] = 0.15f; + mod->phys.p[thep].limitr[1] = 0.15f; + mod->phys.p[thep].limitr[2] = 0.15f; + + token = COM_Parse(&text_p); + ri.Printf(PRINT_WARNING,"%f springiness\n", atof(token)); + mod->phys.p[thep].spring=atof(token); + mod->phys.p[thep].limitl[0] *= mod->phys.p[thep].spring; + mod->phys.p[thep].limitl[1] *= mod->phys.p[thep].spring; + mod->phys.p[thep].limitl[2] *= mod->phys.p[thep].spring; + + thep++; + continue; + + } + break; + } + } + + + } + + + ident = LittleLong(*(unsigned *)buf.u); + if(ident == MDR_IDENT) + { + // Check if there's a physics config + loaded = R_LoadMDR(mod, buf.u, filesize, name); + } + + ri.FS_FreeFile (buf.v); + + if(!loaded) + { + ri.Printf(PRINT_WARNING,"R_RegisterMDP: couldn't load mdr file %s\n", name); + mod->type = MOD_BAD; + return 0; + } + return mod->index; +} + +#endif +#ifdef BROKEN_IQM /* ==================== R_RegisterIQM @@ -181,7 +321,7 @@ qhandle_t R_RegisterIQM(const char *name, model_t *mod) return mod->index; } - +#endif typedef struct { @@ -193,8 +333,14 @@ typedef struct // when there are multiple models of different formats available static modelExtToLoaderMap_t modelLoaders[ ] = { +#ifdef BROKEN_IQM { "iqm", R_RegisterIQM }, +#endif +#ifdef BROKEN_MDRPHYS + { "mdr", R_RegisterMDP }, +#else { "mdr", R_RegisterMDR }, +#endif { "md3", R_RegisterMD3 } }; static int numModelLoaders = ARRAY_LEN(modelLoaders); @@ -763,6 +909,10 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char // first do some copying stuff surf->ident = SF_MDR; +#ifdef BROKEN_MDRPHYS + if (isMDP) + surf->ident = SF_MDP; +#endif Q_strncpyz(surf->name, cursurf->name, sizeof(surf->name)); Q_strncpyz(surf->shader, cursurf->shader, sizeof(surf->shader)); @@ -1078,11 +1228,14 @@ int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFram R_GetAnimTag((mdrHeader_t *) model->modelData, startFrame, tagName, start); R_GetAnimTag((mdrHeader_t *) model->modelData, endFrame, tagName, end); } +#ifdef BROKEN_IQM else if( model->type == MOD_IQM ) { return R_IQMLerpTag( tag, model->modelData, startFrame, endFrame, frac, tagName ); - } else { + } +#endif + else { AxisClear( tag->axis ); VectorClear( tag->origin ); @@ -1154,7 +1307,9 @@ void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) { VectorCopy( frame->bounds[1], maxs ); return; - } else if(model->type == MOD_IQM) { + } +#ifdef BROKEN_IQM + else if(model->type == MOD_IQM) { iqmData_t *iqmData; iqmData = model->modelData; @@ -1166,7 +1321,7 @@ void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) { return; } } - +#endif VectorClear( mins ); VectorClear( maxs ); } diff --git a/code/renderer_oa/tr_model_iqm.c b/code/renderer_oa/tr_model_iqm.c index be7cf992c4..8c59a5a31b 100644 --- a/code/renderer_oa/tr_model_iqm.c +++ b/code/renderer_oa/tr_model_iqm.c @@ -20,7 +20,7 @@ along with Quake III Arena source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ - +#ifdef BROKEN_IQM #include "tr_local.h" #define LL(x) x=LittleLong(x) @@ -1184,3 +1184,5 @@ int R_IQMLerpTag( orientation_t *tag, iqmData_t *data, return qtrue; } + +#endif \ No newline at end of file diff --git a/code/renderer_oa/tr_shade.c b/code/renderer_oa/tr_shade.c index 9e1b2bb784..bbc9604fd3 100644 --- a/code/renderer_oa/tr_shade.c +++ b/code/renderer_oa/tr_shade.c @@ -809,6 +809,52 @@ static void RB_FogPass( void ) { R_DrawElements( tess.numIndexes, tess.indexes ); } + +/* +=================== +RE_GetViewPosition + +leilei + +Returns a vector of the point that is from the renderer. Used to (try) getting accurate positions +of things in the world for Cgame to work with, where cgame may (likely) fail. +=================== +*/ + +void RE_GetViewPosition(vec3_t point) +{ + vec4_t eye, clip, normalized, window; + int i; + R_TransformModelToClip( point, backEnd.or.modelMatrix, + backEnd.viewParms.projectionMatrix, eye, clip ); + + // check to see if the point is completely off screen + for ( i = 0 ; i < 3 ; i++ ) { + if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) { + point[0] = -666; + point[1] = -666; + return; + } + } + + R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window ); + + if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth + || window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) { + point[0] = -666; + point[1] = -666; + return; // shouldn't happen, since we check the clip[] above, except for FP rounding + } + + point[0] = (float)(backEnd.viewParms.viewportX + window[0]); + point[1] = (float)(backEnd.viewParms.viewportY + window[1]); + + point[2] = 0; + //return there; +} + + + /* =============== ComputeColors diff --git a/code/renderer_oa/tr_shade_calc.c b/code/renderer_oa/tr_shade_calc.c index 0e78798283..4e72dedab0 100644 --- a/code/renderer_oa/tr_shade_calc.c +++ b/code/renderer_oa/tr_shade_calc.c @@ -1818,7 +1818,7 @@ void RB_CalcDiffuseColor( unsigned char *colors ) { RB_CalcMaterials( colors, 0xFFFFFF, 0x808080, 0x808080, 0x000000, 128, 255 ); } -#if BROKEN // leilei: FIXME this does not work as intended +#ifdef BROKEN_SHADELOD // leilei: FIXME this does not work as intended else if ((r_shadeMethod->integer > 150) && (r_shadeMethod->integer < 667)) // values in a certain range is an adaptive LOD selection of -1, 0 and 3 { float projectedRadius, fsh, shadescale, radius; diff --git a/code/renderer_oa/tr_shader.c b/code/renderer_oa/tr_shader.c index ac1f1eafaf..8cf2cfe7dd 100644 --- a/code/renderer_oa/tr_shader.c +++ b/code/renderer_oa/tr_shader.c @@ -5379,24 +5379,6 @@ a single large text block that can be scanned for shader names */ #define MAX_SHADER_FILES 4096 -static int Shader_AddFileToList( char *name, char *list[0x1000], int nfiles ) { - int i; - - if ( nfiles == 0x1000 - 1 ) { - return nfiles; - } - for ( i = 0 ; i < nfiles ; i++ ) { - if ( !Q_stricmp( name, list[i] ) ) { - return nfiles; // allready in list - } - } - list[nfiles] = CopyString( name ); - nfiles++; - - return nfiles; -} - - static void ScanAndLoadShaderFiles( void ) { char **shaderFiles; @@ -5404,15 +5386,12 @@ static void ScanAndLoadShaderFiles( void ) char *buffers[MAX_SHADER_FILES]; char *p; int numShaderFiles; - int i, j; + int i; char *oldp, *token, *hashMem, *textEnd; int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size; char shaderName[MAX_QPATH]; int shaderLine; - char **lowShaderFiles; - int numLowShaderFiles; - long sum = 0, summand; // scan for shader files shaderFiles = ri.FS_ListFiles( "scripts", ".shader", &numShaderFiles ); @@ -5477,36 +5456,12 @@ static void ScanAndLoadShaderFiles( void ) if (buffers[i]) sum += summand; } - - // leilei - low end video - if (r_lowEndVideo->integer) - { - - - lowShaderFiles = ri.FS_ListFiles( "scripts", ".low", &numLowShaderFiles ); - // shaderFiles += lowShaderFiles; - // numShaderFiles += numLowShaderFiles; - - // leilei - append in low shader files - if (numLowShaderFiles) - for ( i = 0; i < numLowShaderFiles; i++ ) - { - ri.Printf( PRINT_WARNING, "USING LOW END SHADER: %s\n", lowShaderFiles[i]); - // Shader_AddFileToList (lowShaderFiles[i], shaderFiles, numShaderFiles); - // shaderFiles[numShaderFiles+1] = lowShaderFiles[i];CopyString( lowShaderFiles[i] ); - // numShaderFiles++; - // shaderFiles[numShaderFiles+1] = lowShaderFiles[i]; - - } - } - - if ( numShaderFiles > MAX_SHADER_FILES ) { numShaderFiles = MAX_SHADER_FILES; } // build single large buffer - s_shaderText = ri.Hunk_Alloc( sum + (numShaderFiles*2) + (numLowShaderFiles*2), h_low ); + s_shaderText = ri.Hunk_Alloc( sum + (numShaderFiles*2), h_low ); s_shaderText[ 0 ] = '\0'; textEnd = s_shaderText; diff --git a/code/renderer_oa/tr_surface.c b/code/renderer_oa/tr_surface.c index 7d4eb538e9..730a684d45 100644 --- a/code/renderer_oa/tr_surface.c +++ b/code/renderer_oa/tr_surface.c @@ -853,6 +853,8 @@ static void LerpMeshVertexes(md3Surface_t *surf, float backlerp) #endif // idppc_altivec LerpMeshVertexes_scalar( surf, backlerp ); } +extern float ProjectRadius( float r, vec3_t location ); + /* ============= @@ -874,6 +876,22 @@ static void RB_SurfaceMesh(md3Surface_t *surface) { backlerp = backEnd.currentEntity->e.backlerp; } + if (r_lerpbias->integer) + { + float projectedRadius, fsh, lerpscale, radius; + trRefEntity_t *ent = backEnd.currentEntity; + fsh = 1; + radius = 1; + lerpscale = r_lerpbias->value*-0.2; + if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 ) + { + fsh = 1.0f - projectedRadius * lerpscale; + } + if (fsh > 1) + backlerp = 0; + } + + RB_CHECKOVERFLOW( surface->numVerts, surface->numTriangles*3 ); LerpMeshVertexes (surface, backlerp); @@ -1299,7 +1317,9 @@ void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = { (void(*)(void*))RB_SurfacePolychain, // SF_POLY, (void(*)(void*))RB_SurfaceMesh, // SF_MD3, (void(*)(void*))RB_MDRSurfaceAnim, // SF_MDR, +#ifdef BROKEN_IQM (void(*)(void*))RB_IQMSurfaceAnim, // SF_IQM, +#endif (void(*)(void*))RB_SurfaceFlare, // SF_FLARE, (void(*)(void*))RB_SurfaceEntity, // SF_ENTITY (void(*)(void*))RB_SurfaceDisplayList // SF_DISPLAY_LIST diff --git a/code/renderercommon/tr_public.h b/code/renderercommon/tr_public.h index bc00c779f9..edcc9fedc3 100644 --- a/code/renderercommon/tr_public.h +++ b/code/renderercommon/tr_public.h @@ -70,6 +70,7 @@ typedef struct { void (*RenderScene)( const refdef_t *fd ); void (*LFX_ParticleEffect)( int effect, const vec3_t origin, const vec3_t velocity ); // leilei - particles + void (*GetViewPosition)( vec3_t point ); void (*SetColor)( const float *rgba ); // NULL = 1,1,1,1 void (*DrawStretchPic) ( float x, float y, float w, float h, From 735598b3905f0be5c8099f2fc70e0190385890d5 Mon Sep 17 00:00:00 2001 From: leilei- Date: Thu, 31 Jul 2025 00:55:44 -0400 Subject: [PATCH 18/20] - Model fog fix - Suppressing redundant sound warnings to developer print - Preliminary DDS texture loading - Dropping renderergl1 and renderergl2 as they're unsupported, redundant, stale code with none of the new improvements, and we don't use modularized renderers. Still having these files in the tree implies we use them and that can bring confusion. --- Makefile | 8 +- code/client/snd_dma.c | 12 +- code/renderer_oa/tr_extensions.c | 26 + code/renderer_oa/tr_image.c | 78 +- code/renderer_oa/tr_init.c | 3 + code/renderer_oa/tr_local.h | 5 +- code/renderer_oa/tr_shader.c | 12 +- code/renderercommon/tr_common.h | 25 + code/renderercommon/tr_image_dds.c | 765 ++++ code/renderergl1/tr_animation.c | 521 --- code/renderergl1/tr_backend.c | 1166 ------ code/renderergl1/tr_bsp.c | 1870 ---------- code/renderergl1/tr_cmds.c | 503 --- code/renderergl1/tr_curve.c | 625 ---- code/renderergl1/tr_flares.c | 539 --- code/renderergl1/tr_image.c | 1682 --------- code/renderergl1/tr_init.c | 1370 ------- code/renderergl1/tr_light.c | 394 -- code/renderergl1/tr_local.h | 1600 -------- code/renderergl1/tr_main.c | 1389 ------- code/renderergl1/tr_marks.c | 458 --- code/renderergl1/tr_mesh.c | 412 --- code/renderergl1/tr_model.c | 1127 ------ code/renderergl1/tr_model_iqm.c | 1185 ------ code/renderergl1/tr_scene.c | 411 --- code/renderergl1/tr_shade.c | 1522 -------- code/renderergl1/tr_shade_calc.c | 1216 ------ code/renderergl1/tr_shader.c | 3122 ---------------- code/renderergl1/tr_shadows.c | 343 -- code/renderergl1/tr_sky.c | 794 ---- code/renderergl1/tr_subs.c | 48 - code/renderergl1/tr_surface.c | 1243 ------- code/renderergl1/tr_world.c | 668 ---- code/renderergl2/glsl/bokeh_fp.glsl | 70 - code/renderergl2/glsl/bokeh_vp.glsl | 13 - code/renderergl2/glsl/calclevels4x_fp.glsl | 55 - code/renderergl2/glsl/calclevels4x_vp.glsl | 13 - code/renderergl2/glsl/depthblur_fp.glsl | 58 - code/renderergl2/glsl/depthblur_vp.glsl | 12 - code/renderergl2/glsl/dlight_fp.glsl | 12 - code/renderergl2/glsl/dlight_vp.glsl | 92 - code/renderergl2/glsl/down4x_fp.glsl | 34 - code/renderergl2/glsl/down4x_vp.glsl | 13 - code/renderergl2/glsl/fogpass_fp.glsl | 9 - code/renderergl2/glsl/fogpass_vp.glsl | 118 - code/renderergl2/glsl/generic_fp.glsl | 45 - code/renderergl2/glsl/generic_vp.glsl | 247 -- code/renderergl2/glsl/lightall_fp.glsl | 537 --- code/renderergl2/glsl/lightall_vp.glsl | 260 -- code/renderergl2/glsl/pshadow_fp.glsl | 98 - code/renderergl2/glsl/pshadow_vp.glsl | 15 - code/renderergl2/glsl/shadowfill_fp.glsl | 41 - code/renderergl2/glsl/shadowfill_vp.glsl | 90 - code/renderergl2/glsl/shadowmask_fp.glsl | 127 - code/renderergl2/glsl/shadowmask_vp.glsl | 18 - code/renderergl2/glsl/ssao_fp.glsl | 86 - code/renderergl2/glsl/ssao_vp.glsl | 12 - code/renderergl2/glsl/texturecolor_fp.glsl | 12 - code/renderergl2/glsl/texturecolor_vp.glsl | 15 - code/renderergl2/glsl/tonemap_fp.glsl | 48 - code/renderergl2/glsl/tonemap_vp.glsl | 13 - code/renderergl2/tr_animation.c | 522 --- code/renderergl2/tr_backend.c | 1783 --------- code/renderergl2/tr_bsp.c | 3591 ------------------ code/renderergl2/tr_cmds.c | 575 --- code/renderergl2/tr_curve.c | 761 ---- code/renderergl2/tr_extensions.c | 728 ---- code/renderergl2/tr_extramath.c | 240 -- code/renderergl2/tr_extramath.h | 105 - code/renderergl2/tr_extratypes.h | 40 - code/renderergl2/tr_fbo.c | 867 ----- code/renderergl2/tr_fbo.h | 64 - code/renderergl2/tr_flares.c | 557 --- code/renderergl2/tr_glsl.c | 1802 --------- code/renderergl2/tr_image.c | 3437 ----------------- code/renderergl2/tr_init.c | 1580 -------- code/renderergl2/tr_light.c | 488 --- code/renderergl2/tr_local.h | 2499 ------------- code/renderergl2/tr_main.c | 2913 --------------- code/renderergl2/tr_marks.c | 466 --- code/renderergl2/tr_mesh.c | 404 -- code/renderergl2/tr_model.c | 1388 ------- code/renderergl2/tr_model_iqm.c | 1200 ------ code/renderergl2/tr_postprocess.c | 523 --- code/renderergl2/tr_postprocess.h | 33 - code/renderergl2/tr_scene.c | 559 --- code/renderergl2/tr_shade.c | 1652 --------- code/renderergl2/tr_shade_calc.c | 819 ----- code/renderergl2/tr_shader.c | 3863 -------------------- code/renderergl2/tr_shadows.c | 343 -- code/renderergl2/tr_sky.c | 912 ----- code/renderergl2/tr_subs.c | 48 - code/renderergl2/tr_surface.c | 1650 --------- code/renderergl2/tr_vbo.c | 971 ----- code/renderergl2/tr_world.c | 858 ----- 95 files changed, 915 insertions(+), 64631 deletions(-) create mode 100644 code/renderercommon/tr_image_dds.c delete mode 100644 code/renderergl1/tr_animation.c delete mode 100644 code/renderergl1/tr_backend.c delete mode 100644 code/renderergl1/tr_bsp.c delete mode 100644 code/renderergl1/tr_cmds.c delete mode 100644 code/renderergl1/tr_curve.c delete mode 100644 code/renderergl1/tr_flares.c delete mode 100644 code/renderergl1/tr_image.c delete mode 100644 code/renderergl1/tr_init.c delete mode 100644 code/renderergl1/tr_light.c delete mode 100644 code/renderergl1/tr_local.h delete mode 100644 code/renderergl1/tr_main.c delete mode 100644 code/renderergl1/tr_marks.c delete mode 100644 code/renderergl1/tr_mesh.c delete mode 100644 code/renderergl1/tr_model.c delete mode 100644 code/renderergl1/tr_model_iqm.c delete mode 100644 code/renderergl1/tr_scene.c delete mode 100644 code/renderergl1/tr_shade.c delete mode 100644 code/renderergl1/tr_shade_calc.c delete mode 100644 code/renderergl1/tr_shader.c delete mode 100644 code/renderergl1/tr_shadows.c delete mode 100644 code/renderergl1/tr_sky.c delete mode 100644 code/renderergl1/tr_subs.c delete mode 100644 code/renderergl1/tr_surface.c delete mode 100644 code/renderergl1/tr_world.c delete mode 100644 code/renderergl2/glsl/bokeh_fp.glsl delete mode 100644 code/renderergl2/glsl/bokeh_vp.glsl delete mode 100644 code/renderergl2/glsl/calclevels4x_fp.glsl delete mode 100644 code/renderergl2/glsl/calclevels4x_vp.glsl delete mode 100644 code/renderergl2/glsl/depthblur_fp.glsl delete mode 100644 code/renderergl2/glsl/depthblur_vp.glsl delete mode 100644 code/renderergl2/glsl/dlight_fp.glsl delete mode 100644 code/renderergl2/glsl/dlight_vp.glsl delete mode 100644 code/renderergl2/glsl/down4x_fp.glsl delete mode 100644 code/renderergl2/glsl/down4x_vp.glsl delete mode 100644 code/renderergl2/glsl/fogpass_fp.glsl delete mode 100644 code/renderergl2/glsl/fogpass_vp.glsl delete mode 100644 code/renderergl2/glsl/generic_fp.glsl delete mode 100644 code/renderergl2/glsl/generic_vp.glsl delete mode 100644 code/renderergl2/glsl/lightall_fp.glsl delete mode 100644 code/renderergl2/glsl/lightall_vp.glsl delete mode 100644 code/renderergl2/glsl/pshadow_fp.glsl delete mode 100644 code/renderergl2/glsl/pshadow_vp.glsl delete mode 100644 code/renderergl2/glsl/shadowfill_fp.glsl delete mode 100644 code/renderergl2/glsl/shadowfill_vp.glsl delete mode 100644 code/renderergl2/glsl/shadowmask_fp.glsl delete mode 100644 code/renderergl2/glsl/shadowmask_vp.glsl delete mode 100644 code/renderergl2/glsl/ssao_fp.glsl delete mode 100644 code/renderergl2/glsl/ssao_vp.glsl delete mode 100644 code/renderergl2/glsl/texturecolor_fp.glsl delete mode 100644 code/renderergl2/glsl/texturecolor_vp.glsl delete mode 100644 code/renderergl2/glsl/tonemap_fp.glsl delete mode 100644 code/renderergl2/glsl/tonemap_vp.glsl delete mode 100644 code/renderergl2/tr_animation.c delete mode 100644 code/renderergl2/tr_backend.c delete mode 100644 code/renderergl2/tr_bsp.c delete mode 100644 code/renderergl2/tr_cmds.c delete mode 100644 code/renderergl2/tr_curve.c delete mode 100644 code/renderergl2/tr_extensions.c delete mode 100644 code/renderergl2/tr_extramath.c delete mode 100644 code/renderergl2/tr_extramath.h delete mode 100644 code/renderergl2/tr_extratypes.h delete mode 100644 code/renderergl2/tr_fbo.c delete mode 100644 code/renderergl2/tr_fbo.h delete mode 100644 code/renderergl2/tr_flares.c delete mode 100644 code/renderergl2/tr_glsl.c delete mode 100644 code/renderergl2/tr_image.c delete mode 100644 code/renderergl2/tr_init.c delete mode 100644 code/renderergl2/tr_light.c delete mode 100644 code/renderergl2/tr_local.h delete mode 100644 code/renderergl2/tr_main.c delete mode 100644 code/renderergl2/tr_marks.c delete mode 100644 code/renderergl2/tr_mesh.c delete mode 100644 code/renderergl2/tr_model.c delete mode 100644 code/renderergl2/tr_model_iqm.c delete mode 100644 code/renderergl2/tr_postprocess.c delete mode 100644 code/renderergl2/tr_postprocess.h delete mode 100644 code/renderergl2/tr_scene.c delete mode 100644 code/renderergl2/tr_shade.c delete mode 100644 code/renderergl2/tr_shade_calc.c delete mode 100644 code/renderergl2/tr_shader.c delete mode 100644 code/renderergl2/tr_shadows.c delete mode 100644 code/renderergl2/tr_sky.c delete mode 100644 code/renderergl2/tr_subs.c delete mode 100644 code/renderergl2/tr_surface.c delete mode 100644 code/renderergl2/tr_vbo.c delete mode 100644 code/renderergl2/tr_world.c diff --git a/Makefile b/Makefile index 4cb402553e..18ae5e7007 100644 --- a/Makefile +++ b/Makefile @@ -258,7 +258,7 @@ ifeq ($(WINFOUR),1) BASE_CFLAGS += -DUSE_INTERNAL_JPEG SDL_VERSION=1 USE_CURL=0 - CLIENTBIN=oa95 + # CLIENTBIN=oa95 endif ############################################################################# @@ -1175,7 +1175,7 @@ endif ifeq ($(NO_STRIP),1) STRIP_FLAG = else - STRIP_FLAG = -s + STRIP_FLAG = -s endif BASE_CFLAGS += -DPRODUCT_VERSION=\\\"$(VERSION)\\\" @@ -1288,7 +1288,7 @@ endef ############################################################################# default: release -all: debug release +all: debug release debug: @$(MAKE) targets B=$(BD) CFLAGS="$(CFLAGS) $(BASE_CFLAGS) $(DEPEND_CFLAGS)" \ @@ -1778,6 +1778,7 @@ Q3ROAOBJ = \ $(B)/renderer_oa/tr_image_jpg.o \ $(B)/renderer_oa/tr_image_bmp.o \ $(B)/renderer_oa/tr_image_tga.o \ + $(B)/renderer_oa/tr_image_dds.o \ $(B)/renderer_oa/tr_image_pcx.o \ $(B)/renderer_oa/tr_init.o \ $(B)/renderer_oa/tr_light.o \ @@ -1852,6 +1853,7 @@ Q3RSOFTOBJ = \ $(B)/renderer_oa/tr_image_jpg.o \ $(B)/renderer_oa/tr_image_bmp.o \ $(B)/renderer_oa/tr_image_tga.o \ + $(B)/renderer_oa/tr_image_dds.o \ $(B)/renderer_oa/tr_image_pcx.o \ $(B)/renderer_oa/tr_init.o \ $(B)/renderer_oa/tr_light.o \ diff --git a/code/client/snd_dma.c b/code/client/snd_dma.c index ec8596a9a4..18fba60760 100644 --- a/code/client/snd_dma.c +++ b/code/client/snd_dma.c @@ -267,17 +267,17 @@ static sfx_t *S_FindName( const char *name ) { } if (!name[0]) { - Com_Printf( S_COLOR_YELLOW "WARNING: Sound name is empty\n" ); + Com_DPrintf( S_COLOR_YELLOW "WARNING: Sound name is empty\n" ); return NULL; } if (strlen(name) >= MAX_QPATH) { - Com_Printf( S_COLOR_YELLOW "WARNING: Sound name is too long: %s\n", name ); + Com_DPrintf( S_COLOR_YELLOW "WARNING: Sound name is too long: %s\n", name ); return NULL; } if (name[0] == '*') { - Com_Printf( S_COLOR_YELLOW "WARNING: Tried to load player sound directly: %s\n", name ); + Com_DPrintf( S_COLOR_YELLOW "WARNING: Tried to load player sound directly: %s\n", name ); return NULL; } @@ -371,7 +371,7 @@ sfxHandle_t S_Base_RegisterSound( const char *name, qboolean compressed ) { if ( sfx->soundData ) { if ( sfx->defaultSound ) { - Com_Printf( S_COLOR_YELLOW "WARNING: could not find %s - using default\n", sfx->soundName ); + Com_DPrintf( S_COLOR_YELLOW "WARNING: could not find %s - using default\n", sfx->soundName ); return 0; } return sfx - s_knownSfx; @@ -383,7 +383,7 @@ sfxHandle_t S_Base_RegisterSound( const char *name, qboolean compressed ) { S_memoryLoad(sfx); if ( sfx->defaultSound ) { - Com_Printf( S_COLOR_YELLOW "WARNING: could not find %s - using default\n", sfx->soundName ); + Com_DPrintf( S_COLOR_YELLOW "WARNING: could not find %s - using default\n", sfx->soundName ); return 0; } @@ -1428,7 +1428,7 @@ static void S_OpenBackgroundStream( const char *filename ) { // Open stream s_backgroundStream = S_CodecOpenStream(filename); if(!s_backgroundStream) { - Com_Printf( S_COLOR_YELLOW "WARNING: couldn't open music file %s\n", filename ); + Com_DPrintf( S_COLOR_YELLOW "WARNING: couldn't open music file %s\n", filename ); return; } diff --git a/code/renderer_oa/tr_extensions.c b/code/renderer_oa/tr_extensions.c index 150d660909..fc0f7dfd23 100644 --- a/code/renderer_oa/tr_extensions.c +++ b/code/renderer_oa/tr_extensions.c @@ -112,6 +112,12 @@ GLvoid (APIENTRYP qglGetVertexAttribPointervARB) (GLuint index, GLenum pname, GL GLvoid (APIENTRYP qglColorTableEXT)( GLint, GLint, GLint, GLint, GLint, const GLvoid *); GLvoid (APIENTRYP qglColorTableSGI)( GLint, GLint, GLint, GLint, GLint, const GLvoid *); +// leilei - DDS/DXT + +GLvoid (APIENTRYP qglCompressedTexImage2DARB) (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); +GLvoid (APIENTRYP qglColorTableEXT)( GLint, GLint, GLint, GLint, GLint, const GLvoid *); +GLvoid (APIENTRYP qglColorTableSGI)( GLint, GLint, GLint, GLint, GLint, const GLvoid *); + /* typedef enum { GLHW_GENERIC, // where everthing works the way it should @@ -272,6 +278,26 @@ void GLimp_InitExtraExtensions() { ri.Printf( PRINT_ALL, "...GL_EXT_paletted_texture not found\n" ); } + // leilei - DDS/DXT + textureCompressionSupport = qfalse; + if ( GLimp_HaveExtension( "GL_ARB_texture_compression" ) ) + { + if ( r_loadDDS->integer ) { + qglCompressedTexImage2DARB = (GLvoid (APIENTRYP)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *)) SDL_GL_GetProcAddress("glCompressedTexImage2DARB"); + { + ri.Printf( PRINT_ALL, "...using GL_ARB_texture_compression\n"); + textureCompressionSupport = qtrue; + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_ARB_texture_compression\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_ARB_texture_compression not found\n" ); + } #ifdef _WIN32 // leilei - 3dfx gamma diff --git a/code/renderer_oa/tr_image.c b/code/renderer_oa/tr_image.c index 898e0a8ce0..407d7866eb 100644 --- a/code/renderer_oa/tr_image.c +++ b/code/renderer_oa/tr_image.c @@ -531,8 +531,8 @@ void R_ImageList_f( void ) { sizeSuffix = "Gb"; } - //ri.Printf(PRINT_ALL, "%4i: %4ix%4i %s %4i%s %s\n", i, image->uploadWidth, image->uploadHeight, format, displaySize, sizeSuffix, image->imgName); - ri.Printf(PRINT_ALL, "%4i: %4ix%4i %s %4i%s %s %f %f\n", i, image->uploadWidth, image->uploadHeight, format, displaySize, sizeSuffix, image->imgName, image->loadTime, image->procTime); + ri.Printf(PRINT_ALL, "%4i: %4ix%4i %s %4i%s %s\n", i, image->uploadWidth, image->uploadHeight, format, displaySize, sizeSuffix, image->imgName); + //ri.Printf(PRINT_ALL, "%4i: %4ix%4i %s %4i%s %s %f %f\n", i, image->uploadWidth, image->uploadHeight, format, displaySize, sizeSuffix, image->imgName, image->loadTime, image->procTime); estTotalSize += estSize; estTotalTimeLoaded += image->loadTime + image->procTime; @@ -2131,6 +2131,10 @@ Finds or loads the given image. Returns NULL if it fails, not a default image. ============== */ +#ifdef BROKEN_DDS +// DDS/DXT +image_t *R_LoadDDSImage(const char *name, int bits, filterType_t filterType, wrapType_t wrapType); +#endif image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ) { image_t *image; @@ -2140,7 +2144,9 @@ image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ) long hash; float oldtime; float loadtime; - +#ifdef BROKEN_DDS + char ddsName[1024]; +#endif if (!name) { return NULL; } @@ -2162,6 +2168,31 @@ image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ) return image; } } +#ifdef BROKEN_DDS + // leilei - DDS - do it here, so we can have a hardware compressed texture instead. The normal means of texture loading expects pixels to be returned which we won't do. + if(textureCompressionSupport && r_loadDDS->integer) + { + int bits; // no bits + int whatclamp; + Q_strncpyz(ddsName, name, sizeof(ddsName)); + COM_StripExtension(ddsName, ddsName, sizeof(ddsName)); + Q_strcat(ddsName, sizeof(ddsName), ".dds"); + + // if (glWrapClampMode == GL_CLAMP_TO_EDGE) + // whatclamp = WT_CLAMP; + // else + // whatclamp = WT_REPEAT; + // try to load a customized .dds texture + + image = R_LoadDDSImage(ddsName, bits, 0, whatclamp); + if(image != NULL) + { + // ri.Printf(PRINT_ALL, "found custom .dds '%s'\n", ddsName); + return image; + } + } + +#endif // leilei - Detail texture hack // to kill artifacts of shimmer of pattern of terrible @@ -2953,3 +2984,44 @@ void R_SkinList_f( void ) { ri.Printf (PRINT_ALL, "------------------\n"); } +#ifdef BROKEN_DDS +// leilei - for DDS loading, which relies on this function... +/* +================ +R_AllocImage +================ +*/ +image_t *R_AllocImage(const char *name, qboolean linkIntoHashTable) +{ + image_t *image; + long hash; + char buffer[1024]; + +// if(strlen(name) >= MAX_QPATH) + if(strlen(name) >= 1024) + { + ri.Error(ERR_DROP, "R_AllocImage: \"%s\" image name is too long\n", name); + return NULL; + } + + image = ri.Hunk_Alloc(sizeof(image_t), h_low); + Com_Memset(image, 0, sizeof(image_t)); + + + qglGenTextures(1, &image->texnum); + + //Com_AddToGrowList(&tr.images, image); + + Q_strncpyz(image->imgName, name, sizeof(image->imgName)); + + if(linkIntoHashTable) + { + Q_strncpyz(buffer, name, sizeof(buffer)); + hash = generateHashValue(buffer); + image->next = hashTable[hash]; + hashTable[hash] = image; + } + + return image; +} +#endif \ No newline at end of file diff --git a/code/renderer_oa/tr_init.c b/code/renderer_oa/tr_init.c index 0ae00118dc..cfd7032617 100644 --- a/code/renderer_oa/tr_init.c +++ b/code/renderer_oa/tr_init.c @@ -29,6 +29,7 @@ int maxAnisotropy = 0; float displayAspect = 0.0f; qboolean vertexShaders = qfalse; qboolean postprocess = qfalse; +qboolean textureCompressionSupport = qfalse; // leilei - compressed textures qboolean palettedTextureSupport = qfalse; // leilei - paletted textures char depthimage; @@ -105,6 +106,7 @@ cvar_t *r_ext_texture_env_add; cvar_t *r_ext_texture_filter_anisotropic; cvar_t *r_ext_max_anisotropy; cvar_t *r_ext_vertex_shader; +cvar_t *r_loadDDS; // leilei - loading DDS textures cvar_t *r_ext_paletted_texture; // leilei - Paletted Texture cvar_t *r_ext_gamma_control; // leilei - 3dfx gamma control cvar_t *r_postprocess; @@ -1134,6 +1136,7 @@ void R_Register( void ) r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_ext_max_anisotropy = ri.Cvar_Get( "r_ext_max_anisotropy", "2", CVAR_ARCHIVE | CVAR_LATCH ); + r_loadDDS = ri.Cvar_Get( "r_loadDDS", "1", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - compressed texture support r_ext_paletted_texture = ri.Cvar_Get( "r_ext_paletted_texture", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - paletted texture support r_ext_gamma_control = ri.Cvar_Get( "r_ext_gamma_control", "1", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - 3dfx gamma support diff --git a/code/renderer_oa/tr_local.h b/code/renderer_oa/tr_local.h index 501a818c8c..f8a3913e79 100644 --- a/code/renderer_oa/tr_local.h +++ b/code/renderer_oa/tr_local.h @@ -1,3 +1,4 @@ + /* =========================================================================== Copyright (C) 1999-2005 Id Software, Inc. @@ -49,6 +50,7 @@ typedef unsigned int glIndex_t; #define SHADERNUM_BITS 14 #define MAX_SHADERS (1<rgbMod = CMOD_GLOW; } - if ( !Q_stricmp( token, "uvcol" ) ) + else if ( !Q_stricmp( token, "uvcol" ) ) { // Parse color token = COM_ParseExt( text, qfalse ); @@ -3028,22 +3028,22 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) stage->rgbMod = CMOD_UVCOL; } - if ( !Q_stricmp( token, "normtoalpha" ) ) + else if ( !Q_stricmp( token, "normtoalpha" ) ) { // normalize colors, but average color prior is alpha. stage->rgbMod = CMOD_NORMALIZETOALPHA; } - if ( !Q_stricmp( token, "normtoalphafast" ) ) + else if ( !Q_stricmp( token, "normtoalphafast" ) ) { // normalize and use the first vert's color on whole surface, but average color prior is alpha. stage->rgbMod = CMOD_NORMALIZETOALPHAFAST; } - if ( !Q_stricmp( token, "lighting" ) ) + else if ( !Q_stricmp( token, "lighting" ) ) { // modulate a standard diffuse light on top of existing vertex colors stage->rgbMod = CMOD_LIGHTING; } - if ( !Q_stricmp( token, "opaque" ) ) + else if ( !Q_stricmp( token, "opaque" ) ) { // modulate a standard diffuse light on top of existing vertex colors stage->rgbMod = CMOD_OPAQUE; diff --git a/code/renderercommon/tr_common.h b/code/renderercommon/tr_common.h index 749f57d5c3..37f65620df 100644 --- a/code/renderercommon/tr_common.h +++ b/code/renderercommon/tr_common.h @@ -47,6 +47,26 @@ typedef enum IMGFLAG_GENNORMALMAP = 0x0100, } imgFlags_t; +// DDS stuff + + +typedef enum +{ + FT_DEFAULT, + FT_LINEAR, + FT_NEAREST +} filterType_t; + +typedef enum +{ + WT_REPEAT, + WT_CLAMP, // don't repeat the texture for texture coords outside [0, 1] + WT_EDGE_CLAMP, + WT_ZERO_CLAMP, // guarantee 0,0,0,255 edge for projected textures + WT_ALPHA_ZERO_CLAMP // guarante 0 alpha edge for projected textures +} wrapType_t; + + typedef struct image_s { char imgName[MAX_QPATH]; // game path, including extension int width, height; // source image @@ -67,6 +87,11 @@ typedef struct image_s { float loadTime; // leilei - time taken loading image float procTime; // leilei - time taken processing image/uploading to vram + + // DXT/DDS stuff + GLenum ddsType; + filterType_t filterType; + wrapType_t wrapType; } image_t; // any change in the LIGHTMAP_* defines here MUST be reflected in diff --git a/code/renderercommon/tr_image_dds.c b/code/renderercommon/tr_image_dds.c new file mode 100644 index 0000000000..9fa7f27b29 --- /dev/null +++ b/code/renderercommon/tr_image_dds.c @@ -0,0 +1,765 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. +Copyright (C) 2007 HermitWorks Entertainment Corporation +Copyright (C) 2006-2009 Robert Beckebans + +This file is part of XreaL source code. + +XreaL 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. + +XreaL 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 XreaL source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// +// leilei - this is altered a bit from the usual XreaL/Space Trader image_dds +// +// - Removed depth and cubemap stuff as that is not relevant to our spec (we just want faster textures in less bits) +// - Removed software decoding (patent concerns even if it's expired by now) +// +// TODO: +// - Non-square textures don't get uploaded properly!!! +// - DXT3/5 are not handled properly for alpha support. +// - backport LadyHavoc's halfsize-decoding from Darkplaces +// - figure out why the x.org turks driver fails with this. +// +// +// Because it's super incomplete, i'm shoving it in a define. +// +#ifdef BROKEN_DDS +#include "qgl.h" +#include "../renderer_oa/tr_local.h" + +//extern void (APIENTRY * qglColorTableEXT)( GLint, GLint, GLint, GLint, GLint, const GLvoid); +//extern void (APIENTRY * qglColorTableSGI)( GLint, GLint, GLint, GLint, GLint, const GLvoid); +//extern void (APIENTRY * qglCompressedTexImage2DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); + +typedef struct +{ + unsigned int dwColorSpaceLowValue; // low boundary of color space that is to + // be treated as Color Key, inclusive + + unsigned int dwColorSpaceHighValue; // high boundary of color space that is + // to be treated as Color Key, inclusive +} DDCOLORKEY_t; + +typedef struct +{ + unsigned int dwCaps; // capabilities of surface wanted + unsigned int dwCaps2; + unsigned int dwCaps3; + union + { + unsigned int dwCaps4; + unsigned int dwVolumeDepth; + } u0; +} DDSCAPS2_t; + +typedef struct +{ + unsigned int dwSize; // size of structure + unsigned int dwFlags; // pixel format flags + unsigned int dwFourCC; // (FOURCC code) + + union + { + unsigned int dwRGBBitCount; // how many bits per pixel + unsigned int dwYUVBitCount; // how many bits per pixel + unsigned int dwZBufferBitDepth; // how many total bits/pixel in z buffer (including any stencil bits) + unsigned int dwAlphaBitDepth; // how many bits for alpha channels + unsigned int dwLuminanceBitCount; // how many bits per pixel + unsigned int dwBumpBitCount; // how many bits per "buxel", total + unsigned int dwPrivateFormatBitCount; // Bits per pixel of private driver formats. Only valid in texture + // format list and if DDPF_D3DFORMAT is set + } u0; + + union + { + unsigned int dwRBitMask; // mask for red bit + unsigned int dwYBitMask; // mask for Y bits + unsigned int dwStencilBitDepth; // how many stencil bits (note: dwZBufferBitDepth-dwStencilBitDepth is total Z-only bits) + unsigned int dwLuminanceBitMask; // mask for luminance bits + unsigned int dwBumpDuBitMask; // mask for bump map U delta bits + unsigned int dwOperations; // DDPF_D3DFORMAT Operations + } u1; + + union + { + unsigned int dwGBitMask; // mask for green bits + unsigned int dwUBitMask; // mask for U bits + unsigned int dwZBitMask; // mask for Z bits + unsigned int dwBumpDvBitMask; // mask for bump map V delta bits + struct + { + unsigned short wFlipMSTypes; // Multisample methods supported via flip for this D3DFORMAT + unsigned short wBltMSTypes; // Multisample methods supported via blt for this D3DFORMAT + } MultiSampleCaps; + + } u2; + + union + { + unsigned int dwBBitMask; // mask for blue bits + unsigned int dwVBitMask; // mask for V bits + unsigned int dwStencilBitMask; // mask for stencil bits + unsigned int dwBumpLuminanceBitMask; // mask for luminance in bump map + } u3; + + union + { + unsigned int dwRGBAlphaBitMask; // mask for alpha channel + unsigned int dwYUVAlphaBitMask; // mask for alpha channel + unsigned int dwLuminanceAlphaBitMask; // mask for alpha channel + unsigned int dwRGBZBitMask; // mask for Z channel + unsigned int dwYUVZBitMask; // mask for Z channel + } u4; +} DDPIXELFORMAT_t; + +typedef struct +{ + unsigned int dwSize; // size of the DDSURFACEDESC structure + unsigned int dwFlags; // determines what fields are valid + unsigned int dwHeight; // height of surface to be created + unsigned int dwWidth; // width of input surface + + union + { + int lPitch; // distance to start of next line (return value only) + unsigned int dwLinearSize; // Formless late-allocated optimized surface size + } u0; + + union + { + unsigned int dwBackBufferCount; // number of back buffers requested + unsigned int dwDepth; // the depth if this is a volume texture + } u1; + + union + { + unsigned int dwMipMapCount; // number of mip-map levels requestde + // dwZBufferBitDepth removed, use ddpfPixelFormat one instead + unsigned int dwRefreshRate; // refresh rate (used when display mode is described) + unsigned int dwSrcVBHandle; // The source used in VB::Optimize + } u2; + + unsigned int dwAlphaBitDepth; // depth of alpha buffer requested + unsigned int dwReserved; // reserved + void *lpSurface; // pointer to the associated surface memory + + union + { + DDCOLORKEY_t ddckCKDestOverlay; // color key for destination overlay use + unsigned int dwEmptyFaceColor; // Physical color for empty cubemap faces + } u3; + DDCOLORKEY_t ddckCKDestBlt; // color key for destination blt use + DDCOLORKEY_t ddckCKSrcOverlay; // color key for source overlay use + DDCOLORKEY_t ddckCKSrcBlt; // color key for source blt use + union + { + DDPIXELFORMAT_t ddpfPixelFormat; // pixel format description of the surface + unsigned int dwFVF; // vertex format description of vertex buffers + } u4; + DDSCAPS2_t ddsCaps; // direct draw surface capabilities + unsigned int dwTextureStage; // stage in multitexture cascade +} DDSURFACEDESC2_t; + +// +// DDSURFACEDESC2 flags that mark the validity of the struct data +// +#define DDSD_CAPS 0x00000001l // default +#define DDSD_HEIGHT 0x00000002l // default +#define DDSD_WIDTH 0x00000004l // default +#define DDSD_PIXELFORMAT 0x00001000l // default +#define DDSD_PITCH 0x00000008l // For uncompressed formats +#define DDSD_MIPMAPCOUNT 0x00020000l +#define DDSD_LINEARSIZE 0x00080000l // For compressed formats +#define DDSD_DEPTH 0x00800000l // Volume Textures + +// +// DDPIXELFORMAT flags +// +#define DDPF_ALPHAPIXELS 0x00000001l +#define DDPF_FOURCC 0x00000004l // Compressed formats +#define DDPF_RGB 0x00000040l // Uncompressed formats +#define DDPF_ALPHA 0x00000002l +#define DDPF_COMPRESSED 0x00000080l +#define DDPF_LUMINANCE 0x00020000l +#define DDPF_PALETTEINDEXED4 0x00000008l +#define DDPF_PALETTEINDEXEDTO8 0x00000010l +#define DDPF_PALETTEINDEXED8 0x00000020l + +// +// DDSCAPS flags +// +#define DDSCAPS_COMPLEX 0x00000008l +#define DDSCAPS_TEXTURE 0x00001000l // default +#define DDSCAPS_MIPMAP 0x00400000l + +#define DDSCAPS2_VOLUME 0x00200000l +#define DDSCAPS2_CUBEMAP 0x00000200L +#define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400L +#define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800L +#define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000L +#define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000L +#define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000L +#define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000L + +#ifndef MAKEFOURCC + +#define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((unsigned int)(char)(ch0) | ((unsigned int)(char)(ch1) << 8) | \ + ((unsigned int)(char)(ch2) << 16) | ((unsigned int)(char)(ch3) << 24 )) + +#endif + +#define FOURCC_DDS MAKEFOURCC( 'D', 'D', 'S', ' ' ) + +//FOURCC codes for DXTn compressed-texture pixel formats +#define FOURCC_DXT1 MAKEFOURCC( 'D', 'X', 'T', '1' ) +#define FOURCC_DXT2 MAKEFOURCC( 'D', 'X', 'T', '2' ) +#define FOURCC_DXT3 MAKEFOURCC( 'D', 'X', 'T', '3' ) +#define FOURCC_DXT4 MAKEFOURCC( 'D', 'X', 'T', '4' ) +#define FOURCC_DXT5 MAKEFOURCC( 'D', 'X', 'T', '5' ) + +#define R_LoadDDSImage_MAX_MIPS 16 + + +int swdecode = 0; // not really working + +static void R_UploadCompressedImage2D(image_t * img, GLenum target, int level, GLenum format, int width, int height, int size, + const void *data) +{ + GLenum int_fmat; + + //if(glConfig.textureCompression == TC_S3TC) + + if (!swdecode) + { + qglCompressedTexImage2DARB(target, level, format, width, height, 0, size, data); + + return; + } + else + { + + + // nothing atol + + } + + // leilei - software decoding is ALL STRIPPED!!! Not only for simplicity, + // but there is a patent issue regarding the decoding. + // So, we only support DDS textures though directly + // using the driver itself to upload and don't even try to decode + // any of it. Not even for a lousy PowerVR alpha hack. + // Besides. the intent is to get those old dmm maps working + // as intended. I don't really have big plans for DDS. +} + +static void R_UploadImage2D(image_t * img, GLenum target, int level, GLenum int_fmat, + int width, int height, GLenum format, GLenum type, const void *data) +{ + + + qglTexImage2D(target, level, int_fmat, width, height, 0, format, type, data); +} +extern image_t *R_AllocImage(const char *name, qboolean linkIntoHashTable); + +image_t *R_LoadDDSImageData(void *pImageData, const char *name, int bits, filterType_t filterType, wrapType_t wrapType) +{ + image_t *ret = NULL; + + byte *buff; + + DDSURFACEDESC2_t *ddsd; //used to get at the dds header in the read buffer + + //based on texture type: + // cube width != 0, height == 0, depth == 0 + // 2D width != 0, height != 0, depth == 0 + // volume width != 0, height != 0, depth != 0 + int width, height, depth; + + //mip count and pointers to image data for each mip + //level, idx 0 = top level last pointer does not start + //a mip level, it's just there to mark off the end of + //the final mip data segment (thus the odd + 1) + // + //for cube textures we only find the offsets into the + //first face of the cube, subsequent faces will use the + //same offsets, just shifted over + int mipLevels; + byte *mipOffsets[R_LoadDDSImage_MAX_MIPS + 1]; + + qboolean usingAlpha; + + qboolean compressed; + GLuint format = 0; + GLuint internal_format = 0; + GLenum type = GL_UNSIGNED_BYTE; + + vec4_t zeroClampBorder = { 0, 0, 0, 1 }; + vec4_t alphaZeroClampBorder = { 0, 0, 0, 0 }; + + //comes from R_CreateImage + + + buff = (byte *) pImageData; + + if(strncmp((const char *)buff, "DDS ", 4) != 0) + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: invalid dds header \"%s\"\n", name); + goto ret_error; + } + + ddsd = (DDSURFACEDESC2_t *) (buff + 4); + + if(ddsd->dwSize != sizeof(DDSURFACEDESC2_t) || ddsd->u4.ddpfPixelFormat.dwSize != sizeof(DDPIXELFORMAT_t)) + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: invalid dds header \"%s\"\n", name); + goto ret_error; + } + + usingAlpha = (ddsd->u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) ? qtrue : qfalse; + mipLevels = ((ddsd->dwFlags & DDSD_MIPMAPCOUNT) && (ddsd->u2.dwMipMapCount > 1)) ? ddsd->u2.dwMipMapCount : 1; + + if(mipLevels > R_LoadDDSImage_MAX_MIPS) + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: dds image has too many mip levels \"%s\"\n", name); + goto ret_error; + } + + compressed = (ddsd->u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) ? qtrue : qfalse; + + // either a cube or a volume + if(ddsd->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP) + { + // cube texture + + if(ddsd->dwWidth != ddsd->dwHeight) + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: invalid dds image \"%s\"\n", name); + goto ret_error; + } + + width = ddsd->dwWidth; + height = 0; + depth = 0; + + if(width & (width - 1)) + { + //cubes must be a power of two + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: cube images must be power of two \"%s\"\n", name); + goto ret_error; + } + } + else if((ddsd->ddsCaps.dwCaps2 & DDSCAPS2_VOLUME) && (ddsd->dwFlags & DDSD_DEPTH)) + { + // 3D texture + + width = ddsd->dwWidth; + height = ddsd->dwHeight; + depth = ddsd->u1.dwDepth; + + if(width & (width - 1) || height & (height - 1) || depth & (depth - 1)) + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: volume images must be power of two \"%s\"\n", name); + goto ret_error; + } + } + else + { + // 2D texture + + width = ddsd->dwWidth; + height = ddsd->dwHeight; + depth = 0; + + //these are allowed to be non power of two, will be dealt with later on + //except for compressed images! + if(compressed && (width & (width - 1) || height & (height - 1))) + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: compressed texture images must be power of two \"%s\"\n", name); + goto ret_error; + } + } + + if(compressed) + { + int blockSize; + + if(depth != 0) + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: compressed volume textures are not supported \"%s\"\n", name); + goto ret_error; + } + + //compressed FOURCC formats + switch (ddsd->u4.ddpfPixelFormat.dwFourCC) + { + case FOURCC_DXT1: + blockSize = 8; + usingAlpha = qtrue; + format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; + + case FOURCC_DXT3: + blockSize = 16; + usingAlpha = qtrue; + format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; + + case FOURCC_DXT5: + blockSize = 16; + usingAlpha = qtrue; + format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + + default: + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: unsupported FOURCC \"%s\", \"%s\"\n", + &ddsd->u4.ddpfPixelFormat.dwFourCC, name); + goto ret_error; + } + + //get mip offsets + if(format) + { + int w = width; + int h = height; + int offset = 0; + int i; + + if(h == 0) + h = w; //cube map + + for(i = 0; (i < mipLevels) && (w || h); i++) + { + int qw, qh; + + mipOffsets[i] = buff + 4 + sizeof(DDSURFACEDESC2_t) + offset; + + if(w == 0) + w = 1; + if(h == 0) + h = 1; + + //size formula comes from DX docs (August 2005 SDK reference) + qw = w >> 2; + if(qw == 0) + qw = 1; + qh = h >> 2; + if(qh == 0) + qh = 1; + + offset += qw * qh * blockSize; + + w >>= 1; + h >>= 1; + } + + //put in the trailing offset + mipOffsets[i] = buff + 4 + sizeof(DDSURFACEDESC2_t) + offset; + } + else + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: error reading DDS image \"%s\"\n", name); + goto ret_error; + } + + internal_format = format; + } + else + { + // uncompressed format + if(ddsd->u4.ddpfPixelFormat.dwFlags & DDPF_RGB) + { + switch (ddsd->u4.ddpfPixelFormat.u0.dwRGBBitCount) + { + case 32: + internal_format = usingAlpha ? GL_RGBA8 : GL_RGB8; + format = GL_BGRA_EXT; + break; + + case 24: + internal_format = GL_RGB8; + format = GL_BGR_EXT; + break; + + case 16: + if(usingAlpha) + { + //must be A1R5G5B5 + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: unsupported format, 5551 \"%s\"\n", name); + goto ret_error; + } + else + { + //find out if it's X1R5G5B5 or R5G6B5 + + internal_format = GL_RGB5; + format = GL_RGB; + + if(ddsd->u4.ddpfPixelFormat.u2.dwGBitMask == 0x7E0) + type = GL_UNSIGNED_SHORT_5_6_5; + else + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: unsupported format, 5551 \"%s\"\n", name); + goto ret_error; + } + } + break; + + default: + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: unsupported RGB bit depth \"%s\"\n", name); + goto ret_error; + } + } + else if(ddsd->u4.ddpfPixelFormat.dwFlags & DDPF_LUMINANCE) + { + internal_format = usingAlpha ? GL_LUMINANCE8_ALPHA8 : GL_LUMINANCE8; + format = usingAlpha ? GL_LUMINANCE_ALPHA : GL_LUMINANCE; + } + else if(ddsd->u4.ddpfPixelFormat.dwFlags & DDPF_ALPHA) + { + internal_format = GL_ALPHA8; + format = GL_ALPHA; + } + else if(ddsd->u4.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) + { + internal_format = usingAlpha ? GL_RGB5_A1 : GL_RGB5; + format = GL_COLOR_INDEX4_EXT; + } + else if(ddsd->u4.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) + { + internal_format = usingAlpha ? GL_RGBA : GL_RGB; + format = GL_COLOR_INDEX8_EXT; + } + else + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: unsupported DDS image type \"%s\"\n", name); + goto ret_error; + } + + if(format) + { + int offset = 0; + int w = width; + int h = height; + int d = depth; + int i; + + if(h == 0) + h = w; //cube map + + for(i = 0; (i < mipLevels) && (w || h || d); i++) + { + mipOffsets[i] = buff + 4 + sizeof(DDSURFACEDESC2_t) + offset; + + if(w == 0) + w = 1; + if(h == 0) + h = 1; + if(d == 0) + d = 1; + + offset += (w * h * d * (ddsd->u4.ddpfPixelFormat.u0.dwRGBBitCount / 8)); + + w >>= 1; + h >>= 1; + d >>= 1; + } + + //put in the trailing offset + mipOffsets[i] = buff + 4 + sizeof(DDSURFACEDESC2_t) + offset; + } + else + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: Unexpected error reading DDS image \"%s\"\n", name); + goto ret_error; + } + } + + //we now have a full description of our image set up + //if we fail after this point we still want our image_t + //record in the hash so that we don't go trying to read + //the file again - been printing an error and returning + //NULL up to this point... + ret = R_AllocImage(name, qtrue); + + ret->uploadWidth = ret->width = width; + ret->uploadHeight = ret->height = height; + + ret->internalFormat = internal_format; + + ret->filterType = ((filterType == FT_DEFAULT) && (mipLevels > 1)) ? FT_DEFAULT : FT_LINEAR; + + if(ret->filterType == FT_LINEAR) + mipLevels = 1; + + // leilei - we do not support depth or cubemaps. + + { + // planar texture + + int w = width; + int h = height; + + int i; + + GLuint texnum; + + if(w & (w - 1) || h & (h - 1)) + { + // non-pow2: check extensions + + // if(glConfig.textureNPOTAvailable) + // { + // ret->type = GL_TEXTURE_2D; + // } + // else + { + ret->type = GL_TEXTURE_2D; // FIXME R_StateGetRectTarget(); + } + } + else + { + ret->type = GL_TEXTURE_2D; + } + + texnum = ret->texnum; + + if (w != h){ // leilei - rectangle texture hack + //ret->type = GL_TEXTURE_RECTANGLE_ARB; + h = w; + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: uploading %s, %i x %i\n", ret, w, h); + } + + GL_Bind(ret); + + if(mipLevels == 1) + qglTexParameteri(ret->type, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); + + for(i = 0; i < mipLevels; i++) + { + if(compressed) + { + GLsizei size = mipOffsets[i + 1] - mipOffsets[i]; + R_UploadCompressedImage2D(ret, ret->type, i, internal_format, w, h, size, mipOffsets[i]); + } + else + { + R_UploadImage2D(ret, ret->type, i, internal_format, w, h, format, type, mipOffsets[i]); + } + + w >>= 1; + if(w == 0) + w = 1; + h >>= 1; + if(h == 0) + h = 1; + } + } + + + GL_CheckErrors(); + + // set filter type + ret->filterType = filterType; + + // who cares about filtertype? + if(textureFilterAnisotropic) + qglTexParameterf(ret->type, GL_TEXTURE_MAX_ANISOTROPY_EXT, r_ext_texture_filter_anisotropic->value); + + qglTexParameterf(ret->type, GL_TEXTURE_MIN_FILTER, gl_filter_min); + qglTexParameterf(ret->type, GL_TEXTURE_MAG_FILTER, gl_filter_max); + + GL_CheckErrors(); + + // set wrap type + // we do care about this though. bouncepads etc + ret->wrapType = wrapType; + + switch (wrapType) + { + case WT_REPEAT: + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_S, GL_REPEAT); + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_T, GL_REPEAT); + break; + + case WT_CLAMP: + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_S, GL_CLAMP); + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_T, GL_CLAMP); + break; + + case WT_EDGE_CLAMP: + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + break; + + case WT_ZERO_CLAMP: + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + qglTexParameterfv(ret->type, GL_TEXTURE_BORDER_COLOR, zeroClampBorder); + break; + + case WT_ALPHA_ZERO_CLAMP: + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + qglTexParameterfv(ret->type, GL_TEXTURE_BORDER_COLOR, alphaZeroClampBorder); + break; + + default: + ri.Printf(PRINT_WARNING, "WARNING: unknown wrap type for image '%s'\n", ret->imgName); + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_S, GL_REPEAT); + qglTexParameterf(ret->type, GL_TEXTURE_WRAP_T, GL_REPEAT); + break; + } + + + GL_CheckErrors(); + + //GL_Unbind(); + qglBindTexture(ret->type, 0); + + ret_error: + return ret; +} + + +image_t *R_LoadDDSImage(const char *name, int bits, filterType_t filterType, wrapType_t wrapType) +{ + image_t *ret; + byte *buff; + int len; + + // comes from R_CreateImage + /* + if(tr.numImages == MAX_DRAWIMAGES) + { + ri.Printf(PRINT_WARNING, "R_LoadDDSImage: MAX_DRAWIMAGES hit\n"); + return NULL; + } + */ + + len = ri.FS_ReadFile(name, (void **)&buff); + if(!buff) + return 0; + + ret = R_LoadDDSImageData(buff, name, bits, filterType, wrapType); + + ri.FS_FreeFile(buff); + + return ret; +} + +#endif // BROKEN_DDS \ No newline at end of file diff --git a/code/renderergl1/tr_animation.c b/code/renderergl1/tr_animation.c deleted file mode 100644 index 7bcc5bdf69..0000000000 --- a/code/renderergl1/tr_animation.c +++ /dev/null @@ -1,521 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "tr_local.h" - -/* - -All bones should be an identity orientation to display the mesh exactly -as it is specified. - -For all other frames, the bones represent the transformation from the -orientation of the bone in the base frame to the orientation in this -frame. - -*/ - - -// copied and adapted from tr_mesh.c - -/* -============= -R_MDRCullModel -============= -*/ - -static int R_MDRCullModel( mdrHeader_t *header, trRefEntity_t *ent ) { - vec3_t bounds[2]; - mdrFrame_t *oldFrame, *newFrame; - int i, frameSize; - - frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); - - // compute frame pointers - newFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame); - oldFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.oldframe); - - // cull bounding sphere ONLY if this is not an upscaled entity - if ( !ent->e.nonNormalizedAxes ) - { - if ( ent->e.frame == ent->e.oldframe ) - { - switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) ) - { - // Ummm... yeah yeah I know we don't really have an md3 here.. but we pretend - // we do. After all, the purpose of mdrs are not that different, are they? - - case CULL_OUT: - tr.pc.c_sphere_cull_md3_out++; - return CULL_OUT; - - case CULL_IN: - tr.pc.c_sphere_cull_md3_in++; - return CULL_IN; - - case CULL_CLIP: - tr.pc.c_sphere_cull_md3_clip++; - break; - } - } - else - { - int sphereCull, sphereCullB; - - sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ); - if ( newFrame == oldFrame ) { - sphereCullB = sphereCull; - } else { - sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius ); - } - - if ( sphereCull == sphereCullB ) - { - if ( sphereCull == CULL_OUT ) - { - tr.pc.c_sphere_cull_md3_out++; - return CULL_OUT; - } - else if ( sphereCull == CULL_IN ) - { - tr.pc.c_sphere_cull_md3_in++; - return CULL_IN; - } - else - { - tr.pc.c_sphere_cull_md3_clip++; - } - } - } - } - - // calculate a bounding box in the current coordinate system - for (i = 0 ; i < 3 ; i++) { - bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; - bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; - } - - switch ( R_CullLocalBox( bounds ) ) - { - case CULL_IN: - tr.pc.c_box_cull_md3_in++; - return CULL_IN; - case CULL_CLIP: - tr.pc.c_box_cull_md3_clip++; - return CULL_CLIP; - case CULL_OUT: - default: - tr.pc.c_box_cull_md3_out++; - return CULL_OUT; - } -} - -/* -================= -R_MDRComputeFogNum - -================= -*/ - -int R_MDRComputeFogNum( mdrHeader_t *header, trRefEntity_t *ent ) { - int i, j; - fog_t *fog; - mdrFrame_t *mdrFrame; - vec3_t localOrigin; - int frameSize; - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return 0; - } - - frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); - - // FIXME: non-normalized axis issues - mdrFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame); - VectorAdd( ent->e.origin, mdrFrame->localOrigin, localOrigin ); - for ( i = 1 ; i < tr.world->numfogs ; i++ ) { - fog = &tr.world->fogs[i]; - for ( j = 0 ; j < 3 ; j++ ) { - if ( localOrigin[j] - mdrFrame->radius >= fog->bounds[1][j] ) { - break; - } - if ( localOrigin[j] + mdrFrame->radius <= fog->bounds[0][j] ) { - break; - } - } - if ( j == 3 ) { - return i; - } - } - - return 0; -} - - -/* -============== -R_MDRAddAnimSurfaces -============== -*/ - -// much stuff in there is just copied from R_AddMd3Surfaces in tr_mesh.c - -void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { - mdrHeader_t *header; - mdrSurface_t *surface; - mdrLOD_t *lod; - shader_t *shader; - skin_t *skin; - int i, j; - int lodnum = 0; - int fogNum = 0; - int cull; - qboolean personalModel; - - header = (mdrHeader_t *) tr.currentModel->modelData; - - personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; - - if ( ent->e.renderfx & RF_WRAP_FRAMES ) - { - ent->e.frame %= header->numFrames; - ent->e.oldframe %= header->numFrames; - } - - // - // Validate the frames so there is no chance of a crash. - // This will write directly into the entity structure, so - // when the surfaces are rendered, they don't need to be - // range checked again. - // - if ((ent->e.frame >= header->numFrames) - || (ent->e.frame < 0) - || (ent->e.oldframe >= header->numFrames) - || (ent->e.oldframe < 0) ) - { - ri.Printf( PRINT_DEVELOPER, "R_MDRAddAnimSurfaces: no such frame %d to %d for '%s'\n", - ent->e.oldframe, ent->e.frame, tr.currentModel->name ); - ent->e.frame = 0; - ent->e.oldframe = 0; - } - - // - // cull the entire model if merged bounding box of both frames - // is outside the view frustum. - // - cull = R_MDRCullModel (header, ent); - if ( cull == CULL_OUT ) { - return; - } - - // figure out the current LOD of the model we're rendering, and set the lod pointer respectively. - lodnum = R_ComputeLOD(ent); - // check whether this model has as that many LODs at all. If not, try the closest thing we got. - if(header->numLODs <= 0) - return; - if(header->numLODs <= lodnum) - lodnum = header->numLODs - 1; - - lod = (mdrLOD_t *)( (byte *)header + header->ofsLODs); - for(i = 0; i < lodnum; i++) - { - lod = (mdrLOD_t *) ((byte *) lod + lod->ofsEnd); - } - - // set up lighting - if ( !personalModel || r_shadows->integer > 1 ) - { - R_SetupEntityLighting( &tr.refdef, ent ); - } - - // fogNum? - fogNum = R_MDRComputeFogNum( header, ent ); - - surface = (mdrSurface_t *)( (byte *)lod + lod->ofsSurfaces ); - - for ( i = 0 ; i < lod->numSurfaces ; i++ ) - { - - if(ent->e.customShader) - shader = R_GetShaderByHandle(ent->e.customShader); - else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins) - { - skin = R_GetSkinByHandle(ent->e.customSkin); - shader = tr.defaultShader; - - for(j = 0; j < skin->numSurfaces; j++) - { - if (!strcmp(skin->surfaces[j]->name, surface->name)) - { - shader = skin->surfaces[j]->shader; - break; - } - } - } - else if(surface->shaderIndex > 0) - shader = R_GetShaderByHandle( surface->shaderIndex ); - else - shader = tr.defaultShader; - - // we will add shadows even if the main object isn't visible in the view - - // stencil shadows can't do personal models unless I polyhedron clip - if ( !personalModel - && r_shadows->integer == 2 - && fogNum == 0 - && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) - && shader->sort == SS_OPAQUE ) - { - R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse ); - } - - // projection shadows work fine with personal models - if ( r_shadows->integer == 3 - && fogNum == 0 - && (ent->e.renderfx & RF_SHADOW_PLANE ) - && shader->sort == SS_OPAQUE ) - { - R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse ); - } - - if (!personalModel) - R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse ); - - surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd ); - } -} - -/* -============== -RB_MDRSurfaceAnim -============== -*/ -void RB_MDRSurfaceAnim( mdrSurface_t *surface ) -{ - int i, j, k; - float frontlerp, backlerp; - int *triangles; - int indexes; - int baseIndex, baseVertex; - int numVerts; - mdrVertex_t *v; - mdrHeader_t *header; - mdrFrame_t *frame; - mdrFrame_t *oldFrame; - mdrBone_t bones[MDR_MAX_BONES], *bonePtr, *bone; - - int frameSize; - - // don't lerp if lerping off, or this is the only frame, or the last frame... - // - if (backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame) - { - backlerp = 0; // if backlerp is 0, lerping is off and frontlerp is never used - frontlerp = 1; - } - else - { - backlerp = backEnd.currentEntity->e.backlerp; - frontlerp = 1.0f - backlerp; - } - - header = (mdrHeader_t *)((byte *)surface + surface->ofsHeader); - - frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); - - frame = (mdrFrame_t *)((byte *)header + header->ofsFrames + - backEnd.currentEntity->e.frame * frameSize ); - oldFrame = (mdrFrame_t *)((byte *)header + header->ofsFrames + - backEnd.currentEntity->e.oldframe * frameSize ); - - RB_CheckOverflow( surface->numVerts, surface->numTriangles ); - - triangles = (int *) ((byte *)surface + surface->ofsTriangles); - indexes = surface->numTriangles * 3; - baseIndex = tess.numIndexes; - baseVertex = tess.numVertexes; - - // Set up all triangles. - for (j = 0 ; j < indexes ; j++) - { - tess.indexes[baseIndex + j] = baseVertex + triangles[j]; - } - tess.numIndexes += indexes; - - // - // lerp all the needed bones - // - if ( !backlerp ) - { - // no lerping needed - bonePtr = frame->bones; - } - else - { - bonePtr = bones; - - for ( i = 0 ; i < header->numBones*12 ; i++ ) - { - ((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i] + backlerp * ((float *)oldFrame->bones)[i]; - } - } - - // - // deform the vertexes by the lerped bones - // - numVerts = surface->numVerts; - v = (mdrVertex_t *) ((byte *)surface + surface->ofsVerts); - for ( j = 0; j < numVerts; j++ ) - { - vec3_t tempVert, tempNormal; - mdrWeight_t *w; - - VectorClear( tempVert ); - VectorClear( tempNormal ); - w = v->weights; - for ( k = 0 ; k < v->numWeights ; k++, w++ ) - { - bone = bonePtr + w->boneIndex; - - tempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] ); - tempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] ); - tempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] ); - - tempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal ); - tempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal ); - tempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal ); - } - - tess.xyz[baseVertex + j][0] = tempVert[0]; - tess.xyz[baseVertex + j][1] = tempVert[1]; - tess.xyz[baseVertex + j][2] = tempVert[2]; - - tess.normal[baseVertex + j][0] = tempNormal[0]; - tess.normal[baseVertex + j][1] = tempNormal[1]; - tess.normal[baseVertex + j][2] = tempNormal[2]; - - tess.texCoords[baseVertex + j][0][0] = v->texCoords[0]; - tess.texCoords[baseVertex + j][0][1] = v->texCoords[1]; - - v = (mdrVertex_t *)&v->weights[v->numWeights]; - } - - tess.numVertexes += surface->numVerts; -} - - -#define MC_MASK_X ((1<<(MC_BITS_X))-1) -#define MC_MASK_Y ((1<<(MC_BITS_Y))-1) -#define MC_MASK_Z ((1<<(MC_BITS_Z))-1) -#define MC_MASK_VECT ((1<<(MC_BITS_VECT))-1) - -#define MC_SCALE_VECT (1.0f/(float)((1<<(MC_BITS_VECT-1))-2)) - -#define MC_POS_X (0) -#define MC_SHIFT_X (0) - -#define MC_POS_Y ((((MC_BITS_X))/8)) -#define MC_SHIFT_Y ((((MC_BITS_X)%8))) - -#define MC_POS_Z ((((MC_BITS_X+MC_BITS_Y))/8)) -#define MC_SHIFT_Z ((((MC_BITS_X+MC_BITS_Y)%8))) - -#define MC_POS_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z))/8)) -#define MC_SHIFT_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z)%8))) - -#define MC_POS_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT))/8)) -#define MC_SHIFT_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT)%8))) - -#define MC_POS_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2))/8)) -#define MC_SHIFT_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2)%8))) - -#define MC_POS_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3))/8)) -#define MC_SHIFT_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3)%8))) - -#define MC_POS_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4))/8)) -#define MC_SHIFT_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4)%8))) - -#define MC_POS_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5))/8)) -#define MC_SHIFT_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5)%8))) - -#define MC_POS_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6))/8)) -#define MC_SHIFT_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6)%8))) - -#define MC_POS_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7))/8)) -#define MC_SHIFT_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7)%8))) - -#define MC_POS_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8))/8)) -#define MC_SHIFT_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8)%8))) - -void MC_UnCompress(float mat[3][4],const unsigned char * comp) -{ - int val; - - val=(int)((unsigned short *)(comp))[0]; - val-=1<<(MC_BITS_X-1); - mat[0][3]=((float)(val))*MC_SCALE_X; - - val=(int)((unsigned short *)(comp))[1]; - val-=1<<(MC_BITS_Y-1); - mat[1][3]=((float)(val))*MC_SCALE_Y; - - val=(int)((unsigned short *)(comp))[2]; - val-=1<<(MC_BITS_Z-1); - mat[2][3]=((float)(val))*MC_SCALE_Z; - - val=(int)((unsigned short *)(comp))[3]; - val-=1<<(MC_BITS_VECT-1); - mat[0][0]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[4]; - val-=1<<(MC_BITS_VECT-1); - mat[0][1]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[5]; - val-=1<<(MC_BITS_VECT-1); - mat[0][2]=((float)(val))*MC_SCALE_VECT; - - - val=(int)((unsigned short *)(comp))[6]; - val-=1<<(MC_BITS_VECT-1); - mat[1][0]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[7]; - val-=1<<(MC_BITS_VECT-1); - mat[1][1]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[8]; - val-=1<<(MC_BITS_VECT-1); - mat[1][2]=((float)(val))*MC_SCALE_VECT; - - - val=(int)((unsigned short *)(comp))[9]; - val-=1<<(MC_BITS_VECT-1); - mat[2][0]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[10]; - val-=1<<(MC_BITS_VECT-1); - mat[2][1]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[11]; - val-=1<<(MC_BITS_VECT-1); - mat[2][2]=((float)(val))*MC_SCALE_VECT; -} diff --git a/code/renderergl1/tr_backend.c b/code/renderergl1/tr_backend.c deleted file mode 100644 index 0a3fe03628..0000000000 --- a/code/renderergl1/tr_backend.c +++ /dev/null @@ -1,1166 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - -backEndData_t *backEndData; -backEndState_t backEnd; - - -static float s_flipMatrix[16] = { - // convert from our coordinate system (looking down X) - // to OpenGL's coordinate system (looking down -Z) - 0, 0, -1, 0, - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1 -}; - - -/* -** GL_Bind -*/ -void GL_Bind( image_t *image ) { - int texnum; - - if ( !image ) { - ri.Printf( PRINT_WARNING, "GL_Bind: NULL image\n" ); - texnum = tr.defaultImage->texnum; - } else { - texnum = image->texnum; - } - - if ( r_nobind->integer && tr.dlightImage ) { // performance evaluation option - texnum = tr.dlightImage->texnum; - } - - if ( glState.currenttextures[glState.currenttmu] != texnum ) { - if ( image ) { - image->frameUsed = tr.frameCount; - } - glState.currenttextures[glState.currenttmu] = texnum; - qglBindTexture (GL_TEXTURE_2D, texnum); - } -} - -/* -** GL_SelectTexture -*/ -void GL_SelectTexture( int unit ) -{ - if ( glState.currenttmu == unit ) - { - return; - } - - if ( unit == 0 ) - { - qglActiveTextureARB( GL_TEXTURE0_ARB ); - GLimp_LogComment( "glActiveTextureARB( GL_TEXTURE0_ARB )\n" ); - qglClientActiveTextureARB( GL_TEXTURE0_ARB ); - GLimp_LogComment( "glClientActiveTextureARB( GL_TEXTURE0_ARB )\n" ); - } - else if ( unit == 1 ) - { - qglActiveTextureARB( GL_TEXTURE1_ARB ); - GLimp_LogComment( "glActiveTextureARB( GL_TEXTURE1_ARB )\n" ); - qglClientActiveTextureARB( GL_TEXTURE1_ARB ); - GLimp_LogComment( "glClientActiveTextureARB( GL_TEXTURE1_ARB )\n" ); - } else { - ri.Error( ERR_DROP, "GL_SelectTexture: unit = %i", unit ); - } - - glState.currenttmu = unit; -} - - -/* -** GL_BindMultitexture -*/ -void GL_BindMultitexture( image_t *image0, GLuint env0, image_t *image1, GLuint env1 ) { - int texnum0, texnum1; - - texnum0 = image0->texnum; - texnum1 = image1->texnum; - - if ( r_nobind->integer && tr.dlightImage ) { // performance evaluation option - texnum0 = texnum1 = tr.dlightImage->texnum; - } - - if ( glState.currenttextures[1] != texnum1 ) { - GL_SelectTexture( 1 ); - image1->frameUsed = tr.frameCount; - glState.currenttextures[1] = texnum1; - qglBindTexture( GL_TEXTURE_2D, texnum1 ); - } - if ( glState.currenttextures[0] != texnum0 ) { - GL_SelectTexture( 0 ); - image0->frameUsed = tr.frameCount; - glState.currenttextures[0] = texnum0; - qglBindTexture( GL_TEXTURE_2D, texnum0 ); - } -} - - -/* -** GL_Cull -*/ -void GL_Cull( int cullType ) { - if ( glState.faceCulling == cullType ) { - return; - } - - glState.faceCulling = cullType; - - if ( cullType == CT_TWO_SIDED ) - { - qglDisable( GL_CULL_FACE ); - } - else - { - qboolean cullFront; - qglEnable( GL_CULL_FACE ); - - cullFront = (cullType == CT_FRONT_SIDED); - if ( backEnd.viewParms.isMirror ) - { - cullFront = !cullFront; - } - - qglCullFace( cullFront ? GL_FRONT : GL_BACK ); - } -} - -/* -** GL_TexEnv -*/ -void GL_TexEnv( int env ) -{ - if ( env == glState.texEnv[glState.currenttmu] ) - { - return; - } - - glState.texEnv[glState.currenttmu] = env; - - - switch ( env ) - { - case GL_MODULATE: - qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); - break; - case GL_REPLACE: - qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); - break; - case GL_DECAL: - qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL ); - break; - case GL_ADD: - qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD ); - break; - default: - ri.Error( ERR_DROP, "GL_TexEnv: invalid env '%d' passed", env ); - break; - } -} - -/* -** GL_State -** -** This routine is responsible for setting the most commonly changed state -** in Q3. -*/ -void GL_State( unsigned long stateBits ) -{ - unsigned long diff = stateBits ^ glState.glStateBits; - - if ( !diff ) - { - return; - } - - // - // check depthFunc bits - // - if ( diff & GLS_DEPTHFUNC_EQUAL ) - { - if ( stateBits & GLS_DEPTHFUNC_EQUAL ) - { - qglDepthFunc( GL_EQUAL ); - } - else - { - qglDepthFunc( GL_LEQUAL ); - } - } - - // - // check blend bits - // - if ( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) - { - GLenum srcFactor = GL_ONE, dstFactor = GL_ONE; - - if ( stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) - { - switch ( stateBits & GLS_SRCBLEND_BITS ) - { - case GLS_SRCBLEND_ZERO: - srcFactor = GL_ZERO; - break; - case GLS_SRCBLEND_ONE: - srcFactor = GL_ONE; - break; - case GLS_SRCBLEND_DST_COLOR: - srcFactor = GL_DST_COLOR; - break; - case GLS_SRCBLEND_ONE_MINUS_DST_COLOR: - srcFactor = GL_ONE_MINUS_DST_COLOR; - break; - case GLS_SRCBLEND_SRC_ALPHA: - srcFactor = GL_SRC_ALPHA; - break; - case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA: - srcFactor = GL_ONE_MINUS_SRC_ALPHA; - break; - case GLS_SRCBLEND_DST_ALPHA: - srcFactor = GL_DST_ALPHA; - break; - case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA: - srcFactor = GL_ONE_MINUS_DST_ALPHA; - break; - case GLS_SRCBLEND_ALPHA_SATURATE: - srcFactor = GL_SRC_ALPHA_SATURATE; - break; - default: - ri.Error( ERR_DROP, "GL_State: invalid src blend state bits" ); - break; - } - - switch ( stateBits & GLS_DSTBLEND_BITS ) - { - case GLS_DSTBLEND_ZERO: - dstFactor = GL_ZERO; - break; - case GLS_DSTBLEND_ONE: - dstFactor = GL_ONE; - break; - case GLS_DSTBLEND_SRC_COLOR: - dstFactor = GL_SRC_COLOR; - break; - case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR: - dstFactor = GL_ONE_MINUS_SRC_COLOR; - break; - case GLS_DSTBLEND_SRC_ALPHA: - dstFactor = GL_SRC_ALPHA; - break; - case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA: - dstFactor = GL_ONE_MINUS_SRC_ALPHA; - break; - case GLS_DSTBLEND_DST_ALPHA: - dstFactor = GL_DST_ALPHA; - break; - case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA: - dstFactor = GL_ONE_MINUS_DST_ALPHA; - break; - default: - ri.Error( ERR_DROP, "GL_State: invalid dst blend state bits" ); - break; - } - - qglEnable( GL_BLEND ); - qglBlendFunc( srcFactor, dstFactor ); - } - else - { - qglDisable( GL_BLEND ); - } - } - - // - // check depthmask - // - if ( diff & GLS_DEPTHMASK_TRUE ) - { - if ( stateBits & GLS_DEPTHMASK_TRUE ) - { - qglDepthMask( GL_TRUE ); - } - else - { - qglDepthMask( GL_FALSE ); - } - } - - // - // fill/line mode - // - if ( diff & GLS_POLYMODE_LINE ) - { - if ( stateBits & GLS_POLYMODE_LINE ) - { - qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); - } - else - { - qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); - } - } - - // - // depthtest - // - if ( diff & GLS_DEPTHTEST_DISABLE ) - { - if ( stateBits & GLS_DEPTHTEST_DISABLE ) - { - qglDisable( GL_DEPTH_TEST ); - } - else - { - qglEnable( GL_DEPTH_TEST ); - } - } - - // - // alpha test - // - if ( diff & GLS_ATEST_BITS ) - { - switch ( stateBits & GLS_ATEST_BITS ) - { - case 0: - qglDisable( GL_ALPHA_TEST ); - break; - case GLS_ATEST_GT_0: - qglEnable( GL_ALPHA_TEST ); - qglAlphaFunc( GL_GREATER, 0.0f ); - break; - case GLS_ATEST_LT_80: - qglEnable( GL_ALPHA_TEST ); - qglAlphaFunc( GL_LESS, 0.5f ); - break; - case GLS_ATEST_GE_80: - qglEnable( GL_ALPHA_TEST ); - qglAlphaFunc( GL_GEQUAL, 0.5f ); - break; - default: - assert( 0 ); - break; - } - } - - glState.glStateBits = stateBits; -} - - - -/* -================ -RB_Hyperspace - -A player has predicted a teleport, but hasn't arrived yet -================ -*/ -static void RB_Hyperspace( void ) { - float c; - - if ( !backEnd.isHyperspace ) { - // do initialization shit - } - - c = ( backEnd.refdef.time & 255 ) / 255.0f; - qglClearColor( c, c, c, 1 ); - qglClear( GL_COLOR_BUFFER_BIT ); - - backEnd.isHyperspace = qtrue; -} - - -static void SetViewportAndScissor( void ) { - qglMatrixMode(GL_PROJECTION); - qglLoadMatrixf( backEnd.viewParms.projectionMatrix ); - qglMatrixMode(GL_MODELVIEW); - - // set the window clipping - qglViewport( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, - backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); - qglScissor( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, - backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); -} - -/* -================= -RB_BeginDrawingView - -Any mirrored or portaled views have already been drawn, so prepare -to actually render the visible surfaces for this view -================= -*/ -void RB_BeginDrawingView (void) { - int clearBits = 0; - - // sync with gl if needed - if ( r_finish->integer == 1 && !glState.finishCalled ) { - qglFinish (); - glState.finishCalled = qtrue; - } - if ( r_finish->integer == 0 ) { - glState.finishCalled = qtrue; - } - - // we will need to change the projection matrix before drawing - // 2D images again - backEnd.projection2D = qfalse; - - // - // set the modelview matrix for the viewer - // - SetViewportAndScissor(); - - // ensures that depth writes are enabled for the depth clear - GL_State( GLS_DEFAULT ); - // clear relevant buffers - clearBits = GL_DEPTH_BUFFER_BIT; - - if ( r_measureOverdraw->integer || r_shadows->integer == 2 ) - { - clearBits |= GL_STENCIL_BUFFER_BIT; - } - if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) - { - clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used -#ifdef _DEBUG - qglClearColor( 0.8f, 0.7f, 0.4f, 1.0f ); // FIXME: get color of sky -#else - qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky -#endif - } - qglClear( clearBits ); - - if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) ) - { - RB_Hyperspace(); - return; - } - else - { - backEnd.isHyperspace = qfalse; - } - - glState.faceCulling = -1; // force face culling to set next time - - // we will only draw a sun if there was sky rendered in this view - backEnd.skyRenderedThisView = qfalse; - - // clip to the plane of the portal - if ( backEnd.viewParms.isPortal ) { - float plane[4]; - double plane2[4]; - - plane[0] = backEnd.viewParms.portalPlane.normal[0]; - plane[1] = backEnd.viewParms.portalPlane.normal[1]; - plane[2] = backEnd.viewParms.portalPlane.normal[2]; - plane[3] = backEnd.viewParms.portalPlane.dist; - - plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane); - plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane); - plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane); - plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3]; - - qglLoadMatrixf( s_flipMatrix ); - qglClipPlane (GL_CLIP_PLANE0, plane2); - qglEnable (GL_CLIP_PLANE0); - } else { - qglDisable (GL_CLIP_PLANE0); - } -} - - -#define MAC_EVENT_PUMP_MSEC 5 - -/* -================== -RB_RenderDrawSurfList -================== -*/ -void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { - shader_t *shader, *oldShader; - int fogNum, oldFogNum; - int entityNum, oldEntityNum; - int dlighted, oldDlighted; - qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair; - int i; - drawSurf_t *drawSurf; - int oldSort; - float originalTime; - - // save original time for entity shader offsets - originalTime = backEnd.refdef.floatTime; - - // clear the z buffer, set the modelview, etc - RB_BeginDrawingView (); - - // draw everything - oldEntityNum = -1; - backEnd.currentEntity = &tr.worldEntity; - oldShader = NULL; - oldFogNum = -1; - oldDepthRange = qfalse; - wasCrosshair = qfalse; - oldDlighted = qfalse; - oldSort = -1; - depthRange = qfalse; - - backEnd.pc.c_surfaces += numDrawSurfs; - - for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { - if ( drawSurf->sort == oldSort ) { - // fast path, same as previous sort - rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); - continue; - } - oldSort = drawSurf->sort; - R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); - - // - // change the tess parameters if needed - // a "entityMergable" shader is a shader that can have surfaces from seperate - // entities merged into a single batch, like smoke and blood puff sprites - if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted - || ( entityNum != oldEntityNum && !shader->entityMergable ) ) ) { - if (oldShader != NULL) { - RB_EndSurface(); - } - RB_BeginSurface( shader, fogNum ); - oldShader = shader; - oldFogNum = fogNum; - oldDlighted = dlighted; - } - - // - // change the modelview matrix if needed - // - if ( entityNum != oldEntityNum ) { - depthRange = isCrosshair = qfalse; - - if ( entityNum != REFENTITYNUM_WORLD ) { - backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; - backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; - // we have to reset the shaderTime as well otherwise image animations start - // from the wrong frame - tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; - - // set up the transformation matrix - R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or ); - - // set up the dynamic lighting if needed - if ( backEnd.currentEntity->needDlights ) { - R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); - } - - if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK) - { - // hack the depth range to prevent view model from poking into walls - depthRange = qtrue; - - if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR) - isCrosshair = qtrue; - } - } else { - backEnd.currentEntity = &tr.worldEntity; - backEnd.refdef.floatTime = originalTime; - backEnd.or = backEnd.viewParms.world; - // we have to reset the shaderTime as well otherwise image animations on - // the world (like water) continue with the wrong frame - tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; - R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); - } - - qglLoadMatrixf( backEnd.or.modelMatrix ); - - // - // change depthrange. Also change projection matrix so first person weapon does not look like coming - // out of the screen. - // - if (oldDepthRange != depthRange || wasCrosshair != isCrosshair) - { - if (depthRange) - { - if(backEnd.viewParms.stereoFrame != STEREO_CENTER) - { - if(isCrosshair) - { - if(oldDepthRange) - { - // was not a crosshair but now is, change back proj matrix - qglMatrixMode(GL_PROJECTION); - qglLoadMatrixf(backEnd.viewParms.projectionMatrix); - qglMatrixMode(GL_MODELVIEW); - } - } - else - { - viewParms_t temp = backEnd.viewParms; - - R_SetupProjection(&temp, r_znear->value, qfalse); - - qglMatrixMode(GL_PROJECTION); - qglLoadMatrixf(temp.projectionMatrix); - qglMatrixMode(GL_MODELVIEW); - } - } - - if(!oldDepthRange) - qglDepthRange (0, 0.3); - } - else - { - if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER) - { - qglMatrixMode(GL_PROJECTION); - qglLoadMatrixf(backEnd.viewParms.projectionMatrix); - qglMatrixMode(GL_MODELVIEW); - } - - qglDepthRange (0, 1); - } - - oldDepthRange = depthRange; - wasCrosshair = isCrosshair; - } - - oldEntityNum = entityNum; - } - - // add the triangles for this surface - rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); - } - - backEnd.refdef.floatTime = originalTime; - - // draw the contents of the last shader batch - if (oldShader != NULL) { - RB_EndSurface(); - } - - // go back to the world modelview matrix - qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); - if ( depthRange ) { - qglDepthRange (0, 1); - } - - if (r_drawSun->integer) { - RB_DrawSun(0.1, tr.sunShader); - } - - // darken down any stencil shadows - RB_ShadowFinish(); - - // add light flares on lights that aren't obscured - RB_RenderFlares(); -} - - -/* -============================================================================ - -RENDER BACK END FUNCTIONS - -============================================================================ -*/ - -/* -================ -RB_SetGL2D - -================ -*/ -void RB_SetGL2D (void) { - backEnd.projection2D = qtrue; - - // set 2D virtual screen size - qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); - qglMatrixMode(GL_PROJECTION); - qglLoadIdentity (); - qglOrtho (0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1); - qglMatrixMode(GL_MODELVIEW); - qglLoadIdentity (); - - GL_State( GLS_DEPTHTEST_DISABLE | - GLS_SRCBLEND_SRC_ALPHA | - GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); - - qglDisable( GL_CULL_FACE ); - qglDisable( GL_CLIP_PLANE0 ); - - // set time for 2D shaders - backEnd.refdef.time = ri.Milliseconds(); - backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f; -} - - -/* -============= -RE_StretchRaw - -FIXME: not exactly backend -Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle. -Used for cinematics. -============= -*/ -void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { - int i, j; - int start, end; - - if ( !tr.registered ) { - return; - } - R_IssuePendingRenderCommands(); - - if ( tess.numIndexes ) { - RB_EndSurface(); - } - - // we definately want to sync every frame for the cinematics - qglFinish(); - - start = 0; - if ( r_speeds->integer ) { - start = ri.Milliseconds(); - } - - // make sure rows and cols are powers of 2 - for ( i = 0 ; ( 1 << i ) < cols ; i++ ) { - } - for ( j = 0 ; ( 1 << j ) < rows ; j++ ) { - } - if ( ( 1 << i ) != cols || ( 1 << j ) != rows) { - ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows); - } - - GL_Bind( tr.scratchImage[client] ); - - // if the scratchImage isn't in the format we want, specify it as a new texture - if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { - tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; - tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; - qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - } else { - if (dirty) { - // otherwise, just subimage upload it so that drivers can tell we are going to be changing - // it and don't try and do a texture compression - qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); - } - } - - if ( r_speeds->integer ) { - end = ri.Milliseconds(); - ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start ); - } - - RB_SetGL2D(); - - qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); - - qglBegin (GL_QUADS); - qglTexCoord2f ( 0.5f / cols, 0.5f / rows ); - qglVertex2f (x, y); - qglTexCoord2f ( ( cols - 0.5f ) / cols , 0.5f / rows ); - qglVertex2f (x+w, y); - qglTexCoord2f ( ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows ); - qglVertex2f (x+w, y+h); - qglTexCoord2f ( 0.5f / cols, ( rows - 0.5f ) / rows ); - qglVertex2f (x, y+h); - qglEnd (); -} - -void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { - - GL_Bind( tr.scratchImage[client] ); - - // if the scratchImage isn't in the format we want, specify it as a new texture - if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { - tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; - tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; - qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - } else { - if (dirty) { - // otherwise, just subimage upload it so that drivers can tell we are going to be changing - // it and don't try and do a texture compression - qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); - } - } -} - - -/* -============= -RB_SetColor - -============= -*/ -const void *RB_SetColor( const void *data ) { - const setColorCommand_t *cmd; - - cmd = (const setColorCommand_t *)data; - - backEnd.color2D[0] = cmd->color[0] * 255; - backEnd.color2D[1] = cmd->color[1] * 255; - backEnd.color2D[2] = cmd->color[2] * 255; - backEnd.color2D[3] = cmd->color[3] * 255; - - return (const void *)(cmd + 1); -} - -/* -============= -RB_StretchPic -============= -*/ -const void *RB_StretchPic ( const void *data ) { - const stretchPicCommand_t *cmd; - shader_t *shader; - int numVerts, numIndexes; - - cmd = (const stretchPicCommand_t *)data; - - if ( !backEnd.projection2D ) { - RB_SetGL2D(); - } - - shader = cmd->shader; - if ( shader != tess.shader ) { - if ( tess.numIndexes ) { - RB_EndSurface(); - } - backEnd.currentEntity = &backEnd.entity2D; - RB_BeginSurface( shader, 0 ); - } - - RB_CHECKOVERFLOW( 4, 6 ); - numVerts = tess.numVertexes; - numIndexes = tess.numIndexes; - - tess.numVertexes += 4; - tess.numIndexes += 6; - - tess.indexes[ numIndexes ] = numVerts + 3; - tess.indexes[ numIndexes + 1 ] = numVerts + 0; - tess.indexes[ numIndexes + 2 ] = numVerts + 2; - tess.indexes[ numIndexes + 3 ] = numVerts + 2; - tess.indexes[ numIndexes + 4 ] = numVerts + 0; - tess.indexes[ numIndexes + 5 ] = numVerts + 1; - - *(int *)tess.vertexColors[ numVerts ] = - *(int *)tess.vertexColors[ numVerts + 1 ] = - *(int *)tess.vertexColors[ numVerts + 2 ] = - *(int *)tess.vertexColors[ numVerts + 3 ] = *(int *)backEnd.color2D; - - tess.xyz[ numVerts ][0] = cmd->x; - tess.xyz[ numVerts ][1] = cmd->y; - tess.xyz[ numVerts ][2] = 0; - - tess.texCoords[ numVerts ][0][0] = cmd->s1; - tess.texCoords[ numVerts ][0][1] = cmd->t1; - - tess.xyz[ numVerts + 1 ][0] = cmd->x + cmd->w; - tess.xyz[ numVerts + 1 ][1] = cmd->y; - tess.xyz[ numVerts + 1 ][2] = 0; - - tess.texCoords[ numVerts + 1 ][0][0] = cmd->s2; - tess.texCoords[ numVerts + 1 ][0][1] = cmd->t1; - - tess.xyz[ numVerts + 2 ][0] = cmd->x + cmd->w; - tess.xyz[ numVerts + 2 ][1] = cmd->y + cmd->h; - tess.xyz[ numVerts + 2 ][2] = 0; - - tess.texCoords[ numVerts + 2 ][0][0] = cmd->s2; - tess.texCoords[ numVerts + 2 ][0][1] = cmd->t2; - - tess.xyz[ numVerts + 3 ][0] = cmd->x; - tess.xyz[ numVerts + 3 ][1] = cmd->y + cmd->h; - tess.xyz[ numVerts + 3 ][2] = 0; - - tess.texCoords[ numVerts + 3 ][0][0] = cmd->s1; - tess.texCoords[ numVerts + 3 ][0][1] = cmd->t2; - - return (const void *)(cmd + 1); -} - - -/* -============= -RB_DrawSurfs - -============= -*/ -const void *RB_DrawSurfs( const void *data ) { - const drawSurfsCommand_t *cmd; - - // finish any 2D drawing if needed - if ( tess.numIndexes ) { - RB_EndSurface(); - } - - cmd = (const drawSurfsCommand_t *)data; - - backEnd.refdef = cmd->refdef; - backEnd.viewParms = cmd->viewParms; - - RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); - - return (const void *)(cmd + 1); -} - - -/* -============= -RB_DrawBuffer - -============= -*/ -const void *RB_DrawBuffer( const void *data ) { - const drawBufferCommand_t *cmd; - - cmd = (const drawBufferCommand_t *)data; - - qglDrawBuffer( cmd->buffer ); - - // clear screen for debugging - if ( r_clear->integer ) { - qglClearColor( 1, 0, 0.5, 1 ); - qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - } - - return (const void *)(cmd + 1); -} - -/* -=============== -RB_ShowImages - -Draw all the images to the screen, on top of whatever -was there. This is used to test for texture thrashing. - -Also called by RE_EndRegistration -=============== -*/ -void RB_ShowImages( void ) { - int i; - image_t *image; - float x, y, w, h; - int start, end; - - if ( !backEnd.projection2D ) { - RB_SetGL2D(); - } - - qglClear( GL_COLOR_BUFFER_BIT ); - - qglFinish(); - - start = ri.Milliseconds(); - - for ( i=0 ; iinteger == 2 ) { - w *= image->uploadWidth / 512.0f; - h *= image->uploadHeight / 512.0f; - } - - GL_Bind( image ); - qglBegin (GL_QUADS); - qglTexCoord2f( 0, 0 ); - qglVertex2f( x, y ); - qglTexCoord2f( 1, 0 ); - qglVertex2f( x + w, y ); - qglTexCoord2f( 1, 1 ); - qglVertex2f( x + w, y + h ); - qglTexCoord2f( 0, 1 ); - qglVertex2f( x, y + h ); - qglEnd(); - } - - qglFinish(); - - end = ri.Milliseconds(); - ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start ); - -} - -/* -============= -RB_ColorMask - -============= -*/ -const void *RB_ColorMask(const void *data) -{ - const colorMaskCommand_t *cmd = data; - - qglColorMask(cmd->rgba[0], cmd->rgba[1], cmd->rgba[2], cmd->rgba[3]); - - return (const void *)(cmd + 1); -} - -/* -============= -RB_ClearDepth - -============= -*/ -const void *RB_ClearDepth(const void *data) -{ - const clearDepthCommand_t *cmd = data; - - if(tess.numIndexes) - RB_EndSurface(); - - // texture swapping test - if (r_showImages->integer) - RB_ShowImages(); - - qglClear(GL_DEPTH_BUFFER_BIT); - - return (const void *)(cmd + 1); -} - -/* -============= -RB_SwapBuffers - -============= -*/ -const void *RB_SwapBuffers( const void *data ) { - const swapBuffersCommand_t *cmd; - - // finish any 2D drawing if needed - if ( tess.numIndexes ) { - RB_EndSurface(); - } - - // texture swapping test - if ( r_showImages->integer ) { - RB_ShowImages(); - } - - cmd = (const swapBuffersCommand_t *)data; - - // we measure overdraw by reading back the stencil buffer and - // counting up the number of increments that have happened - if ( r_measureOverdraw->integer ) { - int i; - long sum = 0; - unsigned char *stencilReadback; - - stencilReadback = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight ); - qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback ); - - for ( i = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++ ) { - sum += stencilReadback[i]; - } - - backEnd.pc.c_overDraw += sum; - ri.Hunk_FreeTempMemory( stencilReadback ); - } - - - if ( !glState.finishCalled ) { - qglFinish(); - } - - GLimp_LogComment( "***************** RB_SwapBuffers *****************\n\n\n" ); - - GLimp_EndFrame(); - - backEnd.projection2D = qfalse; - - return (const void *)(cmd + 1); -} - -/* -==================== -RB_ExecuteRenderCommands -==================== -*/ -void RB_ExecuteRenderCommands( const void *data ) { - int t1, t2; - - t1 = ri.Milliseconds (); - - while ( 1 ) { - data = PADP(data, sizeof(void *)); - - switch ( *(const int *)data ) { - case RC_SET_COLOR: - data = RB_SetColor( data ); - break; - case RC_STRETCH_PIC: - data = RB_StretchPic( data ); - break; - case RC_DRAW_SURFS: - data = RB_DrawSurfs( data ); - break; - case RC_DRAW_BUFFER: - data = RB_DrawBuffer( data ); - break; - case RC_SWAP_BUFFERS: - data = RB_SwapBuffers( data ); - break; - case RC_SCREENSHOT: - data = RB_TakeScreenshotCmd( data ); - break; - case RC_VIDEOFRAME: - data = RB_TakeVideoFrameCmd( data ); - break; - case RC_COLORMASK: - data = RB_ColorMask(data); - break; - case RC_CLEARDEPTH: - data = RB_ClearDepth(data); - break; - case RC_END_OF_LIST: - default: - // stop rendering - t2 = ri.Milliseconds (); - backEnd.pc.msec = t2 - t1; - return; - } - } - -} diff --git a/code/renderergl1/tr_bsp.c b/code/renderergl1/tr_bsp.c deleted file mode 100644 index 7ca4d9776b..0000000000 --- a/code/renderergl1/tr_bsp.c +++ /dev/null @@ -1,1870 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_map.c - -#include "tr_local.h" - -/* - -Loads and prepares a map file for scene rendering. - -A single entry point: - -void RE_LoadWorldMap( const char *name ); - -*/ - -static world_t s_worldData; -static byte *fileBase; - -int c_subdivisions; -int c_gridVerts; - -//=============================================================================== - -static void HSVtoRGB( float h, float s, float v, float rgb[3] ) -{ - int i; - float f; - float p, q, t; - - h *= 5; - - i = floor( h ); - f = h - i; - - p = v * ( 1 - s ); - q = v * ( 1 - s * f ); - t = v * ( 1 - s * ( 1 - f ) ); - - switch ( i ) - { - case 0: - rgb[0] = v; - rgb[1] = t; - rgb[2] = p; - break; - case 1: - rgb[0] = q; - rgb[1] = v; - rgb[2] = p; - break; - case 2: - rgb[0] = p; - rgb[1] = v; - rgb[2] = t; - break; - case 3: - rgb[0] = p; - rgb[1] = q; - rgb[2] = v; - break; - case 4: - rgb[0] = t; - rgb[1] = p; - rgb[2] = v; - break; - case 5: - rgb[0] = v; - rgb[1] = p; - rgb[2] = q; - break; - } -} - -/* -=============== -R_ColorShiftLightingBytes - -=============== -*/ -static void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) { - int shift, r, g, b; - - // shift the color data based on overbright range - shift = r_mapOverBrightBits->integer - tr.overbrightBits; - - // shift the data based on overbright range - r = in[0] << shift; - g = in[1] << shift; - b = in[2] << shift; - - // normalize by color instead of saturating to white - if ( ( r | g | b ) > 255 ) { - int max; - - max = r > g ? r : g; - max = max > b ? max : b; - r = r * 255 / max; - g = g * 255 / max; - b = b * 255 / max; - } - - out[0] = r; - out[1] = g; - out[2] = b; - out[3] = in[3]; -} - -/* -=============== -R_LoadLightmaps - -=============== -*/ -#define LIGHTMAP_SIZE 128 -static void R_LoadLightmaps( lump_t *l ) { - byte *buf, *buf_p; - int len; - byte image[LIGHTMAP_SIZE*LIGHTMAP_SIZE*4]; - int i, j; - float maxIntensity = 0; - double sumIntensity = 0; - - len = l->filelen; - if ( !len ) { - return; - } - buf = fileBase + l->fileofs; - - // we are about to upload textures - R_IssuePendingRenderCommands(); - - // create all the lightmaps - tr.numLightmaps = len / (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3); - if ( tr.numLightmaps == 1 ) { - //FIXME: HACK: maps with only one lightmap turn up fullbright for some reason. - //this avoids this, but isn't the correct solution. - tr.numLightmaps++; - } - - // if we are in r_vertexLight mode, we don't need the lightmaps at all - if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) { - return; - } - - tr.lightmaps = ri.Hunk_Alloc( tr.numLightmaps * sizeof(image_t *), h_low ); - for ( i = 0 ; i < tr.numLightmaps ; i++ ) { - // expand the 24 bit on-disk to 32 bit - buf_p = buf + i * LIGHTMAP_SIZE*LIGHTMAP_SIZE * 3; - - if ( r_lightmap->integer == 2 ) - { // color code by intensity as development tool (FIXME: check range) - for ( j = 0; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ ) - { - float r = buf_p[j*3+0]; - float g = buf_p[j*3+1]; - float b = buf_p[j*3+2]; - float intensity; - float out[3] = {0.0, 0.0, 0.0}; - - intensity = 0.33f * r + 0.685f * g + 0.063f * b; - - if ( intensity > 255 ) - intensity = 1.0f; - else - intensity /= 255.0f; - - if ( intensity > maxIntensity ) - maxIntensity = intensity; - - HSVtoRGB( intensity, 1.00, 0.50, out ); - - image[j*4+0] = out[0] * 255; - image[j*4+1] = out[1] * 255; - image[j*4+2] = out[2] * 255; - image[j*4+3] = 255; - - sumIntensity += intensity; - } - } else { - for ( j = 0 ; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ ) { - R_ColorShiftLightingBytes( &buf_p[j*3], &image[j*4] ); - image[j*4+3] = 255; - } - } - tr.lightmaps[i] = R_CreateImage( va("*lightmap%d",i), image, - LIGHTMAP_SIZE, LIGHTMAP_SIZE, IMGTYPE_COLORALPHA, - IMGFLAG_NOLIGHTSCALE | IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, 0 ); - } - - if ( r_lightmap->integer == 2 ) { - ri.Printf( PRINT_ALL, "Brightest lightmap value: %d\n", ( int ) ( maxIntensity * 255 ) ); - } -} - - -/* -================= -RE_SetWorldVisData - -This is called by the clipmodel subsystem so we can share the 1.8 megs of -space in big maps... -================= -*/ -void RE_SetWorldVisData( const byte *vis ) { - tr.externalVisData = vis; -} - - -/* -================= -R_LoadVisibility -================= -*/ -static void R_LoadVisibility( lump_t *l ) { - int len; - byte *buf; - - len = ( s_worldData.numClusters + 63 ) & ~63; - s_worldData.novis = ri.Hunk_Alloc( len, h_low ); - Com_Memset( s_worldData.novis, 0xff, len ); - - len = l->filelen; - if ( !len ) { - return; - } - buf = fileBase + l->fileofs; - - s_worldData.numClusters = LittleLong( ((int *)buf)[0] ); - s_worldData.clusterBytes = LittleLong( ((int *)buf)[1] ); - - // CM_Load should have given us the vis data to share, so - // we don't need to allocate another copy - if ( tr.externalVisData ) { - s_worldData.vis = tr.externalVisData; - } else { - byte *dest; - - dest = ri.Hunk_Alloc( len - 8, h_low ); - Com_Memcpy( dest, buf + 8, len - 8 ); - s_worldData.vis = dest; - } -} - -//=============================================================================== - - -/* -=============== -ShaderForShaderNum -=============== -*/ -static shader_t *ShaderForShaderNum( int shaderNum, int lightmapNum ) { - shader_t *shader; - dshader_t *dsh; - - int _shaderNum = LittleLong( shaderNum ); - if ( _shaderNum < 0 || _shaderNum >= s_worldData.numShaders ) { - ri.Error( ERR_DROP, "ShaderForShaderNum: bad num %i", _shaderNum ); - } - dsh = &s_worldData.shaders[ _shaderNum ]; - - if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) { - lightmapNum = LIGHTMAP_BY_VERTEX; - } - - if ( r_fullbright->integer ) { - lightmapNum = LIGHTMAP_WHITEIMAGE; - } - - shader = R_FindShader( dsh->shader, lightmapNum, qtrue ); - - // if the shader had errors, just use default shader - if ( shader->defaultShader ) { - return tr.defaultShader; - } - - return shader; -} - -/* -=============== -ParseFace -=============== -*/ -static void ParseFace( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) { - int i, j; - srfSurfaceFace_t *cv; - int numPoints, numIndexes; - int lightmapNum; - int sfaceSize, ofsIndexes; - - lightmapNum = LittleLong( ds->lightmapNum ); - - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; - - // get shader value - surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } - - numPoints = LittleLong( ds->numVerts ); - if (numPoints > MAX_FACE_POINTS) { - ri.Printf( PRINT_WARNING, "WARNING: MAX_FACE_POINTS exceeded: %i\n", numPoints); - numPoints = MAX_FACE_POINTS; - surf->shader = tr.defaultShader; - } - - numIndexes = LittleLong( ds->numIndexes ); - - // create the srfSurfaceFace_t - sfaceSize = ( size_t ) &((srfSurfaceFace_t *)0)->points[numPoints]; - ofsIndexes = sfaceSize; - sfaceSize += sizeof( int ) * numIndexes; - - cv = ri.Hunk_Alloc( sfaceSize, h_low ); - cv->surfaceType = SF_FACE; - cv->numPoints = numPoints; - cv->numIndices = numIndexes; - cv->ofsIndices = ofsIndexes; - - verts += LittleLong( ds->firstVert ); - for ( i = 0 ; i < numPoints ; i++ ) { - for ( j = 0 ; j < 3 ; j++ ) { - cv->points[i][j] = LittleFloat( verts[i].xyz[j] ); - } - for ( j = 0 ; j < 2 ; j++ ) { - cv->points[i][3+j] = LittleFloat( verts[i].st[j] ); - cv->points[i][5+j] = LittleFloat( verts[i].lightmap[j] ); - } - R_ColorShiftLightingBytes( verts[i].color, (byte *)&cv->points[i][7] ); - } - - indexes += LittleLong( ds->firstIndex ); - for ( i = 0 ; i < numIndexes ; i++ ) { - ((int *)((byte *)cv + cv->ofsIndices ))[i] = LittleLong( indexes[ i ] ); - } - - // take the plane information from the lightmap vector - for ( i = 0 ; i < 3 ; i++ ) { - cv->plane.normal[i] = LittleFloat( ds->lightmapVecs[2][i] ); - } - cv->plane.dist = DotProduct( cv->points[0], cv->plane.normal ); - SetPlaneSignbits( &cv->plane ); - cv->plane.type = PlaneTypeForNormal( cv->plane.normal ); - - surf->data = (surfaceType_t *)cv; -} - - -/* -=============== -ParseMesh -=============== -*/ -static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, msurface_t *surf ) { - srfGridMesh_t *grid; - int i, j; - int width, height, numPoints; - drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE]; - int lightmapNum; - vec3_t bounds[2]; - vec3_t tmpVec; - static surfaceType_t skipData = SF_SKIP; - - lightmapNum = LittleLong( ds->lightmapNum ); - - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; - - // get shader value - surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } - - // we may have a nodraw surface, because they might still need to - // be around for movement clipping - if ( s_worldData.shaders[ LittleLong( ds->shaderNum ) ].surfaceFlags & SURF_NODRAW ) { - surf->data = &skipData; - return; - } - - width = LittleLong( ds->patchWidth ); - height = LittleLong( ds->patchHeight ); - - verts += LittleLong( ds->firstVert ); - numPoints = width * height; - for ( i = 0 ; i < numPoints ; i++ ) { - for ( j = 0 ; j < 3 ; j++ ) { - points[i].xyz[j] = LittleFloat( verts[i].xyz[j] ); - points[i].normal[j] = LittleFloat( verts[i].normal[j] ); - } - for ( j = 0 ; j < 2 ; j++ ) { - points[i].st[j] = LittleFloat( verts[i].st[j] ); - points[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] ); - } - R_ColorShiftLightingBytes( verts[i].color, points[i].color ); - } - - // pre-tesseleate - grid = R_SubdividePatchToGrid( width, height, points ); - surf->data = (surfaceType_t *)grid; - - // copy the level of detail origin, which is the center - // of the group of all curves that must subdivide the same - // to avoid cracking - for ( i = 0 ; i < 3 ; i++ ) { - bounds[0][i] = LittleFloat( ds->lightmapVecs[0][i] ); - bounds[1][i] = LittleFloat( ds->lightmapVecs[1][i] ); - } - VectorAdd( bounds[0], bounds[1], bounds[1] ); - VectorScale( bounds[1], 0.5f, grid->lodOrigin ); - VectorSubtract( bounds[0], grid->lodOrigin, tmpVec ); - grid->lodRadius = VectorLength( tmpVec ); -} - -/* -=============== -ParseTriSurf -=============== -*/ -static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) { - srfTriangles_t *tri; - int i, j; - int numVerts, numIndexes; - - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; - - // get shader - surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } - - numVerts = LittleLong( ds->numVerts ); - numIndexes = LittleLong( ds->numIndexes ); - - tri = ri.Hunk_Alloc( sizeof( *tri ) + numVerts * sizeof( tri->verts[0] ) - + numIndexes * sizeof( tri->indexes[0] ), h_low ); - tri->surfaceType = SF_TRIANGLES; - tri->numVerts = numVerts; - tri->numIndexes = numIndexes; - tri->verts = (drawVert_t *)(tri + 1); - tri->indexes = (int *)(tri->verts + tri->numVerts ); - - surf->data = (surfaceType_t *)tri; - - // copy vertexes - ClearBounds( tri->bounds[0], tri->bounds[1] ); - verts += LittleLong( ds->firstVert ); - for ( i = 0 ; i < numVerts ; i++ ) { - for ( j = 0 ; j < 3 ; j++ ) { - tri->verts[i].xyz[j] = LittleFloat( verts[i].xyz[j] ); - tri->verts[i].normal[j] = LittleFloat( verts[i].normal[j] ); - } - AddPointToBounds( tri->verts[i].xyz, tri->bounds[0], tri->bounds[1] ); - for ( j = 0 ; j < 2 ; j++ ) { - tri->verts[i].st[j] = LittleFloat( verts[i].st[j] ); - tri->verts[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] ); - } - - R_ColorShiftLightingBytes( verts[i].color, tri->verts[i].color ); - } - - // copy indexes - indexes += LittleLong( ds->firstIndex ); - for ( i = 0 ; i < numIndexes ; i++ ) { - tri->indexes[i] = LittleLong( indexes[i] ); - if ( tri->indexes[i] < 0 || tri->indexes[i] >= numVerts ) { - ri.Error( ERR_DROP, "Bad index in triangle surface" ); - } - } -} - -/* -=============== -ParseFlare -=============== -*/ -static void ParseFlare( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) { - srfFlare_t *flare; - int i; - - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; - - // get shader - surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } - - flare = ri.Hunk_Alloc( sizeof( *flare ), h_low ); - flare->surfaceType = SF_FLARE; - - surf->data = (surfaceType_t *)flare; - - for ( i = 0 ; i < 3 ; i++ ) { - flare->origin[i] = LittleFloat( ds->lightmapOrigin[i] ); - flare->color[i] = LittleFloat( ds->lightmapVecs[0][i] ); - flare->normal[i] = LittleFloat( ds->lightmapVecs[2][i] ); - } -} - - -/* -================= -R_MergedWidthPoints - -returns true if there are grid points merged on a width edge -================= -*/ -int R_MergedWidthPoints(srfGridMesh_t *grid, int offset) { - int i, j; - - for (i = 1; i < grid->width-1; i++) { - for (j = i + 1; j < grid->width-1; j++) { - if ( fabs(grid->verts[i + offset].xyz[0] - grid->verts[j + offset].xyz[0]) > .1) continue; - if ( fabs(grid->verts[i + offset].xyz[1] - grid->verts[j + offset].xyz[1]) > .1) continue; - if ( fabs(grid->verts[i + offset].xyz[2] - grid->verts[j + offset].xyz[2]) > .1) continue; - return qtrue; - } - } - return qfalse; -} - -/* -================= -R_MergedHeightPoints - -returns true if there are grid points merged on a height edge -================= -*/ -int R_MergedHeightPoints(srfGridMesh_t *grid, int offset) { - int i, j; - - for (i = 1; i < grid->height-1; i++) { - for (j = i + 1; j < grid->height-1; j++) { - if ( fabs(grid->verts[grid->width * i + offset].xyz[0] - grid->verts[grid->width * j + offset].xyz[0]) > .1) continue; - if ( fabs(grid->verts[grid->width * i + offset].xyz[1] - grid->verts[grid->width * j + offset].xyz[1]) > .1) continue; - if ( fabs(grid->verts[grid->width * i + offset].xyz[2] - grid->verts[grid->width * j + offset].xyz[2]) > .1) continue; - return qtrue; - } - } - return qfalse; -} - -/* -================= -R_FixSharedVertexLodError_r - -NOTE: never sync LoD through grid edges with merged points! - -FIXME: write generalized version that also avoids cracks between a patch and one that meets half way? -================= -*/ -void R_FixSharedVertexLodError_r( int start, srfGridMesh_t *grid1 ) { - int j, k, l, m, n, offset1, offset2, touch; - srfGridMesh_t *grid2; - - for ( j = start; j < s_worldData.numsurfaces; j++ ) { - // - grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data; - // if this surface is not a grid - if ( grid2->surfaceType != SF_GRID ) continue; - // if the LOD errors are already fixed for this patch - if ( grid2->lodFixed == 2 ) continue; - // grids in the same LOD group should have the exact same lod radius - if ( grid1->lodRadius != grid2->lodRadius ) continue; - // grids in the same LOD group should have the exact same lod origin - if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue; - if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue; - if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue; - // - touch = qfalse; - for (n = 0; n < 2; n++) { - // - if (n) offset1 = (grid1->height-1) * grid1->width; - else offset1 = 0; - if (R_MergedWidthPoints(grid1, offset1)) continue; - for (k = 1; k < grid1->width-1; k++) { - for (m = 0; m < 2; m++) { - - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - if (R_MergedWidthPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->width-1; l++) { - // - if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->widthLodError[l] = grid1->widthLodError[k]; - touch = qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (m) offset2 = grid2->width-1; - else offset2 = 0; - if (R_MergedHeightPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->height-1; l++) { - // - if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->heightLodError[l] = grid1->widthLodError[k]; - touch = qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = grid1->width-1; - else offset1 = 0; - if (R_MergedHeightPoints(grid1, offset1)) continue; - for (k = 1; k < grid1->height-1; k++) { - for (m = 0; m < 2; m++) { - - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - if (R_MergedWidthPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->width-1; l++) { - // - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->widthLodError[l] = grid1->heightLodError[k]; - touch = qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (m) offset2 = grid2->width-1; - else offset2 = 0; - if (R_MergedHeightPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->height-1; l++) { - // - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->heightLodError[l] = grid1->heightLodError[k]; - touch = qtrue; - } - } - } - } - if (touch) { - grid2->lodFixed = 2; - R_FixSharedVertexLodError_r ( start, grid2 ); - //NOTE: this would be correct but makes things really slow - //grid2->lodFixed = 1; - } - } -} - -/* -================= -R_FixSharedVertexLodError - -This function assumes that all patches in one group are nicely stitched together for the highest LoD. -If this is not the case this function will still do its job but won't fix the highest LoD cracks. -================= -*/ -void R_FixSharedVertexLodError( void ) { - int i; - srfGridMesh_t *grid1; - - for ( i = 0; i < s_worldData.numsurfaces; i++ ) { - // - grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data; - // if this surface is not a grid - if ( grid1->surfaceType != SF_GRID ) - continue; - // - if ( grid1->lodFixed ) - continue; - // - grid1->lodFixed = 2; - // recursively fix other patches in the same LOD group - R_FixSharedVertexLodError_r( i + 1, grid1); - } -} - - -/* -=============== -R_StitchPatches -=============== -*/ -int R_StitchPatches( int grid1num, int grid2num ) { - float *v1, *v2; - srfGridMesh_t *grid1, *grid2; - int k, l, m, n, offset1, offset2, row, column; - - grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data; - grid2 = (srfGridMesh_t *) s_worldData.surfaces[grid2num].data; - for (n = 0; n < 2; n++) { - // - if (n) offset1 = (grid1->height-1) * grid1->width; - else offset1 = 0; - if (R_MergedWidthPoints(grid1, offset1)) - continue; - for (k = 0; k < grid1->width-2; k += 2) { - - for (m = 0; m < 2; m++) { - - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[k + 2 + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[k + 2 + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = grid1->width-1; - else offset1 = 0; - if (R_MergedHeightPoints(grid1, offset1)) - continue; - for (k = 0; k < grid1->height-2; k += 2) { - for (m = 0; m < 2; m++) { - - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[(l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = (grid1->height-1) * grid1->width; - else offset1 = 0; - if (R_MergedWidthPoints(grid1, offset1)) - continue; - for (k = grid1->width-1; k > 1; k -= 2) { - - for (m = 0; m < 2; m++) { - - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[k - 2 + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[(l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[k - 2 + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]); - if (!grid2) - break; - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = grid1->width-1; - else offset1 = 0; - if (R_MergedHeightPoints(grid1, offset1)) - continue; - for (k = grid1->height-1; k > 1; k -= 2) { - for (m = 0; m < 2; m++) { - - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[(l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - return qfalse; -} - -/* -=============== -R_TryStitchPatch - -This function will try to stitch patches in the same LoD group together for the highest LoD. - -Only single missing vertice cracks will be fixed. - -Vertices will be joined at the patch side a crack is first found, at the other side -of the patch (on the same row or column) the vertices will not be joined and cracks -might still appear at that side. -=============== -*/ -int R_TryStitchingPatch( int grid1num ) { - int j, numstitches; - srfGridMesh_t *grid1, *grid2; - - numstitches = 0; - grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data; - for ( j = 0; j < s_worldData.numsurfaces; j++ ) { - // - grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data; - // if this surface is not a grid - if ( grid2->surfaceType != SF_GRID ) continue; - // grids in the same LOD group should have the exact same lod radius - if ( grid1->lodRadius != grid2->lodRadius ) continue; - // grids in the same LOD group should have the exact same lod origin - if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue; - if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue; - if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue; - // - while (R_StitchPatches(grid1num, j)) - { - numstitches++; - } - } - return numstitches; -} - -/* -=============== -R_StitchAllPatches -=============== -*/ -void R_StitchAllPatches( void ) { - int i, stitched, numstitches; - srfGridMesh_t *grid1; - - numstitches = 0; - do - { - stitched = qfalse; - for ( i = 0; i < s_worldData.numsurfaces; i++ ) { - // - grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data; - // if this surface is not a grid - if ( grid1->surfaceType != SF_GRID ) - continue; - // - if ( grid1->lodStitched ) - continue; - // - grid1->lodStitched = qtrue; - stitched = qtrue; - // - numstitches += R_TryStitchingPatch( i ); - } - } - while (stitched); - ri.Printf( PRINT_ALL, "stitched %d LoD cracks\n", numstitches ); -} - -/* -=============== -R_MovePatchSurfacesToHunk -=============== -*/ -void R_MovePatchSurfacesToHunk(void) { - int i, size; - srfGridMesh_t *grid, *hunkgrid; - - for ( i = 0; i < s_worldData.numsurfaces; i++ ) { - // - grid = (srfGridMesh_t *) s_worldData.surfaces[i].data; - // if this surface is not a grid - if ( grid->surfaceType != SF_GRID ) - continue; - // - size = (grid->width * grid->height - 1) * sizeof( drawVert_t ) + sizeof( *grid ); - hunkgrid = ri.Hunk_Alloc( size, h_low ); - Com_Memcpy(hunkgrid, grid, size); - - hunkgrid->widthLodError = ri.Hunk_Alloc( grid->width * 4, h_low ); - Com_Memcpy( hunkgrid->widthLodError, grid->widthLodError, grid->width * 4 ); - - hunkgrid->heightLodError = ri.Hunk_Alloc( grid->height * 4, h_low ); - Com_Memcpy( hunkgrid->heightLodError, grid->heightLodError, grid->height * 4 ); - - R_FreeSurfaceGridMesh( grid ); - - s_worldData.surfaces[i].data = (void *) hunkgrid; - } -} - -/* -=============== -R_LoadSurfaces -=============== -*/ -static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) { - dsurface_t *in; - msurface_t *out; - drawVert_t *dv; - int *indexes; - int count; - int numFaces, numMeshes, numTriSurfs, numFlares; - int i; - - numFaces = 0; - numMeshes = 0; - numTriSurfs = 0; - numFlares = 0; - - in = (void *)(fileBase + surfs->fileofs); - if (surfs->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = surfs->filelen / sizeof(*in); - - dv = (void *)(fileBase + verts->fileofs); - if (verts->filelen % sizeof(*dv)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - - indexes = (void *)(fileBase + indexLump->fileofs); - if ( indexLump->filelen % sizeof(*indexes)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - - out = ri.Hunk_Alloc ( count * sizeof(*out), h_low ); - - s_worldData.surfaces = out; - s_worldData.numsurfaces = count; - - for ( i = 0 ; i < count ; i++, in++, out++ ) { - switch ( LittleLong( in->surfaceType ) ) { - case MST_PATCH: - ParseMesh ( in, dv, out ); - numMeshes++; - break; - case MST_TRIANGLE_SOUP: - ParseTriSurf( in, dv, out, indexes ); - numTriSurfs++; - break; - case MST_PLANAR: - ParseFace( in, dv, out, indexes ); - numFaces++; - break; - case MST_FLARE: - ParseFlare( in, dv, out, indexes ); - numFlares++; - break; - default: - ri.Error( ERR_DROP, "Bad surfaceType" ); - } - } - -#ifdef PATCH_STITCHING - R_StitchAllPatches(); -#endif - - R_FixSharedVertexLodError(); - -#ifdef PATCH_STITCHING - R_MovePatchSurfacesToHunk(); -#endif - - ri.Printf( PRINT_ALL, "...loaded %d faces, %i meshes, %i trisurfs, %i flares\n", - numFaces, numMeshes, numTriSurfs, numFlares ); -} - - - -/* -================= -R_LoadSubmodels -================= -*/ -static void R_LoadSubmodels( lump_t *l ) { - dmodel_t *in; - bmodel_t *out; - int i, j, count; - - in = (void *)(fileBase + l->fileofs); - if (l->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = l->filelen / sizeof(*in); - - s_worldData.bmodels = out = ri.Hunk_Alloc( count * sizeof(*out), h_low ); - - for ( i=0 ; itype = MOD_BRUSH; - model->bmodel = out; - Com_sprintf( model->name, sizeof( model->name ), "*%d", i ); - - for (j=0 ; j<3 ; j++) { - out->bounds[0][j] = LittleFloat (in->mins[j]); - out->bounds[1][j] = LittleFloat (in->maxs[j]); - } - - out->firstSurface = s_worldData.surfaces + LittleLong( in->firstSurface ); - out->numSurfaces = LittleLong( in->numSurfaces ); - } -} - - - -//================================================================== - -/* -================= -R_SetParent -================= -*/ -static void R_SetParent (mnode_t *node, mnode_t *parent) -{ - node->parent = parent; - if (node->contents != -1) - return; - R_SetParent (node->children[0], node); - R_SetParent (node->children[1], node); -} - -/* -================= -R_LoadNodesAndLeafs -================= -*/ -static void R_LoadNodesAndLeafs (lump_t *nodeLump, lump_t *leafLump) { - int i, j, p; - dnode_t *in; - dleaf_t *inLeaf; - mnode_t *out; - int numNodes, numLeafs; - - in = (void *)(fileBase + nodeLump->fileofs); - if (nodeLump->filelen % sizeof(dnode_t) || - leafLump->filelen % sizeof(dleaf_t) ) { - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - } - numNodes = nodeLump->filelen / sizeof(dnode_t); - numLeafs = leafLump->filelen / sizeof(dleaf_t); - - out = ri.Hunk_Alloc ( (numNodes + numLeafs) * sizeof(*out), h_low); - - s_worldData.nodes = out; - s_worldData.numnodes = numNodes + numLeafs; - s_worldData.numDecisionNodes = numNodes; - - // load nodes - for ( i=0 ; imins[j] = LittleLong (in->mins[j]); - out->maxs[j] = LittleLong (in->maxs[j]); - } - - p = LittleLong(in->planeNum); - out->plane = s_worldData.planes + p; - - out->contents = CONTENTS_NODE; // differentiate from leafs - - for (j=0 ; j<2 ; j++) - { - p = LittleLong (in->children[j]); - if (p >= 0) - out->children[j] = s_worldData.nodes + p; - else - out->children[j] = s_worldData.nodes + numNodes + (-1 - p); - } - } - - // load leafs - inLeaf = (void *)(fileBase + leafLump->fileofs); - for ( i=0 ; imins[j] = LittleLong (inLeaf->mins[j]); - out->maxs[j] = LittleLong (inLeaf->maxs[j]); - } - - out->cluster = LittleLong(inLeaf->cluster); - out->area = LittleLong(inLeaf->area); - - if ( out->cluster >= s_worldData.numClusters ) { - s_worldData.numClusters = out->cluster + 1; - } - - out->firstmarksurface = s_worldData.marksurfaces + - LittleLong(inLeaf->firstLeafSurface); - out->nummarksurfaces = LittleLong(inLeaf->numLeafSurfaces); - } - - // chain decendants - R_SetParent (s_worldData.nodes, NULL); -} - -//============================================================================= - -/* -================= -R_LoadShaders -================= -*/ -static void R_LoadShaders( lump_t *l ) { - int i, count; - dshader_t *in, *out; - - in = (void *)(fileBase + l->fileofs); - if (l->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = l->filelen / sizeof(*in); - out = ri.Hunk_Alloc ( count*sizeof(*out), h_low ); - - s_worldData.shaders = out; - s_worldData.numShaders = count; - - Com_Memcpy( out, in, count*sizeof(*out) ); - - for ( i=0 ; ifileofs); - if (l->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = l->filelen / sizeof(*in); - out = ri.Hunk_Alloc ( count*sizeof(*out), h_low); - - s_worldData.marksurfaces = out; - s_worldData.nummarksurfaces = count; - - for ( i=0 ; ifileofs); - if (l->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = l->filelen / sizeof(*in); - out = ri.Hunk_Alloc ( count*2*sizeof(*out), h_low); - - s_worldData.planes = out; - s_worldData.numplanes = count; - - for ( i=0 ; inormal[j] = LittleFloat (in->normal[j]); - if (out->normal[j] < 0) { - bits |= 1<dist = LittleFloat (in->dist); - out->type = PlaneTypeForNormal( out->normal ); - out->signbits = bits; - } -} - -/* -================= -R_LoadFogs - -================= -*/ -static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) { - int i; - fog_t *out; - dfog_t *fogs; - dbrush_t *brushes, *brush; - dbrushside_t *sides; - int count, brushesCount, sidesCount; - int sideNum; - int planeNum; - shader_t *shader; - float d; - int firstSide; - - fogs = (void *)(fileBase + l->fileofs); - if (l->filelen % sizeof(*fogs)) { - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - } - count = l->filelen / sizeof(*fogs); - - // create fog strucutres for them - s_worldData.numfogs = count + 1; - s_worldData.fogs = ri.Hunk_Alloc ( s_worldData.numfogs*sizeof(*out), h_low); - out = s_worldData.fogs + 1; - - if ( !count ) { - return; - } - - brushes = (void *)(fileBase + brushesLump->fileofs); - if (brushesLump->filelen % sizeof(*brushes)) { - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - } - brushesCount = brushesLump->filelen / sizeof(*brushes); - - sides = (void *)(fileBase + sidesLump->fileofs); - if (sidesLump->filelen % sizeof(*sides)) { - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - } - sidesCount = sidesLump->filelen / sizeof(*sides); - - for ( i=0 ; ioriginalBrushNumber = LittleLong( fogs->brushNum ); - - if ( (unsigned)out->originalBrushNumber >= brushesCount ) { - ri.Error( ERR_DROP, "fog brushNumber out of range" ); - } - brush = brushes + out->originalBrushNumber; - - firstSide = LittleLong( brush->firstSide ); - - if ( (unsigned)firstSide > sidesCount - 6 ) { - ri.Error( ERR_DROP, "fog brush sideNumber out of range" ); - } - - // brushes are always sorted with the axial sides first - sideNum = firstSide + 0; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[0][0] = -s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 1; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[1][0] = s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 2; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[0][1] = -s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 3; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[1][1] = s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 4; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[0][2] = -s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 5; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[1][2] = s_worldData.planes[ planeNum ].dist; - - // get information from the shader for fog parameters - shader = R_FindShader( fogs->shader, LIGHTMAP_NONE, qtrue ); - - out->parms = shader->fogParms; - - out->colorInt = ColorBytes4 ( shader->fogParms.color[0] * tr.identityLight, - shader->fogParms.color[1] * tr.identityLight, - shader->fogParms.color[2] * tr.identityLight, 1.0 ); - - d = shader->fogParms.depthForOpaque < 1 ? 1 : shader->fogParms.depthForOpaque; - out->tcScale = 1.0f / ( d * 8 ); - - // set the gradient vector - sideNum = LittleLong( fogs->visibleSide ); - - if ( sideNum == -1 ) { - out->hasSurface = qfalse; - } else { - out->hasSurface = qtrue; - planeNum = LittleLong( sides[ firstSide + sideNum ].planeNum ); - VectorSubtract( vec3_origin, s_worldData.planes[ planeNum ].normal, out->surface ); - out->surface[3] = -s_worldData.planes[ planeNum ].dist; - } - - out++; - } - -} - - -/* -================ -R_LoadLightGrid - -================ -*/ -void R_LoadLightGrid( lump_t *l ) { - int i; - vec3_t maxs; - int numGridPoints; - world_t *w; - float *wMins, *wMaxs; - - w = &s_worldData; - - w->lightGridInverseSize[0] = 1.0f / w->lightGridSize[0]; - w->lightGridInverseSize[1] = 1.0f / w->lightGridSize[1]; - w->lightGridInverseSize[2] = 1.0f / w->lightGridSize[2]; - - wMins = w->bmodels[0].bounds[0]; - wMaxs = w->bmodels[0].bounds[1]; - - for ( i = 0 ; i < 3 ; i++ ) { - w->lightGridOrigin[i] = w->lightGridSize[i] * ceil( wMins[i] / w->lightGridSize[i] ); - maxs[i] = w->lightGridSize[i] * floor( wMaxs[i] / w->lightGridSize[i] ); - w->lightGridBounds[i] = (maxs[i] - w->lightGridOrigin[i])/w->lightGridSize[i] + 1; - } - - numGridPoints = w->lightGridBounds[0] * w->lightGridBounds[1] * w->lightGridBounds[2]; - - if ( l->filelen != numGridPoints * 8 ) { - ri.Printf( PRINT_WARNING, "WARNING: light grid mismatch\n" ); - w->lightGridData = NULL; - return; - } - - w->lightGridData = ri.Hunk_Alloc( l->filelen, h_low ); - Com_Memcpy( w->lightGridData, (void *)(fileBase + l->fileofs), l->filelen ); - - // deal with overbright bits - for ( i = 0 ; i < numGridPoints ; i++ ) { - R_ColorShiftLightingBytes( &w->lightGridData[i*8], &w->lightGridData[i*8] ); - R_ColorShiftLightingBytes( &w->lightGridData[i*8+3], &w->lightGridData[i*8+3] ); - } -} - -/* -================ -R_LoadEntities -================ -*/ -void R_LoadEntities( lump_t *l ) { - char *p, *token, *s; - char keyname[MAX_TOKEN_CHARS]; - char value[MAX_TOKEN_CHARS]; - world_t *w; - - w = &s_worldData; - w->lightGridSize[0] = 64; - w->lightGridSize[1] = 64; - w->lightGridSize[2] = 128; - - p = (char *)(fileBase + l->fileofs); - - // store for reference by the cgame - w->entityString = ri.Hunk_Alloc( l->filelen + 1, h_low ); - strcpy( w->entityString, p ); - w->entityParsePoint = w->entityString; - - token = COM_ParseExt( &p, qtrue ); - if (!*token || *token != '{') { - return; - } - - // only parse the world spawn - while ( 1 ) { - // parse key - token = COM_ParseExt( &p, qtrue ); - - if ( !*token || *token == '}' ) { - break; - } - Q_strncpyz(keyname, token, sizeof(keyname)); - - // parse value - token = COM_ParseExt( &p, qtrue ); - - if ( !*token || *token == '}' ) { - break; - } - Q_strncpyz(value, token, sizeof(value)); - - // check for remapping of shaders for vertex lighting - s = "vertexremapshader"; - if (!Q_strncmp(keyname, s, strlen(s)) ) { - s = strchr(value, ';'); - if (!s) { - ri.Printf( PRINT_WARNING, "WARNING: no semi colon in vertexshaderremap '%s'\n", value ); - break; - } - *s++ = 0; - if (r_vertexLight->integer) { - R_RemapShader(value, s, "0"); - } - continue; - } - // check for remapping of shaders - s = "remapshader"; - if (!Q_strncmp(keyname, s, strlen(s)) ) { - s = strchr(value, ';'); - if (!s) { - ri.Printf( PRINT_WARNING, "WARNING: no semi colon in shaderremap '%s'\n", value ); - break; - } - *s++ = 0; - R_RemapShader(value, s, "0"); - continue; - } - // check for a different grid size - if (!Q_stricmp(keyname, "gridsize")) { - sscanf(value, "%f %f %f", &w->lightGridSize[0], &w->lightGridSize[1], &w->lightGridSize[2] ); - continue; - } - } -} - -/* -================= -R_GetEntityToken -================= -*/ -qboolean R_GetEntityToken( char *buffer, int size ) { - const char *s; - - s = COM_Parse( &s_worldData.entityParsePoint ); - Q_strncpyz( buffer, s, size ); - if ( !s_worldData.entityParsePoint || !s[0] ) { - s_worldData.entityParsePoint = s_worldData.entityString; - return qfalse; - } else { - return qtrue; - } -} - -/* -================= -RE_LoadWorldMap - -Called directly from cgame -================= -*/ -void RE_LoadWorldMap( const char *name ) { - int i; - dheader_t *header; - union { - byte *b; - void *v; - } buffer; - byte *startMarker; - - if ( tr.worldMapLoaded ) { - ri.Error( ERR_DROP, "ERROR: attempted to redundantly load world map" ); - } - - // set default sun direction to be used if it isn't - // overridden by a shader - tr.sunDirection[0] = 0.45f; - tr.sunDirection[1] = 0.3f; - tr.sunDirection[2] = 0.9f; - - VectorNormalize( tr.sunDirection ); - - tr.worldMapLoaded = qtrue; - - // load it - ri.FS_ReadFile( name, &buffer.v ); - if ( !buffer.b ) { - ri.Error (ERR_DROP, "RE_LoadWorldMap: %s not found", name); - } - - // clear tr.world so if the level fails to load, the next - // try will not look at the partially loaded version - tr.world = NULL; - - Com_Memset( &s_worldData, 0, sizeof( s_worldData ) ); - Q_strncpyz( s_worldData.name, name, sizeof( s_worldData.name ) ); - - Q_strncpyz( s_worldData.baseName, COM_SkipPath( s_worldData.name ), sizeof( s_worldData.name ) ); - COM_StripExtension(s_worldData.baseName, s_worldData.baseName, sizeof(s_worldData.baseName)); - - startMarker = ri.Hunk_Alloc(0, h_low); - c_gridVerts = 0; - - header = (dheader_t *)buffer.b; - fileBase = (byte *)header; - - i = LittleLong (header->version); - if ( i != BSP_VERSION ) { - ri.Error (ERR_DROP, "RE_LoadWorldMap: %s has wrong version number (%i should be %i)", - name, i, BSP_VERSION); - } - - // swap all the lumps - for (i=0 ; ilumps[LUMP_SHADERS] ); - R_LoadLightmaps( &header->lumps[LUMP_LIGHTMAPS] ); - R_LoadPlanes (&header->lumps[LUMP_PLANES]); - R_LoadFogs( &header->lumps[LUMP_FOGS], &header->lumps[LUMP_BRUSHES], &header->lumps[LUMP_BRUSHSIDES] ); - R_LoadSurfaces( &header->lumps[LUMP_SURFACES], &header->lumps[LUMP_DRAWVERTS], &header->lumps[LUMP_DRAWINDEXES] ); - R_LoadMarksurfaces (&header->lumps[LUMP_LEAFSURFACES]); - R_LoadNodesAndLeafs (&header->lumps[LUMP_NODES], &header->lumps[LUMP_LEAFS]); - R_LoadSubmodels (&header->lumps[LUMP_MODELS]); - R_LoadVisibility( &header->lumps[LUMP_VISIBILITY] ); - R_LoadEntities( &header->lumps[LUMP_ENTITIES] ); - R_LoadLightGrid( &header->lumps[LUMP_LIGHTGRID] ); - - s_worldData.dataSize = (byte *)ri.Hunk_Alloc(0, h_low) - startMarker; - - // only set tr.world now that we know the entire level has loaded properly - tr.world = &s_worldData; - - ri.FS_FreeFile( buffer.v ); -} - diff --git a/code/renderergl1/tr_cmds.c b/code/renderergl1/tr_cmds.c deleted file mode 100644 index 00b819acd8..0000000000 --- a/code/renderergl1/tr_cmds.c +++ /dev/null @@ -1,503 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - -/* -===================== -R_PerformanceCounters -===================== -*/ -void R_PerformanceCounters( void ) { - if ( !r_speeds->integer ) { - // clear the counters even if we aren't printing - Com_Memset( &tr.pc, 0, sizeof( tr.pc ) ); - Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) ); - return; - } - - if (r_speeds->integer == 1) { - ri.Printf (PRINT_ALL, "%i/%i shaders/surfs %i leafs %i verts %i/%i tris %.2f mtex %.2f dc\n", - backEnd.pc.c_shaders, backEnd.pc.c_surfaces, tr.pc.c_leafs, backEnd.pc.c_vertexes, - backEnd.pc.c_indexes/3, backEnd.pc.c_totalIndexes/3, - R_SumOfUsedImages()/(1000000.0f), backEnd.pc.c_overDraw / (float)(glConfig.vidWidth * glConfig.vidHeight) ); - } else if (r_speeds->integer == 2) { - ri.Printf (PRINT_ALL, "(patch) %i sin %i sclip %i sout %i bin %i bclip %i bout\n", - tr.pc.c_sphere_cull_patch_in, tr.pc.c_sphere_cull_patch_clip, tr.pc.c_sphere_cull_patch_out, - tr.pc.c_box_cull_patch_in, tr.pc.c_box_cull_patch_clip, tr.pc.c_box_cull_patch_out ); - ri.Printf (PRINT_ALL, "(md3) %i sin %i sclip %i sout %i bin %i bclip %i bout\n", - tr.pc.c_sphere_cull_md3_in, tr.pc.c_sphere_cull_md3_clip, tr.pc.c_sphere_cull_md3_out, - tr.pc.c_box_cull_md3_in, tr.pc.c_box_cull_md3_clip, tr.pc.c_box_cull_md3_out ); - } else if (r_speeds->integer == 3) { - ri.Printf (PRINT_ALL, "viewcluster: %i\n", tr.viewCluster ); - } else if (r_speeds->integer == 4) { - if ( backEnd.pc.c_dlightVertexes ) { - ri.Printf (PRINT_ALL, "dlight srf:%i culled:%i verts:%i tris:%i\n", - tr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled, - backEnd.pc.c_dlightVertexes, backEnd.pc.c_dlightIndexes / 3 ); - } - } - else if (r_speeds->integer == 5 ) - { - ri.Printf( PRINT_ALL, "zFar: %.0f\n", tr.viewParms.zFar ); - } - else if (r_speeds->integer == 6 ) - { - ri.Printf( PRINT_ALL, "flare adds:%i tests:%i renders:%i\n", - backEnd.pc.c_flareAdds, backEnd.pc.c_flareTests, backEnd.pc.c_flareRenders ); - } - - Com_Memset( &tr.pc, 0, sizeof( tr.pc ) ); - Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) ); -} - - -/* -==================== -R_IssueRenderCommands -==================== -*/ -void R_IssueRenderCommands( qboolean runPerformanceCounters ) { - renderCommandList_t *cmdList; - - cmdList = &backEndData->commands; - assert(cmdList); - // add an end-of-list command - *(int *)(cmdList->cmds + cmdList->used) = RC_END_OF_LIST; - - // clear it out, in case this is a sync and not a buffer flip - cmdList->used = 0; - - if ( runPerformanceCounters ) { - R_PerformanceCounters(); - } - - // actually start the commands going - if ( !r_skipBackEnd->integer ) { - // let it start on the new batch - RB_ExecuteRenderCommands( cmdList->cmds ); - } -} - - -/* -==================== -R_IssuePendingRenderCommands - -Issue any pending commands and wait for them to complete. -==================== -*/ -void R_IssuePendingRenderCommands( void ) { - if ( !tr.registered ) { - return; - } - R_IssueRenderCommands( qfalse ); -} - -/* -============ -R_GetCommandBuffer - -make sure there is enough command space -============ -*/ -void *R_GetCommandBuffer( int bytes ) { - renderCommandList_t *cmdList; - - cmdList = &backEndData->commands; - bytes = PAD(bytes, sizeof(void *)); - - // always leave room for the end of list command - if ( cmdList->used + bytes + 4 > MAX_RENDER_COMMANDS ) { - if ( bytes > MAX_RENDER_COMMANDS - 4 ) { - ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes ); - } - // if we run out of room, just start dropping commands - return NULL; - } - - cmdList->used += bytes; - - return cmdList->cmds + cmdList->used - bytes; -} - - -/* -============= -R_AddDrawSurfCmd - -============= -*/ -void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ) { - drawSurfsCommand_t *cmd; - - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_DRAW_SURFS; - - cmd->drawSurfs = drawSurfs; - cmd->numDrawSurfs = numDrawSurfs; - - cmd->refdef = tr.refdef; - cmd->viewParms = tr.viewParms; -} - - -/* -============= -RE_SetColor - -Passing NULL will set the color to white -============= -*/ -void RE_SetColor( const float *rgba ) { - setColorCommand_t *cmd; - - if ( !tr.registered ) { - return; - } - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_SET_COLOR; - if ( !rgba ) { - static float colorWhite[4] = { 1, 1, 1, 1 }; - - rgba = colorWhite; - } - - cmd->color[0] = rgba[0]; - cmd->color[1] = rgba[1]; - cmd->color[2] = rgba[2]; - cmd->color[3] = rgba[3]; -} - - -/* -============= -RE_StretchPic -============= -*/ -void RE_StretchPic ( float x, float y, float w, float h, - float s1, float t1, float s2, float t2, qhandle_t hShader ) { - stretchPicCommand_t *cmd; - - if (!tr.registered) { - return; - } - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_STRETCH_PIC; - cmd->shader = R_GetShaderByHandle( hShader ); - cmd->x = x; - cmd->y = y; - cmd->w = w; - cmd->h = h; - cmd->s1 = s1; - cmd->t1 = t1; - cmd->s2 = s2; - cmd->t2 = t2; -} - -#define MODE_RED_CYAN 1 -#define MODE_RED_BLUE 2 -#define MODE_RED_GREEN 3 -#define MODE_GREEN_MAGENTA 4 -#define MODE_MAX MODE_GREEN_MAGENTA - -void R_SetColorMode(GLboolean *rgba, stereoFrame_t stereoFrame, int colormode) -{ - rgba[0] = rgba[1] = rgba[2] = rgba[3] = GL_TRUE; - - if(colormode > MODE_MAX) - { - if(stereoFrame == STEREO_LEFT) - stereoFrame = STEREO_RIGHT; - else if(stereoFrame == STEREO_RIGHT) - stereoFrame = STEREO_LEFT; - - colormode -= MODE_MAX; - } - - if(colormode == MODE_GREEN_MAGENTA) - { - if(stereoFrame == STEREO_LEFT) - rgba[0] = rgba[2] = GL_FALSE; - else if(stereoFrame == STEREO_RIGHT) - rgba[1] = GL_FALSE; - } - else - { - if(stereoFrame == STEREO_LEFT) - rgba[1] = rgba[2] = GL_FALSE; - else if(stereoFrame == STEREO_RIGHT) - { - rgba[0] = GL_FALSE; - - if(colormode == MODE_RED_BLUE) - rgba[1] = GL_FALSE; - else if(colormode == MODE_RED_GREEN) - rgba[2] = GL_FALSE; - } - } -} - - -/* -==================== -RE_BeginFrame - -If running in stereo, RE_BeginFrame will be called twice -for each RE_EndFrame -==================== -*/ -void RE_BeginFrame( stereoFrame_t stereoFrame ) { - drawBufferCommand_t *cmd = NULL; - colorMaskCommand_t *colcmd = NULL; - - if ( !tr.registered ) { - return; - } - glState.finishCalled = qfalse; - - tr.frameCount++; - tr.frameSceneNum = 0; - - // - // do overdraw measurement - // - if ( r_measureOverdraw->integer ) - { - if ( glConfig.stencilBits < 4 ) - { - ri.Printf( PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits ); - ri.Cvar_Set( "r_measureOverdraw", "0" ); - r_measureOverdraw->modified = qfalse; - } - else if ( r_shadows->integer == 2 ) - { - ri.Printf( PRINT_ALL, "Warning: stencil shadows and overdraw measurement are mutually exclusive\n" ); - ri.Cvar_Set( "r_measureOverdraw", "0" ); - r_measureOverdraw->modified = qfalse; - } - else - { - R_IssuePendingRenderCommands(); - qglEnable( GL_STENCIL_TEST ); - qglStencilMask( ~0U ); - qglClearStencil( 0U ); - qglStencilFunc( GL_ALWAYS, 0U, ~0U ); - qglStencilOp( GL_KEEP, GL_INCR, GL_INCR ); - } - r_measureOverdraw->modified = qfalse; - } - else - { - // this is only reached if it was on and is now off - if ( r_measureOverdraw->modified ) { - R_IssuePendingRenderCommands(); - qglDisable( GL_STENCIL_TEST ); - } - r_measureOverdraw->modified = qfalse; - } - - // - // texturemode stuff - // - if ( r_textureMode->modified ) { - R_IssuePendingRenderCommands(); - GL_TextureMode( r_textureMode->string ); - r_textureMode->modified = qfalse; - } - - // - // gamma stuff - // - if ( r_gamma->modified ) { - r_gamma->modified = qfalse; - - R_IssuePendingRenderCommands(); - R_SetColorMappings(); - } - - // check for errors - if ( !r_ignoreGLErrors->integer ) - { - int err; - - R_IssuePendingRenderCommands(); - if ((err = qglGetError()) != GL_NO_ERROR) - ri.Error(ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!", err); - } - - if (glConfig.stereoEnabled) { - if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) ) - return; - - cmd->commandId = RC_DRAW_BUFFER; - - if ( stereoFrame == STEREO_LEFT ) { - cmd->buffer = (int)GL_BACK_LEFT; - } else if ( stereoFrame == STEREO_RIGHT ) { - cmd->buffer = (int)GL_BACK_RIGHT; - } else { - ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame ); - } - } - else - { - if(r_anaglyphMode->integer) - { - if(r_anaglyphMode->modified) - { - // clear both, front and backbuffer. - qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - qglClearColor(0.0f, 0.0f, 0.0f, 1.0f); - - qglDrawBuffer(GL_FRONT); - qglClear(GL_COLOR_BUFFER_BIT); - qglDrawBuffer(GL_BACK); - qglClear(GL_COLOR_BUFFER_BIT); - - r_anaglyphMode->modified = qfalse; - } - - if(stereoFrame == STEREO_LEFT) - { - if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) ) - return; - - if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) ) - return; - } - else if(stereoFrame == STEREO_RIGHT) - { - clearDepthCommand_t *cldcmd; - - if( !(cldcmd = R_GetCommandBuffer(sizeof(*cldcmd))) ) - return; - - cldcmd->commandId = RC_CLEARDEPTH; - - if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) ) - return; - } - else - ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame ); - - R_SetColorMode(colcmd->rgba, stereoFrame, r_anaglyphMode->integer); - colcmd->commandId = RC_COLORMASK; - } - else - { - if(stereoFrame != STEREO_CENTER) - ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame ); - - if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) ) - return; - } - - if(cmd) - { - cmd->commandId = RC_DRAW_BUFFER; - - if(r_anaglyphMode->modified) - { - qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - r_anaglyphMode->modified = qfalse; - } - - if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT")) - cmd->buffer = (int)GL_FRONT; - else - cmd->buffer = (int)GL_BACK; - } - } - - tr.refdef.stereoFrame = stereoFrame; -} - - -/* -============= -RE_EndFrame - -Returns the number of msec spent in the back end -============= -*/ -void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) { - swapBuffersCommand_t *cmd; - - if ( !tr.registered ) { - return; - } - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_SWAP_BUFFERS; - - R_IssueRenderCommands( qtrue ); - - R_InitNextFrame(); - - if ( frontEndMsec ) { - *frontEndMsec = tr.frontEndMsec; - } - tr.frontEndMsec = 0; - if ( backEndMsec ) { - *backEndMsec = backEnd.pc.msec; - } - backEnd.pc.msec = 0; -} - -/* -============= -RE_TakeVideoFrame -============= -*/ -void RE_TakeVideoFrame( int width, int height, - byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg ) -{ - videoFrameCommand_t *cmd; - - if( !tr.registered ) { - return; - } - - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if( !cmd ) { - return; - } - - cmd->commandId = RC_VIDEOFRAME; - - cmd->width = width; - cmd->height = height; - cmd->captureBuffer = captureBuffer; - cmd->encodeBuffer = encodeBuffer; - cmd->motionJpeg = motionJpeg; -} diff --git a/code/renderergl1/tr_curve.c b/code/renderergl1/tr_curve.c deleted file mode 100644 index 40537eacde..0000000000 --- a/code/renderergl1/tr_curve.c +++ /dev/null @@ -1,625 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "tr_local.h" - -/* - -This file does all of the processing necessary to turn a raw grid of points -read from the map file into a srfGridMesh_t ready for rendering. - -The level of detail solution is direction independent, based only on subdivided -distance from the true curve. - -Only a single entry point: - -srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, - drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) { - -*/ - - -/* -============ -LerpDrawVert -============ -*/ -static void LerpDrawVert( drawVert_t *a, drawVert_t *b, drawVert_t *out ) { - out->xyz[0] = 0.5f * (a->xyz[0] + b->xyz[0]); - out->xyz[1] = 0.5f * (a->xyz[1] + b->xyz[1]); - out->xyz[2] = 0.5f * (a->xyz[2] + b->xyz[2]); - - out->st[0] = 0.5f * (a->st[0] + b->st[0]); - out->st[1] = 0.5f * (a->st[1] + b->st[1]); - - out->lightmap[0] = 0.5f * (a->lightmap[0] + b->lightmap[0]); - out->lightmap[1] = 0.5f * (a->lightmap[1] + b->lightmap[1]); - - out->color[0] = (a->color[0] + b->color[0]) >> 1; - out->color[1] = (a->color[1] + b->color[1]) >> 1; - out->color[2] = (a->color[2] + b->color[2]) >> 1; - out->color[3] = (a->color[3] + b->color[3]) >> 1; -} - -/* -============ -Transpose -============ -*/ -static void Transpose( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) { - int i, j; - drawVert_t temp; - - if ( width > height ) { - for ( i = 0 ; i < height ; i++ ) { - for ( j = i + 1 ; j < width ; j++ ) { - if ( j < height ) { - // swap the value - temp = ctrl[j][i]; - ctrl[j][i] = ctrl[i][j]; - ctrl[i][j] = temp; - } else { - // just copy - ctrl[j][i] = ctrl[i][j]; - } - } - } - } else { - for ( i = 0 ; i < width ; i++ ) { - for ( j = i + 1 ; j < height ; j++ ) { - if ( j < width ) { - // swap the value - temp = ctrl[i][j]; - ctrl[i][j] = ctrl[j][i]; - ctrl[j][i] = temp; - } else { - // just copy - ctrl[i][j] = ctrl[j][i]; - } - } - } - } - -} - - -/* -================= -MakeMeshNormals - -Handles all the complicated wrapping and degenerate cases -================= -*/ -static void MakeMeshNormals( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) { - int i, j, k, dist; - vec3_t normal; - vec3_t sum; - int count = 0; - vec3_t base; - vec3_t delta; - int x, y; - drawVert_t *dv; - vec3_t around[8], temp; - qboolean good[8]; - qboolean wrapWidth, wrapHeight; - float len; -static int neighbors[8][2] = { - {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1} - }; - - wrapWidth = qfalse; - for ( i = 0 ; i < height ; i++ ) { - VectorSubtract( ctrl[i][0].xyz, ctrl[i][width-1].xyz, delta ); - len = VectorLengthSquared( delta ); - if ( len > 1.0 ) { - break; - } - } - if ( i == height ) { - wrapWidth = qtrue; - } - - wrapHeight = qfalse; - for ( i = 0 ; i < width ; i++ ) { - VectorSubtract( ctrl[0][i].xyz, ctrl[height-1][i].xyz, delta ); - len = VectorLengthSquared( delta ); - if ( len > 1.0 ) { - break; - } - } - if ( i == width) { - wrapHeight = qtrue; - } - - - for ( i = 0 ; i < width ; i++ ) { - for ( j = 0 ; j < height ; j++ ) { - count = 0; - dv = &ctrl[j][i]; - VectorCopy( dv->xyz, base ); - for ( k = 0 ; k < 8 ; k++ ) { - VectorClear( around[k] ); - good[k] = qfalse; - - for ( dist = 1 ; dist <= 3 ; dist++ ) { - x = i + neighbors[k][0] * dist; - y = j + neighbors[k][1] * dist; - if ( wrapWidth ) { - if ( x < 0 ) { - x = width - 1 + x; - } else if ( x >= width ) { - x = 1 + x - width; - } - } - if ( wrapHeight ) { - if ( y < 0 ) { - y = height - 1 + y; - } else if ( y >= height ) { - y = 1 + y - height; - } - } - - if ( x < 0 || x >= width || y < 0 || y >= height ) { - break; // edge of patch - } - VectorSubtract( ctrl[y][x].xyz, base, temp ); - if ( VectorNormalize2( temp, temp ) == 0 ) { - continue; // degenerate edge, get more dist - } else { - good[k] = qtrue; - VectorCopy( temp, around[k] ); - break; // good edge - } - } - } - - VectorClear( sum ); - for ( k = 0 ; k < 8 ; k++ ) { - if ( !good[k] || !good[(k+1)&7] ) { - continue; // didn't get two points - } - CrossProduct( around[(k+1)&7], around[k], normal ); - if ( VectorNormalize2( normal, normal ) == 0 ) { - continue; - } - VectorAdd( normal, sum, sum ); - count++; - } - //if ( count == 0 ) { - // printf("bad normal\n"); - //} - VectorNormalize2( sum, dv->normal ); - } - } -} - - -/* -============ -InvertCtrl -============ -*/ -static void InvertCtrl( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) { - int i, j; - drawVert_t temp; - - for ( i = 0 ; i < height ; i++ ) { - for ( j = 0 ; j < width/2 ; j++ ) { - temp = ctrl[i][j]; - ctrl[i][j] = ctrl[i][width-1-j]; - ctrl[i][width-1-j] = temp; - } - } -} - - -/* -================= -InvertErrorTable -================= -*/ -static void InvertErrorTable( float errorTable[2][MAX_GRID_SIZE], int width, int height ) { - int i; - float copy[2][MAX_GRID_SIZE]; - - Com_Memcpy( copy, errorTable, sizeof( copy ) ); - - for ( i = 0 ; i < width ; i++ ) { - errorTable[1][i] = copy[0][i]; //[width-1-i]; - } - - for ( i = 0 ; i < height ; i++ ) { - errorTable[0][i] = copy[1][height-1-i]; - } - -} - -/* -================== -PutPointsOnCurve -================== -*/ -static void PutPointsOnCurve( drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], - int width, int height ) { - int i, j; - drawVert_t prev, next; - - for ( i = 0 ; i < width ; i++ ) { - for ( j = 1 ; j < height ; j += 2 ) { - LerpDrawVert( &ctrl[j][i], &ctrl[j+1][i], &prev ); - LerpDrawVert( &ctrl[j][i], &ctrl[j-1][i], &next ); - LerpDrawVert( &prev, &next, &ctrl[j][i] ); - } - } - - - for ( j = 0 ; j < height ; j++ ) { - for ( i = 1 ; i < width ; i += 2 ) { - LerpDrawVert( &ctrl[j][i], &ctrl[j][i+1], &prev ); - LerpDrawVert( &ctrl[j][i], &ctrl[j][i-1], &next ); - LerpDrawVert( &prev, &next, &ctrl[j][i] ); - } - } -} - -/* -================= -R_CreateSurfaceGridMesh -================= -*/ -srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height, - drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE] ) { - int i, j, size; - drawVert_t *vert; - vec3_t tmpVec; - srfGridMesh_t *grid; - - // copy the results out to a grid - size = (width * height - 1) * sizeof( drawVert_t ) + sizeof( *grid ); - -#ifdef PATCH_STITCHING - grid = /*ri.Hunk_Alloc*/ ri.Malloc( size ); - Com_Memset(grid, 0, size); - - grid->widthLodError = /*ri.Hunk_Alloc*/ ri.Malloc( width * 4 ); - Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 ); - - grid->heightLodError = /*ri.Hunk_Alloc*/ ri.Malloc( height * 4 ); - Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 ); -#else - grid = ri.Hunk_Alloc( size ); - Com_Memset(grid, 0, size); - - grid->widthLodError = ri.Hunk_Alloc( width * 4 ); - Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 ); - - grid->heightLodError = ri.Hunk_Alloc( height * 4 ); - Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 ); -#endif - - grid->width = width; - grid->height = height; - grid->surfaceType = SF_GRID; - ClearBounds( grid->meshBounds[0], grid->meshBounds[1] ); - for ( i = 0 ; i < width ; i++ ) { - for ( j = 0 ; j < height ; j++ ) { - vert = &grid->verts[j*width+i]; - *vert = ctrl[j][i]; - AddPointToBounds( vert->xyz, grid->meshBounds[0], grid->meshBounds[1] ); - } - } - - // compute local origin and bounds - VectorAdd( grid->meshBounds[0], grid->meshBounds[1], grid->localOrigin ); - VectorScale( grid->localOrigin, 0.5f, grid->localOrigin ); - VectorSubtract( grid->meshBounds[0], grid->localOrigin, tmpVec ); - grid->meshRadius = VectorLength( tmpVec ); - - VectorCopy( grid->localOrigin, grid->lodOrigin ); - grid->lodRadius = grid->meshRadius; - // - return grid; -} - -/* -================= -R_FreeSurfaceGridMesh -================= -*/ -void R_FreeSurfaceGridMesh( srfGridMesh_t *grid ) { - ri.Free(grid->widthLodError); - ri.Free(grid->heightLodError); - ri.Free(grid); -} - -/* -================= -R_SubdividePatchToGrid -================= -*/ -srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, - drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) { - int i, j, k, l; - drawVert_t_cleared( prev ); - drawVert_t_cleared( next ); - drawVert_t_cleared( mid ); - float len, maxLen; - int dir; - int t; - drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; - float errorTable[2][MAX_GRID_SIZE]; - - for ( i = 0 ; i < width ; i++ ) { - for ( j = 0 ; j < height ; j++ ) { - ctrl[j][i] = points[j*width+i]; - } - } - - for ( dir = 0 ; dir < 2 ; dir++ ) { - - for ( j = 0 ; j < MAX_GRID_SIZE ; j++ ) { - errorTable[dir][j] = 0; - } - - // horizontal subdivisions - for ( j = 0 ; j + 2 < width ; j += 2 ) { - // check subdivided midpoints against control points - - // FIXME: also check midpoints of adjacent patches against the control points - // this would basically stitch all patches in the same LOD group together. - - maxLen = 0; - for ( i = 0 ; i < height ; i++ ) { - vec3_t midxyz; - vec3_t midxyz2; - vec3_t dir; - vec3_t projected; - float d; - - // calculate the point on the curve - for ( l = 0 ; l < 3 ; l++ ) { - midxyz[l] = (ctrl[i][j].xyz[l] + ctrl[i][j+1].xyz[l] * 2 - + ctrl[i][j+2].xyz[l] ) * 0.25f; - } - - // see how far off the line it is - // using dist-from-line will not account for internal - // texture warping, but it gives a lot less polygons than - // dist-from-midpoint - VectorSubtract( midxyz, ctrl[i][j].xyz, midxyz ); - VectorSubtract( ctrl[i][j+2].xyz, ctrl[i][j].xyz, dir ); - VectorNormalize( dir ); - - d = DotProduct( midxyz, dir ); - VectorScale( dir, d, projected ); - VectorSubtract( midxyz, projected, midxyz2); - len = VectorLengthSquared( midxyz2 ); // we will do the sqrt later - if ( len > maxLen ) { - maxLen = len; - } - } - - maxLen = sqrt(maxLen); - - // if all the points are on the lines, remove the entire columns - if ( maxLen < 0.1f ) { - errorTable[dir][j+1] = 999; - continue; - } - - // see if we want to insert subdivided columns - if ( width + 2 > MAX_GRID_SIZE ) { - errorTable[dir][j+1] = 1.0f/maxLen; - continue; // can't subdivide any more - } - - if ( maxLen <= r_subdivisions->value ) { - errorTable[dir][j+1] = 1.0f/maxLen; - continue; // didn't need subdivision - } - - errorTable[dir][j+2] = 1.0f/maxLen; - - // insert two columns and replace the peak - width += 2; - for ( i = 0 ; i < height ; i++ ) { - LerpDrawVert( &ctrl[i][j], &ctrl[i][j+1], &prev ); - LerpDrawVert( &ctrl[i][j+1], &ctrl[i][j+2], &next ); - LerpDrawVert( &prev, &next, &mid ); - - for ( k = width - 1 ; k > j + 3 ; k-- ) { - ctrl[i][k] = ctrl[i][k-2]; - } - ctrl[i][j + 1] = prev; - ctrl[i][j + 2] = mid; - ctrl[i][j + 3] = next; - } - - // back up and recheck this set again, it may need more subdivision - j -= 2; - - } - - Transpose( width, height, ctrl ); - t = width; - width = height; - height = t; - } - - - // put all the aproximating points on the curve - PutPointsOnCurve( ctrl, width, height ); - - // cull out any rows or columns that are colinear - for ( i = 1 ; i < width-1 ; i++ ) { - if ( errorTable[0][i] != 999 ) { - continue; - } - for ( j = i+1 ; j < width ; j++ ) { - for ( k = 0 ; k < height ; k++ ) { - ctrl[k][j-1] = ctrl[k][j]; - } - errorTable[0][j-1] = errorTable[0][j]; - } - width--; - } - - for ( i = 1 ; i < height-1 ; i++ ) { - if ( errorTable[1][i] != 999 ) { - continue; - } - for ( j = i+1 ; j < height ; j++ ) { - for ( k = 0 ; k < width ; k++ ) { - ctrl[j-1][k] = ctrl[j][k]; - } - errorTable[1][j-1] = errorTable[1][j]; - } - height--; - } - -#if 1 - // flip for longest tristrips as an optimization - // the results should be visually identical with or - // without this step - if ( height > width ) { - Transpose( width, height, ctrl ); - InvertErrorTable( errorTable, width, height ); - t = width; - width = height; - height = t; - InvertCtrl( width, height, ctrl ); - } -#endif - - // calculate normals - MakeMeshNormals( width, height, ctrl ); - - return R_CreateSurfaceGridMesh( width, height, ctrl, errorTable ); -} - -/* -=============== -R_GridInsertColumn -=============== -*/ -srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror ) { - int i, j; - int width, height, oldwidth; - drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; - float errorTable[2][MAX_GRID_SIZE]; - float lodRadius; - vec3_t lodOrigin; - - oldwidth = 0; - width = grid->width + 1; - if (width > MAX_GRID_SIZE) - return NULL; - height = grid->height; - for (i = 0; i < width; i++) { - if (i == column) { - //insert new column - for (j = 0; j < grid->height; j++) { - LerpDrawVert( &grid->verts[j * grid->width + i-1], &grid->verts[j * grid->width + i], &ctrl[j][i] ); - if (j == row) - VectorCopy(point, ctrl[j][i].xyz); - } - errorTable[0][i] = loderror; - continue; - } - errorTable[0][i] = grid->widthLodError[oldwidth]; - for (j = 0; j < grid->height; j++) { - ctrl[j][i] = grid->verts[j * grid->width + oldwidth]; - } - oldwidth++; - } - for (j = 0; j < grid->height; j++) { - errorTable[1][j] = grid->heightLodError[j]; - } - // put all the aproximating points on the curve - //PutPointsOnCurve( ctrl, width, height ); - // calculate normals - MakeMeshNormals( width, height, ctrl ); - - VectorCopy(grid->lodOrigin, lodOrigin); - lodRadius = grid->lodRadius; - // free the old grid - R_FreeSurfaceGridMesh(grid); - // create a new grid - grid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable ); - grid->lodRadius = lodRadius; - VectorCopy(lodOrigin, grid->lodOrigin); - return grid; -} - -/* -=============== -R_GridInsertRow -=============== -*/ -srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror ) { - int i, j; - int width, height, oldheight; - drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; - float errorTable[2][MAX_GRID_SIZE]; - float lodRadius; - vec3_t lodOrigin; - - oldheight = 0; - width = grid->width; - height = grid->height + 1; - if (height > MAX_GRID_SIZE) - return NULL; - for (i = 0; i < height; i++) { - if (i == row) { - //insert new row - for (j = 0; j < grid->width; j++) { - LerpDrawVert( &grid->verts[(i-1) * grid->width + j], &grid->verts[i * grid->width + j], &ctrl[i][j] ); - if (j == column) - VectorCopy(point, ctrl[i][j].xyz); - } - errorTable[1][i] = loderror; - continue; - } - errorTable[1][i] = grid->heightLodError[oldheight]; - for (j = 0; j < grid->width; j++) { - ctrl[i][j] = grid->verts[oldheight * grid->width + j]; - } - oldheight++; - } - for (j = 0; j < grid->width; j++) { - errorTable[0][j] = grid->widthLodError[j]; - } - // put all the aproximating points on the curve - //PutPointsOnCurve( ctrl, width, height ); - // calculate normals - MakeMeshNormals( width, height, ctrl ); - - VectorCopy(grid->lodOrigin, lodOrigin); - lodRadius = grid->lodRadius; - // free the old grid - R_FreeSurfaceGridMesh(grid); - // create a new grid - grid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable ); - grid->lodRadius = lodRadius; - VectorCopy(lodOrigin, grid->lodOrigin); - return grid; -} diff --git a/code/renderergl1/tr_flares.c b/code/renderergl1/tr_flares.c deleted file mode 100644 index 7bd95194f0..0000000000 --- a/code/renderergl1/tr_flares.c +++ /dev/null @@ -1,539 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_flares.c - -#include "tr_local.h" - -/* -============================================================================= - -LIGHT FLARES - -A light flare is an effect that takes place inside the eye when bright light -sources are visible. The size of the flare relative to the screen is nearly -constant, irrespective of distance, but the intensity should be proportional to the -projected area of the light source. - -A surface that has been flagged as having a light flare will calculate the depth -buffer value that its midpoint should have when the surface is added. - -After all opaque surfaces have been rendered, the depth buffer is read back for -each flare in view. If the point has not been obscured by a closer surface, the -flare should be drawn. - -Surfaces that have a repeated texture should never be flagged as flaring, because -there will only be a single flare added at the midpoint of the polygon. - -To prevent abrupt popping, the intensity of the flare is interpolated up and -down as it changes visibility. This involves scene to scene state, unlike almost -all other aspects of the renderer, and is complicated by the fact that a single -frame may have multiple scenes. - -RB_RenderFlares() will be called once per view (twice in a mirrored scene, potentially -up to five or more times in a frame with 3D status bar icons). - -============================================================================= -*/ - - -// flare states maintain visibility over multiple frames for fading -// layers: view, mirror, menu -typedef struct flare_s { - struct flare_s *next; // for active chain - - int addedFrame; - - qboolean inPortal; // true if in a portal view of the scene - int frameSceneNum; - void *surface; - int fogNum; - - int fadeTime; - - qboolean visible; // state of last test - float drawIntensity; // may be non 0 even if !visible due to fading - - int windowX, windowY; - float eyeZ; - - vec3_t origin; - vec3_t color; -} flare_t; - -#define MAX_FLARES 256 - -flare_t r_flareStructs[MAX_FLARES]; -flare_t *r_activeFlares, *r_inactiveFlares; - -int flareCoeff; - -/* -================== -R_SetFlareCoeff -================== -*/ -static void R_SetFlareCoeff( void ) { - - if(r_flareCoeff->value == 0.0f) - flareCoeff = atof(FLARE_STDCOEFF); - else - flareCoeff = r_flareCoeff->value; -} - -/* -================== -R_ClearFlares -================== -*/ -void R_ClearFlares( void ) { - int i; - - Com_Memset( r_flareStructs, 0, sizeof( r_flareStructs ) ); - r_activeFlares = NULL; - r_inactiveFlares = NULL; - - for ( i = 0 ; i < MAX_FLARES ; i++ ) { - r_flareStructs[i].next = r_inactiveFlares; - r_inactiveFlares = &r_flareStructs[i]; - } - - R_SetFlareCoeff(); -} - - -/* -================== -RB_AddFlare - -This is called at surface tesselation time -================== -*/ -void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ) { - int i; - flare_t *f; - vec3_t local; - float d = 1; - vec4_t eye, clip, normalized, window; - - backEnd.pc.c_flareAdds++; - - if(normal && (normal[0] || normal[1] || normal[2])) - { - VectorSubtract( backEnd.viewParms.or.origin, point, local ); - VectorNormalizeFast(local); - d = DotProduct(local, normal); - - // If the viewer is behind the flare don't add it. - if(d < 0) - return; - } - - // if the point is off the screen, don't bother adding it - // calculate screen coordinates and depth - R_TransformModelToClip( point, backEnd.or.modelMatrix, - backEnd.viewParms.projectionMatrix, eye, clip ); - - // check to see if the point is completely off screen - for ( i = 0 ; i < 3 ; i++ ) { - if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) { - return; - } - } - - R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window ); - - if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth - || window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) { - return; // shouldn't happen, since we check the clip[] above, except for FP rounding - } - - // see if a flare with a matching surface, scene, and view exists - for ( f = r_activeFlares ; f ; f = f->next ) { - if ( f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum - && f->inPortal == backEnd.viewParms.isPortal ) { - break; - } - } - - // allocate a new one - if (!f ) { - if ( !r_inactiveFlares ) { - // the list is completely full - return; - } - f = r_inactiveFlares; - r_inactiveFlares = r_inactiveFlares->next; - f->next = r_activeFlares; - r_activeFlares = f; - - f->surface = surface; - f->frameSceneNum = backEnd.viewParms.frameSceneNum; - f->inPortal = backEnd.viewParms.isPortal; - f->addedFrame = -1; - } - - if ( f->addedFrame != backEnd.viewParms.frameCount - 1 ) { - f->visible = qfalse; - f->fadeTime = backEnd.refdef.time - 2000; - } - - f->addedFrame = backEnd.viewParms.frameCount; - f->fogNum = fogNum; - - VectorCopy(point, f->origin); - VectorCopy( color, f->color ); - - // fade the intensity of the flare down as the - // light surface turns away from the viewer - VectorScale( f->color, d, f->color ); - - // save info needed to test - f->windowX = backEnd.viewParms.viewportX + window[0]; - f->windowY = backEnd.viewParms.viewportY + window[1]; - - f->eyeZ = eye[2]; -} - -/* -================== -RB_AddDlightFlares -================== -*/ -void RB_AddDlightFlares( void ) { - dlight_t *l; - int i, j, k; - fog_t *fog = NULL; - - if ( !r_flares->integer ) { - return; - } - - l = backEnd.refdef.dlights; - - if(tr.world) - fog = tr.world->fogs; - - for (i=0 ; inumfogs ; j++ ) { - fog = &tr.world->fogs[j]; - for ( k = 0 ; k < 3 ; k++ ) { - if ( l->origin[k] < fog->bounds[0][k] || l->origin[k] > fog->bounds[1][k] ) { - break; - } - } - if ( k == 3 ) { - break; - } - } - if ( j == tr.world->numfogs ) { - j = 0; - } - } - else - j = 0; - - RB_AddFlare( (void *)l, j, l->origin, l->color, NULL ); - } -} - -/* -=============================================================================== - -FLARE BACK END - -=============================================================================== -*/ - -/* -================== -RB_TestFlare -================== -*/ -void RB_TestFlare( flare_t *f ) { - float depth; - qboolean visible; - float fade; - float screenZ; - - backEnd.pc.c_flareTests++; - - // doing a readpixels is as good as doing a glFinish(), so - // don't bother with another sync - glState.finishCalled = qfalse; - - // read back the z buffer contents - qglReadPixels( f->windowX, f->windowY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth ); - - screenZ = backEnd.viewParms.projectionMatrix[14] / - ( ( 2*depth - 1 ) * backEnd.viewParms.projectionMatrix[11] - backEnd.viewParms.projectionMatrix[10] ); - - visible = ( -f->eyeZ - -screenZ ) < 24; - - if ( visible ) { - if ( !f->visible ) { - f->visible = qtrue; - f->fadeTime = backEnd.refdef.time - 1; - } - fade = ( ( backEnd.refdef.time - f->fadeTime ) /1000.0f ) * r_flareFade->value; - } else { - if ( f->visible ) { - f->visible = qfalse; - f->fadeTime = backEnd.refdef.time - 1; - } - fade = 1.0f - ( ( backEnd.refdef.time - f->fadeTime ) / 1000.0f ) * r_flareFade->value; - } - - if ( fade < 0 ) { - fade = 0; - } - if ( fade > 1 ) { - fade = 1; - } - - f->drawIntensity = fade; -} - - -/* -================== -RB_RenderFlare -================== -*/ -void RB_RenderFlare( flare_t *f ) { - float size; - vec3_t color; - int iColor[3]; - float distance, intensity, factor; - byte fogFactors[3] = {255, 255, 255}; - - backEnd.pc.c_flareRenders++; - - // We don't want too big values anyways when dividing by distance. - if(f->eyeZ > -1.0f) - distance = 1.0f; - else - distance = -f->eyeZ; - - // calculate the flare size.. - size = backEnd.viewParms.viewportWidth * ( r_flareSize->value/640.0f + 8 / distance ); - -/* - * This is an alternative to intensity scaling. It changes the size of the flare on screen instead - * with growing distance. See in the description at the top why this is not the way to go. - // size will change ~ 1/r. - size = backEnd.viewParms.viewportWidth * (r_flareSize->value / (distance * -2.0f)); -*/ - -/* - * As flare sizes stay nearly constant with increasing distance we must decrease the intensity - * to achieve a reasonable visual result. The intensity is ~ (size^2 / distance^2) which can be - * got by considering the ratio of - * (flaresurface on screen) : (Surface of sphere defined by flare origin and distance from flare) - * An important requirement is: - * intensity <= 1 for all distances. - * - * The formula used here to compute the intensity is as follows: - * intensity = flareCoeff * size^2 / (distance + size*sqrt(flareCoeff))^2 - * As you can see, the intensity will have a max. of 1 when the distance is 0. - * The coefficient flareCoeff will determine the falloff speed with increasing distance. - */ - - factor = distance + size * sqrt(flareCoeff); - - intensity = flareCoeff * size * size / (factor * factor); - - VectorScale(f->color, f->drawIntensity * intensity, color); - - // Calculations for fogging - if(tr.world && f->fogNum > 0 && f->fogNum < tr.world->numfogs) - { - tess.numVertexes = 1; - VectorCopy(f->origin, tess.xyz[0]); - tess.fogNum = f->fogNum; - - RB_CalcModulateColorsByFog(fogFactors); - - // We don't need to render the flare if colors are 0 anyways. - if(!(fogFactors[0] || fogFactors[1] || fogFactors[2])) - return; - } - - iColor[0] = color[0] * fogFactors[0]; - iColor[1] = color[1] * fogFactors[1]; - iColor[2] = color[2] * fogFactors[2]; - - RB_BeginSurface( tr.flareShader, f->fogNum ); - - // FIXME: use quadstamp? - tess.xyz[tess.numVertexes][0] = f->windowX - size; - tess.xyz[tess.numVertexes][1] = f->windowY - size; - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = iColor[0]; - tess.vertexColors[tess.numVertexes][1] = iColor[1]; - tess.vertexColors[tess.numVertexes][2] = iColor[2]; - tess.vertexColors[tess.numVertexes][3] = 255; - tess.numVertexes++; - - tess.xyz[tess.numVertexes][0] = f->windowX - size; - tess.xyz[tess.numVertexes][1] = f->windowY + size; - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = iColor[0]; - tess.vertexColors[tess.numVertexes][1] = iColor[1]; - tess.vertexColors[tess.numVertexes][2] = iColor[2]; - tess.vertexColors[tess.numVertexes][3] = 255; - tess.numVertexes++; - - tess.xyz[tess.numVertexes][0] = f->windowX + size; - tess.xyz[tess.numVertexes][1] = f->windowY + size; - tess.texCoords[tess.numVertexes][0][0] = 1; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = iColor[0]; - tess.vertexColors[tess.numVertexes][1] = iColor[1]; - tess.vertexColors[tess.numVertexes][2] = iColor[2]; - tess.vertexColors[tess.numVertexes][3] = 255; - tess.numVertexes++; - - tess.xyz[tess.numVertexes][0] = f->windowX + size; - tess.xyz[tess.numVertexes][1] = f->windowY - size; - tess.texCoords[tess.numVertexes][0][0] = 1; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = iColor[0]; - tess.vertexColors[tess.numVertexes][1] = iColor[1]; - tess.vertexColors[tess.numVertexes][2] = iColor[2]; - tess.vertexColors[tess.numVertexes][3] = 255; - tess.numVertexes++; - - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 1; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 3; - - RB_EndSurface(); -} - -/* -================== -RB_RenderFlares - -Because flares are simulating an occular effect, they should be drawn after -everything (all views) in the entire frame has been drawn. - -Because of the way portals use the depth buffer to mark off areas, the -needed information would be lost after each view, so we are forced to draw -flares after each view. - -The resulting artifact is that flares in mirrors or portals don't dim properly -when occluded by something in the main view, and portal flares that should -extend past the portal edge will be overwritten. -================== -*/ -void RB_RenderFlares (void) { - flare_t *f; - flare_t **prev; - qboolean draw; - - if ( !r_flares->integer ) { - return; - } - - if(r_flareCoeff->modified) - { - R_SetFlareCoeff(); - r_flareCoeff->modified = qfalse; - } - - // Reset currentEntity to world so that any previously referenced entities - // don't have influence on the rendering of these flares (i.e. RF_ renderer flags). - backEnd.currentEntity = &tr.worldEntity; - backEnd.or = backEnd.viewParms.world; - -// RB_AddDlightFlares(); - - // perform z buffer readback on each flare in this view - draw = qfalse; - prev = &r_activeFlares; - while ( ( f = *prev ) != NULL ) { - // throw out any flares that weren't added last frame - if ( f->addedFrame < backEnd.viewParms.frameCount - 1 ) { - *prev = f->next; - f->next = r_inactiveFlares; - r_inactiveFlares = f; - continue; - } - - // don't draw any here that aren't from this scene / portal - f->drawIntensity = 0; - if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum - && f->inPortal == backEnd.viewParms.isPortal ) { - RB_TestFlare( f ); - if ( f->drawIntensity ) { - draw = qtrue; - } else { - // this flare has completely faded out, so remove it from the chain - *prev = f->next; - f->next = r_inactiveFlares; - r_inactiveFlares = f; - continue; - } - } - - prev = &f->next; - } - - if ( !draw ) { - return; // none visible - } - - if ( backEnd.viewParms.isPortal ) { - qglDisable (GL_CLIP_PLANE0); - } - - qglPushMatrix(); - qglLoadIdentity(); - qglMatrixMode( GL_PROJECTION ); - qglPushMatrix(); - qglLoadIdentity(); - qglOrtho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth, - backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight, - -99999, 99999 ); - - for ( f = r_activeFlares ; f ; f = f->next ) { - if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum - && f->inPortal == backEnd.viewParms.isPortal - && f->drawIntensity ) { - RB_RenderFlare( f ); - } - } - - qglPopMatrix(); - qglMatrixMode( GL_MODELVIEW ); - qglPopMatrix(); -} - diff --git a/code/renderergl1/tr_image.c b/code/renderergl1/tr_image.c deleted file mode 100644 index d1127829b8..0000000000 --- a/code/renderergl1/tr_image.c +++ /dev/null @@ -1,1682 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_image.c -#include "tr_local.h" - -static byte s_intensitytable[256]; -static unsigned char s_gammatable[256]; - -int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST; -int gl_filter_max = GL_LINEAR; - -#define FILE_HASH_SIZE 1024 -static image_t* hashTable[FILE_HASH_SIZE]; - -/* -** R_GammaCorrect -*/ -void R_GammaCorrect( byte *buffer, int bufSize ) { - int i; - - for ( i = 0; i < bufSize; i++ ) { - buffer[i] = s_gammatable[buffer[i]]; - } -} - -typedef struct { - char *name; - int minimize, maximize; -} textureMode_t; - -textureMode_t modes[] = { - {"GL_NEAREST", GL_NEAREST, GL_NEAREST}, - {"GL_LINEAR", GL_LINEAR, GL_LINEAR}, - {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, - {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, - {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}, - {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} -}; - -/* -================ -return a hash value for the filename -================ -*/ -static long generateHashValue( const char *fname ) { - int i; - long hash; - char letter; - - hash = 0; - i = 0; - while (fname[i] != '\0') { - letter = tolower(fname[i]); - if (letter =='.') break; // don't include extension - if (letter =='\\') letter = '/'; // damn path names - hash+=(long)(letter)*(i+119); - i++; - } - hash &= (FILE_HASH_SIZE-1); - return hash; -} - -/* -=============== -GL_TextureMode -=============== -*/ -void GL_TextureMode( const char *string ) { - int i; - image_t *glt; - - for ( i=0 ; i< 6 ; i++ ) { - if ( !Q_stricmp( modes[i].name, string ) ) { - break; - } - } - - // hack to prevent trilinear from being set on voodoo, - // because their driver freaks... - if ( i == 5 && glConfig.hardwareType == GLHW_3DFX_2D3D ) { - ri.Printf( PRINT_ALL, "Refusing to set trilinear on a voodoo.\n" ); - i = 3; - } - - - if ( i == 6 ) { - ri.Printf (PRINT_ALL, "bad filter name\n"); - return; - } - - gl_filter_min = modes[i].minimize; - gl_filter_max = modes[i].maximize; - - // change all the existing mipmap texture objects - for ( i = 0 ; i < tr.numImages ; i++ ) { - glt = tr.images[ i ]; - if ( glt->flags & IMGFLAG_MIPMAP ) { - GL_Bind (glt); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); - } - } -} - -/* -=============== -R_SumOfUsedImages -=============== -*/ -int R_SumOfUsedImages( void ) { - int total; - int i; - - total = 0; - for ( i = 0; i < tr.numImages; i++ ) { - if ( tr.images[i]->frameUsed == tr.frameCount ) { - total += tr.images[i]->uploadWidth * tr.images[i]->uploadHeight; - } - } - - return total; -} - -/* -=============== -R_ImageList_f -=============== -*/ -void R_ImageList_f( void ) { - int i; - int estTotalSize = 0; - - ri.Printf(PRINT_ALL, "\n -w-- -h-- type -size- --name-------\n"); - - for ( i = 0 ; i < tr.numImages ; i++ ) - { - image_t *image = tr.images[i]; - char *format = "???? "; - char *sizeSuffix; - int estSize; - int displaySize; - - estSize = image->uploadHeight * image->uploadWidth; - - switch(image->internalFormat) - { - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: - format = "sDXT1"; - // 64 bits per 16 pixels, so 4 bits per pixel - estSize /= 2; - break; - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: - format = "sDXT5"; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB: - format = "sBPTC"; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: - format = "LATC "; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - format = "DXT1 "; - // 64 bits per 16 pixels, so 4 bits per pixel - estSize /= 2; - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - format = "DXT5 "; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB: - format = "BPTC "; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_RGB4_S3TC: - format = "S3TC "; - // same as DXT1? - estSize /= 2; - break; - case GL_RGBA4: - case GL_RGBA8: - case GL_RGBA: - format = "RGBA "; - // 4 bytes per pixel - estSize *= 4; - break; - case GL_LUMINANCE8: - case GL_LUMINANCE16: - case GL_LUMINANCE: - format = "L "; - // 1 byte per pixel? - break; - case GL_RGB5: - case GL_RGB8: - case GL_RGB: - format = "RGB "; - // 3 bytes per pixel? - estSize *= 3; - break; - case GL_LUMINANCE8_ALPHA8: - case GL_LUMINANCE16_ALPHA16: - case GL_LUMINANCE_ALPHA: - format = "LA "; - // 2 bytes per pixel? - estSize *= 2; - break; - case GL_SRGB_EXT: - case GL_SRGB8_EXT: - format = "sRGB "; - // 3 bytes per pixel? - estSize *= 3; - break; - case GL_SRGB_ALPHA_EXT: - case GL_SRGB8_ALPHA8_EXT: - format = "sRGBA"; - // 4 bytes per pixel? - estSize *= 4; - break; - case GL_SLUMINANCE_EXT: - case GL_SLUMINANCE8_EXT: - format = "sL "; - // 1 byte per pixel? - break; - case GL_SLUMINANCE_ALPHA_EXT: - case GL_SLUMINANCE8_ALPHA8_EXT: - format = "sLA "; - // 2 byte per pixel? - estSize *= 2; - break; - } - - // mipmap adds about 50% - if (image->flags & IMGFLAG_MIPMAP) - estSize += estSize / 2; - - sizeSuffix = "b "; - displaySize = estSize; - - if (displaySize > 1024) - { - displaySize /= 1024; - sizeSuffix = "kb"; - } - - if (displaySize > 1024) - { - displaySize /= 1024; - sizeSuffix = "Mb"; - } - - if (displaySize > 1024) - { - displaySize /= 1024; - sizeSuffix = "Gb"; - } - - ri.Printf(PRINT_ALL, "%4i: %4ix%4i %s %4i%s %s\n", i, image->uploadWidth, image->uploadHeight, format, displaySize, sizeSuffix, image->imgName); - estTotalSize += estSize; - } - - ri.Printf (PRINT_ALL, " ---------\n"); - ri.Printf (PRINT_ALL, " approx %i bytes\n", estTotalSize); - ri.Printf (PRINT_ALL, " %i total images\n\n", tr.numImages ); -} - -//======================================================================= - -/* -================ -ResampleTexture - -Used to resample images in a more general than quartering fashion. - -This will only be filtered properly if the resampled size -is greater than half the original size. - -If a larger shrinking is needed, use the mipmap function -before or after. -================ -*/ -static void ResampleTexture( unsigned *in, int inwidth, int inheight, unsigned *out, - int outwidth, int outheight ) { - int i, j; - unsigned *inrow, *inrow2; - unsigned frac, fracstep; - unsigned p1[2048], p2[2048]; - byte *pix1, *pix2, *pix3, *pix4; - - if (outwidth>2048) - ri.Error(ERR_DROP, "ResampleTexture: max width"); - - fracstep = inwidth*0x10000/outwidth; - - frac = fracstep>>2; - for ( i=0 ; i>16); - frac += fracstep; - } - frac = 3*(fracstep>>2); - for ( i=0 ; i>16); - frac += fracstep; - } - - for (i=0 ; i>2; - ((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2; - ((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2; - ((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2; - } - } -} - -/* -================ -R_LightScaleTexture - -Scale up the pixel values in a texture to increase the -lighting range -================ -*/ -void R_LightScaleTexture (unsigned *in, int inwidth, int inheight, qboolean only_gamma ) -{ - if ( only_gamma ) - { - if ( !glConfig.deviceSupportsGamma ) - { - int i, c; - byte *p; - - p = (byte *)in; - - c = inwidth*inheight; - for (i=0 ; i> 1; - outHeight = inHeight >> 1; - temp = ri.Hunk_AllocateTempMemory( outWidth * outHeight * 4 ); - - inWidthMask = inWidth - 1; - inHeightMask = inHeight - 1; - - for ( i = 0 ; i < outHeight ; i++ ) { - for ( j = 0 ; j < outWidth ; j++ ) { - outpix = (byte *) ( temp + i * outWidth + j ); - for ( k = 0 ; k < 4 ; k++ ) { - total = - 1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] + - 2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] + - 2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] + - 1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] + - - 2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] + - 4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] + - 4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] + - 2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] + - - 2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] + - 4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] + - 4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] + - 2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] + - - 1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] + - 2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] + - 2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] + - 1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k]; - outpix[k] = total / 36; - } - } - } - - Com_Memcpy( in, temp, outWidth * outHeight * 4 ); - ri.Hunk_FreeTempMemory( temp ); -} - -/* -================ -R_MipMap - -Operates in place, quartering the size of the texture -================ -*/ -static void R_MipMap (byte *in, int width, int height) { - int i, j; - byte *out; - int row; - - if ( !r_simpleMipMaps->integer ) { - R_MipMap2( (unsigned *)in, width, height ); - return; - } - - if ( width == 1 && height == 1 ) { - return; - } - - row = width * 4; - out = in; - width >>= 1; - height >>= 1; - - if ( width == 0 || height == 0 ) { - width += height; // get largest - for (i=0 ; i>1; - out[1] = ( in[1] + in[5] )>>1; - out[2] = ( in[2] + in[6] )>>1; - out[3] = ( in[3] + in[7] )>>1; - } - return; - } - - for (i=0 ; i>2; - out[1] = (in[1] + in[5] + in[row+1] + in[row+5])>>2; - out[2] = (in[2] + in[6] + in[row+2] + in[row+6])>>2; - out[3] = (in[3] + in[7] + in[row+3] + in[row+7])>>2; - } - } -} - - -/* -================== -R_BlendOverTexture - -Apply a color blend over a set of pixels -================== -*/ -static void R_BlendOverTexture( byte *data, int pixelCount, byte blend[4] ) { - int i; - int inverseAlpha; - int premult[3]; - - inverseAlpha = 255 - blend[3]; - premult[0] = blend[0] * blend[3]; - premult[1] = blend[1] * blend[3]; - premult[2] = blend[2] * blend[3]; - - for ( i = 0 ; i < pixelCount ; i++, data+=4 ) { - data[0] = ( data[0] * inverseAlpha + premult[0] ) >> 9; - data[1] = ( data[1] * inverseAlpha + premult[1] ) >> 9; - data[2] = ( data[2] * inverseAlpha + premult[2] ) >> 9; - } -} - -byte mipBlendColors[16][4] = { - {0,0,0,0}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, -}; - - -/* -=============== -Upload32 - -=============== -*/ -extern qboolean charSet; -static void Upload32( unsigned *data, - int width, int height, - qboolean mipmap, - qboolean picmip, - qboolean lightMap, - int *format, - int *pUploadWidth, int *pUploadHeight ) -{ - int samples; - unsigned *scaledBuffer = NULL; - unsigned *resampledBuffer = NULL; - int scaled_width, scaled_height; - int i, c; - byte *scan; - GLenum internalFormat = GL_RGB; - float rMax = 0, gMax = 0, bMax = 0; - - // - // convert to exact power of 2 sizes - // - for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1) - ; - for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1) - ; - if ( r_roundImagesDown->integer && scaled_width > width ) - scaled_width >>= 1; - if ( r_roundImagesDown->integer && scaled_height > height ) - scaled_height >>= 1; - - if ( scaled_width != width || scaled_height != height ) { - resampledBuffer = ri.Hunk_AllocateTempMemory( scaled_width * scaled_height * 4 ); - ResampleTexture (data, width, height, resampledBuffer, scaled_width, scaled_height); - data = resampledBuffer; - width = scaled_width; - height = scaled_height; - } - - // - // perform optional picmip operation - // - if ( picmip ) { - scaled_width >>= r_picmip->integer; - scaled_height >>= r_picmip->integer; - } - - // - // clamp to minimum size - // - if (scaled_width < 1) { - scaled_width = 1; - } - if (scaled_height < 1) { - scaled_height = 1; - } - - // - // clamp to the current upper OpenGL limit - // scale both axis down equally so we don't have to - // deal with a half mip resampling - // - while ( scaled_width > glConfig.maxTextureSize - || scaled_height > glConfig.maxTextureSize ) { - scaled_width >>= 1; - scaled_height >>= 1; - } - - scaledBuffer = ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height ); - - // - // scan the texture for each channel's max values - // and verify if the alpha channel is being used or not - // - c = width*height; - scan = ((byte *)data); - samples = 3; - - if( r_greyscale->integer ) - { - for ( i = 0; i < c; i++ ) - { - byte luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]); - scan[i*4] = luma; - scan[i*4 + 1] = luma; - scan[i*4 + 2] = luma; - } - } - else if( r_greyscale->value ) - { - for ( i = 0; i < c; i++ ) - { - float luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]); - scan[i*4] = LERP(scan[i*4], luma, r_greyscale->value); - scan[i*4 + 1] = LERP(scan[i*4 + 1], luma, r_greyscale->value); - scan[i*4 + 2] = LERP(scan[i*4 + 2], luma, r_greyscale->value); - } - } - - if(lightMap) - { - if(r_greyscale->integer) - internalFormat = GL_LUMINANCE; - else - internalFormat = GL_RGB; - } - else - { - for ( i = 0; i < c; i++ ) - { - if ( scan[i*4+0] > rMax ) - { - rMax = scan[i*4+0]; - } - if ( scan[i*4+1] > gMax ) - { - gMax = scan[i*4+1]; - } - if ( scan[i*4+2] > bMax ) - { - bMax = scan[i*4+2]; - } - if ( scan[i*4 + 3] != 255 ) - { - samples = 4; - break; - } - } - // select proper internal format - if ( samples == 3 ) - { - if(r_greyscale->integer) - { - if(r_texturebits->integer == 16) - internalFormat = GL_LUMINANCE8; - else if(r_texturebits->integer == 32) - internalFormat = GL_LUMINANCE16; - else - internalFormat = GL_LUMINANCE; - } - else - { - if ( glConfig.textureCompression == TC_S3TC_ARB ) - { - internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - } - else if ( glConfig.textureCompression == TC_S3TC ) - { - internalFormat = GL_RGB4_S3TC; - } - else if ( r_texturebits->integer == 16 ) - { - internalFormat = GL_RGB5; - } - else if ( r_texturebits->integer == 32 ) - { - internalFormat = GL_RGB8; - } - else - { - internalFormat = GL_RGB; - } - } - } - else if ( samples == 4 ) - { - if(r_greyscale->integer) - { - if(r_texturebits->integer == 16) - internalFormat = GL_LUMINANCE8_ALPHA8; - else if(r_texturebits->integer == 32) - internalFormat = GL_LUMINANCE16_ALPHA16; - else - internalFormat = GL_LUMINANCE_ALPHA; - } - else - { - if ( r_texturebits->integer == 16 ) - { - internalFormat = GL_RGBA4; - } - else if ( r_texturebits->integer == 32 ) - { - internalFormat = GL_RGBA8; - } - else - { - internalFormat = GL_RGBA; - } - } - } - } - - // copy or resample data as appropriate for first MIP level - if ( ( scaled_width == width ) && - ( scaled_height == height ) ) { - if (!mipmap) - { - qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - *pUploadWidth = scaled_width; - *pUploadHeight = scaled_height; - *format = internalFormat; - - goto done; - } - Com_Memcpy (scaledBuffer, data, width*height*4); - } - else - { - // use the normal mip-mapping function to go down from here - while ( width > scaled_width || height > scaled_height ) { - R_MipMap( (byte *)data, width, height ); - width >>= 1; - height >>= 1; - if ( width < 1 ) { - width = 1; - } - if ( height < 1 ) { - height = 1; - } - } - Com_Memcpy( scaledBuffer, data, width * height * 4 ); - } - - R_LightScaleTexture (scaledBuffer, scaled_width, scaled_height, !mipmap ); - - *pUploadWidth = scaled_width; - *pUploadHeight = scaled_height; - *format = internalFormat; - - qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer ); - - if (mipmap) - { - int miplevel; - - miplevel = 0; - while (scaled_width > 1 || scaled_height > 1) - { - R_MipMap( (byte *)scaledBuffer, scaled_width, scaled_height ); - scaled_width >>= 1; - scaled_height >>= 1; - if (scaled_width < 1) - scaled_width = 1; - if (scaled_height < 1) - scaled_height = 1; - miplevel++; - - if ( r_colorMipLevels->integer ) { - R_BlendOverTexture( (byte *)scaledBuffer, scaled_width * scaled_height, mipBlendColors[miplevel] ); - } - - qglTexImage2D (GL_TEXTURE_2D, miplevel, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer ); - } - } -done: - - if (mipmap) - { - if ( textureFilterAnisotropic ) - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, - (GLint)Com_Clamp( 1, maxAnisotropy, r_ext_max_anisotropy->integer ) ); - - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); - } - else - { - if ( textureFilterAnisotropic ) - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 ); - - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - } - - GL_CheckErrors(); - - if ( scaledBuffer != 0 ) - ri.Hunk_FreeTempMemory( scaledBuffer ); - if ( resampledBuffer != 0 ) - ri.Hunk_FreeTempMemory( resampledBuffer ); -} - - -/* -================ -R_CreateImage - -This is the only way any image_t are created -================ -*/ -image_t *R_CreateImage( const char *name, byte *pic, int width, int height, - imgType_t type, imgFlags_t flags, int internalFormat ) { - image_t *image; - qboolean isLightmap = qfalse; - long hash; - int glWrapClampMode; - - if (strlen(name) >= MAX_QPATH ) { - ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long", name); - } - if ( !strncmp( name, "*lightmap", 9 ) ) { - isLightmap = qtrue; - } - - if ( tr.numImages == MAX_DRAWIMAGES ) { - ri.Error( ERR_DROP, "R_CreateImage: MAX_DRAWIMAGES hit"); - } - - image = tr.images[tr.numImages] = ri.Hunk_Alloc( sizeof( image_t ), h_low ); - image->texnum = 1024 + tr.numImages; - tr.numImages++; - - image->type = type; - image->flags = flags; - - strcpy (image->imgName, name); - - image->width = width; - image->height = height; - if (flags & IMGFLAG_CLAMPTOEDGE) - glWrapClampMode = GL_CLAMP_TO_EDGE; - else - glWrapClampMode = GL_REPEAT; - - // lightmaps are always allocated on TMU 1 - if ( qglActiveTextureARB && isLightmap ) { - image->TMU = 1; - } else { - image->TMU = 0; - } - - if ( qglActiveTextureARB ) { - GL_SelectTexture( image->TMU ); - } - - GL_Bind(image); - - Upload32( (unsigned *)pic, image->width, image->height, - image->flags & IMGFLAG_MIPMAP, - image->flags & IMGFLAG_PICMIP, - isLightmap, - &image->internalFormat, - &image->uploadWidth, - &image->uploadHeight ); - - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode ); - - // FIXME: this stops fog from setting border color? - glState.currenttextures[glState.currenttmu] = 0; - qglBindTexture( GL_TEXTURE_2D, 0 ); - - if ( image->TMU == 1 ) { - GL_SelectTexture( 0 ); - } - - hash = generateHashValue(name); - image->next = hashTable[hash]; - hashTable[hash] = image; - - return image; -} - -//=================================================================== - -typedef struct -{ - char *ext; - void (*ImageLoader)( const char *, unsigned char **, int *, int * ); -} imageExtToLoaderMap_t; - -// Note that the ordering indicates the order of preference used -// when there are multiple images of different formats available -static imageExtToLoaderMap_t imageLoaders[ ] = -{ - { "tga", R_LoadTGA }, - { "jpg", R_LoadJPG }, - { "jpeg", R_LoadJPG }, - { "png", R_LoadPNG }, - { "pcx", R_LoadPCX }, - { "bmp", R_LoadBMP } -}; - -static int numImageLoaders = ARRAY_LEN( imageLoaders ); - -/* -================= -R_LoadImage - -Loads any of the supported image types into a cannonical -32 bit format. -================= -*/ -void R_LoadImage( const char *name, byte **pic, int *width, int *height ) -{ - qboolean orgNameFailed = qfalse; - int orgLoader = -1; - int i; - char localName[ MAX_QPATH ]; - const char *ext; - char *altName; - - *pic = NULL; - *width = 0; - *height = 0; - - Q_strncpyz( localName, name, MAX_QPATH ); - - ext = COM_GetExtension( localName ); - - if( *ext ) - { - // Look for the correct loader and use it - for( i = 0; i < numImageLoaders; i++ ) - { - if( !Q_stricmp( ext, imageLoaders[ i ].ext ) ) - { - // Load - imageLoaders[ i ].ImageLoader( localName, pic, width, height ); - break; - } - } - - // A loader was found - if( i < numImageLoaders ) - { - if( *pic == NULL ) - { - // Loader failed, most likely because the file isn't there; - // try again without the extension - orgNameFailed = qtrue; - orgLoader = i; - COM_StripExtension( name, localName, MAX_QPATH ); - } - else - { - // Something loaded - return; - } - } - } - - // Try and find a suitable match using all - // the image formats supported - for( i = 0; i < numImageLoaders; i++ ) - { - if (i == orgLoader) - continue; - - altName = va( "%s.%s", localName, imageLoaders[ i ].ext ); - - // Load - imageLoaders[ i ].ImageLoader( altName, pic, width, height ); - - if( *pic ) - { - if( orgNameFailed ) - { - ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n", - name, altName ); - } - - break; - } - } -} - - -/* -=============== -R_FindImageFile - -Finds or loads the given image. -Returns NULL if it fails, not a default image. -============== -*/ -image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ) -{ - image_t *image; - int width, height; - byte *pic; - long hash; - - if (!name) { - return NULL; - } - - hash = generateHashValue(name); - - // - // see if the image is already loaded - // - for (image=hashTable[hash]; image; image=image->next) { - if ( !strcmp( name, image->imgName ) ) { - // the white image can be used with any set of parms, but other mismatches are errors - if ( strcmp( name, "*white" ) ) { - if ( image->flags != flags ) { - ri.Printf( PRINT_DEVELOPER, "WARNING: reused image %s with mixed flags (%i vs %i)\n", name, image->flags, flags ); - } - } - return image; - } - } - - // - // load the pic from disk - // - R_LoadImage( name, &pic, &width, &height ); - if ( pic == NULL ) { - return NULL; - } - - image = R_CreateImage( ( char * ) name, pic, width, height, type, flags, 0 ); - ri.Free( pic ); - return image; -} - - -/* -================ -R_CreateDlightImage -================ -*/ -#define DLIGHT_SIZE 16 -static void R_CreateDlightImage( void ) { - int x,y; - byte data[DLIGHT_SIZE][DLIGHT_SIZE][4]; - int b; - - // make a centered inverse-square falloff blob for dynamic lighting - for (x=0 ; x 255) { - b = 255; - } else if ( b < 75 ) { - b = 0; - } - data[y][x][0] = - data[y][x][1] = - data[y][x][2] = b; - data[y][x][3] = 255; - } - } - tr.dlightImage = R_CreateImage("*dlight", (byte *)data, DLIGHT_SIZE, DLIGHT_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_CLAMPTOEDGE, 0 ); -} - - -/* -================= -R_InitFogTable -================= -*/ -void R_InitFogTable( void ) { - int i; - float d; - float exp; - - exp = 0.5; - - for ( i = 0 ; i < FOG_TABLE_SIZE ; i++ ) { - d = pow ( (float)i/(FOG_TABLE_SIZE-1), exp ); - - tr.fogTable[i] = d; - } -} - -/* -================ -R_FogFactor - -Returns a 0.0 to 1.0 fog density value -This is called for each texel of the fog texture on startup -and for each vertex of transparent shaders in fog dynamically -================ -*/ -float R_FogFactor( float s, float t ) { - float d; - - s -= 1.0/512; - if ( s < 0 ) { - return 0; - } - if ( t < 1.0/32 ) { - return 0; - } - if ( t < 31.0/32 ) { - s *= (t - 1.0f/32.0f) / (30.0f/32.0f); - } - - // we need to leave a lot of clamp range - s *= 8; - - if ( s > 1.0 ) { - s = 1.0; - } - - d = tr.fogTable[ (int)(s * (FOG_TABLE_SIZE-1)) ]; - - return d; -} - -/* -================ -R_CreateFogImage -================ -*/ -#define FOG_S 256 -#define FOG_T 32 -static void R_CreateFogImage( void ) { - int x,y; - byte *data; - float d; - float borderColor[4]; - - data = ri.Hunk_AllocateTempMemory( FOG_S * FOG_T * 4 ); - - // S is distance, T is depth - for (x=0 ; xinteger; - if ( !glConfig.deviceSupportsGamma ) { - tr.overbrightBits = 0; // need hardware gamma for overbright - } - - // never overbright in windowed mode - if ( !glConfig.isFullscreen ) - { - tr.overbrightBits = 0; - } - - // allow 2 overbright bits in 24 bit, but only 1 in 16 bit - if ( glConfig.colorBits > 16 ) { - if ( tr.overbrightBits > 2 ) { - tr.overbrightBits = 2; - } - } else { - if ( tr.overbrightBits > 1 ) { - tr.overbrightBits = 1; - } - } - if ( tr.overbrightBits < 0 ) { - tr.overbrightBits = 0; - } - - tr.identityLight = 1.0f / ( 1 << tr.overbrightBits ); - tr.identityLightByte = 255 * tr.identityLight; - - - if ( r_intensity->value <= 1 ) { - ri.Cvar_Set( "r_intensity", "1" ); - } - - if ( r_gamma->value < 0.5f ) { - ri.Cvar_Set( "r_gamma", "0.5" ); - } else if ( r_gamma->value > 3.0f ) { - ri.Cvar_Set( "r_gamma", "3.0" ); - } - - g = r_gamma->value; - - shift = tr.overbrightBits; - - for ( i = 0; i < 256; i++ ) { - if ( g == 1 ) { - inf = i; - } else { - inf = 255 * pow ( i/255.0f, 1.0f / g ) + 0.5f; - } - inf <<= shift; - if (inf < 0) { - inf = 0; - } - if (inf > 255) { - inf = 255; - } - s_gammatable[i] = inf; - } - - for (i=0 ; i<256 ; i++) { - j = i * r_intensity->value; - if (j > 255) { - j = 255; - } - s_intensitytable[i] = j; - } - - if ( glConfig.deviceSupportsGamma ) - { - GLimp_SetGamma( s_gammatable, s_gammatable, s_gammatable ); - } -} - -/* -=============== -R_InitImages -=============== -*/ -void R_InitImages( void ) { - Com_Memset(hashTable, 0, sizeof(hashTable)); - // build brightness translation tables - R_SetColorMappings(); - - // create default texture and white texture - R_CreateBuiltinImages(); -} - -/* -=============== -R_DeleteTextures -=============== -*/ -void R_DeleteTextures( void ) { - int i; - - for ( i=0; itexnum ); - } - Com_Memset( tr.images, 0, sizeof( tr.images ) ); - - tr.numImages = 0; - - Com_Memset( glState.currenttextures, 0, sizeof( glState.currenttextures ) ); - if ( qglActiveTextureARB ) { - GL_SelectTexture( 1 ); - qglBindTexture( GL_TEXTURE_2D, 0 ); - GL_SelectTexture( 0 ); - qglBindTexture( GL_TEXTURE_2D, 0 ); - } else { - qglBindTexture( GL_TEXTURE_2D, 0 ); - } -} - -/* -============================================================================ - -SKINS - -============================================================================ -*/ - -/* -================== -CommaParse - -This is unfortunate, but the skin files aren't -compatable with our normal parsing rules. -================== -*/ -static char *CommaParse( char **data_p ) { - int c = 0, len; - char *data; - static char com_token[MAX_TOKEN_CHARS]; - - data = *data_p; - len = 0; - com_token[0] = 0; - - // make sure incoming data is valid - if ( !data ) { - *data_p = NULL; - return com_token; - } - - while ( 1 ) { - // skip whitespace - while( (c = *data) <= ' ') { - if( !c ) { - break; - } - data++; - } - - - c = *data; - - // skip double slash comments - if ( c == '/' && data[1] == '/' ) - { - while (*data && *data != '\n') - data++; - } - // skip /* */ comments - else if ( c=='/' && data[1] == '*' ) - { - while ( *data && ( *data != '*' || data[1] != '/' ) ) - { - data++; - } - if ( *data ) - { - data += 2; - } - } - else - { - break; - } - } - - if ( c == 0 ) { - return ""; - } - - // handle quoted strings - if (c == '\"') - { - data++; - while (1) - { - c = *data++; - if (c=='\"' || !c) - { - com_token[len] = 0; - *data_p = ( char * ) data; - return com_token; - } - if (len < MAX_TOKEN_CHARS) - { - com_token[len] = c; - len++; - } - } - } - - // parse a regular word - do - { - if (len < MAX_TOKEN_CHARS) - { - com_token[len] = c; - len++; - } - data++; - c = *data; - } while (c>32 && c != ',' ); - - if (len == MAX_TOKEN_CHARS) - { -// ri.Printf (PRINT_DEVELOPER, "Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS); - len = 0; - } - com_token[len] = 0; - - *data_p = ( char * ) data; - return com_token; -} - - -/* -=============== -RE_RegisterSkin - -=============== -*/ -qhandle_t RE_RegisterSkin( const char *name ) { - qhandle_t hSkin; - skin_t *skin; - skinSurface_t *surf; - union { - char *c; - void *v; - } text; - char *text_p; - char *token; - char surfName[MAX_QPATH]; - - if ( !name || !name[0] ) { - ri.Printf( PRINT_DEVELOPER, "Empty name passed to RE_RegisterSkin\n" ); - return 0; - } - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_DEVELOPER, "Skin name exceeds MAX_QPATH\n" ); - return 0; - } - - - // see if the skin is already loaded - for ( hSkin = 1; hSkin < tr.numSkins ; hSkin++ ) { - skin = tr.skins[hSkin]; - if ( !Q_stricmp( skin->name, name ) ) { - if( skin->numSurfaces == 0 ) { - return 0; // default skin - } - return hSkin; - } - } - - // allocate a new skin - if ( tr.numSkins == MAX_SKINS ) { - ri.Printf( PRINT_WARNING, "WARNING: RE_RegisterSkin( '%s' ) MAX_SKINS hit\n", name ); - return 0; - } - tr.numSkins++; - skin = ri.Hunk_Alloc( sizeof( skin_t ), h_low ); - tr.skins[hSkin] = skin; - Q_strncpyz( skin->name, name, sizeof( skin->name ) ); - skin->numSurfaces = 0; - - R_IssuePendingRenderCommands(); - - // If not a .skin file, load as a single shader - if ( strcmp( name + strlen( name ) - 5, ".skin" ) ) { - skin->numSurfaces = 1; - skin->surfaces[0] = ri.Hunk_Alloc( sizeof(skin->surfaces[0]), h_low ); - skin->surfaces[0]->shader = R_FindShader( name, LIGHTMAP_NONE, qtrue ); - return hSkin; - } - - // load and parse the skin file - ri.FS_ReadFile( name, &text.v ); - if ( !text.c ) { - return 0; - } - - text_p = text.c; - while ( text_p && *text_p ) { - // get surface name - token = CommaParse( &text_p ); - Q_strncpyz( surfName, token, sizeof( surfName ) ); - - if ( !token[0] ) { - break; - } - // lowercase the surface name so skin compares are faster - Q_strlwr( surfName ); - - if ( *text_p == ',' ) { - text_p++; - } - - if ( strstr( token, "tag_" ) ) { - continue; - } - - // parse the shader name - token = CommaParse( &text_p ); - - if ( skin->numSurfaces >= MD3_MAX_SURFACES ) { - ri.Printf( PRINT_WARNING, "WARNING: Ignoring surfaces in '%s', the max is %d surfaces!\n", name, MD3_MAX_SURFACES ); - break; - } - - surf = skin->surfaces[ skin->numSurfaces ] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low ); - Q_strncpyz( surf->name, surfName, sizeof( surf->name ) ); - surf->shader = R_FindShader( token, LIGHTMAP_NONE, qtrue ); - skin->numSurfaces++; - } - - ri.FS_FreeFile( text.v ); - - - // never let a skin have 0 shaders - if ( skin->numSurfaces == 0 ) { - return 0; // use default skin - } - - return hSkin; -} - - -/* -=============== -R_InitSkins -=============== -*/ -void R_InitSkins( void ) { - skin_t *skin; - - tr.numSkins = 1; - - // make the default skin have all default shaders - skin = tr.skins[0] = ri.Hunk_Alloc( sizeof( skin_t ), h_low ); - Q_strncpyz( skin->name, "", sizeof( skin->name ) ); - skin->numSurfaces = 1; - skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces ), h_low ); - skin->surfaces[0]->shader = tr.defaultShader; -} - -/* -=============== -R_GetSkinByHandle -=============== -*/ -skin_t *R_GetSkinByHandle( qhandle_t hSkin ) { - if ( hSkin < 1 || hSkin >= tr.numSkins ) { - return tr.skins[0]; - } - return tr.skins[ hSkin ]; -} - -/* -=============== -R_SkinList_f -=============== -*/ -void R_SkinList_f( void ) { - int i, j; - skin_t *skin; - - ri.Printf (PRINT_ALL, "------------------\n"); - - for ( i = 0 ; i < tr.numSkins ; i++ ) { - skin = tr.skins[i]; - - ri.Printf( PRINT_ALL, "%3i:%s\n", i, skin->name ); - for ( j = 0 ; j < skin->numSurfaces ; j++ ) { - ri.Printf( PRINT_ALL, " %s = %s\n", - skin->surfaces[j]->name, skin->surfaces[j]->shader->name ); - } - } - ri.Printf (PRINT_ALL, "------------------\n"); -} - diff --git a/code/renderergl1/tr_init.c b/code/renderergl1/tr_init.c deleted file mode 100644 index 2a934e93b9..0000000000 --- a/code/renderergl1/tr_init.c +++ /dev/null @@ -1,1370 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_init.c -- functions that are not called every frame - -#include "tr_local.h" - -glconfig_t glConfig; -qboolean textureFilterAnisotropic = qfalse; -int maxAnisotropy = 0; -float displayAspect = 0.0f; - -glstate_t glState; - -static void GfxInfo_f( void ); - -#ifdef USE_RENDERER_DLOPEN -cvar_t *com_altivec; -#endif - -cvar_t *r_flareSize; -cvar_t *r_flareFade; -cvar_t *r_flareCoeff; - -cvar_t *r_railWidth; -cvar_t *r_railCoreWidth; -cvar_t *r_railSegmentLength; - -cvar_t *r_ignoreFastPath; - -cvar_t *r_verbose; -cvar_t *r_ignore; - -cvar_t *r_detailTextures; - -cvar_t *r_znear; -cvar_t *r_zproj; -cvar_t *r_stereoSeparation; - -cvar_t *r_skipBackEnd; - -cvar_t *r_stereoEnabled; -cvar_t *r_anaglyphMode; - -cvar_t *r_greyscale; - -cvar_t *r_ignorehwgamma; -cvar_t *r_measureOverdraw; - -cvar_t *r_inGameVideo; -cvar_t *r_fastsky; -cvar_t *r_drawSun; -cvar_t *r_dynamiclight; -cvar_t *r_dlightBacks; - -cvar_t *r_lodbias; -cvar_t *r_lodscale; - -cvar_t *r_norefresh; -cvar_t *r_drawentities; -cvar_t *r_drawworld; -cvar_t *r_speeds; -cvar_t *r_fullbright; -cvar_t *r_novis; -cvar_t *r_nocull; -cvar_t *r_facePlaneCull; -cvar_t *r_showcluster; -cvar_t *r_nocurves; - -cvar_t *r_allowExtensions; - -cvar_t *r_ext_compressed_textures; -cvar_t *r_ext_multitexture; -cvar_t *r_ext_compiled_vertex_array; -cvar_t *r_ext_texture_env_add; -cvar_t *r_ext_texture_filter_anisotropic; -cvar_t *r_ext_max_anisotropy; - -cvar_t *r_ignoreGLErrors; -cvar_t *r_logFile; - -cvar_t *r_stencilbits; -cvar_t *r_depthbits; -cvar_t *r_colorbits; -cvar_t *r_primitives; -cvar_t *r_texturebits; -cvar_t *r_ext_multisample; - -cvar_t *r_drawBuffer; -cvar_t *r_lightmap; -cvar_t *r_vertexLight; -cvar_t *r_uiFullScreen; -cvar_t *r_shadows; -cvar_t *r_flares; -cvar_t *r_mode; -cvar_t *r_nobind; -cvar_t *r_singleShader; -cvar_t *r_roundImagesDown; -cvar_t *r_colorMipLevels; -cvar_t *r_picmip; -cvar_t *r_showtris; -cvar_t *r_showsky; -cvar_t *r_shownormals; -cvar_t *r_finish; -cvar_t *r_clear; -cvar_t *r_swapInterval; -cvar_t *r_textureMode; -cvar_t *r_offsetFactor; -cvar_t *r_offsetUnits; -cvar_t *r_gamma; -cvar_t *r_intensity; -cvar_t *r_lockpvs; -cvar_t *r_noportals; -cvar_t *r_portalOnly; - -cvar_t *r_subdivisions; -cvar_t *r_lodCurveError; - -cvar_t *r_fullscreen; -cvar_t *r_noborder; - -cvar_t *r_customwidth; -cvar_t *r_customheight; -cvar_t *r_customPixelAspect; - -cvar_t *r_overBrightBits; -cvar_t *r_mapOverBrightBits; - -cvar_t *r_debugSurface; -cvar_t *r_simpleMipMaps; - -cvar_t *r_showImages; - -cvar_t *r_ambientScale; -cvar_t *r_directedScale; -cvar_t *r_debugLight; -cvar_t *r_debugSort; -cvar_t *r_printShaders; -cvar_t *r_saveFontData; - -cvar_t *r_marksOnTriangleMeshes; - -cvar_t *r_aviMotionJpegQuality; -cvar_t *r_screenshotJpegQuality; - -cvar_t *r_maxpolys; -int max_polys; -cvar_t *r_maxpolyverts; -int max_polyverts; - -/* -** InitOpenGL -** -** This function is responsible for initializing a valid OpenGL subsystem. This -** is done by calling GLimp_Init (which gives us a working OGL subsystem) then -** setting variables, checking GL constants, and reporting the gfx system config -** to the user. -*/ -static void InitOpenGL( void ) -{ - char renderer_buffer[1024]; - - // - // initialize OS specific portions of the renderer - // - // GLimp_Init directly or indirectly references the following cvars: - // - r_fullscreen - // - r_mode - // - r_(color|depth|stencil)bits - // - r_ignorehwgamma - // - r_gamma - // - - if ( glConfig.vidWidth == 0 ) - { - GLint temp; - - GLimp_Init(); - - strcpy( renderer_buffer, glConfig.renderer_string ); - Q_strlwr( renderer_buffer ); - - // OpenGL driver constants - qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp ); - glConfig.maxTextureSize = temp; - - // stubbed or broken drivers may have reported 0... - if ( glConfig.maxTextureSize <= 0 ) - { - glConfig.maxTextureSize = 0; - } - } - - // set default state - GL_SetDefaultState(); -} - -/* -================== -GL_CheckErrors -================== -*/ -void GL_CheckErrors( void ) { - int err; - char s[64]; - - err = qglGetError(); - if ( err == GL_NO_ERROR ) { - return; - } - if ( r_ignoreGLErrors->integer ) { - return; - } - switch( err ) { - case GL_INVALID_ENUM: - strcpy( s, "GL_INVALID_ENUM" ); - break; - case GL_INVALID_VALUE: - strcpy( s, "GL_INVALID_VALUE" ); - break; - case GL_INVALID_OPERATION: - strcpy( s, "GL_INVALID_OPERATION" ); - break; - case GL_STACK_OVERFLOW: - strcpy( s, "GL_STACK_OVERFLOW" ); - break; - case GL_STACK_UNDERFLOW: - strcpy( s, "GL_STACK_UNDERFLOW" ); - break; - case GL_OUT_OF_MEMORY: - strcpy( s, "GL_OUT_OF_MEMORY" ); - break; - default: - Com_sprintf( s, sizeof(s), "%i", err); - break; - } - - ri.Error( ERR_FATAL, "GL_CheckErrors: %s", s ); -} - - -/* -** R_GetModeInfo -*/ -typedef struct vidmode_s -{ - const char *description; - int width, height; - float pixelAspect; // pixel width / height -} vidmode_t; - -vidmode_t r_vidModes[] = -{ - { "Mode 0: 320x240", 320, 240, 1 }, - { "Mode 1: 400x300", 400, 300, 1 }, - { "Mode 2: 512x384", 512, 384, 1 }, - { "Mode 3: 640x480", 640, 480, 1 }, - { "Mode 4: 800x600", 800, 600, 1 }, - { "Mode 5: 960x720", 960, 720, 1 }, - { "Mode 6: 1024x768", 1024, 768, 1 }, - { "Mode 7: 1152x864", 1152, 864, 1 }, - { "Mode 8: 1280x1024", 1280, 1024, 1 }, - { "Mode 9: 1600x1200", 1600, 1200, 1 }, - { "Mode 10: 2048x1536", 2048, 1536, 1 }, - { "Mode 11: 856x480 (wide)",856, 480, 1 } -}; -static int s_numVidModes = ARRAY_LEN( r_vidModes ); - -qboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode ) { - vidmode_t *vm; - float pixelAspect; - - if ( mode < -1 ) { - return qfalse; - } - if ( mode >= s_numVidModes ) { - return qfalse; - } - - if ( mode == -1 ) { - *width = r_customwidth->integer; - *height = r_customheight->integer; - pixelAspect = r_customPixelAspect->value; - } else { - vm = &r_vidModes[mode]; - - *width = vm->width; - *height = vm->height; - pixelAspect = vm->pixelAspect; - } - - *windowAspect = (float)*width / ( *height * pixelAspect ); - - return qtrue; -} - -/* -** R_ModeList_f -*/ -static void R_ModeList_f( void ) -{ - int i; - - ri.Printf( PRINT_ALL, "\n" ); - for ( i = 0; i < s_numVidModes; i++ ) - { - ri.Printf( PRINT_ALL, "%s\n", r_vidModes[i].description ); - } - ri.Printf( PRINT_ALL, "\n" ); -} - - -/* -============================================================================== - - SCREEN SHOTS - -NOTE TTimo -some thoughts about the screenshots system: -screenshots get written in fs_homepath + fs_gamedir -vanilla q3 .. baseq3/screenshots/ *.tga -team arena .. missionpack/screenshots/ *.tga - -two commands: "screenshot" and "screenshotJPEG" -we use statics to store a count and start writing the first screenshot/screenshot????.tga (.jpg) available -(with FS_FileExists / FS_FOpenFileWrite calls) -FIXME: the statics don't get a reinit between fs_game changes - -============================================================================== -*/ - -/* -================== -RB_ReadPixels - -Reads an image but takes care of alignment issues for reading RGB images. - -Reads a minimum offset for where the RGB data starts in the image from -integer stored at pointer offset. When the function has returned the actual -offset was written back to address offset. This address will always have an -alignment of packAlign to ensure efficient copying. - -Stores the length of padding after a line of pixels to address padlen - -Return value must be freed with ri.Hunk_FreeTempMemory() -================== -*/ - -byte *RB_ReadPixels(int x, int y, int width, int height, size_t *offset, int *padlen) -{ - byte *buffer, *bufstart; - int padwidth, linelen; - GLint packAlign; - - qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign); - - linelen = width * 3; - padwidth = PAD(linelen, packAlign); - - // Allocate a few more bytes so that we can choose an alignment we like - buffer = ri.Hunk_AllocateTempMemory(padwidth * height + *offset + packAlign - 1); - - bufstart = PADP((intptr_t) buffer + *offset, packAlign); - qglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, bufstart); - - *offset = bufstart - buffer; - *padlen = padwidth - linelen; - - return buffer; -} - -/* -================== -RB_TakeScreenshot -================== -*/ -void RB_TakeScreenshot(int x, int y, int width, int height, char *fileName) -{ - byte *allbuf, *buffer; - byte *srcptr, *destptr; - byte *endline, *endmem; - byte temp; - - int linelen, padlen; - size_t offset = 18, memcount; - - allbuf = RB_ReadPixels(x, y, width, height, &offset, &padlen); - buffer = allbuf + offset - 18; - - Com_Memset (buffer, 0, 18); - buffer[2] = 2; // uncompressed type - buffer[12] = width & 255; - buffer[13] = width >> 8; - buffer[14] = height & 255; - buffer[15] = height >> 8; - buffer[16] = 24; // pixel size - - // swap rgb to bgr and remove padding from line endings - linelen = width * 3; - - srcptr = destptr = allbuf + offset; - endmem = srcptr + (linelen + padlen) * height; - - while(srcptr < endmem) - { - endline = srcptr + linelen; - - while(srcptr < endline) - { - temp = srcptr[0]; - *destptr++ = srcptr[2]; - *destptr++ = srcptr[1]; - *destptr++ = temp; - - srcptr += 3; - } - - // Skip the pad - srcptr += padlen; - } - - memcount = linelen * height; - - // gamma correct - if(glConfig.deviceSupportsGamma) - R_GammaCorrect(allbuf + offset, memcount); - - ri.FS_WriteFile(fileName, buffer, memcount + 18); - - ri.Hunk_FreeTempMemory(allbuf); -} - -/* -================== -RB_TakeScreenshotJPEG -================== -*/ - -void RB_TakeScreenshotJPEG(int x, int y, int width, int height, char *fileName) -{ - byte *buffer; - size_t offset = 0, memcount; - int padlen; - - buffer = RB_ReadPixels(x, y, width, height, &offset, &padlen); - memcount = (width * 3 + padlen) * height; - - // gamma correct - if(glConfig.deviceSupportsGamma) - R_GammaCorrect(buffer + offset, memcount); - - RE_SaveJPG(fileName, r_screenshotJpegQuality->integer, width, height, buffer + offset, padlen); - ri.Hunk_FreeTempMemory(buffer); -} - -/* -================== -RB_TakeScreenshotCmd -================== -*/ -const void *RB_TakeScreenshotCmd( const void *data ) { - const screenshotCommand_t *cmd; - - cmd = (const screenshotCommand_t *)data; - - if (cmd->jpeg) - RB_TakeScreenshotJPEG( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName); - else - RB_TakeScreenshot( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName); - - return (const void *)(cmd + 1); -} - -/* -================== -R_TakeScreenshot -================== -*/ -void R_TakeScreenshot( int x, int y, int width, int height, char *name, qboolean jpeg ) { - static char fileName[MAX_OSPATH]; // bad things if two screenshots per frame? - screenshotCommand_t *cmd; - - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_SCREENSHOT; - - cmd->x = x; - cmd->y = y; - cmd->width = width; - cmd->height = height; - Q_strncpyz( fileName, name, sizeof(fileName) ); - cmd->fileName = fileName; - cmd->jpeg = jpeg; -} - -/* -================== -R_ScreenshotFilename -================== -*/ -void R_ScreenshotFilename( int lastNumber, char *fileName ) { - int a,b,c,d; - - if ( lastNumber < 0 || lastNumber > 9999 ) { - Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot9999.tga" ); - return; - } - - a = lastNumber / 1000; - lastNumber -= a*1000; - b = lastNumber / 100; - lastNumber -= b*100; - c = lastNumber / 10; - lastNumber -= c*10; - d = lastNumber; - - Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot%i%i%i%i.tga" - , a, b, c, d ); -} - -/* -================== -R_ScreenshotFilename -================== -*/ -void R_ScreenshotFilenameJPEG( int lastNumber, char *fileName ) { - int a,b,c,d; - - if ( lastNumber < 0 || lastNumber > 9999 ) { - Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot9999.jpg" ); - return; - } - - a = lastNumber / 1000; - lastNumber -= a*1000; - b = lastNumber / 100; - lastNumber -= b*100; - c = lastNumber / 10; - lastNumber -= c*10; - d = lastNumber; - - Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot%i%i%i%i.jpg" - , a, b, c, d ); -} - -/* -==================== -R_LevelShot - -levelshots are specialized 128*128 thumbnails for -the menu system, sampled down from full screen distorted images -==================== -*/ -void R_LevelShot( void ) { - char checkname[MAX_OSPATH]; - byte *buffer; - byte *source, *allsource; - byte *src, *dst; - size_t offset = 0; - int padlen; - int x, y; - int r, g, b; - float xScale, yScale; - int xx, yy; - - Com_sprintf(checkname, sizeof(checkname), "levelshots/%s.tga", tr.world->baseName); - - allsource = RB_ReadPixels(0, 0, glConfig.vidWidth, glConfig.vidHeight, &offset, &padlen); - source = allsource + offset; - - buffer = ri.Hunk_AllocateTempMemory(128 * 128*3 + 18); - Com_Memset (buffer, 0, 18); - buffer[2] = 2; // uncompressed type - buffer[12] = 128; - buffer[14] = 128; - buffer[16] = 24; // pixel size - - // resample from source - xScale = glConfig.vidWidth / 512.0f; - yScale = glConfig.vidHeight / 384.0f; - for ( y = 0 ; y < 128 ; y++ ) { - for ( x = 0 ; x < 128 ; x++ ) { - r = g = b = 0; - for ( yy = 0 ; yy < 3 ; yy++ ) { - for ( xx = 0 ; xx < 4 ; xx++ ) { - src = source + (3 * glConfig.vidWidth + padlen) * (int)((y*3 + yy) * yScale) + - 3 * (int) ((x*4 + xx) * xScale); - r += src[0]; - g += src[1]; - b += src[2]; - } - } - dst = buffer + 18 + 3 * ( y * 128 + x ); - dst[0] = b / 12; - dst[1] = g / 12; - dst[2] = r / 12; - } - } - - // gamma correct - if ( glConfig.deviceSupportsGamma ) { - R_GammaCorrect( buffer + 18, 128 * 128 * 3 ); - } - - ri.FS_WriteFile( checkname, buffer, 128 * 128*3 + 18 ); - - ri.Hunk_FreeTempMemory(buffer); - ri.Hunk_FreeTempMemory(allsource); - - ri.Printf( PRINT_ALL, "Wrote %s\n", checkname ); -} - -/* -================== -R_ScreenShot_f - -screenshot -screenshot [silent] -screenshot [levelshot] -screenshot [filename] - -Doesn't print the pacifier message if there is a second arg -================== -*/ -void R_ScreenShot_f (void) { - char checkname[MAX_OSPATH]; - static int lastNumber = -1; - qboolean silent; - - if ( !strcmp( ri.Cmd_Argv(1), "levelshot" ) ) { - R_LevelShot(); - return; - } - - if ( !strcmp( ri.Cmd_Argv(1), "silent" ) ) { - silent = qtrue; - } else { - silent = qfalse; - } - - if ( ri.Cmd_Argc() == 2 && !silent ) { - // explicit filename - Com_sprintf( checkname, MAX_OSPATH, "screenshots/%s.tga", ri.Cmd_Argv( 1 ) ); - } else { - // scan for a free filename - - // if we have saved a previous screenshot, don't scan - // again, because recording demo avis can involve - // thousands of shots - if ( lastNumber == -1 ) { - lastNumber = 0; - } - // scan for a free number - for ( ; lastNumber <= 9999 ; lastNumber++ ) { - R_ScreenshotFilename( lastNumber, checkname ); - - if (!ri.FS_FileExists( checkname )) - { - break; // file doesn't exist - } - } - - if ( lastNumber >= 9999 ) { - ri.Printf (PRINT_ALL, "ScreenShot: Couldn't create a file\n"); - return; - } - - lastNumber++; - } - - R_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, qfalse ); - - if ( !silent ) { - ri.Printf (PRINT_ALL, "Wrote %s\n", checkname); - } -} - -void R_ScreenShotJPEG_f (void) { - char checkname[MAX_OSPATH]; - static int lastNumber = -1; - qboolean silent; - - if ( !strcmp( ri.Cmd_Argv(1), "levelshot" ) ) { - R_LevelShot(); - return; - } - - if ( !strcmp( ri.Cmd_Argv(1), "silent" ) ) { - silent = qtrue; - } else { - silent = qfalse; - } - - if ( ri.Cmd_Argc() == 2 && !silent ) { - // explicit filename - Com_sprintf( checkname, MAX_OSPATH, "screenshots/%s.jpg", ri.Cmd_Argv( 1 ) ); - } else { - // scan for a free filename - - // if we have saved a previous screenshot, don't scan - // again, because recording demo avis can involve - // thousands of shots - if ( lastNumber == -1 ) { - lastNumber = 0; - } - // scan for a free number - for ( ; lastNumber <= 9999 ; lastNumber++ ) { - R_ScreenshotFilenameJPEG( lastNumber, checkname ); - - if (!ri.FS_FileExists( checkname )) - { - break; // file doesn't exist - } - } - - if ( lastNumber == 10000 ) { - ri.Printf (PRINT_ALL, "ScreenShot: Couldn't create a file\n"); - return; - } - - lastNumber++; - } - - R_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, qtrue ); - - if ( !silent ) { - ri.Printf (PRINT_ALL, "Wrote %s\n", checkname); - } -} - -//============================================================================ - -/* -================== -RB_TakeVideoFrameCmd -================== -*/ -const void *RB_TakeVideoFrameCmd( const void *data ) -{ - const videoFrameCommand_t *cmd; - byte *cBuf; - size_t memcount, linelen; - int padwidth, avipadwidth, padlen, avipadlen; - GLint packAlign; - - cmd = (const videoFrameCommand_t *)data; - - qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign); - - linelen = cmd->width * 3; - - // Alignment stuff for glReadPixels - padwidth = PAD(linelen, packAlign); - padlen = padwidth - linelen; - // AVI line padding - avipadwidth = PAD(linelen, AVI_LINE_PADDING); - avipadlen = avipadwidth - linelen; - - cBuf = PADP(cmd->captureBuffer, packAlign); - - qglReadPixels(0, 0, cmd->width, cmd->height, GL_RGB, - GL_UNSIGNED_BYTE, cBuf); - - memcount = padwidth * cmd->height; - - // gamma correct - if(glConfig.deviceSupportsGamma) - R_GammaCorrect(cBuf, memcount); - - if(cmd->motionJpeg) - { - memcount = RE_SaveJPGToBuffer(cmd->encodeBuffer, linelen * cmd->height, - r_aviMotionJpegQuality->integer, - cmd->width, cmd->height, cBuf, padlen); - ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, memcount); - } - else - { - byte *lineend, *memend; - byte *srcptr, *destptr; - - srcptr = cBuf; - destptr = cmd->encodeBuffer; - memend = srcptr + memcount; - - // swap R and B and remove line paddings - while(srcptr < memend) - { - lineend = srcptr + linelen; - while(srcptr < lineend) - { - *destptr++ = srcptr[2]; - *destptr++ = srcptr[1]; - *destptr++ = srcptr[0]; - srcptr += 3; - } - - Com_Memset(destptr, '\0', avipadlen); - destptr += avipadlen; - - srcptr += padlen; - } - - ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, avipadwidth * cmd->height); - } - - return (const void *)(cmd + 1); -} - -//============================================================================ - -/* -** GL_SetDefaultState -*/ -void GL_SetDefaultState( void ) -{ - qglClearDepth( 1.0f ); - - qglCullFace(GL_FRONT); - - qglColor4f (1,1,1,1); - - // initialize downstream texture unit if we're running - // in a multitexture environment - if ( qglActiveTextureARB ) { - GL_SelectTexture( 1 ); - GL_TextureMode( r_textureMode->string ); - GL_TexEnv( GL_MODULATE ); - qglDisable( GL_TEXTURE_2D ); - GL_SelectTexture( 0 ); - } - - qglEnable(GL_TEXTURE_2D); - GL_TextureMode( r_textureMode->string ); - GL_TexEnv( GL_MODULATE ); - - qglShadeModel( GL_SMOOTH ); - qglDepthFunc( GL_LEQUAL ); - - // the vertex array is always enabled, but the color and texture - // arrays are enabled and disabled around the compiled vertex array call - qglEnableClientState (GL_VERTEX_ARRAY); - - // - // make sure our GL state vector is set correctly - // - glState.glStateBits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_TRUE; - - qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); - qglDepthMask( GL_TRUE ); - qglDisable( GL_DEPTH_TEST ); - qglEnable( GL_SCISSOR_TEST ); - qglDisable( GL_CULL_FACE ); - qglDisable( GL_BLEND ); -} - -/* -================ -R_PrintLongString - -Workaround for ri.Printf's 1024 characters buffer limit. -================ -*/ -void R_PrintLongString(const char *string) { - char buffer[1024]; - const char *p; - int size = strlen(string); - - p = string; - while(size > 0) - { - Q_strncpyz(buffer, p, sizeof (buffer) ); - ri.Printf( PRINT_ALL, "%s", buffer ); - p += 1023; - size -= 1023; - } -} - -/* -================ -GfxInfo_f -================ -*/ -void GfxInfo_f( void ) -{ - const char *enablestrings[] = - { - "disabled", - "enabled" - }; - const char *fsstrings[] = - { - "windowed", - "fullscreen" - }; - - ri.Printf( PRINT_ALL, "\nGL_VENDOR: %s\n", glConfig.vendor_string ); - ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glConfig.renderer_string ); - ri.Printf( PRINT_ALL, "GL_VERSION: %s\n", glConfig.version_string ); - ri.Printf( PRINT_ALL, "GL_EXTENSIONS: " ); - R_PrintLongString( glConfig.extensions_string ); - ri.Printf( PRINT_ALL, "\n" ); - ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_SIZE: %d\n", glConfig.maxTextureSize ); - ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_UNITS_ARB: %d\n", glConfig.numTextureUnits ); - ri.Printf( PRINT_ALL, "\nPIXELFORMAT: color(%d-bits) Z(%d-bit) stencil(%d-bits)\n", glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits ); - ri.Printf( PRINT_ALL, "MODE: %d, %d x %d %s hz:", r_mode->integer, glConfig.vidWidth, glConfig.vidHeight, fsstrings[r_fullscreen->integer == 1] ); - if ( glConfig.displayFrequency ) - { - ri.Printf( PRINT_ALL, "%d\n", glConfig.displayFrequency ); - } - else - { - ri.Printf( PRINT_ALL, "N/A\n" ); - } - if ( glConfig.deviceSupportsGamma ) - { - ri.Printf( PRINT_ALL, "GAMMA: hardware w/ %d overbright bits\n", tr.overbrightBits ); - } - else - { - ri.Printf( PRINT_ALL, "GAMMA: software w/ %d overbright bits\n", tr.overbrightBits ); - } - - // rendering primitives - { - int primitives; - - // default is to use triangles if compiled vertex arrays are present - ri.Printf( PRINT_ALL, "rendering primitives: " ); - primitives = r_primitives->integer; - if ( primitives == 0 ) { - if ( qglLockArraysEXT ) { - primitives = 2; - } else { - primitives = 1; - } - } - if ( primitives == -1 ) { - ri.Printf( PRINT_ALL, "none\n" ); - } else if ( primitives == 2 ) { - ri.Printf( PRINT_ALL, "single glDrawElements\n" ); - } else if ( primitives == 1 ) { - ri.Printf( PRINT_ALL, "multiple glArrayElement\n" ); - } else if ( primitives == 3 ) { - ri.Printf( PRINT_ALL, "multiple glColor4ubv + glTexCoord2fv + glVertex3fv\n" ); - } - } - - ri.Printf( PRINT_ALL, "texturemode: %s\n", r_textureMode->string ); - ri.Printf( PRINT_ALL, "picmip: %d\n", r_picmip->integer ); - ri.Printf( PRINT_ALL, "texture bits: %d\n", r_texturebits->integer ); - ri.Printf( PRINT_ALL, "multitexture: %s\n", enablestrings[qglActiveTextureARB != 0] ); - ri.Printf( PRINT_ALL, "compiled vertex arrays: %s\n", enablestrings[qglLockArraysEXT != 0 ] ); - ri.Printf( PRINT_ALL, "texenv add: %s\n", enablestrings[glConfig.textureEnvAddAvailable != 0] ); - ri.Printf( PRINT_ALL, "compressed textures: %s\n", enablestrings[glConfig.textureCompression!=TC_NONE] ); - if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) - { - ri.Printf( PRINT_ALL, "HACK: using vertex lightmap approximation\n" ); - } - if ( glConfig.hardwareType == GLHW_RAGEPRO ) - { - ri.Printf( PRINT_ALL, "HACK: ragePro approximations\n" ); - } - if ( glConfig.hardwareType == GLHW_RIVA128 ) - { - ri.Printf( PRINT_ALL, "HACK: riva128 approximations\n" ); - } - if ( r_finish->integer ) { - ri.Printf( PRINT_ALL, "Forcing glFinish\n" ); - } -} - -/* -=============== -R_Register -=============== -*/ -void R_Register( void ) -{ - #ifdef USE_RENDERER_DLOPEN - com_altivec = ri.Cvar_Get("com_altivec", "1", CVAR_ARCHIVE); - #endif - - // - // latched and archived variables - // - r_allowExtensions = ri.Cvar_Get( "r_allowExtensions", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_compressed_textures = ri.Cvar_Get( "r_ext_compressed_textures", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_multitexture = ri.Cvar_Get( "r_ext_multitexture", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_compiled_vertex_array = ri.Cvar_Get( "r_ext_compiled_vertex_array", "1", CVAR_ARCHIVE | CVAR_LATCH); - r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE | CVAR_LATCH); - - r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic", - "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_max_anisotropy = ri.Cvar_Get( "r_ext_max_anisotropy", "2", CVAR_ARCHIVE | CVAR_LATCH ); - - r_picmip = ri.Cvar_Get ("r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_roundImagesDown = ri.Cvar_Get ("r_roundImagesDown", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_colorMipLevels = ri.Cvar_Get ("r_colorMipLevels", "0", CVAR_LATCH ); - ri.Cvar_CheckRange( r_picmip, 0, 16, qtrue ); - r_detailTextures = ri.Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_texturebits = ri.Cvar_Get( "r_texturebits", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_colorbits = ri.Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_stencilbits = ri.Cvar_Get( "r_stencilbits", "8", CVAR_ARCHIVE | CVAR_LATCH ); - r_depthbits = ri.Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_multisample = ri.Cvar_Get( "r_ext_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH ); - ri.Cvar_CheckRange( r_ext_multisample, 0, 4, qtrue ); - r_overBrightBits = ri.Cvar_Get ("r_overBrightBits", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_ignorehwgamma = ri.Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH); - r_mode = ri.Cvar_Get( "r_mode", "3", CVAR_ARCHIVE | CVAR_LATCH ); - r_fullscreen = ri.Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE ); - r_noborder = ri.Cvar_Get("r_noborder", "0", CVAR_ARCHIVE | CVAR_LATCH); - r_customwidth = ri.Cvar_Get( "r_customwidth", "1600", CVAR_ARCHIVE | CVAR_LATCH ); - r_customheight = ri.Cvar_Get( "r_customheight", "1024", CVAR_ARCHIVE | CVAR_LATCH ); - r_customPixelAspect = ri.Cvar_Get( "r_customPixelAspect", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_simpleMipMaps = ri.Cvar_Get( "r_simpleMipMaps", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_vertexLight = ri.Cvar_Get( "r_vertexLight", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_uiFullScreen = ri.Cvar_Get( "r_uifullscreen", "0", 0); - r_subdivisions = ri.Cvar_Get ("r_subdivisions", "4", CVAR_ARCHIVE | CVAR_LATCH); - r_stereoEnabled = ri.Cvar_Get( "r_stereoEnabled", "0", CVAR_ARCHIVE | CVAR_LATCH); - r_ignoreFastPath = ri.Cvar_Get( "r_ignoreFastPath", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_greyscale = ri.Cvar_Get("r_greyscale", "0", CVAR_ARCHIVE | CVAR_LATCH); - ri.Cvar_CheckRange(r_greyscale, 0, 1, qfalse); - - // - // temporary latched variables that can only change over a restart - // - r_fullbright = ri.Cvar_Get ("r_fullbright", "0", CVAR_LATCH|CVAR_CHEAT ); - r_mapOverBrightBits = ri.Cvar_Get ("r_mapOverBrightBits", "2", CVAR_LATCH ); - r_intensity = ri.Cvar_Get ("r_intensity", "1", CVAR_LATCH ); - r_singleShader = ri.Cvar_Get ("r_singleShader", "0", CVAR_CHEAT | CVAR_LATCH ); - - // - // archived variables that can change at any time - // - r_lodCurveError = ri.Cvar_Get( "r_lodCurveError", "250", CVAR_ARCHIVE|CVAR_CHEAT ); - r_lodbias = ri.Cvar_Get( "r_lodbias", "0", CVAR_ARCHIVE ); - r_flares = ri.Cvar_Get ("r_flares", "0", CVAR_ARCHIVE ); - r_znear = ri.Cvar_Get( "r_znear", "4", CVAR_CHEAT ); - ri.Cvar_CheckRange( r_znear, 0.001f, 200, qfalse ); - r_zproj = ri.Cvar_Get( "r_zproj", "64", CVAR_ARCHIVE ); - r_stereoSeparation = ri.Cvar_Get( "r_stereoSeparation", "64", CVAR_ARCHIVE ); - r_ignoreGLErrors = ri.Cvar_Get( "r_ignoreGLErrors", "1", CVAR_ARCHIVE ); - r_fastsky = ri.Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE ); - r_inGameVideo = ri.Cvar_Get( "r_inGameVideo", "1", CVAR_ARCHIVE ); - r_drawSun = ri.Cvar_Get( "r_drawSun", "0", CVAR_ARCHIVE ); - r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE ); - r_dlightBacks = ri.Cvar_Get( "r_dlightBacks", "1", CVAR_ARCHIVE ); - r_finish = ri.Cvar_Get ("r_finish", "0", CVAR_ARCHIVE); - r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE ); - r_swapInterval = ri.Cvar_Get( "r_swapInterval", "0", - CVAR_ARCHIVE | CVAR_LATCH ); - r_gamma = ri.Cvar_Get( "r_gamma", "1", CVAR_ARCHIVE ); - r_facePlaneCull = ri.Cvar_Get ("r_facePlaneCull", "1", CVAR_ARCHIVE ); - - r_railWidth = ri.Cvar_Get( "r_railWidth", "16", CVAR_ARCHIVE ); - r_railCoreWidth = ri.Cvar_Get( "r_railCoreWidth", "6", CVAR_ARCHIVE ); - r_railSegmentLength = ri.Cvar_Get( "r_railSegmentLength", "32", CVAR_ARCHIVE ); - - r_primitives = ri.Cvar_Get( "r_primitives", "0", CVAR_ARCHIVE ); - - r_ambientScale = ri.Cvar_Get( "r_ambientScale", "0.6", CVAR_CHEAT ); - r_directedScale = ri.Cvar_Get( "r_directedScale", "1", CVAR_CHEAT ); - - r_anaglyphMode = ri.Cvar_Get("r_anaglyphMode", "0", CVAR_ARCHIVE); - - // - // temporary variables that can change at any time - // - r_showImages = ri.Cvar_Get( "r_showImages", "0", CVAR_TEMP ); - - r_debugLight = ri.Cvar_Get( "r_debuglight", "0", CVAR_TEMP ); - r_debugSort = ri.Cvar_Get( "r_debugSort", "0", CVAR_CHEAT ); - r_printShaders = ri.Cvar_Get( "r_printShaders", "0", 0 ); - r_saveFontData = ri.Cvar_Get( "r_saveFontData", "0", 0 ); - - r_nocurves = ri.Cvar_Get ("r_nocurves", "0", CVAR_CHEAT ); - r_drawworld = ri.Cvar_Get ("r_drawworld", "1", CVAR_CHEAT ); - r_lightmap = ri.Cvar_Get ("r_lightmap", "0", 0 ); - r_portalOnly = ri.Cvar_Get ("r_portalOnly", "0", CVAR_CHEAT ); - - r_flareSize = ri.Cvar_Get ("r_flareSize", "40", CVAR_CHEAT); - r_flareFade = ri.Cvar_Get ("r_flareFade", "7", CVAR_CHEAT); - r_flareCoeff = ri.Cvar_Get ("r_flareCoeff", FLARE_STDCOEFF, CVAR_CHEAT); - - r_skipBackEnd = ri.Cvar_Get ("r_skipBackEnd", "0", CVAR_CHEAT); - - r_measureOverdraw = ri.Cvar_Get( "r_measureOverdraw", "0", CVAR_CHEAT ); - r_lodscale = ri.Cvar_Get( "r_lodscale", "5", CVAR_CHEAT ); - r_norefresh = ri.Cvar_Get ("r_norefresh", "0", CVAR_CHEAT); - r_drawentities = ri.Cvar_Get ("r_drawentities", "1", CVAR_CHEAT ); - r_ignore = ri.Cvar_Get( "r_ignore", "1", CVAR_CHEAT ); - r_nocull = ri.Cvar_Get ("r_nocull", "0", CVAR_CHEAT); - r_novis = ri.Cvar_Get ("r_novis", "0", CVAR_CHEAT); - r_showcluster = ri.Cvar_Get ("r_showcluster", "0", CVAR_CHEAT); - r_speeds = ri.Cvar_Get ("r_speeds", "0", CVAR_CHEAT); - r_verbose = ri.Cvar_Get( "r_verbose", "0", CVAR_CHEAT ); - r_logFile = ri.Cvar_Get( "r_logFile", "0", CVAR_CHEAT ); - r_debugSurface = ri.Cvar_Get ("r_debugSurface", "0", CVAR_CHEAT); - r_nobind = ri.Cvar_Get ("r_nobind", "0", CVAR_CHEAT); - r_showtris = ri.Cvar_Get ("r_showtris", "0", CVAR_CHEAT); - r_showsky = ri.Cvar_Get ("r_showsky", "0", CVAR_CHEAT); - r_shownormals = ri.Cvar_Get ("r_shownormals", "0", CVAR_CHEAT); - r_clear = ri.Cvar_Get ("r_clear", "0", CVAR_CHEAT); - r_offsetFactor = ri.Cvar_Get( "r_offsetfactor", "-1", CVAR_CHEAT ); - r_offsetUnits = ri.Cvar_Get( "r_offsetunits", "-2", CVAR_CHEAT ); - r_drawBuffer = ri.Cvar_Get( "r_drawBuffer", "GL_BACK", CVAR_CHEAT ); - r_lockpvs = ri.Cvar_Get ("r_lockpvs", "0", CVAR_CHEAT); - r_noportals = ri.Cvar_Get ("r_noportals", "0", CVAR_CHEAT); - r_shadows = ri.Cvar_Get( "cg_shadows", "1", 0 ); - - r_marksOnTriangleMeshes = ri.Cvar_Get("r_marksOnTriangleMeshes", "0", CVAR_ARCHIVE); - - r_aviMotionJpegQuality = ri.Cvar_Get("r_aviMotionJpegQuality", "90", CVAR_ARCHIVE); - r_screenshotJpegQuality = ri.Cvar_Get("r_screenshotJpegQuality", "90", CVAR_ARCHIVE); - - r_maxpolys = ri.Cvar_Get( "r_maxpolys", va("%d", MAX_POLYS), 0); - r_maxpolyverts = ri.Cvar_Get( "r_maxpolyverts", va("%d", MAX_POLYVERTS), 0); - - // make sure all the commands added here are also - // removed in R_Shutdown - ri.Cmd_AddCommand( "imagelist", R_ImageList_f ); - ri.Cmd_AddCommand( "shaderlist", R_ShaderList_f ); - ri.Cmd_AddCommand( "skinlist", R_SkinList_f ); - ri.Cmd_AddCommand( "modellist", R_Modellist_f ); - ri.Cmd_AddCommand( "modelist", R_ModeList_f ); - ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f ); - ri.Cmd_AddCommand( "screenshotJPEG", R_ScreenShotJPEG_f ); - ri.Cmd_AddCommand( "gfxinfo", GfxInfo_f ); - ri.Cmd_AddCommand( "minimize", GLimp_Minimize ); -} - -/* -=============== -R_Init -=============== -*/ -void R_Init( void ) { - int err; - int i; - byte *ptr; - - ri.Printf( PRINT_ALL, "----- R_Init -----\n" ); - - // clear all our internal state - Com_Memset( &tr, 0, sizeof( tr ) ); - Com_Memset( &backEnd, 0, sizeof( backEnd ) ); - Com_Memset( &tess, 0, sizeof( tess ) ); - - if(sizeof(glconfig_t) != 11332) - ri.Error( ERR_FATAL, "Mod ABI incompatible: sizeof(glconfig_t) == %u != 11332", (unsigned int) sizeof(glconfig_t)); - -// Swap_Init(); - - if ( (intptr_t)tess.xyz & 15 ) { - ri.Printf( PRINT_WARNING, "tess.xyz not 16 byte aligned\n" ); - } - Com_Memset( tess.constantColor255, 255, sizeof( tess.constantColor255 ) ); - - // - // init function tables - // - for ( i = 0; i < FUNCTABLE_SIZE; i++ ) - { - tr.sinTable[i] = sin( DEG2RAD( i * 360.0f / ( ( float ) ( FUNCTABLE_SIZE - 1 ) ) ) ); - tr.squareTable[i] = ( i < FUNCTABLE_SIZE/2 ) ? 1.0f : -1.0f; - tr.sawToothTable[i] = (float)i / FUNCTABLE_SIZE; - tr.inverseSawToothTable[i] = 1.0f - tr.sawToothTable[i]; - - if ( i < FUNCTABLE_SIZE / 2 ) - { - if ( i < FUNCTABLE_SIZE / 4 ) - { - tr.triangleTable[i] = ( float ) i / ( FUNCTABLE_SIZE / 4 ); - } - else - { - tr.triangleTable[i] = 1.0f - tr.triangleTable[i-FUNCTABLE_SIZE / 4]; - } - } - else - { - tr.triangleTable[i] = -tr.triangleTable[i-FUNCTABLE_SIZE/2]; - } - } - - R_InitFogTable(); - - R_NoiseInit(); - - R_Register(); - - max_polys = r_maxpolys->integer; - if (max_polys < MAX_POLYS) - max_polys = MAX_POLYS; - - max_polyverts = r_maxpolyverts->integer; - if (max_polyverts < MAX_POLYVERTS) - max_polyverts = MAX_POLYVERTS; - - ptr = ri.Hunk_Alloc( sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low); - backEndData = (backEndData_t *) ptr; - backEndData->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData )); - backEndData->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys); - R_InitNextFrame(); - - InitOpenGL(); - - R_InitImages(); - - R_InitShaders(); - - R_InitSkins(); - - R_ModelInit(); - - R_InitFreeType(); - - - err = qglGetError(); - if ( err != GL_NO_ERROR ) - ri.Printf (PRINT_ALL, "glGetError() = 0x%x\n", err); - - // print info - GfxInfo_f(); - ri.Printf( PRINT_ALL, "----- finished R_Init -----\n" ); -} - -/* -=============== -RE_Shutdown -=============== -*/ -void RE_Shutdown( qboolean destroyWindow ) { - - ri.Printf( PRINT_ALL, "RE_Shutdown( %i )\n", destroyWindow ); - - ri.Cmd_RemoveCommand ("modellist"); - ri.Cmd_RemoveCommand ("screenshotJPEG"); - ri.Cmd_RemoveCommand ("screenshot"); - ri.Cmd_RemoveCommand ("imagelist"); - ri.Cmd_RemoveCommand ("shaderlist"); - ri.Cmd_RemoveCommand ("skinlist"); - ri.Cmd_RemoveCommand ("gfxinfo"); - ri.Cmd_RemoveCommand("minimize"); - ri.Cmd_RemoveCommand( "modelist" ); - ri.Cmd_RemoveCommand( "shaderstate" ); - - - if ( tr.registered ) { - R_IssuePendingRenderCommands(); - R_DeleteTextures(); - } - - R_DoneFreeType(); - - // shut down platform specific OpenGL stuff - if ( destroyWindow ) { - GLimp_Shutdown(); - - Com_Memset( &glConfig, 0, sizeof( glConfig ) ); - Com_Memset( &glState, 0, sizeof( glState ) ); - } - - tr.registered = qfalse; -} - - -/* -============= -RE_EndRegistration - -Touch all images to make sure they are resident -============= -*/ -void RE_EndRegistration( void ) { - R_IssuePendingRenderCommands(); - if (!ri.Sys_LowPhysicalMemory()) { - RB_ShowImages(); - } -} - - -/* -@@@@@@@@@@@@@@@@@@@@@ -GetRefAPI - -@@@@@@@@@@@@@@@@@@@@@ -*/ -#ifdef USE_RENDERER_DLOPEN -Q_EXPORT refexport_t* QDECL GetRefAPI ( int apiVersion, refimport_t *rimp ) { -#else -refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) { -#endif - - static refexport_t re; - - ri = *rimp; - - Com_Memset( &re, 0, sizeof( re ) ); - - if ( apiVersion != REF_API_VERSION ) { - ri.Printf(PRINT_ALL, "Mismatched REF_API_VERSION: expected %i, got %i\n", - REF_API_VERSION, apiVersion ); - return NULL; - } - - // the RE_ functions are Renderer Entry points - - re.Shutdown = RE_Shutdown; - - re.BeginRegistration = RE_BeginRegistration; - re.RegisterModel = RE_RegisterModel; - re.RegisterSkin = RE_RegisterSkin; - re.RegisterShader = RE_RegisterShader; - re.RegisterShaderNoMip = RE_RegisterShaderNoMip; - re.LoadWorld = RE_LoadWorldMap; - re.SetWorldVisData = RE_SetWorldVisData; - re.EndRegistration = RE_EndRegistration; - - re.BeginFrame = RE_BeginFrame; - re.EndFrame = RE_EndFrame; - - re.MarkFragments = R_MarkFragments; - re.LerpTag = R_LerpTag; - re.ModelBounds = R_ModelBounds; - - re.ClearScene = RE_ClearScene; - re.AddRefEntityToScene = RE_AddRefEntityToScene; - re.AddPolyToScene = RE_AddPolyToScene; - re.LFX_ParticleEffect = NULL; - re.LightForPoint = R_LightForPoint; - re.AddLightToScene = RE_AddLightToScene; - re.AddAdditiveLightToScene = RE_AddAdditiveLightToScene; - re.RenderScene = RE_RenderScene; - - re.SetColor = RE_SetColor; - re.DrawStretchPic = RE_StretchPic; - re.DrawStretchRaw = RE_StretchRaw; - re.UploadCinematic = RE_UploadCinematic; - - re.RegisterFont = RE_RegisterFont; - re.RemapShader = R_RemapShader; - re.GetEntityToken = R_GetEntityToken; - re.inPVS = R_inPVS; - - re.TakeVideoFrame = RE_TakeVideoFrame; - - return &re; -} diff --git a/code/renderergl1/tr_light.c b/code/renderergl1/tr_light.c deleted file mode 100644 index fc6af6a917..0000000000 --- a/code/renderergl1/tr_light.c +++ /dev/null @@ -1,394 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_light.c - -#include "tr_local.h" - -#define DLIGHT_AT_RADIUS 16 -// at the edge of a dlight's influence, this amount of light will be added - -#define DLIGHT_MINIMUM_RADIUS 16 -// never calculate a range less than this to prevent huge light numbers - - -/* -=============== -R_TransformDlights - -Transforms the origins of an array of dlights. -Used by both the front end (for DlightBmodel) and -the back end (before doing the lighting calculation) -=============== -*/ -void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or) { - int i; - vec3_t temp; - - for ( i = 0 ; i < count ; i++, dl++ ) { - VectorSubtract( dl->origin, or->origin, temp ); - dl->transformed[0] = DotProduct( temp, or->axis[0] ); - dl->transformed[1] = DotProduct( temp, or->axis[1] ); - dl->transformed[2] = DotProduct( temp, or->axis[2] ); - } -} - -/* -============= -R_DlightBmodel - -Determine which dynamic lights may effect this bmodel -============= -*/ -void R_DlightBmodel( bmodel_t *bmodel ) { - int i, j; - dlight_t *dl; - int mask; - msurface_t *surf; - - // transform all the lights - R_TransformDlights( tr.refdef.num_dlights, tr.refdef.dlights, &tr.or ); - - mask = 0; - for ( i=0 ; itransformed[j] - bmodel->bounds[1][j] > dl->radius ) { - break; - } - if ( bmodel->bounds[0][j] - dl->transformed[j] > dl->radius ) { - break; - } - } - if ( j < 3 ) { - continue; - } - - // we need to check this light - mask |= 1 << i; - } - - tr.currentEntity->needDlights = (mask != 0); - - // set the dlight bits in all the surfaces - for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) { - surf = bmodel->firstSurface + i; - - if ( *surf->data == SF_FACE ) { - ((srfSurfaceFace_t *)surf->data)->dlightBits = mask; - } else if ( *surf->data == SF_GRID ) { - ((srfGridMesh_t *)surf->data)->dlightBits = mask; - } else if ( *surf->data == SF_TRIANGLES ) { - ((srfTriangles_t *)surf->data)->dlightBits = mask; - } - } -} - - -/* -============================================================================= - -LIGHT SAMPLING - -============================================================================= -*/ - -extern cvar_t *r_ambientScale; -extern cvar_t *r_directedScale; -extern cvar_t *r_debugLight; - -/* -================= -R_SetupEntityLightingGrid - -================= -*/ -static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) { - vec3_t lightOrigin; - int pos[3]; - int i, j; - byte *gridData; - float frac[3]; - int gridStep[3]; - vec3_t direction; - float totalFactor; - - if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { - // seperate lightOrigins are needed so an object that is - // sinking into the ground can still be lit, and so - // multi-part models can be lit identically - VectorCopy( ent->e.lightingOrigin, lightOrigin ); - } else { - VectorCopy( ent->e.origin, lightOrigin ); - } - - VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin ); - for ( i = 0 ; i < 3 ; i++ ) { - float v; - - v = lightOrigin[i]*tr.world->lightGridInverseSize[i]; - pos[i] = floor( v ); - frac[i] = v - pos[i]; - if ( pos[i] < 0 ) { - pos[i] = 0; - } else if ( pos[i] >= tr.world->lightGridBounds[i] - 1 ) { - pos[i] = tr.world->lightGridBounds[i] - 1; - } - } - - VectorClear( ent->ambientLight ); - VectorClear( ent->directedLight ); - VectorClear( direction ); - - assert( tr.world->lightGridData ); // NULL with -nolight maps - - // trilerp the light value - gridStep[0] = 8; - gridStep[1] = 8 * tr.world->lightGridBounds[0]; - gridStep[2] = 8 * tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1]; - gridData = tr.world->lightGridData + pos[0] * gridStep[0] - + pos[1] * gridStep[1] + pos[2] * gridStep[2]; - - totalFactor = 0; - for ( i = 0 ; i < 8 ; i++ ) { - float factor; - byte *data; - int lat, lng; - vec3_t normal; - #if idppc - float d0, d1, d2, d3, d4, d5; - #endif - factor = 1.0; - data = gridData; - for ( j = 0 ; j < 3 ; j++ ) { - if ( i & (1<ambientLight[0] += factor * d0; - ent->ambientLight[1] += factor * d1; - ent->ambientLight[2] += factor * d2; - - ent->directedLight[0] += factor * d3; - ent->directedLight[1] += factor * d4; - ent->directedLight[2] += factor * d5; - #else - ent->ambientLight[0] += factor * data[0]; - ent->ambientLight[1] += factor * data[1]; - ent->ambientLight[2] += factor * data[2]; - - ent->directedLight[0] += factor * data[3]; - ent->directedLight[1] += factor * data[4]; - ent->directedLight[2] += factor * data[5]; - #endif - lat = data[7]; - lng = data[6]; - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - normal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - VectorMA( direction, factor, normal, direction ); - } - - if ( totalFactor > 0 && totalFactor < 0.99 ) { - totalFactor = 1.0f / totalFactor; - VectorScale( ent->ambientLight, totalFactor, ent->ambientLight ); - VectorScale( ent->directedLight, totalFactor, ent->directedLight ); - } - - VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight ); - VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight ); - - VectorNormalize2( direction, ent->lightDir ); -} - - -/* -=============== -LogLight -=============== -*/ -static void LogLight( trRefEntity_t *ent ) { - int max1, max2; - - if ( !(ent->e.renderfx & RF_FIRST_PERSON ) ) { - return; - } - - max1 = ent->ambientLight[0]; - if ( ent->ambientLight[1] > max1 ) { - max1 = ent->ambientLight[1]; - } else if ( ent->ambientLight[2] > max1 ) { - max1 = ent->ambientLight[2]; - } - - max2 = ent->directedLight[0]; - if ( ent->directedLight[1] > max2 ) { - max2 = ent->directedLight[1]; - } else if ( ent->directedLight[2] > max2 ) { - max2 = ent->directedLight[2]; - } - - ri.Printf( PRINT_ALL, "amb:%i dir:%i\n", max1, max2 ); -} - -/* -================= -R_SetupEntityLighting - -Calculates all the lighting values that will be used -by the Calc_* functions -================= -*/ -void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) { - int i; - dlight_t *dl; - float power; - vec3_t dir; - float d; - vec3_t lightDir; - vec3_t lightOrigin; - - // lighting calculations - if ( ent->lightingCalculated ) { - return; - } - ent->lightingCalculated = qtrue; - - // - // trace a sample point down to find ambient light - // - if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { - // seperate lightOrigins are needed so an object that is - // sinking into the ground can still be lit, and so - // multi-part models can be lit identically - VectorCopy( ent->e.lightingOrigin, lightOrigin ); - } else { - VectorCopy( ent->e.origin, lightOrigin ); - } - - // if NOWORLDMODEL, only use dynamic lights (menu system, etc) - if ( !(refdef->rdflags & RDF_NOWORLDMODEL ) - && tr.world->lightGridData ) { - R_SetupEntityLightingGrid( ent ); - } else { - ent->ambientLight[0] = ent->ambientLight[1] = - ent->ambientLight[2] = tr.identityLight * 150; - ent->directedLight[0] = ent->directedLight[1] = - ent->directedLight[2] = tr.identityLight * 150; - VectorCopy( tr.sunDirection, ent->lightDir ); - } - - // bonus items and view weapons have a fixed minimum add - if ( 1 /* ent->e.renderfx & RF_MINLIGHT */ ) { - // give everything a minimum light add - ent->ambientLight[0] += tr.identityLight * 32; - ent->ambientLight[1] += tr.identityLight * 32; - ent->ambientLight[2] += tr.identityLight * 32; - } - - // - // modify the light by dynamic lights - // - d = VectorLength( ent->directedLight ); - VectorScale( ent->lightDir, d, lightDir ); - - for ( i = 0 ; i < refdef->num_dlights ; i++ ) { - dl = &refdef->dlights[i]; - VectorSubtract( dl->origin, lightOrigin, dir ); - d = VectorNormalize( dir ); - - power = DLIGHT_AT_RADIUS * ( dl->radius * dl->radius ); - if ( d < DLIGHT_MINIMUM_RADIUS ) { - d = DLIGHT_MINIMUM_RADIUS; - } - d = power / ( d * d ); - - VectorMA( ent->directedLight, d, dl->color, ent->directedLight ); - VectorMA( lightDir, d, dir, lightDir ); - } - - // clamp ambient - for ( i = 0 ; i < 3 ; i++ ) { - if ( ent->ambientLight[i] > tr.identityLightByte ) { - ent->ambientLight[i] = tr.identityLightByte; - } - } - - if ( r_debugLight->integer ) { - LogLight( ent ); - } - - // save out the byte packet version - ((byte *)&ent->ambientLightInt)[0] = ri.ftol(ent->ambientLight[0]); - ((byte *)&ent->ambientLightInt)[1] = ri.ftol(ent->ambientLight[1]); - ((byte *)&ent->ambientLightInt)[2] = ri.ftol(ent->ambientLight[2]); - ((byte *)&ent->ambientLightInt)[3] = 0xff; - - // transform the direction to local space - VectorNormalize( lightDir ); - ent->lightDir[0] = DotProduct( lightDir, ent->e.axis[0] ); - ent->lightDir[1] = DotProduct( lightDir, ent->e.axis[1] ); - ent->lightDir[2] = DotProduct( lightDir, ent->e.axis[2] ); -} - -/* -================= -R_LightForPoint -================= -*/ -int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ) -{ - trRefEntity_t ent; - - if ( tr.world->lightGridData == NULL ) - return qfalse; - - Com_Memset(&ent, 0, sizeof(ent)); - VectorCopy( point, ent.e.origin ); - R_SetupEntityLightingGrid( &ent ); - VectorCopy(ent.ambientLight, ambientLight); - VectorCopy(ent.directedLight, directedLight); - VectorCopy(ent.lightDir, lightDir); - - return qtrue; -} diff --git a/code/renderergl1/tr_local.h b/code/renderergl1/tr_local.h deleted file mode 100644 index 66c13d4514..0000000000 --- a/code/renderergl1/tr_local.h +++ /dev/null @@ -1,1600 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - - -#ifndef TR_LOCAL_H -#define TR_LOCAL_H - -#include "../qcommon/q_shared.h" -#include "../qcommon/qfiles.h" -#include "../qcommon/qcommon.h" -#include "../renderercommon/tr_public.h" -#include "../renderercommon/tr_common.h" -#include "../renderercommon/iqm.h" -#include "../renderercommon/qgl.h" - -#define GL_INDEX_TYPE GL_UNSIGNED_INT -typedef unsigned int glIndex_t; - -// 14 bits -// can't be increased without changing bit packing for drawsurfs -// see QSORT_SHADERNUM_SHIFT -#define SHADERNUM_BITS 14 -#define MAX_SHADERS (1<or.origin in local coordinates - float modelMatrix[16]; -} orientationr_t; - -//=============================================================================== - -typedef enum { - SS_BAD, - SS_PORTAL, // mirrors, portals, viewscreens - SS_ENVIRONMENT, // sky box - SS_OPAQUE, // opaque - - SS_DECAL, // scorch marks, etc. - SS_SEE_THROUGH, // ladders, grates, grills that may have small blended edges - // in addition to alpha test - SS_BANNER, - - SS_FOG, - - SS_UNDERWATER, // for items that should be drawn in front of the water plane - - SS_BLEND0, // regular transparency and filters - SS_BLEND1, // generally only used for additive type effects - SS_BLEND2, - SS_BLEND3, - - SS_BLEND6, - SS_STENCIL_SHADOW, - SS_ALMOST_NEAREST, // gun smoke puffs - - SS_NEAREST // blood blobs -} shaderSort_t; - - -#define MAX_SHADER_STAGES 8 - -typedef enum { - GF_NONE, - - GF_SIN, - GF_SQUARE, - GF_TRIANGLE, - GF_SAWTOOTH, - GF_INVERSE_SAWTOOTH, - - GF_NOISE - -} genFunc_t; - - -typedef enum { - DEFORM_NONE, - DEFORM_WAVE, - DEFORM_NORMALS, - DEFORM_BULGE, - DEFORM_MOVE, - DEFORM_PROJECTION_SHADOW, - DEFORM_AUTOSPRITE, - DEFORM_AUTOSPRITE2, - DEFORM_TEXT0, - DEFORM_TEXT1, - DEFORM_TEXT2, - DEFORM_TEXT3, - DEFORM_TEXT4, - DEFORM_TEXT5, - DEFORM_TEXT6, - DEFORM_TEXT7 -} deform_t; - -typedef enum { - AGEN_IDENTITY, - AGEN_SKIP, - AGEN_ENTITY, - AGEN_ONE_MINUS_ENTITY, - AGEN_VERTEX, - AGEN_ONE_MINUS_VERTEX, - AGEN_LIGHTING_SPECULAR, - AGEN_WAVEFORM, - AGEN_PORTAL, - AGEN_CONST -} alphaGen_t; - -typedef enum { - CGEN_BAD, - CGEN_IDENTITY_LIGHTING, // tr.identityLight - CGEN_IDENTITY, // always (1,1,1,1) - CGEN_ENTITY, // grabbed from entity's modulate field - CGEN_ONE_MINUS_ENTITY, // grabbed from 1 - entity.modulate - CGEN_EXACT_VERTEX, // tess.vertexColors - CGEN_VERTEX, // tess.vertexColors * tr.identityLight - CGEN_ONE_MINUS_VERTEX, - CGEN_WAVEFORM, // programmatically generated - CGEN_LIGHTING_DIFFUSE, - CGEN_FOG, // standard fog - CGEN_CONST // fixed color -} colorGen_t; - -typedef enum { - TCGEN_BAD, - TCGEN_IDENTITY, // clear to 0,0 - TCGEN_LIGHTMAP, - TCGEN_TEXTURE, - TCGEN_ENVIRONMENT_MAPPED, - TCGEN_FOG, - TCGEN_VECTOR // S and T from world coordinates -} texCoordGen_t; - -typedef enum { - ACFF_NONE, - ACFF_MODULATE_RGB, - ACFF_MODULATE_RGBA, - ACFF_MODULATE_ALPHA -} acff_t; - -typedef struct { - genFunc_t func; - - float base; - float amplitude; - float phase; - float frequency; -} waveForm_t; - -#define TR_MAX_TEXMODS 4 - -typedef enum { - TMOD_NONE, - TMOD_TRANSFORM, - TMOD_TURBULENT, - TMOD_SCROLL, - TMOD_SCALE, - TMOD_STRETCH, - TMOD_ROTATE, - TMOD_ENTITY_TRANSLATE -} texMod_t; - -#define MAX_SHADER_DEFORMS 3 -typedef struct { - deform_t deformation; // vertex coordinate modification type - - vec3_t moveVector; - waveForm_t deformationWave; - float deformationSpread; - - float bulgeWidth; - float bulgeHeight; - float bulgeSpeed; -} deformStage_t; - - -typedef struct { - texMod_t type; - - // used for TMOD_TURBULENT and TMOD_STRETCH - waveForm_t wave; - - // used for TMOD_TRANSFORM - float matrix[2][2]; // s' = s * m[0][0] + t * m[1][0] + trans[0] - float translate[2]; // t' = s * m[0][1] + t * m[0][1] + trans[1] - - // used for TMOD_SCALE - float scale[2]; // s *= scale[0] - // t *= scale[1] - - // used for TMOD_SCROLL - float scroll[2]; // s' = s + scroll[0] * time - // t' = t + scroll[1] * time - - // + = clockwise - // - = counterclockwise - float rotateSpeed; - -} texModInfo_t; - - -#define MAX_IMAGE_ANIMATIONS 8 - -typedef struct { - image_t *image[MAX_IMAGE_ANIMATIONS]; - int numImageAnimations; - float imageAnimationSpeed; - - texCoordGen_t tcGen; - vec3_t tcGenVectors[2]; - - int numTexMods; - texModInfo_t *texMods; - - int videoMapHandle; - qboolean isLightmap; - qboolean isVideoMap; -} textureBundle_t; - -#define NUM_TEXTURE_BUNDLES 2 - -typedef struct { - qboolean active; - - textureBundle_t bundle[NUM_TEXTURE_BUNDLES]; - - waveForm_t rgbWave; - colorGen_t rgbGen; - - waveForm_t alphaWave; - alphaGen_t alphaGen; - - byte constantColor[4]; // for CGEN_CONST and AGEN_CONST - - unsigned stateBits; // GLS_xxxx mask - - acff_t adjustColorsForFog; - - qboolean isDetail; -} shaderStage_t; - -struct shaderCommands_s; - -typedef enum { - CT_FRONT_SIDED, - CT_BACK_SIDED, - CT_TWO_SIDED -} cullType_t; - -typedef enum { - FP_NONE, // surface is translucent and will just be adjusted properly - FP_EQUAL, // surface is opaque but possibly alpha tested - FP_LE // surface is trnaslucent, but still needs a fog pass (fog surface) -} fogPass_t; - -typedef struct { - float cloudHeight; - image_t *outerbox[6], *innerbox[6]; -} skyParms_t; - -typedef struct { - vec3_t color; - float depthForOpaque; -} fogParms_t; - - -typedef struct shader_s { - char name[MAX_QPATH]; // game path, including extension - int lightmapIndex; // for a shader to match, both name and lightmapIndex must match - - int index; // this shader == tr.shaders[index] - int sortedIndex; // this shader == tr.sortedShaders[sortedIndex] - - float sort; // lower numbered shaders draw before higher numbered - - qboolean defaultShader; // we want to return index 0 if the shader failed to - // load for some reason, but R_FindShader should - // still keep a name allocated for it, so if - // something calls RE_RegisterShader again with - // the same name, we don't try looking for it again - - qboolean explicitlyDefined; // found in a .shader file - - int surfaceFlags; // if explicitlyDefined, this will have SURF_* flags - int contentFlags; - - qboolean entityMergable; // merge across entites optimizable (smoke, blood) - - qboolean isSky; - skyParms_t sky; - fogParms_t fogParms; - - float portalRange; // distance to fog out at - - int multitextureEnv; // 0, GL_MODULATE, GL_ADD (FIXME: put in stage) - - cullType_t cullType; // CT_FRONT_SIDED, CT_BACK_SIDED, or CT_TWO_SIDED - qboolean polygonOffset; // set for decals and other items that must be offset - qboolean noMipMaps; // for console fonts, 2D elements, etc. - qboolean noPicMip; // for images that must always be full resolution - - fogPass_t fogPass; // draw a blended pass, possibly with depth test equals - - qboolean needsNormal; // not all shaders will need all data to be gathered - qboolean needsST1; - qboolean needsST2; - qboolean needsColor; - - int numDeforms; - deformStage_t deforms[MAX_SHADER_DEFORMS]; - - int numUnfoggedPasses; - shaderStage_t *stages[MAX_SHADER_STAGES]; - - void (*optimalStageIteratorFunc)( void ); - - float clampTime; // time this shader is clamped to - float timeOffset; // current time offset for this shader - - struct shader_s *remappedShader; // current shader this one is remapped too - - struct shader_s *next; -} shader_t; - - -// trRefdef_t holds everything that comes in refdef_t, -// as well as the locally generated scene information -typedef struct { - int x, y, width, height; - float fov_x, fov_y; - vec3_t vieworg; - vec3_t viewaxis[3]; // transformation matrix - - stereoFrame_t stereoFrame; - - int time; // time in milliseconds for shader effects and other time dependent rendering issues - int rdflags; // RDF_NOWORLDMODEL, etc - - // 1 bits will prevent the associated area from rendering at all - byte areamask[MAX_MAP_AREA_BYTES]; - qboolean areamaskModified; // qtrue if areamask changed since last scene - - float floatTime; // tr.refdef.time / 1000.0 - - // text messages for deform text shaders - char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH]; - - int num_entities; - trRefEntity_t *entities; - - int num_dlights; - struct dlight_s *dlights; - - int numPolys; - struct srfPoly_s *polys; - - int numDrawSurfs; - struct drawSurf_s *drawSurfs; - - -} trRefdef_t; - - -//================================================================================= - -// skins allow models to be retextured without modifying the model file -typedef struct { - char name[MAX_QPATH]; - shader_t *shader; -} skinSurface_t; - -typedef struct skin_s { - char name[MAX_QPATH]; // game path, including extension - int numSurfaces; - skinSurface_t *surfaces[MD3_MAX_SURFACES]; -} skin_t; - - -typedef struct { - int originalBrushNumber; - vec3_t bounds[2]; - - unsigned colorInt; // in packed byte format - float tcScale; // texture coordinate vector scales - fogParms_t parms; - - // for clipping distance in fog when outside - qboolean hasSurface; - float surface[4]; -} fog_t; - -typedef struct { - orientationr_t or; - orientationr_t world; - vec3_t pvsOrigin; // may be different than or.origin for portals - qboolean isPortal; // true if this view is through a portal - qboolean isMirror; // the portal is a mirror, invert the face culling - int frameSceneNum; // copied from tr.frameSceneNum - int frameCount; // copied from tr.frameCount - cplane_t portalPlane; // clip anything behind this if mirroring - int viewportX, viewportY, viewportWidth, viewportHeight; - float fovX, fovY; - float projectionMatrix[16]; - cplane_t frustum[4]; - vec3_t visBounds[2]; - float zFar; - stereoFrame_t stereoFrame; -} viewParms_t; - - -/* -============================================================================== - -SURFACES - -============================================================================== -*/ - -// any changes in surfaceType must be mirrored in rb_surfaceTable[] -typedef enum { - SF_BAD, - SF_SKIP, // ignore - SF_FACE, - SF_GRID, - SF_TRIANGLES, - SF_POLY, - SF_MD3, - SF_MDR, - SF_IQM, - SF_FLARE, - SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity - SF_DISPLAY_LIST, - - SF_NUM_SURFACE_TYPES, - SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int ) -} surfaceType_t; - -typedef struct drawSurf_s { - unsigned sort; // bit combination for fast compares - surfaceType_t *surface; // any of surface*_t -} drawSurf_t; - -#define MAX_FACE_POINTS 64 - -#define MAX_PATCH_SIZE 32 // max dimensions of a patch mesh in map file -#define MAX_GRID_SIZE 65 // max dimensions of a grid mesh in memory - -// when cgame directly specifies a polygon, it becomes a srfPoly_t -// as soon as it is called -typedef struct srfPoly_s { - surfaceType_t surfaceType; - qhandle_t hShader; - int fogIndex; - int numVerts; - polyVert_t *verts; -} srfPoly_t; - -typedef struct srfDisplayList_s { - surfaceType_t surfaceType; - int listNum; -} srfDisplayList_t; - - -typedef struct srfFlare_s { - surfaceType_t surfaceType; - vec3_t origin; - vec3_t normal; - vec3_t color; -} srfFlare_t; - -typedef struct srfGridMesh_s { - surfaceType_t surfaceType; - - // dynamic lighting information - int dlightBits; - - // culling information - vec3_t meshBounds[2]; - vec3_t localOrigin; - float meshRadius; - - // lod information, which may be different - // than the culling information to allow for - // groups of curves that LOD as a unit - vec3_t lodOrigin; - float lodRadius; - int lodFixed; - int lodStitched; - - // vertexes - int width, height; - float *widthLodError; - float *heightLodError; - drawVert_t verts[1]; // variable sized -} srfGridMesh_t; - - - -#define VERTEXSIZE 8 -typedef struct { - surfaceType_t surfaceType; - cplane_t plane; - - // dynamic lighting information - int dlightBits; - - // triangle definitions (no normals at points) - int numPoints; - int numIndices; - int ofsIndices; - float points[1][VERTEXSIZE]; // variable sized - // there is a variable length list of indices here also -} srfSurfaceFace_t; - - -// misc_models in maps are turned into direct geometry by q3map -typedef struct { - surfaceType_t surfaceType; - - // dynamic lighting information - int dlightBits; - - // culling information (FIXME: use this!) - vec3_t bounds[2]; - vec3_t localOrigin; - float radius; - - // triangle definitions - int numIndexes; - int *indexes; - - int numVerts; - drawVert_t *verts; -} srfTriangles_t; - -// inter-quake-model -typedef struct { - int num_vertexes; - int num_triangles; - int num_frames; - int num_surfaces; - int num_joints; - int num_poses; - struct srfIQModel_s *surfaces; - - float *positions; - float *texcoords; - float *normals; - float *tangents; - byte *blendIndexes; - union { - float *f; - byte *b; - } blendWeights; - byte *colors; - int *triangles; - - // depending upon the exporter, blend indices and weights might be int/float - // as opposed to the recommended byte/byte, for example Noesis exports - // int/float whereas the official IQM tool exports byte/byte - byte blendWeightsType; // IQM_UBYTE or IQM_FLOAT - - int *jointParents; - float *jointMats; - float *poseMats; - float *bounds; - char *names; -} iqmData_t; - -// inter-quake-model surface -typedef struct srfIQModel_s { - surfaceType_t surfaceType; - char name[MAX_QPATH]; - shader_t *shader; - iqmData_t *data; - int first_vertex, num_vertexes; - int first_triangle, num_triangles; -} srfIQModel_t; - - -extern void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])(void *); - -/* -============================================================================== - -BRUSH MODELS - -============================================================================== -*/ - - -// -// in memory representation -// - -#define SIDE_FRONT 0 -#define SIDE_BACK 1 -#define SIDE_ON 2 - -typedef struct msurface_s { - int viewCount; // if == tr.viewCount, already added - struct shader_s *shader; - int fogIndex; - - surfaceType_t *data; // any of srf*_t -} msurface_t; - - - -#define CONTENTS_NODE -1 -typedef struct mnode_s { - // common with leaf and node - int contents; // -1 for nodes, to differentiate from leafs - int visframe; // node needs to be traversed if current - vec3_t mins, maxs; // for bounding box culling - struct mnode_s *parent; - - // node specific - cplane_t *plane; - struct mnode_s *children[2]; - - // leaf specific - int cluster; - int area; - - msurface_t **firstmarksurface; - int nummarksurfaces; -} mnode_t; - -typedef struct { - vec3_t bounds[2]; // for culling - msurface_t *firstSurface; - int numSurfaces; -} bmodel_t; - -typedef struct { - char name[MAX_QPATH]; // ie: maps/tim_dm2.bsp - char baseName[MAX_QPATH]; // ie: tim_dm2 - - int dataSize; - - int numShaders; - dshader_t *shaders; - - bmodel_t *bmodels; - - int numplanes; - cplane_t *planes; - - int numnodes; // includes leafs - int numDecisionNodes; - mnode_t *nodes; - - int numsurfaces; - msurface_t *surfaces; - - int nummarksurfaces; - msurface_t **marksurfaces; - - int numfogs; - fog_t *fogs; - - vec3_t lightGridOrigin; - vec3_t lightGridSize; - vec3_t lightGridInverseSize; - int lightGridBounds[3]; - byte *lightGridData; - - - int numClusters; - int clusterBytes; - const byte *vis; // may be passed in by CM_LoadMap to save space - - byte *novis; // clusterBytes of 0xff - - char *entityString; - char *entityParsePoint; -} world_t; - -//====================================================================== - -typedef enum { - MOD_BAD, - MOD_BRUSH, - MOD_MESH, - MOD_MDR, - MOD_IQM -} modtype_t; - -typedef struct model_s { - char name[MAX_QPATH]; - modtype_t type; - int index; // model = tr.models[model->index] - - int dataSize; // just for listing purposes - bmodel_t *bmodel; // only if type == MOD_BRUSH - md3Header_t *md3[MD3_MAX_LODS]; // only if type == MOD_MESH - void *modelData; // only if type == (MOD_MDR | MOD_IQM) - - int numLods; -} model_t; - - -#define MAX_MOD_KNOWN 1024 - -void R_ModelInit (void); -model_t *R_GetModelByHandle( qhandle_t hModel ); -int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, - float frac, const char *tagName ); -void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ); - -void R_Modellist_f (void); - -//==================================================== - -#define MAX_DRAWIMAGES 2048 -#define MAX_SKINS 1024 - - -#define MAX_DRAWSURFS 0x10000 -#define DRAWSURF_MASK (MAX_DRAWSURFS-1) - -/* - -the drawsurf sort data is packed into a single 32 bit value so it can be -compared quickly during the qsorting process - -the bits are allocated as follows: - -0 - 1 : dlightmap index -//2 : used to be clipped flag REMOVED - 03.21.00 rad -2 - 6 : fog index -11 - 20 : entity index -21 - 31 : sorted shader index - - TTimo - 1.32 -0-1 : dlightmap index -2-6 : fog index -7-16 : entity index -17-30 : sorted shader index -*/ -#define QSORT_FOGNUM_SHIFT 2 -#define QSORT_REFENTITYNUM_SHIFT 7 -#define QSORT_SHADERNUM_SHIFT (QSORT_REFENTITYNUM_SHIFT+REFENTITYNUM_BITS) -#if (QSORT_SHADERNUM_SHIFT+SHADERNUM_BITS) > 32 - #error "Need to update sorting, too many bits." -#endif - -extern int gl_filter_min, gl_filter_max; - -/* -** performanceCounters_t -*/ -typedef struct { - int c_sphere_cull_patch_in, c_sphere_cull_patch_clip, c_sphere_cull_patch_out; - int c_box_cull_patch_in, c_box_cull_patch_clip, c_box_cull_patch_out; - int c_sphere_cull_md3_in, c_sphere_cull_md3_clip, c_sphere_cull_md3_out; - int c_box_cull_md3_in, c_box_cull_md3_clip, c_box_cull_md3_out; - - int c_leafs; - int c_dlightSurfaces; - int c_dlightSurfacesCulled; -} frontEndCounters_t; - -#define FOG_TABLE_SIZE 256 -#define FUNCTABLE_SIZE 1024 -#define FUNCTABLE_SIZE2 10 -#define FUNCTABLE_MASK (FUNCTABLE_SIZE-1) - - -// the renderer front end should never modify glstate_t -typedef struct { - int currenttextures[2]; - int currenttmu; - qboolean finishCalled; - int texEnv[2]; - int faceCulling; - unsigned long glStateBits; -} glstate_t; - -typedef struct { - int c_surfaces, c_shaders, c_vertexes, c_indexes, c_totalIndexes; - float c_overDraw; - - int c_dlightVertexes; - int c_dlightIndexes; - - int c_flareAdds; - int c_flareTests; - int c_flareRenders; - - int msec; // total msec for backend run -} backEndCounters_t; - -// all state modified by the back end is seperated -// from the front end state -typedef struct { - trRefdef_t refdef; - viewParms_t viewParms; - orientationr_t or; - backEndCounters_t pc; - qboolean isHyperspace; - trRefEntity_t *currentEntity; - qboolean skyRenderedThisView; // flag for drawing sun - - qboolean projection2D; // if qtrue, drawstretchpic doesn't need to change modes - byte color2D[4]; - qboolean vertexes2D; // shader needs to be finished - trRefEntity_t entity2D; // currentEntity will point at this when doing 2D rendering -} backEndState_t; - -/* -** trGlobals_t -** -** Most renderer globals are defined here. -** backend functions should never modify any of these fields, -** but may read fields that aren't dynamically modified -** by the frontend. -*/ -typedef struct { - qboolean registered; // cleared at shutdown, set at beginRegistration - - int visCount; // incremented every time a new vis cluster is entered - int frameCount; // incremented every frame - int sceneCount; // incremented every scene - int viewCount; // incremented every view (twice a scene if portaled) - // and every R_MarkFragments call - - int frameSceneNum; // zeroed at RE_BeginFrame - - qboolean worldMapLoaded; - world_t *world; - - const byte *externalVisData; // from RE_SetWorldVisData, shared with CM_Load - - image_t *defaultImage; - image_t *scratchImage[32]; - image_t *fogImage; - image_t *dlightImage; // inverse-quare highlight for projective adding - image_t *flareImage; - image_t *whiteImage; // full of 0xff - image_t *identityLightImage; // full of tr.identityLightByte - - shader_t *defaultShader; - shader_t *shadowShader; - shader_t *projectionShadowShader; - - shader_t *flareShader; - shader_t *sunShader; - - int numLightmaps; - image_t **lightmaps; - - trRefEntity_t *currentEntity; - trRefEntity_t worldEntity; // point currentEntity at this when rendering world - int currentEntityNum; - int shiftedEntityNum; // currentEntityNum << QSORT_REFENTITYNUM_SHIFT - model_t *currentModel; - - viewParms_t viewParms; - - float identityLight; // 1.0 / ( 1 << overbrightBits ) - int identityLightByte; // identityLight * 255 - int overbrightBits; // r_overbrightBits->integer, but set to 0 if no hw gamma - - orientationr_t or; // for current entity - - trRefdef_t refdef; - - int viewCluster; - - vec3_t sunLight; // from the sky shader for this level - vec3_t sunDirection; - - frontEndCounters_t pc; - int frontEndMsec; // not in pc due to clearing issue - - // - // put large tables at the end, so most elements will be - // within the +/32K indexed range on risc processors - // - model_t *models[MAX_MOD_KNOWN]; - int numModels; - - int numImages; - image_t *images[MAX_DRAWIMAGES]; - - // shader indexes from other modules will be looked up in tr.shaders[] - // shader indexes from drawsurfs will be looked up in sortedShaders[] - // lower indexed sortedShaders must be rendered first (opaque surfaces before translucent) - int numShaders; - shader_t *shaders[MAX_SHADERS]; - shader_t *sortedShaders[MAX_SHADERS]; - - int numSkins; - skin_t *skins[MAX_SKINS]; - - float sinTable[FUNCTABLE_SIZE]; - float squareTable[FUNCTABLE_SIZE]; - float triangleTable[FUNCTABLE_SIZE]; - float sawToothTable[FUNCTABLE_SIZE]; - float inverseSawToothTable[FUNCTABLE_SIZE]; - float fogTable[FOG_TABLE_SIZE]; -} trGlobals_t; - -extern backEndState_t backEnd; -extern trGlobals_t tr; -extern glstate_t glState; // outside of TR since it shouldn't be cleared during ref re-init - -// -// cvars -// -extern cvar_t *r_flareSize; -extern cvar_t *r_flareFade; -// coefficient for the flare intensity falloff function. -#define FLARE_STDCOEFF "150" -extern cvar_t *r_flareCoeff; - -extern cvar_t *r_railWidth; -extern cvar_t *r_railCoreWidth; -extern cvar_t *r_railSegmentLength; - -extern cvar_t *r_ignore; // used for debugging anything -extern cvar_t *r_verbose; // used for verbose debug spew -extern cvar_t *r_ignoreFastPath; // allows us to ignore our Tess fast paths - -extern cvar_t *r_znear; // near Z clip plane -extern cvar_t *r_zproj; // z distance of projection plane -extern cvar_t *r_stereoSeparation; // separation of cameras for stereo rendering - -extern cvar_t *r_measureOverdraw; // enables stencil buffer overdraw measurement - -extern cvar_t *r_lodbias; // push/pull LOD transitions -extern cvar_t *r_lodscale; - -extern cvar_t *r_primitives; // "0" = based on compiled vertex array existance - // "1" = glDrawElemet tristrips - // "2" = glDrawElements triangles - // "-1" = no drawing - -extern cvar_t *r_inGameVideo; // controls whether in game video should be draw -extern cvar_t *r_fastsky; // controls whether sky should be cleared or drawn -extern cvar_t *r_drawSun; // controls drawing of sun quad -extern cvar_t *r_dynamiclight; // dynamic lights enabled/disabled -extern cvar_t *r_dlightBacks; // dlight non-facing surfaces for continuity - -extern cvar_t *r_norefresh; // bypasses the ref rendering -extern cvar_t *r_drawentities; // disable/enable entity rendering -extern cvar_t *r_drawworld; // disable/enable world rendering -extern cvar_t *r_speeds; // various levels of information display -extern cvar_t *r_detailTextures; // enables/disables detail texturing stages -extern cvar_t *r_novis; // disable/enable usage of PVS -extern cvar_t *r_nocull; -extern cvar_t *r_facePlaneCull; // enables culling of planar surfaces with back side test -extern cvar_t *r_nocurves; -extern cvar_t *r_showcluster; - -extern cvar_t *r_gamma; - -extern cvar_t *r_nobind; // turns off binding to appropriate textures -extern cvar_t *r_singleShader; // make most world faces use default shader -extern cvar_t *r_roundImagesDown; -extern cvar_t *r_colorMipLevels; // development aid to see texture mip usage -extern cvar_t *r_picmip; // controls picmip values -extern cvar_t *r_finish; -extern cvar_t *r_textureMode; -extern cvar_t *r_offsetFactor; -extern cvar_t *r_offsetUnits; - -extern cvar_t *r_fullbright; // avoid lightmap pass -extern cvar_t *r_lightmap; // render lightmaps only -extern cvar_t *r_vertexLight; // vertex lighting mode for better performance -extern cvar_t *r_uiFullScreen; // ui is running fullscreen - -extern cvar_t *r_logFile; // number of frames to emit GL logs -extern cvar_t *r_showtris; // enables wireframe rendering of the world -extern cvar_t *r_showsky; // forces sky in front of all surfaces -extern cvar_t *r_shownormals; // draws wireframe normals -extern cvar_t *r_clear; // force screen clear every frame - -extern cvar_t *r_shadows; // controls shadows: 0 = none, 1 = blur, 2 = stencil, 3 = black planar projection -extern cvar_t *r_flares; // light flares - -extern cvar_t *r_intensity; - -extern cvar_t *r_lockpvs; -extern cvar_t *r_noportals; -extern cvar_t *r_portalOnly; - -extern cvar_t *r_subdivisions; -extern cvar_t *r_lodCurveError; -extern cvar_t *r_skipBackEnd; - -extern cvar_t *r_anaglyphMode; - -extern cvar_t *r_greyscale; - -extern cvar_t *r_ignoreGLErrors; - -extern cvar_t *r_overBrightBits; -extern cvar_t *r_mapOverBrightBits; - -extern cvar_t *r_debugSurface; -extern cvar_t *r_simpleMipMaps; - -extern cvar_t *r_showImages; -extern cvar_t *r_debugSort; - -extern cvar_t *r_printShaders; - -extern cvar_t *r_marksOnTriangleMeshes; - -//==================================================================== - -void R_SwapBuffers( int ); - -void R_RenderView( viewParms_t *parms ); - -void R_AddMD3Surfaces( trRefEntity_t *e ); -void R_AddNullModelSurfaces( trRefEntity_t *e ); -void R_AddBeamSurfaces( trRefEntity_t *e ); -void R_AddRailSurfaces( trRefEntity_t *e, qboolean isUnderwater ); -void R_AddLightningBoltSurfaces( trRefEntity_t *e ); - -void R_AddPolygonSurfaces( void ); - -void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader, - int *fogNum, int *dlightMap ); - -void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int fogIndex, int dlightMap ); - - -#define CULL_IN 0 // completely unclipped -#define CULL_CLIP 1 // clipped by one or more planes -#define CULL_OUT 2 // completely outside the clipping planes -void R_LocalNormalToWorld (vec3_t local, vec3_t world); -void R_LocalPointToWorld (vec3_t local, vec3_t world); -int R_CullLocalBox (vec3_t bounds[2]); -int R_CullPointAndRadius( vec3_t origin, float radius ); -int R_CullLocalPointAndRadius( vec3_t origin, float radius ); - -void R_SetupProjection(viewParms_t *dest, float zProj, qboolean computeFrustum); -void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, orientationr_t *or ); - -/* -** GL wrapper/helper functions -*/ -void GL_Bind( image_t *image ); -void GL_SetDefaultState (void); -void GL_SelectTexture( int unit ); -void GL_TextureMode( const char *string ); -void GL_CheckErrors( void ); -void GL_State( unsigned long stateVector ); -void GL_TexEnv( int env ); -void GL_Cull( int cullType ); - -#define GLS_SRCBLEND_ZERO 0x00000001 -#define GLS_SRCBLEND_ONE 0x00000002 -#define GLS_SRCBLEND_DST_COLOR 0x00000003 -#define GLS_SRCBLEND_ONE_MINUS_DST_COLOR 0x00000004 -#define GLS_SRCBLEND_SRC_ALPHA 0x00000005 -#define GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA 0x00000006 -#define GLS_SRCBLEND_DST_ALPHA 0x00000007 -#define GLS_SRCBLEND_ONE_MINUS_DST_ALPHA 0x00000008 -#define GLS_SRCBLEND_ALPHA_SATURATE 0x00000009 -#define GLS_SRCBLEND_BITS 0x0000000f - -#define GLS_DSTBLEND_ZERO 0x00000010 -#define GLS_DSTBLEND_ONE 0x00000020 -#define GLS_DSTBLEND_SRC_COLOR 0x00000030 -#define GLS_DSTBLEND_ONE_MINUS_SRC_COLOR 0x00000040 -#define GLS_DSTBLEND_SRC_ALPHA 0x00000050 -#define GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA 0x00000060 -#define GLS_DSTBLEND_DST_ALPHA 0x00000070 -#define GLS_DSTBLEND_ONE_MINUS_DST_ALPHA 0x00000080 -#define GLS_DSTBLEND_BITS 0x000000f0 - -#define GLS_DEPTHMASK_TRUE 0x00000100 - -#define GLS_POLYMODE_LINE 0x00001000 - -#define GLS_DEPTHTEST_DISABLE 0x00010000 -#define GLS_DEPTHFUNC_EQUAL 0x00020000 - -#define GLS_ATEST_GT_0 0x10000000 -#define GLS_ATEST_LT_80 0x20000000 -#define GLS_ATEST_GE_80 0x40000000 -#define GLS_ATEST_BITS 0x70000000 - -#define GLS_DEFAULT GLS_DEPTHMASK_TRUE - -void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty); -void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty); - -void RE_BeginFrame( stereoFrame_t stereoFrame ); -void RE_BeginRegistration( glconfig_t *glconfig ); -void RE_LoadWorldMap( const char *mapname ); -void RE_SetWorldVisData( const byte *vis ); -qhandle_t RE_RegisterModel( const char *name ); -qhandle_t RE_RegisterSkin( const char *name ); -void RE_Shutdown( qboolean destroyWindow ); - -qboolean R_GetEntityToken( char *buffer, int size ); - -model_t *R_AllocModel( void ); - -void R_Init( void ); - -void R_SetColorMappings( void ); -void R_GammaCorrect( byte *buffer, int bufSize ); - -void R_ImageList_f( void ); -void R_SkinList_f( void ); -// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=516 -const void *RB_TakeScreenshotCmd( const void *data ); -void R_ScreenShot_f( void ); - -void R_InitFogTable( void ); -float R_FogFactor( float s, float t ); -void R_InitImages( void ); -void R_DeleteTextures( void ); -int R_SumOfUsedImages( void ); -void R_InitSkins( void ); -skin_t *R_GetSkinByHandle( qhandle_t hSkin ); - -int R_ComputeLOD( trRefEntity_t *ent ); - -const void *RB_TakeVideoFrameCmd( const void *data ); - -// -// tr_shader.c -// -shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ); -shader_t *R_GetShaderByHandle( qhandle_t hShader ); -shader_t *R_GetShaderByState( int index, long *cycleTime ); -shader_t *R_FindShaderByName( const char *name ); -void R_InitShaders( void ); -void R_ShaderList_f( void ); -void R_RemapShader(const char *oldShader, const char *newShader, const char *timeOffset); - -/* -==================================================================== - -TESSELATOR/SHADER DECLARATIONS - -==================================================================== -*/ -typedef byte color4ub_t[4]; - -typedef struct stageVars -{ - color4ub_t colors[SHADER_MAX_VERTEXES]; - vec2_t texcoords[NUM_TEXTURE_BUNDLES][SHADER_MAX_VERTEXES]; -} stageVars_t; - - -typedef struct shaderCommands_s -{ - glIndex_t indexes[SHADER_MAX_INDEXES] QALIGN(16); - vec4_t xyz[SHADER_MAX_VERTEXES] QALIGN(16); - vec4_t normal[SHADER_MAX_VERTEXES] QALIGN(16); - vec2_t texCoords[SHADER_MAX_VERTEXES][2] QALIGN(16); - color4ub_t vertexColors[SHADER_MAX_VERTEXES] QALIGN(16); - int vertexDlightBits[SHADER_MAX_VERTEXES] QALIGN(16); - - stageVars_t svars QALIGN(16); - - color4ub_t constantColor255[SHADER_MAX_VERTEXES] QALIGN(16); - - shader_t *shader; - float shaderTime; - int fogNum; - - int dlightBits; // or together of all vertexDlightBits - - int numIndexes; - int numVertexes; - - // info extracted from current shader - int numPasses; - void (*currentStageIteratorFunc)( void ); - shaderStage_t **xstages; -} shaderCommands_t; - -extern shaderCommands_t tess; - -void RB_BeginSurface(shader_t *shader, int fogNum ); -void RB_EndSurface(void); -void RB_CheckOverflow( int verts, int indexes ); -#define RB_CHECKOVERFLOW(v,i) if (tess.numVertexes + (v) >= SHADER_MAX_VERTEXES || tess.numIndexes + (i) >= SHADER_MAX_INDEXES ) {RB_CheckOverflow(v,i);} - -void RB_StageIteratorGeneric( void ); -void RB_StageIteratorSky( void ); -void RB_StageIteratorVertexLitTexture( void ); -void RB_StageIteratorLightmappedMultitexture( void ); - -void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, byte *color ); -void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, float s1, float t1, float s2, float t2 ); - -void RB_ShowImages( void ); - - -/* -============================================================ - -WORLD MAP - -============================================================ -*/ - -void R_AddBrushModelSurfaces( trRefEntity_t *e ); -void R_AddWorldSurfaces( void ); -qboolean R_inPVS( const vec3_t p1, const vec3_t p2 ); - - -/* -============================================================ - -FLARES - -============================================================ -*/ - -void R_ClearFlares( void ); - -void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ); -void RB_AddDlightFlares( void ); -void RB_RenderFlares (void); - -/* -============================================================ - -LIGHTS - -============================================================ -*/ - -void R_DlightBmodel( bmodel_t *bmodel ); -void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ); -void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or ); -int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ); - - -/* -============================================================ - -SHADOWS - -============================================================ -*/ - -void RB_ShadowTessEnd( void ); -void RB_ShadowFinish( void ); -void RB_ProjectionShadowDeform( void ); - -/* -============================================================ - -SKIES - -============================================================ -*/ - -void R_BuildCloudData( shaderCommands_t *shader ); -void R_InitSkyTexCoords( float cloudLayerHeight ); -void R_DrawSkyBox( shaderCommands_t *shader ); -void RB_DrawSun( float scale, shader_t *shader ); -void RB_ClipSkyPolygons( shaderCommands_t *shader ); - -/* -============================================================ - -CURVE TESSELATION - -============================================================ -*/ - -#define PATCH_STITCHING - -srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, - drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ); -srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror ); -srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror ); -void R_FreeSurfaceGridMesh( srfGridMesh_t *grid ); - -/* -============================================================ - -MARKERS, POLYGON PROJECTION ON WORLD POLYGONS - -============================================================ -*/ - -int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, - int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ); - - -/* -============================================================ - -SCENE GENERATION - -============================================================ -*/ - -void R_InitNextFrame( void ); - -void RE_ClearScene( void ); -void RE_AddRefEntityToScene( const refEntity_t *ent ); -void RE_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num ); -void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ); -void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ); -void RE_RenderScene( const refdef_t *fd ); - -/* -============================================================= - -UNCOMPRESSING BONES - -============================================================= -*/ - -#define MC_BITS_X (16) -#define MC_BITS_Y (16) -#define MC_BITS_Z (16) -#define MC_BITS_VECT (16) - -#define MC_SCALE_X (1.0f/64) -#define MC_SCALE_Y (1.0f/64) -#define MC_SCALE_Z (1.0f/64) - -void MC_UnCompress(float mat[3][4],const unsigned char * comp); - -/* -============================================================= - -ANIMATED MODELS - -============================================================= -*/ - -void R_MDRAddAnimSurfaces( trRefEntity_t *ent ); -void RB_MDRSurfaceAnim( mdrSurface_t *surface ); -qboolean R_LoadIQM (model_t *mod, void *buffer, int filesize, const char *name ); -void R_AddIQMSurfaces( trRefEntity_t *ent ); -void RB_IQMSurfaceAnim( surfaceType_t *surface ); -int R_IQMLerpTag( orientation_t *tag, iqmData_t *data, - int startFrame, int endFrame, - float frac, const char *tagName ); - -/* -============================================================= - -IMAGE LOADERS - -============================================================= -*/ - -void R_LoadBMP( const char *name, byte **pic, int *width, int *height ); -void R_LoadJPG( const char *name, byte **pic, int *width, int *height ); -void R_LoadPCX( const char *name, byte **pic, int *width, int *height ); -void R_LoadPNG( const char *name, byte **pic, int *width, int *height ); -void R_LoadTGA( const char *name, byte **pic, int *width, int *height ); - -/* -============================================================= -============================================================= -*/ -void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix, - vec4_t eye, vec4_t dst ); -void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ); - -void RB_DeformTessGeometry( void ); - -void RB_CalcEnvironmentTexCoords( float *dstTexCoords ); -void RB_CalcFogTexCoords( float *dstTexCoords ); -void RB_CalcScrollTexCoords( const float scroll[2], float *dstTexCoords ); -void RB_CalcRotateTexCoords( float rotSpeed, float *dstTexCoords ); -void RB_CalcScaleTexCoords( const float scale[2], float *dstTexCoords ); -void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *dstTexCoords ); -void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *dstTexCoords ); -void RB_CalcModulateColorsByFog( unsigned char *dstColors ); -void RB_CalcModulateAlphasByFog( unsigned char *dstColors ); -void RB_CalcModulateRGBAsByFog( unsigned char *dstColors ); -void RB_CalcWaveAlpha( const waveForm_t *wf, unsigned char *dstColors ); -void RB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors ); -void RB_CalcAlphaFromEntity( unsigned char *dstColors ); -void RB_CalcAlphaFromOneMinusEntity( unsigned char *dstColors ); -void RB_CalcStretchTexCoords( const waveForm_t *wf, float *texCoords ); -void RB_CalcColorFromEntity( unsigned char *dstColors ); -void RB_CalcColorFromOneMinusEntity( unsigned char *dstColors ); -void RB_CalcSpecularAlpha( unsigned char *alphas ); -void RB_CalcDiffuseColor( unsigned char *colors ); - -/* -============================================================= - -RENDERER BACK END FUNCTIONS - -============================================================= -*/ - -void RB_ExecuteRenderCommands( const void *data ); - -/* -============================================================= - -RENDERER BACK END COMMAND QUEUE - -============================================================= -*/ - -#define MAX_RENDER_COMMANDS 0x40000 - -typedef struct { - byte cmds[MAX_RENDER_COMMANDS]; - int used; -} renderCommandList_t; - -typedef struct { - int commandId; - float color[4]; -} setColorCommand_t; - -typedef struct { - int commandId; - int buffer; -} drawBufferCommand_t; - -typedef struct { - int commandId; - image_t *image; - int width; - int height; - void *data; -} subImageCommand_t; - -typedef struct { - int commandId; -} swapBuffersCommand_t; - -typedef struct { - int commandId; - int buffer; -} endFrameCommand_t; - -typedef struct { - int commandId; - shader_t *shader; - float x, y; - float w, h; - float s1, t1; - float s2, t2; -} stretchPicCommand_t; - -typedef struct { - int commandId; - trRefdef_t refdef; - viewParms_t viewParms; - drawSurf_t *drawSurfs; - int numDrawSurfs; -} drawSurfsCommand_t; - -typedef struct { - int commandId; - int x; - int y; - int width; - int height; - char *fileName; - qboolean jpeg; -} screenshotCommand_t; - -typedef struct { - int commandId; - int width; - int height; - byte *captureBuffer; - byte *encodeBuffer; - qboolean motionJpeg; -} videoFrameCommand_t; - -typedef struct -{ - int commandId; - - GLboolean rgba[4]; -} colorMaskCommand_t; - -typedef struct -{ - int commandId; -} clearDepthCommand_t; - -typedef enum { - RC_END_OF_LIST, - RC_SET_COLOR, - RC_STRETCH_PIC, - RC_DRAW_SURFS, - RC_DRAW_BUFFER, - RC_SWAP_BUFFERS, - RC_SCREENSHOT, - RC_VIDEOFRAME, - RC_COLORMASK, - RC_CLEARDEPTH -} renderCommand_t; - - -// these are sort of arbitrary limits. -// the limits apply to the sum of all scenes in a frame -- -// the main view, all the 3D icons, etc -#define MAX_POLYS 600 -#define MAX_POLYVERTS 3000 - -// all of the information needed by the back end must be -// contained in a backEndData_t -typedef struct { - drawSurf_t drawSurfs[MAX_DRAWSURFS]; - dlight_t dlights[MAX_DLIGHTS]; - trRefEntity_t entities[MAX_REFENTITIES]; - srfPoly_t *polys;//[MAX_POLYS]; - polyVert_t *polyVerts;//[MAX_POLYVERTS]; - renderCommandList_t commands; -} backEndData_t; - -extern int max_polys; -extern int max_polyverts; - -extern backEndData_t *backEndData; // the second one may not be allocated - - -void *R_GetCommandBuffer( int bytes ); -void RB_ExecuteRenderCommands( const void *data ); - -void R_IssuePendingRenderCommands( void ); - -void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ); - -void RE_SetColor( const float *rgba ); -void RE_StretchPic ( float x, float y, float w, float h, - float s1, float t1, float s2, float t2, qhandle_t hShader ); -void RE_BeginFrame( stereoFrame_t stereoFrame ); -void RE_EndFrame( int *frontEndMsec, int *backEndMsec ); -void RE_SaveJPG(char * filename, int quality, int image_width, int image_height, - unsigned char *image_buffer, int padding); -size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality, - int image_width, int image_height, byte *image_buffer, int padding); -void RE_TakeVideoFrame( int width, int height, - byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg ); - - -#endif //TR_LOCAL_H diff --git a/code/renderergl1/tr_main.c b/code/renderergl1/tr_main.c deleted file mode 100644 index 6a2118f169..0000000000 --- a/code/renderergl1/tr_main.c +++ /dev/null @@ -1,1389 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_main.c -- main control flow for each frame - -#include "tr_local.h" - -#include // memcpy - -trGlobals_t tr; - -static float s_flipMatrix[16] = { - // convert from our coordinate system (looking down X) - // to OpenGL's coordinate system (looking down -Z) - 0, 0, -1, 0, - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1 -}; - - -refimport_t ri; - -// entities that will have procedurally generated surfaces will just -// point at this for their sorting surface -surfaceType_t entitySurface = SF_ENTITY; - -/* -================= -R_CullLocalBox - -Returns CULL_IN, CULL_CLIP, or CULL_OUT -================= -*/ -int R_CullLocalBox (vec3_t bounds[2]) { - int i, j; - vec3_t transformed[8]; - float dists[8]; - vec3_t v; - cplane_t *frust; - int anyBack; - int front, back; - - if ( r_nocull->integer ) { - return CULL_CLIP; - } - - // transform into world space - for (i = 0 ; i < 8 ; i++) { - v[0] = bounds[i&1][0]; - v[1] = bounds[(i>>1)&1][1]; - v[2] = bounds[(i>>2)&1][2]; - - VectorCopy( tr.or.origin, transformed[i] ); - VectorMA( transformed[i], v[0], tr.or.axis[0], transformed[i] ); - VectorMA( transformed[i], v[1], tr.or.axis[1], transformed[i] ); - VectorMA( transformed[i], v[2], tr.or.axis[2], transformed[i] ); - } - - // check against frustum planes - anyBack = 0; - for (i = 0 ; i < 4 ; i++) { - frust = &tr.viewParms.frustum[i]; - - front = back = 0; - for (j = 0 ; j < 8 ; j++) { - dists[j] = DotProduct(transformed[j], frust->normal); - if ( dists[j] > frust->dist ) { - front = 1; - if ( back ) { - break; // a point is in front - } - } else { - back = 1; - } - } - if ( !front ) { - // all points were behind one of the planes - return CULL_OUT; - } - anyBack |= back; - } - - if ( !anyBack ) { - return CULL_IN; // completely inside frustum - } - - return CULL_CLIP; // partially clipped -} - -/* -** R_CullLocalPointAndRadius -*/ -int R_CullLocalPointAndRadius( vec3_t pt, float radius ) -{ - vec3_t transformed; - - R_LocalPointToWorld( pt, transformed ); - - return R_CullPointAndRadius( transformed, radius ); -} - -/* -** R_CullPointAndRadius -*/ -int R_CullPointAndRadius( vec3_t pt, float radius ) -{ - int i; - float dist; - cplane_t *frust; - qboolean mightBeClipped = qfalse; - - if ( r_nocull->integer ) { - return CULL_CLIP; - } - - // check against frustum planes - for (i = 0 ; i < 4 ; i++) - { - frust = &tr.viewParms.frustum[i]; - - dist = DotProduct( pt, frust->normal) - frust->dist; - if ( dist < -radius ) - { - return CULL_OUT; - } - else if ( dist <= radius ) - { - mightBeClipped = qtrue; - } - } - - if ( mightBeClipped ) - { - return CULL_CLIP; - } - - return CULL_IN; // completely inside frustum -} - - -/* -================= -R_LocalNormalToWorld - -================= -*/ -void R_LocalNormalToWorld (vec3_t local, vec3_t world) { - world[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0]; - world[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1]; - world[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2]; -} - -/* -================= -R_LocalPointToWorld - -================= -*/ -void R_LocalPointToWorld (vec3_t local, vec3_t world) { - world[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0] + tr.or.origin[0]; - world[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1] + tr.or.origin[1]; - world[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2] + tr.or.origin[2]; -} - -/* -================= -R_WorldToLocal - -================= -*/ -void R_WorldToLocal (vec3_t world, vec3_t local) { - local[0] = DotProduct(world, tr.or.axis[0]); - local[1] = DotProduct(world, tr.or.axis[1]); - local[2] = DotProduct(world, tr.or.axis[2]); -} - -/* -========================== -R_TransformModelToClip - -========================== -*/ -void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix, - vec4_t eye, vec4_t dst ) { - int i; - - for ( i = 0 ; i < 4 ; i++ ) { - eye[i] = - src[0] * modelMatrix[ i + 0 * 4 ] + - src[1] * modelMatrix[ i + 1 * 4 ] + - src[2] * modelMatrix[ i + 2 * 4 ] + - 1 * modelMatrix[ i + 3 * 4 ]; - } - - for ( i = 0 ; i < 4 ; i++ ) { - dst[i] = - eye[0] * projectionMatrix[ i + 0 * 4 ] + - eye[1] * projectionMatrix[ i + 1 * 4 ] + - eye[2] * projectionMatrix[ i + 2 * 4 ] + - eye[3] * projectionMatrix[ i + 3 * 4 ]; - } -} - -/* -========================== -R_TransformClipToWindow - -========================== -*/ -void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ) { - normalized[0] = clip[0] / clip[3]; - normalized[1] = clip[1] / clip[3]; - normalized[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] ); - - window[0] = 0.5f * ( 1.0f + normalized[0] ) * view->viewportWidth; - window[1] = 0.5f * ( 1.0f + normalized[1] ) * view->viewportHeight; - window[2] = normalized[2]; - - window[0] = (int) ( window[0] + 0.5 ); - window[1] = (int) ( window[1] + 0.5 ); -} - - -/* -========================== -myGlMultMatrix - -========================== -*/ -void myGlMultMatrix( const float *a, const float *b, float *out ) { - int i, j; - - for ( i = 0 ; i < 4 ; i++ ) { - for ( j = 0 ; j < 4 ; j++ ) { - out[ i * 4 + j ] = - a [ i * 4 + 0 ] * b [ 0 * 4 + j ] - + a [ i * 4 + 1 ] * b [ 1 * 4 + j ] - + a [ i * 4 + 2 ] * b [ 2 * 4 + j ] - + a [ i * 4 + 3 ] * b [ 3 * 4 + j ]; - } - } -} - -/* -================= -R_RotateForEntity - -Generates an orientation for an entity and viewParms -Does NOT produce any GL calls -Called by both the front end and the back end -================= -*/ -void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, - orientationr_t *or ) { - float glMatrix[16]; - vec3_t delta; - float axisLength; - - if ( ent->e.reType != RT_MODEL ) { - *or = viewParms->world; - return; - } - - VectorCopy( ent->e.origin, or->origin ); - - VectorCopy( ent->e.axis[0], or->axis[0] ); - VectorCopy( ent->e.axis[1], or->axis[1] ); - VectorCopy( ent->e.axis[2], or->axis[2] ); - - glMatrix[0] = or->axis[0][0]; - glMatrix[4] = or->axis[1][0]; - glMatrix[8] = or->axis[2][0]; - glMatrix[12] = or->origin[0]; - - glMatrix[1] = or->axis[0][1]; - glMatrix[5] = or->axis[1][1]; - glMatrix[9] = or->axis[2][1]; - glMatrix[13] = or->origin[1]; - - glMatrix[2] = or->axis[0][2]; - glMatrix[6] = or->axis[1][2]; - glMatrix[10] = or->axis[2][2]; - glMatrix[14] = or->origin[2]; - - glMatrix[3] = 0; - glMatrix[7] = 0; - glMatrix[11] = 0; - glMatrix[15] = 1; - - myGlMultMatrix( glMatrix, viewParms->world.modelMatrix, or->modelMatrix ); - - // calculate the viewer origin in the model's space - // needed for fog, specular, and environment mapping - VectorSubtract( viewParms->or.origin, or->origin, delta ); - - // compensate for scale in the axes if necessary - if ( ent->e.nonNormalizedAxes ) { - axisLength = VectorLength( ent->e.axis[0] ); - if ( !axisLength ) { - axisLength = 0; - } else { - axisLength = 1.0f / axisLength; - } - } else { - axisLength = 1.0f; - } - - or->viewOrigin[0] = DotProduct( delta, or->axis[0] ) * axisLength; - or->viewOrigin[1] = DotProduct( delta, or->axis[1] ) * axisLength; - or->viewOrigin[2] = DotProduct( delta, or->axis[2] ) * axisLength; -} - -/* -================= -R_RotateForViewer - -Sets up the modelview matrix for a given viewParm -================= -*/ -void R_RotateForViewer (void) -{ - float viewerMatrix[16]; - vec3_t origin; - - Com_Memset (&tr.or, 0, sizeof(tr.or)); - tr.or.axis[0][0] = 1; - tr.or.axis[1][1] = 1; - tr.or.axis[2][2] = 1; - VectorCopy (tr.viewParms.or.origin, tr.or.viewOrigin); - - // transform by the camera placement - VectorCopy( tr.viewParms.or.origin, origin ); - - viewerMatrix[0] = tr.viewParms.or.axis[0][0]; - viewerMatrix[4] = tr.viewParms.or.axis[0][1]; - viewerMatrix[8] = tr.viewParms.or.axis[0][2]; - viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8]; - - viewerMatrix[1] = tr.viewParms.or.axis[1][0]; - viewerMatrix[5] = tr.viewParms.or.axis[1][1]; - viewerMatrix[9] = tr.viewParms.or.axis[1][2]; - viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9]; - - viewerMatrix[2] = tr.viewParms.or.axis[2][0]; - viewerMatrix[6] = tr.viewParms.or.axis[2][1]; - viewerMatrix[10] = tr.viewParms.or.axis[2][2]; - viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10]; - - viewerMatrix[3] = 0; - viewerMatrix[7] = 0; - viewerMatrix[11] = 0; - viewerMatrix[15] = 1; - - // convert from our coordinate system (looking down X) - // to OpenGL's coordinate system (looking down -Z) - myGlMultMatrix( viewerMatrix, s_flipMatrix, tr.or.modelMatrix ); - - tr.viewParms.world = tr.or; - -} - -/* -** SetFarClip -*/ -static void R_SetFarClip( void ) -{ - float farthestCornerDistance = 0; - int i; - - // if not rendering the world (icons, menus, etc) - // set a 2k far clip plane - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - tr.viewParms.zFar = 2048; - return; - } - - // - // set far clipping planes dynamically - // - farthestCornerDistance = 0; - for ( i = 0; i < 8; i++ ) - { - vec3_t v; - vec3_t vecTo; - float distance; - - if ( i & 1 ) - { - v[0] = tr.viewParms.visBounds[0][0]; - } - else - { - v[0] = tr.viewParms.visBounds[1][0]; - } - - if ( i & 2 ) - { - v[1] = tr.viewParms.visBounds[0][1]; - } - else - { - v[1] = tr.viewParms.visBounds[1][1]; - } - - if ( i & 4 ) - { - v[2] = tr.viewParms.visBounds[0][2]; - } - else - { - v[2] = tr.viewParms.visBounds[1][2]; - } - - VectorSubtract( v, tr.viewParms.or.origin, vecTo ); - - distance = vecTo[0] * vecTo[0] + vecTo[1] * vecTo[1] + vecTo[2] * vecTo[2]; - - if ( distance > farthestCornerDistance ) - { - farthestCornerDistance = distance; - } - } - tr.viewParms.zFar = sqrt( farthestCornerDistance ); -} - -/* -================= -R_SetupFrustum - -Set up the culling frustum planes for the current view using the results we got from computing the first two rows of -the projection matrix. -================= -*/ -void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, float zProj, float stereoSep) -{ - vec3_t ofsorigin; - float oppleg, adjleg, length; - int i; - - if(stereoSep == 0 && xmin == -xmax) - { - // symmetric case can be simplified - VectorCopy(dest->or.origin, ofsorigin); - - length = sqrt(xmax * xmax + zProj * zProj); - oppleg = xmax / length; - adjleg = zProj / length; - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[0].normal); - VectorMA(dest->frustum[0].normal, adjleg, dest->or.axis[1], dest->frustum[0].normal); - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[1].normal); - VectorMA(dest->frustum[1].normal, -adjleg, dest->or.axis[1], dest->frustum[1].normal); - } - else - { - // In stereo rendering, due to the modification of the projection matrix, dest->or.origin is not the - // actual origin that we're rendering so offset the tip of the view pyramid. - VectorMA(dest->or.origin, stereoSep, dest->or.axis[1], ofsorigin); - - oppleg = xmax + stereoSep; - length = sqrt(oppleg * oppleg + zProj * zProj); - VectorScale(dest->or.axis[0], oppleg / length, dest->frustum[0].normal); - VectorMA(dest->frustum[0].normal, zProj / length, dest->or.axis[1], dest->frustum[0].normal); - - oppleg = xmin + stereoSep; - length = sqrt(oppleg * oppleg + zProj * zProj); - VectorScale(dest->or.axis[0], -oppleg / length, dest->frustum[1].normal); - VectorMA(dest->frustum[1].normal, -zProj / length, dest->or.axis[1], dest->frustum[1].normal); - } - - length = sqrt(ymax * ymax + zProj * zProj); - oppleg = ymax / length; - adjleg = zProj / length; - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[2].normal); - VectorMA(dest->frustum[2].normal, adjleg, dest->or.axis[2], dest->frustum[2].normal); - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[3].normal); - VectorMA(dest->frustum[3].normal, -adjleg, dest->or.axis[2], dest->frustum[3].normal); - - for (i=0 ; i<4 ; i++) { - dest->frustum[i].type = PLANE_NON_AXIAL; - dest->frustum[i].dist = DotProduct (ofsorigin, dest->frustum[i].normal); - SetPlaneSignbits( &dest->frustum[i] ); - } -} - -/* -=============== -R_SetupProjection -=============== -*/ -void R_SetupProjection(viewParms_t *dest, float zProj, qboolean computeFrustum) -{ - float xmin, xmax, ymin, ymax; - float width, height, stereoSep = r_stereoSeparation->value; - - /* - * offset the view origin of the viewer for stereo rendering - * by setting the projection matrix appropriately. - */ - - if(stereoSep != 0) - { - if(dest->stereoFrame == STEREO_LEFT) - stereoSep = zProj / stereoSep; - else if(dest->stereoFrame == STEREO_RIGHT) - stereoSep = zProj / -stereoSep; - else - stereoSep = 0; - } - - ymax = zProj * tan(dest->fovY * M_PI / 360.0f); - ymin = -ymax; - - xmax = zProj * tan(dest->fovX * M_PI / 360.0f); - xmin = -xmax; - - width = xmax - xmin; - height = ymax - ymin; - - dest->projectionMatrix[0] = 2 * zProj / width; - dest->projectionMatrix[4] = 0; - dest->projectionMatrix[8] = (xmax + xmin + 2 * stereoSep) / width; - dest->projectionMatrix[12] = 2 * zProj * stereoSep / width; - - dest->projectionMatrix[1] = 0; - dest->projectionMatrix[5] = 2 * zProj / height; - dest->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0 - dest->projectionMatrix[13] = 0; - - dest->projectionMatrix[3] = 0; - dest->projectionMatrix[7] = 0; - dest->projectionMatrix[11] = -1; - dest->projectionMatrix[15] = 0; - - // Now that we have all the data for the projection matrix we can also setup the view frustum. - if(computeFrustum) - R_SetupFrustum(dest, xmin, xmax, ymax, zProj, stereoSep); -} - -/* -=============== -R_SetupProjectionZ - -Sets the z-component transformation part in the projection matrix -=============== -*/ -void R_SetupProjectionZ(viewParms_t *dest) -{ - float zNear, zFar, depth; - - zNear = r_znear->value; - zFar = dest->zFar; - depth = zFar - zNear; - - dest->projectionMatrix[2] = 0; - dest->projectionMatrix[6] = 0; - dest->projectionMatrix[10] = -( zFar + zNear ) / depth; - dest->projectionMatrix[14] = -2 * zFar * zNear / depth; -} - -/* -================= -R_MirrorPoint -================= -*/ -void R_MirrorPoint (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) { - int i; - vec3_t local; - vec3_t transformed; - float d; - - VectorSubtract( in, surface->origin, local ); - - VectorClear( transformed ); - for ( i = 0 ; i < 3 ; i++ ) { - d = DotProduct(local, surface->axis[i]); - VectorMA( transformed, d, camera->axis[i], transformed ); - } - - VectorAdd( transformed, camera->origin, out ); -} - -void R_MirrorVector (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) { - int i; - float d; - - VectorClear( out ); - for ( i = 0 ; i < 3 ; i++ ) { - d = DotProduct(in, surface->axis[i]); - VectorMA( out, d, camera->axis[i], out ); - } -} - - -/* -============= -R_PlaneForSurface -============= -*/ -void R_PlaneForSurface (surfaceType_t *surfType, cplane_t *plane) { - srfTriangles_t *tri; - srfPoly_t *poly; - drawVert_t *v1, *v2, *v3; - vec4_t plane4; - - if (!surfType) { - Com_Memset (plane, 0, sizeof(*plane)); - plane->normal[0] = 1; - return; - } - switch (*surfType) { - case SF_FACE: - *plane = ((srfSurfaceFace_t *)surfType)->plane; - return; - case SF_TRIANGLES: - tri = (srfTriangles_t *)surfType; - v1 = tri->verts + tri->indexes[0]; - v2 = tri->verts + tri->indexes[1]; - v3 = tri->verts + tri->indexes[2]; - PlaneFromPoints( plane4, v1->xyz, v2->xyz, v3->xyz ); - VectorCopy( plane4, plane->normal ); - plane->dist = plane4[3]; - return; - case SF_POLY: - poly = (srfPoly_t *)surfType; - PlaneFromPoints( plane4, poly->verts[0].xyz, poly->verts[1].xyz, poly->verts[2].xyz ); - VectorCopy( plane4, plane->normal ); - plane->dist = plane4[3]; - return; - default: - Com_Memset (plane, 0, sizeof(*plane)); - plane->normal[0] = 1; - return; - } -} - -/* -================= -R_GetPortalOrientation - -entityNum is the entity that the portal surface is a part of, which may -be moving and rotating. - -Returns qtrue if it should be mirrored -================= -*/ -qboolean R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum, - orientation_t *surface, orientation_t *camera, - vec3_t pvsOrigin, qboolean *mirror ) { - int i; - cplane_t originalPlane, plane; - trRefEntity_t *e; - float d; - vec3_t transformed; - - // create plane axis for the portal we are seeing - R_PlaneForSurface( drawSurf->surface, &originalPlane ); - - // rotate the plane if necessary - if ( entityNum != REFENTITYNUM_WORLD ) { - tr.currentEntityNum = entityNum; - tr.currentEntity = &tr.refdef.entities[entityNum]; - - // get the orientation of the entity - R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or ); - - // rotate the plane, but keep the non-rotated version for matching - // against the portalSurface entities - R_LocalNormalToWorld( originalPlane.normal, plane.normal ); - plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin ); - - // translate the original plane - originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin ); - } else { - plane = originalPlane; - } - - VectorCopy( plane.normal, surface->axis[0] ); - PerpendicularVector( surface->axis[1], surface->axis[0] ); - CrossProduct( surface->axis[0], surface->axis[1], surface->axis[2] ); - - // locate the portal entity closest to this plane. - // origin will be the origin of the portal, origin2 will be - // the origin of the camera - for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) { - e = &tr.refdef.entities[i]; - if ( e->e.reType != RT_PORTALSURFACE ) { - continue; - } - - d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist; - if ( d > 64 || d < -64) { - continue; - } - - // get the pvsOrigin from the entity - VectorCopy( e->e.oldorigin, pvsOrigin ); - - // if the entity is just a mirror, don't use as a camera point - if ( e->e.oldorigin[0] == e->e.origin[0] && - e->e.oldorigin[1] == e->e.origin[1] && - e->e.oldorigin[2] == e->e.origin[2] ) { - VectorScale( plane.normal, plane.dist, surface->origin ); - VectorCopy( surface->origin, camera->origin ); - VectorSubtract( vec3_origin, surface->axis[0], camera->axis[0] ); - VectorCopy( surface->axis[1], camera->axis[1] ); - VectorCopy( surface->axis[2], camera->axis[2] ); - - *mirror = qtrue; - return qtrue; - } - - // project the origin onto the surface plane to get - // an origin point we can rotate around - d = DotProduct( e->e.origin, plane.normal ) - plane.dist; - VectorMA( e->e.origin, -d, surface->axis[0], surface->origin ); - - // now get the camera origin and orientation - VectorCopy( e->e.oldorigin, camera->origin ); - AxisCopy( e->e.axis, camera->axis ); - VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] ); - VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] ); - - // optionally rotate - if ( e->e.oldframe ) { - // if a speed is specified - if ( e->e.frame ) { - // continuous rotate - d = (tr.refdef.time/1000.0f) * e->e.frame; - VectorCopy( camera->axis[1], transformed ); - RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); - CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); - } else { - // bobbing rotate, with skinNum being the rotation offset - d = sin( tr.refdef.time * 0.003f ); - d = e->e.skinNum + d * 4; - VectorCopy( camera->axis[1], transformed ); - RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); - CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); - } - } - else if ( e->e.skinNum ) { - d = e->e.skinNum; - VectorCopy( camera->axis[1], transformed ); - RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); - CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); - } - *mirror = qfalse; - return qtrue; - } - - // if we didn't locate a portal entity, don't render anything. - // We don't want to just treat it as a mirror, because without a - // portal entity the server won't have communicated a proper entity set - // in the snapshot - - // unfortunately, with local movement prediction it is easily possible - // to see a surface before the server has communicated the matching - // portal surface entity, so we don't want to print anything here... - - //ri.Printf( PRINT_ALL, "Portal surface without a portal entity\n" ); - - return qfalse; -} - -static qboolean IsMirror( const drawSurf_t *drawSurf, int entityNum ) -{ - int i; - cplane_t originalPlane, plane; - trRefEntity_t *e; - float d; - - // create plane axis for the portal we are seeing - R_PlaneForSurface( drawSurf->surface, &originalPlane ); - - // rotate the plane if necessary - if ( entityNum != REFENTITYNUM_WORLD ) - { - tr.currentEntityNum = entityNum; - tr.currentEntity = &tr.refdef.entities[entityNum]; - - // get the orientation of the entity - R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or ); - - // rotate the plane, but keep the non-rotated version for matching - // against the portalSurface entities - R_LocalNormalToWorld( originalPlane.normal, plane.normal ); - plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin ); - - // translate the original plane - originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin ); - } - - // locate the portal entity closest to this plane. - // origin will be the origin of the portal, origin2 will be - // the origin of the camera - for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) - { - e = &tr.refdef.entities[i]; - if ( e->e.reType != RT_PORTALSURFACE ) { - continue; - } - - d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist; - if ( d > 64 || d < -64) { - continue; - } - - // if the entity is just a mirror, don't use as a camera point - if ( e->e.oldorigin[0] == e->e.origin[0] && - e->e.oldorigin[1] == e->e.origin[1] && - e->e.oldorigin[2] == e->e.origin[2] ) - { - return qtrue; - } - - return qfalse; - } - return qfalse; -} - -/* -** SurfIsOffscreen -** -** Determines if a surface is completely offscreen. -*/ -static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) { - float shortest = 100000000; - int entityNum; - int numTriangles; - shader_t *shader; - int fogNum; - int dlighted; - vec4_t clip, eye; - int i; - unsigned int pointOr = 0; - unsigned int pointAnd = (unsigned int)~0; - - R_RotateForViewer(); - - R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); - RB_BeginSurface( shader, fogNum ); - rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); - - assert( tess.numVertexes < 128 ); - - for ( i = 0; i < tess.numVertexes; i++ ) - { - int j; - unsigned int pointFlags = 0; - - R_TransformModelToClip( tess.xyz[i], tr.or.modelMatrix, tr.viewParms.projectionMatrix, eye, clip ); - - for ( j = 0; j < 3; j++ ) - { - if ( clip[j] >= clip[3] ) - { - pointFlags |= (1 << (j*2)); - } - else if ( clip[j] <= -clip[3] ) - { - pointFlags |= ( 1 << (j*2+1)); - } - } - pointAnd &= pointFlags; - pointOr |= pointFlags; - } - - // trivially reject - if ( pointAnd ) - { - return qtrue; - } - - // determine if this surface is backfaced and also determine the distance - // to the nearest vertex so we can cull based on portal range. Culling - // based on vertex distance isn't 100% correct (we should be checking for - // range to the surface), but it's good enough for the types of portals - // we have in the game right now. - numTriangles = tess.numIndexes / 3; - - for ( i = 0; i < tess.numIndexes; i += 3 ) - { - vec3_t normal; - float len; - - VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.or.origin, normal ); - - len = VectorLengthSquared( normal ); // lose the sqrt - if ( len < shortest ) - { - shortest = len; - } - - if ( DotProduct( normal, tess.normal[tess.indexes[i]] ) >= 0 ) - { - numTriangles--; - } - } - if ( !numTriangles ) - { - return qtrue; - } - - // mirrors can early out at this point, since we don't do a fade over distance - // with them (although we could) - if ( IsMirror( drawSurf, entityNum ) ) - { - return qfalse; - } - - if ( shortest > (tess.shader->portalRange*tess.shader->portalRange) ) - { - return qtrue; - } - - return qfalse; -} - -/* -======================== -R_MirrorViewBySurface - -Returns qtrue if another view has been rendered -======================== -*/ -qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) { - vec4_t clipDest[128]; - viewParms_t newParms; - viewParms_t oldParms; - orientation_t surface, camera; - - // don't recursively mirror - if (tr.viewParms.isPortal) { - ri.Printf( PRINT_DEVELOPER, "WARNING: recursive mirror/portal found\n" ); - return qfalse; - } - - if ( r_noportals->integer || (r_fastsky->integer == 1) ) { - return qfalse; - } - - // trivially reject portal/mirror - if ( SurfIsOffscreen( drawSurf, clipDest ) ) { - return qfalse; - } - - // save old viewParms so we can return to it after the mirror view - oldParms = tr.viewParms; - - newParms = tr.viewParms; - newParms.isPortal = qtrue; - if ( !R_GetPortalOrientations( drawSurf, entityNum, &surface, &camera, - newParms.pvsOrigin, &newParms.isMirror ) ) { - return qfalse; // bad portal, no portalentity - } - - R_MirrorPoint (oldParms.or.origin, &surface, &camera, newParms.or.origin ); - - VectorSubtract( vec3_origin, camera.axis[0], newParms.portalPlane.normal ); - newParms.portalPlane.dist = DotProduct( camera.origin, newParms.portalPlane.normal ); - - R_MirrorVector (oldParms.or.axis[0], &surface, &camera, newParms.or.axis[0]); - R_MirrorVector (oldParms.or.axis[1], &surface, &camera, newParms.or.axis[1]); - R_MirrorVector (oldParms.or.axis[2], &surface, &camera, newParms.or.axis[2]); - - // OPTIMIZE: restrict the viewport on the mirrored view - - // render the mirror view - R_RenderView (&newParms); - - tr.viewParms = oldParms; - - return qtrue; -} - -/* -================= -R_SpriteFogNum - -See if a sprite is inside a fog volume -================= -*/ -int R_SpriteFogNum( trRefEntity_t *ent ) { - int i, j; - fog_t *fog; - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return 0; - } - - for ( i = 1 ; i < tr.world->numfogs ; i++ ) { - fog = &tr.world->fogs[i]; - for ( j = 0 ; j < 3 ; j++ ) { - if ( ent->e.origin[j] - ent->e.radius >= fog->bounds[1][j] ) { - break; - } - if ( ent->e.origin[j] + ent->e.radius <= fog->bounds[0][j] ) { - break; - } - } - if ( j == 3 ) { - return i; - } - } - - return 0; -} - -/* -========================================================================================== - -DRAWSURF SORTING - -========================================================================================== -*/ - -/* -=============== -R_Radix -=============== -*/ -static ID_INLINE void R_Radix( int byte, int size, drawSurf_t *source, drawSurf_t *dest ) -{ - int count[ 256 ] = { 0 }; - int index[ 256 ]; - int i; - unsigned char *sortKey = NULL; - unsigned char *end = NULL; - - sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte; - end = sortKey + ( size * sizeof( drawSurf_t ) ); - for( ; sortKey < end; sortKey += sizeof( drawSurf_t ) ) - ++count[ *sortKey ]; - - index[ 0 ] = 0; - - for( i = 1; i < 256; ++i ) - index[ i ] = index[ i - 1 ] + count[ i - 1 ]; - - sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte; - for( i = 0; i < size; ++i, sortKey += sizeof( drawSurf_t ) ) - dest[ index[ *sortKey ]++ ] = source[ i ]; -} - -/* -=============== -R_RadixSort - -Radix sort with 4 byte size buckets -=============== -*/ -static void R_RadixSort( drawSurf_t *source, int size ) -{ - static drawSurf_t scratch[ MAX_DRAWSURFS ]; -#ifdef Q3_LITTLE_ENDIAN - R_Radix( 0, size, source, scratch ); - R_Radix( 1, size, scratch, source ); - R_Radix( 2, size, source, scratch ); - R_Radix( 3, size, scratch, source ); -#else - R_Radix( 3, size, source, scratch ); - R_Radix( 2, size, scratch, source ); - R_Radix( 1, size, source, scratch ); - R_Radix( 0, size, scratch, source ); -#endif //Q3_LITTLE_ENDIAN -} - -//========================================================================================== - -/* -================= -R_AddDrawSurf -================= -*/ -void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, - int fogIndex, int dlightMap ) { - int index; - - // instead of checking for overflow, we just mask the index - // so it wraps around - index = tr.refdef.numDrawSurfs & DRAWSURF_MASK; - // the sort data is packed into a single 32 bit value so it can be - // compared quickly during the qsorting process - tr.refdef.drawSurfs[index].sort = (shader->sortedIndex << QSORT_SHADERNUM_SHIFT) - | tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT ) | (int)dlightMap; - tr.refdef.drawSurfs[index].surface = surface; - tr.refdef.numDrawSurfs++; -} - -/* -================= -R_DecomposeSort -================= -*/ -void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader, - int *fogNum, int *dlightMap ) { - *fogNum = ( sort >> QSORT_FOGNUM_SHIFT ) & 31; - *shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1) ]; - *entityNum = ( sort >> QSORT_REFENTITYNUM_SHIFT ) & REFENTITYNUM_MASK; - *dlightMap = sort & 3; -} - -/* -================= -R_SortDrawSurfs -================= -*/ -void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) { - shader_t *shader; - int fogNum; - int entityNum; - int dlighted; - int i; - - // it is possible for some views to not have any surfaces - if ( numDrawSurfs < 1 ) { - // we still need to add it for hyperspace cases - R_AddDrawSurfCmd( drawSurfs, numDrawSurfs ); - return; - } - - // if we overflowed MAX_DRAWSURFS, the drawsurfs - // wrapped around in the buffer and we will be missing - // the first surfaces, not the last ones - if ( numDrawSurfs > MAX_DRAWSURFS ) { - numDrawSurfs = MAX_DRAWSURFS; - } - - // sort the drawsurfs by sort type, then orientation, then shader - R_RadixSort( drawSurfs, numDrawSurfs ); - - // check for any pass through drawing, which - // may cause another view to be rendered first - for ( i = 0 ; i < numDrawSurfs ; i++ ) { - R_DecomposeSort( (drawSurfs+i)->sort, &entityNum, &shader, &fogNum, &dlighted ); - - if ( shader->sort > SS_PORTAL ) { - break; - } - - // no shader should ever have this sort type - if ( shader->sort == SS_BAD ) { - ri.Error (ERR_DROP, "Shader '%s'with sort == SS_BAD", shader->name ); - } - - // if the mirror was completely clipped away, we may need to check another surface - if ( R_MirrorViewBySurface( (drawSurfs+i), entityNum) ) { - // this is a debug option to see exactly what is being mirrored - if ( r_portalOnly->integer ) { - return; - } - break; // only one mirror view at a time - } - } - - R_AddDrawSurfCmd( drawSurfs, numDrawSurfs ); -} - -/* -============= -R_AddEntitySurfaces -============= -*/ -void R_AddEntitySurfaces (void) { - trRefEntity_t *ent; - shader_t *shader; - - if ( !r_drawentities->integer ) { - return; - } - - for ( tr.currentEntityNum = 0; - tr.currentEntityNum < tr.refdef.num_entities; - tr.currentEntityNum++ ) { - ent = tr.currentEntity = &tr.refdef.entities[tr.currentEntityNum]; - - ent->needDlights = qfalse; - - // preshift the value we are going to OR into the drawsurf sort - tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT; - - // - // the weapon model must be handled special -- - // we don't want the hacked weapon position showing in - // mirrors, because the true body position will already be drawn - // - if ( (ent->e.renderfx & RF_FIRST_PERSON) && tr.viewParms.isPortal) { - continue; - } - - // simple generated models, like sprites and beams, are not culled - switch ( ent->e.reType ) { - case RT_PORTALSURFACE: - break; // don't draw anything - case RT_SPRITE: - case RT_BEAM: - case RT_LIGHTNING: - case RT_RAIL_CORE: - case RT_RAIL_RINGS: - // self blood sprites, talk balloons, etc should not be drawn in the primary - // view. We can't just do this check for all entities, because md3 - // entities may still want to cast shadows from them - if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) { - continue; - } - shader = R_GetShaderByHandle( ent->e.customShader ); - R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0 ); - break; - - case RT_MODEL: - // we must set up parts of tr.or for model culling - R_RotateForEntity( ent, &tr.viewParms, &tr.or ); - - tr.currentModel = R_GetModelByHandle( ent->e.hModel ); - if (!tr.currentModel) { - R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0 ); - } else { - switch ( tr.currentModel->type ) { - case MOD_MESH: - R_AddMD3Surfaces( ent ); - break; - case MOD_MDR: - R_MDRAddAnimSurfaces( ent ); - break; - case MOD_IQM: - R_AddIQMSurfaces( ent ); - break; - case MOD_BRUSH: - R_AddBrushModelSurfaces( ent ); - break; - case MOD_BAD: // null model axis - if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) { - break; - } - R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0 ); - break; - default: - ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" ); - break; - } - } - break; - default: - ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad reType" ); - } - } - -} - - -/* -==================== -R_GenerateDrawSurfs -==================== -*/ -void R_GenerateDrawSurfs( void ) { - R_AddWorldSurfaces (); - - R_AddPolygonSurfaces(); - - // set the projection matrix with the minimum zfar - // now that we have the world bounded - // this needs to be done before entities are - // added, because they use the projection - // matrix for lod calculation - - // dynamically compute far clip plane distance - R_SetFarClip(); - - // we know the size of the clipping volume. Now set the rest of the projection matrix. - R_SetupProjectionZ (&tr.viewParms); - - R_AddEntitySurfaces (); -} - -/* -================ -R_DebugPolygon -================ -*/ -void R_DebugPolygon( int color, int numPoints, float *points ) { - int i; - - GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - - // draw solid shade - - qglColor3f( color&1, (color>>1)&1, (color>>2)&1 ); - qglBegin( GL_POLYGON ); - for ( i = 0 ; i < numPoints ; i++ ) { - qglVertex3fv( points + i * 3 ); - } - qglEnd(); - - // draw wireframe outline - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - qglDepthRange( 0, 0 ); - qglColor3f( 1, 1, 1 ); - qglBegin( GL_POLYGON ); - for ( i = 0 ; i < numPoints ; i++ ) { - qglVertex3fv( points + i * 3 ); - } - qglEnd(); - qglDepthRange( 0, 1 ); -} - -/* -==================== -R_DebugGraphics - -Visualization aid for movement clipping debugging -==================== -*/ -void R_DebugGraphics( void ) { - if ( !r_debugSurface->integer ) { - return; - } - - R_IssuePendingRenderCommands(); - - GL_Bind( tr.whiteImage); - GL_Cull( CT_FRONT_SIDED ); - ri.CM_DrawDebugSurface( R_DebugPolygon ); -} - - -/* -================ -R_RenderView - -A view may be either the actual camera view, -or a mirror / remote location -================ -*/ -void R_RenderView (viewParms_t *parms) { - int firstDrawSurf; - - if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) { - return; - } - - tr.viewCount++; - - tr.viewParms = *parms; - tr.viewParms.frameSceneNum = tr.frameSceneNum; - tr.viewParms.frameCount = tr.frameCount; - - firstDrawSurf = tr.refdef.numDrawSurfs; - - tr.viewCount++; - - // set viewParms.world - R_RotateForViewer (); - - R_SetupProjection(&tr.viewParms, r_zproj->value, qtrue); - - R_GenerateDrawSurfs(); - - R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf ); - - // draw main system development information (surface outlines, etc) - R_DebugGraphics(); -} - - - diff --git a/code/renderergl1/tr_marks.c b/code/renderergl1/tr_marks.c deleted file mode 100644 index e2c92b6c72..0000000000 --- a/code/renderergl1/tr_marks.c +++ /dev/null @@ -1,458 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_marks.c -- polygon projection on the world polygons - -#include "tr_local.h" -//#include "assert.h" - -#define MAX_VERTS_ON_POLY 64 - -#define MARKER_OFFSET 0 // 1 - -/* -============= -R_ChopPolyBehindPlane - -Out must have space for two more vertexes than in -============= -*/ -#define SIDE_FRONT 0 -#define SIDE_BACK 1 -#define SIDE_ON 2 -static void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY], - int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY], - vec3_t normal, vec_t dist, vec_t epsilon) { - float dists[MAX_VERTS_ON_POLY+4] = { 0 }; - int sides[MAX_VERTS_ON_POLY+4] = { 0 }; - int counts[3]; - float dot; - int i, j; - float *p1, *p2, *clip; - float d; - - // don't clip if it might overflow - if ( numInPoints >= MAX_VERTS_ON_POLY - 2 ) { - *numOutPoints = 0; - return; - } - - counts[0] = counts[1] = counts[2] = 0; - - // determine sides for each point - for ( i = 0 ; i < numInPoints ; i++ ) { - dot = DotProduct( inPoints[i], normal ); - dot -= dist; - dists[i] = dot; - if ( dot > epsilon ) { - sides[i] = SIDE_FRONT; - } else if ( dot < -epsilon ) { - sides[i] = SIDE_BACK; - } else { - sides[i] = SIDE_ON; - } - counts[sides[i]]++; - } - sides[i] = sides[0]; - dists[i] = dists[0]; - - *numOutPoints = 0; - - if ( !counts[0] ) { - return; - } - if ( !counts[1] ) { - *numOutPoints = numInPoints; - Com_Memcpy( outPoints, inPoints, numInPoints * sizeof(vec3_t) ); - return; - } - - for ( i = 0 ; i < numInPoints ; i++ ) { - p1 = inPoints[i]; - clip = outPoints[ *numOutPoints ]; - - if ( sides[i] == SIDE_ON ) { - VectorCopy( p1, clip ); - (*numOutPoints)++; - continue; - } - - if ( sides[i] == SIDE_FRONT ) { - VectorCopy( p1, clip ); - (*numOutPoints)++; - clip = outPoints[ *numOutPoints ]; - } - - if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) { - continue; - } - - // generate a split point - p2 = inPoints[ (i+1) % numInPoints ]; - - d = dists[i] - dists[i+1]; - if ( d == 0 ) { - dot = 0; - } else { - dot = dists[i] / d; - } - - // clip xyz - - for (j=0 ; j<3 ; j++) { - clip[j] = p1[j] + dot * ( p2[j] - p1[j] ); - } - - (*numOutPoints)++; - } -} - -/* -================= -R_BoxSurfaces_r - -================= -*/ -void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir) { - - int s, c; - msurface_t *surf, **mark; - - // do the tail recursion in a loop - while ( node->contents == -1 ) { - s = BoxOnPlaneSide( mins, maxs, node->plane ); - if (s == 1) { - node = node->children[0]; - } else if (s == 2) { - node = node->children[1]; - } else { - R_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir); - node = node->children[1]; - } - } - - // add the individual surfaces - mark = node->firstmarksurface; - c = node->nummarksurfaces; - while (c--) { - // - if (*listlength >= listsize) break; - // - surf = *mark; - // check if the surface has NOIMPACT or NOMARKS set - if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) ) - || ( surf->shader->contentFlags & CONTENTS_FOG ) ) { - surf->viewCount = tr.viewCount; - } - // extra check for surfaces to avoid list overflows - else if (*(surf->data) == SF_FACE) { - // the face plane should go through the box - s = BoxOnPlaneSide( mins, maxs, &(( srfSurfaceFace_t * ) surf->data)->plane ); - if (s == 1 || s == 2) { - surf->viewCount = tr.viewCount; - } else if (DotProduct((( srfSurfaceFace_t * ) surf->data)->plane.normal, dir) > -0.5) { - // don't add faces that make sharp angles with the projection direction - surf->viewCount = tr.viewCount; - } - } - else if (*(surfaceType_t *) (surf->data) != SF_GRID && - *(surfaceType_t *) (surf->data) != SF_TRIANGLES) - surf->viewCount = tr.viewCount; - // check the viewCount because the surface may have - // already been added if it spans multiple leafs - if (surf->viewCount != tr.viewCount) { - surf->viewCount = tr.viewCount; - list[*listlength] = (surfaceType_t *) surf->data; - (*listlength)++; - } - mark++; - } -} - -/* -================= -R_AddMarkFragments - -================= -*/ -void R_AddMarkFragments(int numClipPoints, vec3_t clipPoints[2][MAX_VERTS_ON_POLY], - int numPlanes, vec3_t *normals, float *dists, - int maxPoints, vec3_t pointBuffer, - int maxFragments, markFragment_t *fragmentBuffer, - int *returnedPoints, int *returnedFragments, - vec3_t mins, vec3_t maxs) { - int pingPong, i; - markFragment_t *mf; - - // chop the surface by all the bounding planes of the to be projected polygon - pingPong = 0; - - for ( i = 0 ; i < numPlanes ; i++ ) { - - R_ChopPolyBehindPlane( numClipPoints, clipPoints[pingPong], - &numClipPoints, clipPoints[!pingPong], - normals[i], dists[i], 0.5 ); - pingPong ^= 1; - if ( numClipPoints == 0 ) { - break; - } - } - // completely clipped away? - if ( numClipPoints == 0 ) { - return; - } - - // add this fragment to the returned list - if ( numClipPoints + (*returnedPoints) > maxPoints ) { - return; // not enough space for this polygon - } - /* - // all the clip points should be within the bounding box - for ( i = 0 ; i < numClipPoints ; i++ ) { - int j; - for ( j = 0 ; j < 3 ; j++ ) { - if (clipPoints[pingPong][i][j] < mins[j] - 0.5) break; - if (clipPoints[pingPong][i][j] > maxs[j] + 0.5) break; - } - if (j < 3) break; - } - if (i < numClipPoints) return; - */ - - mf = fragmentBuffer + (*returnedFragments); - mf->firstPoint = (*returnedPoints); - mf->numPoints = numClipPoints; - Com_Memcpy( pointBuffer + (*returnedPoints) * 3, clipPoints[pingPong], numClipPoints * sizeof(vec3_t) ); - - (*returnedPoints) += numClipPoints; - (*returnedFragments)++; -} - -/* -================= -R_MarkFragments - -================= -*/ -int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, - int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) { - int numsurfaces, numPlanes; - int i, j, k, m, n; - surfaceType_t *surfaces[64]; - vec3_t mins, maxs; - int returnedFragments; - int returnedPoints; - vec3_t normals[MAX_VERTS_ON_POLY+2]; - float dists[MAX_VERTS_ON_POLY+2]; - vec3_t clipPoints[2][MAX_VERTS_ON_POLY]; - int numClipPoints; - float *v; - srfGridMesh_t *cv; - drawVert_t *dv; - vec3_t normal; - vec3_t projectionDir; - vec3_t v1, v2; - int *indexes; - - if (numPoints <= 0) { - return 0; - } - - //increment view count for double check prevention - tr.viewCount++; - - // - VectorNormalize2( projection, projectionDir ); - // find all the brushes that are to be considered - ClearBounds( mins, maxs ); - for ( i = 0 ; i < numPoints ; i++ ) { - vec3_t temp; - - AddPointToBounds( points[i], mins, maxs ); - VectorAdd( points[i], projection, temp ); - AddPointToBounds( temp, mins, maxs ); - // make sure we get all the leafs (also the one(s) in front of the hit surface) - VectorMA( points[i], -20, projectionDir, temp ); - AddPointToBounds( temp, mins, maxs ); - } - - if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY; - // create the bounding planes for the to be projected polygon - for ( i = 0 ; i < numPoints ; i++ ) { - VectorSubtract(points[(i+1)%numPoints], points[i], v1); - VectorAdd(points[i], projection, v2); - VectorSubtract(points[i], v2, v2); - CrossProduct(v1, v2, normals[i]); - VectorNormalizeFast(normals[i]); - dists[i] = DotProduct(normals[i], points[i]); - } - // add near and far clipping planes for projection - VectorCopy(projectionDir, normals[numPoints]); - dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32; - VectorCopy(projectionDir, normals[numPoints+1]); - VectorInverse(normals[numPoints+1]); - dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20; - numPlanes = numPoints + 2; - - numsurfaces = 0; - R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir); - //assert(numsurfaces <= 64); - //assert(numsurfaces != 64); - - returnedPoints = 0; - returnedFragments = 0; - - for ( i = 0 ; i < numsurfaces ; i++ ) { - - if (*surfaces[i] == SF_GRID) { - - cv = (srfGridMesh_t *) surfaces[i]; - for ( m = 0 ; m < cv->height - 1 ; m++ ) { - for ( n = 0 ; n < cv->width - 1 ; n++ ) { - // We triangulate the grid and chop all triangles within - // the bounding planes of the to be projected polygon. - // LOD is not taken into account, not such a big deal though. - // - // It's probably much nicer to chop the grid itself and deal - // with this grid as a normal SF_GRID surface so LOD will - // be applied. However the LOD of that chopped grid must - // be synced with the LOD of the original curve. - // One way to do this; the chopped grid shares vertices with - // the original curve. When LOD is applied to the original - // curve the unused vertices are flagged. Now the chopped curve - // should skip the flagged vertices. This still leaves the - // problems with the vertices at the chopped grid edges. - // - // To avoid issues when LOD applied to "hollow curves" (like - // the ones around many jump pads) we now just add a 2 unit - // offset to the triangle vertices. - // The offset is added in the vertex normal vector direction - // so all triangles will still fit together. - // The 2 unit offset should avoid pretty much all LOD problems. - - numClipPoints = 3; - - dv = cv->verts + m * cv->width + n; - - VectorCopy(dv[0].xyz, clipPoints[0][0]); - VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]); - VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); - VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); - VectorCopy(dv[1].xyz, clipPoints[0][2]); - VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]); - // check the normal of this triangle - VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); - VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); - CrossProduct(v1, v2, normal); - VectorNormalizeFast(normal); - if (DotProduct(normal, projectionDir) < -0.1) { - // add the fragments of this triangle - R_AddMarkFragments(numClipPoints, clipPoints, - numPlanes, normals, dists, - maxPoints, pointBuffer, - maxFragments, fragmentBuffer, - &returnedPoints, &returnedFragments, mins, maxs); - - if ( returnedFragments == maxFragments ) { - return returnedFragments; // not enough space for more fragments - } - } - - VectorCopy(dv[1].xyz, clipPoints[0][0]); - VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]); - VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); - VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); - VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]); - VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]); - // check the normal of this triangle - VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); - VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); - CrossProduct(v1, v2, normal); - VectorNormalizeFast(normal); - if (DotProduct(normal, projectionDir) < -0.05) { - // add the fragments of this triangle - R_AddMarkFragments(numClipPoints, clipPoints, - numPlanes, normals, dists, - maxPoints, pointBuffer, - maxFragments, fragmentBuffer, - &returnedPoints, &returnedFragments, mins, maxs); - - if ( returnedFragments == maxFragments ) { - return returnedFragments; // not enough space for more fragments - } - } - } - } - } - else if (*surfaces[i] == SF_FACE) { - - srfSurfaceFace_t *surf = ( srfSurfaceFace_t * ) surfaces[i]; - - // check the normal of this face - if (DotProduct(surf->plane.normal, projectionDir) > -0.5) { - continue; - } - - indexes = (int *)( (byte *)surf + surf->ofsIndices ); - for ( k = 0 ; k < surf->numIndices ; k += 3 ) { - for ( j = 0 ; j < 3 ; j++ ) { - v = surf->points[0] + VERTEXSIZE * indexes[k+j];; - VectorMA( v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] ); - } - - // add the fragments of this face - R_AddMarkFragments( 3 , clipPoints, - numPlanes, normals, dists, - maxPoints, pointBuffer, - maxFragments, fragmentBuffer, - &returnedPoints, &returnedFragments, mins, maxs); - if ( returnedFragments == maxFragments ) { - return returnedFragments; // not enough space for more fragments - } - } - } - else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) { - - srfTriangles_t *surf = (srfTriangles_t *) surfaces[i]; - - for (k = 0; k < surf->numIndexes; k += 3) - { - for(j = 0; j < 3; j++) - { - v = surf->verts[surf->indexes[k + j]].xyz; - VectorMA(v, MARKER_OFFSET, surf->verts[surf->indexes[k + j]].normal, clipPoints[0][j]); - } - - // add the fragments of this face - R_AddMarkFragments(3, clipPoints, - numPlanes, normals, dists, - maxPoints, pointBuffer, - maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs); - if(returnedFragments == maxFragments) - { - return returnedFragments; // not enough space for more fragments - } - } - } - } - return returnedFragments; -} - diff --git a/code/renderergl1/tr_mesh.c b/code/renderergl1/tr_mesh.c deleted file mode 100644 index d0be29bc2e..0000000000 --- a/code/renderergl1/tr_mesh.c +++ /dev/null @@ -1,412 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_mesh.c: triangle model functions - -#include "tr_local.h" - -static float ProjectRadius( float r, vec3_t location ) -{ - float pr; - float dist; - float c; - vec3_t p; - float projected[4]; - - c = DotProduct( tr.viewParms.or.axis[0], tr.viewParms.or.origin ); - dist = DotProduct( tr.viewParms.or.axis[0], location ) - c; - - if ( dist <= 0 ) - return 0; - - p[0] = 0; - p[1] = fabs( r ); - p[2] = -dist; - - projected[0] = p[0] * tr.viewParms.projectionMatrix[0] + - p[1] * tr.viewParms.projectionMatrix[4] + - p[2] * tr.viewParms.projectionMatrix[8] + - tr.viewParms.projectionMatrix[12]; - - projected[1] = p[0] * tr.viewParms.projectionMatrix[1] + - p[1] * tr.viewParms.projectionMatrix[5] + - p[2] * tr.viewParms.projectionMatrix[9] + - tr.viewParms.projectionMatrix[13]; - - projected[2] = p[0] * tr.viewParms.projectionMatrix[2] + - p[1] * tr.viewParms.projectionMatrix[6] + - p[2] * tr.viewParms.projectionMatrix[10] + - tr.viewParms.projectionMatrix[14]; - - projected[3] = p[0] * tr.viewParms.projectionMatrix[3] + - p[1] * tr.viewParms.projectionMatrix[7] + - p[2] * tr.viewParms.projectionMatrix[11] + - tr.viewParms.projectionMatrix[15]; - - - pr = projected[1] / projected[3]; - - if ( pr > 1.0f ) - pr = 1.0f; - - return pr; -} - -/* -============= -R_CullModel -============= -*/ -static int R_CullModel( md3Header_t *header, trRefEntity_t *ent ) { - vec3_t bounds[2]; - md3Frame_t *oldFrame, *newFrame; - int i; - - // compute frame pointers - newFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame; - oldFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.oldframe; - - // cull bounding sphere ONLY if this is not an upscaled entity - if ( !ent->e.nonNormalizedAxes ) - { - if ( ent->e.frame == ent->e.oldframe ) - { - switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) ) - { - case CULL_OUT: - tr.pc.c_sphere_cull_md3_out++; - return CULL_OUT; - - case CULL_IN: - tr.pc.c_sphere_cull_md3_in++; - return CULL_IN; - - case CULL_CLIP: - tr.pc.c_sphere_cull_md3_clip++; - break; - } - } - else - { - int sphereCull, sphereCullB; - - sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ); - if ( newFrame == oldFrame ) { - sphereCullB = sphereCull; - } else { - sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius ); - } - - if ( sphereCull == sphereCullB ) - { - if ( sphereCull == CULL_OUT ) - { - tr.pc.c_sphere_cull_md3_out++; - return CULL_OUT; - } - else if ( sphereCull == CULL_IN ) - { - tr.pc.c_sphere_cull_md3_in++; - return CULL_IN; - } - else - { - tr.pc.c_sphere_cull_md3_clip++; - } - } - } - } - - // calculate a bounding box in the current coordinate system - for (i = 0 ; i < 3 ; i++) { - bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; - bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; - } - - switch ( R_CullLocalBox( bounds ) ) - { - case CULL_IN: - tr.pc.c_box_cull_md3_in++; - return CULL_IN; - case CULL_CLIP: - tr.pc.c_box_cull_md3_clip++; - return CULL_CLIP; - case CULL_OUT: - default: - tr.pc.c_box_cull_md3_out++; - return CULL_OUT; - } -} - - -/* -================= -R_ComputeLOD - -================= -*/ -int R_ComputeLOD( trRefEntity_t *ent ) { - float radius; - float flod, lodscale; - float projectedRadius; - md3Frame_t *frame; - mdrHeader_t *mdr; - mdrFrame_t *mdrframe; - int lod; - - if ( tr.currentModel->numLods < 2 ) - { - // model has only 1 LOD level, skip computations and bias - lod = 0; - } - else - { - // multiple LODs exist, so compute projected bounding sphere - // and use that as a criteria for selecting LOD - - if(tr.currentModel->type == MOD_MDR) - { - int frameSize; - mdr = (mdrHeader_t *) tr.currentModel->modelData; - frameSize = (size_t) (&((mdrFrame_t *)0)->bones[mdr->numBones]); - - mdrframe = (mdrFrame_t *) ((byte *) mdr + mdr->ofsFrames + frameSize * ent->e.frame); - - radius = RadiusFromBounds(mdrframe->bounds[0], mdrframe->bounds[1]); - } - else - { - frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames ); - - frame += ent->e.frame; - - radius = RadiusFromBounds( frame->bounds[0], frame->bounds[1] ); - } - - if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 ) - { - lodscale = r_lodscale->value; - if (lodscale > 20) lodscale = 20; - flod = 1.0f - projectedRadius * lodscale; - } - else - { - // object intersects near view plane, e.g. view weapon - flod = 0; - } - - flod *= tr.currentModel->numLods; - lod = ri.ftol(flod); - - if ( lod < 0 ) - { - lod = 0; - } - else if ( lod >= tr.currentModel->numLods ) - { - lod = tr.currentModel->numLods - 1; - } - } - - lod += r_lodbias->integer; - - if ( lod >= tr.currentModel->numLods ) - lod = tr.currentModel->numLods - 1; - if ( lod < 0 ) - lod = 0; - - return lod; -} - -/* -================= -R_ComputeFogNum - -================= -*/ -int R_ComputeFogNum( md3Header_t *header, trRefEntity_t *ent ) { - int i, j; - fog_t *fog; - md3Frame_t *md3Frame; - vec3_t localOrigin; - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return 0; - } - - // FIXME: non-normalized axis issues - md3Frame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame; - VectorAdd( ent->e.origin, md3Frame->localOrigin, localOrigin ); - for ( i = 1 ; i < tr.world->numfogs ; i++ ) { - fog = &tr.world->fogs[i]; - for ( j = 0 ; j < 3 ; j++ ) { - if ( localOrigin[j] - md3Frame->radius >= fog->bounds[1][j] ) { - break; - } - if ( localOrigin[j] + md3Frame->radius <= fog->bounds[0][j] ) { - break; - } - } - if ( j == 3 ) { - return i; - } - } - - return 0; -} - -/* -================= -R_AddMD3Surfaces - -================= -*/ -void R_AddMD3Surfaces( trRefEntity_t *ent ) { - int i; - md3Header_t *header = NULL; - md3Surface_t *surface = NULL; - md3Shader_t *md3Shader = NULL; - shader_t *shader = NULL; - int cull; - int lod; - int fogNum; - qboolean personalModel; - - // don't add third_person objects if not in a portal - personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; - - if ( ent->e.renderfx & RF_WRAP_FRAMES ) { - ent->e.frame %= tr.currentModel->md3[0]->numFrames; - ent->e.oldframe %= tr.currentModel->md3[0]->numFrames; - } - - // - // Validate the frames so there is no chance of a crash. - // This will write directly into the entity structure, so - // when the surfaces are rendered, they don't need to be - // range checked again. - // - if ( (ent->e.frame >= tr.currentModel->md3[0]->numFrames) - || (ent->e.frame < 0) - || (ent->e.oldframe >= tr.currentModel->md3[0]->numFrames) - || (ent->e.oldframe < 0) ) { - ri.Printf( PRINT_DEVELOPER, "R_AddMD3Surfaces: no such frame %d to %d for '%s'\n", - ent->e.oldframe, ent->e.frame, - tr.currentModel->name ); - ent->e.frame = 0; - ent->e.oldframe = 0; - } - - // - // compute LOD - // - lod = R_ComputeLOD( ent ); - - header = tr.currentModel->md3[lod]; - - // - // cull the entire model if merged bounding box of both frames - // is outside the view frustum. - // - cull = R_CullModel ( header, ent ); - if ( cull == CULL_OUT ) { - return; - } - - // - // set up lighting now that we know we aren't culled - // - if ( !personalModel || r_shadows->integer > 1 ) { - R_SetupEntityLighting( &tr.refdef, ent ); - } - - // - // see if we are in a fog volume - // - fogNum = R_ComputeFogNum( header, ent ); - - // - // draw all surfaces - // - surface = (md3Surface_t *)( (byte *)header + header->ofsSurfaces ); - for ( i = 0 ; i < header->numSurfaces ; i++ ) { - - if ( ent->e.customShader ) { - shader = R_GetShaderByHandle( ent->e.customShader ); - } else if ( ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins ) { - skin_t *skin; - int j; - - skin = R_GetSkinByHandle( ent->e.customSkin ); - - // match the surface name to something in the skin file - shader = tr.defaultShader; - for ( j = 0 ; j < skin->numSurfaces ; j++ ) { - // the names have both been lowercased - if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) { - shader = skin->surfaces[j]->shader; - break; - } - } - if (shader == tr.defaultShader) { - ri.Printf( PRINT_DEVELOPER, "WARNING: no shader for surface %s in skin %s\n", surface->name, skin->name); - } - else if (shader->defaultShader) { - ri.Printf( PRINT_DEVELOPER, "WARNING: shader %s in skin %s not found\n", shader->name, skin->name); - } - } else if ( surface->numShaders <= 0 ) { - shader = tr.defaultShader; - } else { - md3Shader = (md3Shader_t *) ( (byte *)surface + surface->ofsShaders ); - md3Shader += ent->e.skinNum % surface->numShaders; - shader = tr.shaders[ md3Shader->shaderIndex ]; - } - - - // we will add shadows even if the main object isn't visible in the view - - // stencil shadows can't do personal models unless I polyhedron clip - if ( !personalModel - && r_shadows->integer == 2 - && fogNum == 0 - && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) - && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse ); - } - - // projection shadows work fine with personal models - if ( r_shadows->integer == 3 - && fogNum == 0 - && (ent->e.renderfx & RF_SHADOW_PLANE ) - && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse ); - } - - // don't add third_person objects if not viewing through a portal - if ( !personalModel ) { - R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse ); - } - - surface = (md3Surface_t *)( (byte *)surface + surface->ofsEnd ); - } - -} - diff --git a/code/renderergl1/tr_model.c b/code/renderergl1/tr_model.c deleted file mode 100644 index a3f91aeee1..0000000000 --- a/code/renderergl1/tr_model.c +++ /dev/null @@ -1,1127 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_models.c -- model loading and caching - -#include "tr_local.h" - -#define LL(x) x=LittleLong(x) - -static qboolean R_LoadMD3(model_t *mod, int lod, void *buffer, const char *name ); -static qboolean R_LoadMDR(model_t *mod, void *buffer, int filesize, const char *name ); - -/* -==================== -R_RegisterMD3 -==================== -*/ -qhandle_t R_RegisterMD3(const char *name, model_t *mod) -{ - union { - unsigned *u; - void *v; - } buf; - int lod; - int ident; - qboolean loaded = qfalse; - int numLoaded; - char filename[MAX_QPATH], namebuf[MAX_QPATH+20]; - char *fext, defex[] = "md3"; - - numLoaded = 0; - - strcpy(filename, name); - - fext = strchr(filename, '.'); - if(!fext) - fext = defex; - else - { - *fext = '\0'; - fext++; - } - - for (lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod--) - { - if(lod) - Com_sprintf(namebuf, sizeof(namebuf), "%s_%d.%s", filename, lod, fext); - else - Com_sprintf(namebuf, sizeof(namebuf), "%s.%s", filename, fext); - - ri.FS_ReadFile( namebuf, &buf.v ); - if(!buf.u) - continue; - - ident = LittleLong(* (unsigned *) buf.u); - if (ident == MD3_IDENT) - loaded = R_LoadMD3(mod, lod, buf.u, name); - else - ri.Printf(PRINT_WARNING,"R_RegisterMD3: unknown fileid for %s\n", name); - - ri.FS_FreeFile(buf.v); - - if(loaded) - { - mod->numLods++; - numLoaded++; - } - else - break; - } - - if(numLoaded) - { - // duplicate into higher lod spots that weren't - // loaded, in case the user changes r_lodbias on the fly - for(lod--; lod >= 0; lod--) - { - mod->numLods++; - mod->md3[lod] = mod->md3[lod + 1]; - } - - return mod->index; - } - -#ifdef _DEBUG - ri.Printf(PRINT_WARNING,"R_RegisterMD3: couldn't load %s\n", name); -#endif - - mod->type = MOD_BAD; - return 0; -} - -/* -==================== -R_RegisterMDR -==================== -*/ -qhandle_t R_RegisterMDR(const char *name, model_t *mod) -{ - union { - unsigned *u; - void *v; - } buf; - int ident; - qboolean loaded = qfalse; - int filesize; - - filesize = ri.FS_ReadFile(name, (void **) &buf.v); - if(!buf.u) - { - mod->type = MOD_BAD; - return 0; - } - - ident = LittleLong(*(unsigned *)buf.u); - if(ident == MDR_IDENT) - loaded = R_LoadMDR(mod, buf.u, filesize, name); - - ri.FS_FreeFile (buf.v); - - if(!loaded) - { - ri.Printf(PRINT_WARNING,"R_RegisterMDR: couldn't load mdr file %s\n", name); - mod->type = MOD_BAD; - return 0; - } - - return mod->index; -} - -/* -==================== -R_RegisterIQM -==================== -*/ -qhandle_t R_RegisterIQM(const char *name, model_t *mod) -{ - union { - unsigned *u; - void *v; - } buf; - qboolean loaded = qfalse; - int filesize; - - filesize = ri.FS_ReadFile(name, (void **) &buf.v); - if(!buf.u) - { - mod->type = MOD_BAD; - return 0; - } - - loaded = R_LoadIQM(mod, buf.u, filesize, name); - - ri.FS_FreeFile (buf.v); - - if(!loaded) - { - ri.Printf(PRINT_WARNING,"R_RegisterIQM: couldn't load iqm file %s\n", name); - mod->type = MOD_BAD; - return 0; - } - - return mod->index; -} - - -typedef struct -{ - char *ext; - qhandle_t (*ModelLoader)( const char *, model_t * ); -} modelExtToLoaderMap_t; - -// Note that the ordering indicates the order of preference used -// when there are multiple models of different formats available -static modelExtToLoaderMap_t modelLoaders[ ] = -{ - { "iqm", R_RegisterIQM }, - { "mdr", R_RegisterMDR }, - { "md3", R_RegisterMD3 } -}; - -static int numModelLoaders = ARRAY_LEN(modelLoaders); - -//=============================================================================== - -/* -** R_GetModelByHandle -*/ -model_t *R_GetModelByHandle( qhandle_t index ) { - model_t *mod; - - // out of range gets the defualt model - if ( index < 1 || index >= tr.numModels ) { - return tr.models[0]; - } - - mod = tr.models[index]; - - return mod; -} - -//=============================================================================== - -/* -** R_AllocModel -*/ -model_t *R_AllocModel( void ) { - model_t *mod; - - if ( tr.numModels == MAX_MOD_KNOWN ) { - return NULL; - } - - mod = ri.Hunk_Alloc( sizeof( *tr.models[tr.numModels] ), h_low ); - mod->index = tr.numModels; - tr.models[tr.numModels] = mod; - tr.numModels++; - - return mod; -} - -/* -==================== -RE_RegisterModel - -Loads in a model for the given name - -Zero will be returned if the model fails to load. -An entry will be retained for failed models as an -optimization to prevent disk rescanning if they are -asked for again. -==================== -*/ -qhandle_t RE_RegisterModel( const char *name ) { - model_t *mod; - qhandle_t hModel; - qboolean orgNameFailed = qfalse; - int orgLoader = -1; - int i; - char localName[ MAX_QPATH ]; - const char *ext; - char altName[ MAX_QPATH ]; - - if ( !name || !name[0] ) { - ri.Printf( PRINT_ALL, "RE_RegisterModel: NULL name\n" ); - return 0; - } - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_ALL, "Model name exceeds MAX_QPATH\n" ); - return 0; - } - - // - // search the currently loaded models - // - for ( hModel = 1 ; hModel < tr.numModels; hModel++ ) { - mod = tr.models[hModel]; - if ( !strcmp( mod->name, name ) ) { - if( mod->type == MOD_BAD ) { - return 0; - } - return hModel; - } - } - - // allocate a new model_t - - if ( ( mod = R_AllocModel() ) == NULL ) { - ri.Printf( PRINT_WARNING, "RE_RegisterModel: R_AllocModel() failed for '%s'\n", name); - return 0; - } - - // only set the name after the model has been successfully loaded - Q_strncpyz( mod->name, name, sizeof( mod->name ) ); - - - R_IssuePendingRenderCommands(); - - mod->type = MOD_BAD; - mod->numLods = 0; - - // - // load the files - // - Q_strncpyz( localName, name, MAX_QPATH ); - - ext = COM_GetExtension( localName ); - - if( *ext ) - { - // Look for the correct loader and use it - for( i = 0; i < numModelLoaders; i++ ) - { - if( !Q_stricmp( ext, modelLoaders[ i ].ext ) ) - { - // Load - hModel = modelLoaders[ i ].ModelLoader( localName, mod ); - break; - } - } - - // A loader was found - if( i < numModelLoaders ) - { - if( !hModel ) - { - // Loader failed, most likely because the file isn't there; - // try again without the extension - orgNameFailed = qtrue; - orgLoader = i; - COM_StripExtension( name, localName, MAX_QPATH ); - } - else - { - // Something loaded - return mod->index; - } - } - } - - // Try and find a suitable match using all - // the model formats supported - for( i = 0; i < numModelLoaders; i++ ) - { - if (i == orgLoader) - continue; - - Com_sprintf( altName, sizeof (altName), "%s.%s", localName, modelLoaders[ i ].ext ); - - // Load - hModel = modelLoaders[ i ].ModelLoader( altName, mod ); - - if( hModel ) - { - if( orgNameFailed ) - { - ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n", - name, altName ); - } - - break; - } - } - - return hModel; -} - -/* -================= -R_LoadMD3 -================= -*/ -static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name ) { - int i, j; - md3Header_t *pinmodel; - md3Frame_t *frame; - md3Surface_t *surf; - md3Shader_t *shader; - md3Triangle_t *tri; - md3St_t *st; - md3XyzNormal_t *xyz; - md3Tag_t *tag; - int version; - int size; - - pinmodel = (md3Header_t *)buffer; - - version = LittleLong (pinmodel->version); - if (version != MD3_VERSION) { - ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n", - mod_name, version, MD3_VERSION); - return qfalse; - } - - mod->type = MOD_MESH; - size = LittleLong(pinmodel->ofsEnd); - mod->dataSize += size; - mod->md3[lod] = ri.Hunk_Alloc( size, h_low ); - - Com_Memcpy (mod->md3[lod], buffer, LittleLong(pinmodel->ofsEnd) ); - - LL(mod->md3[lod]->ident); - LL(mod->md3[lod]->version); - LL(mod->md3[lod]->numFrames); - LL(mod->md3[lod]->numTags); - LL(mod->md3[lod]->numSurfaces); - LL(mod->md3[lod]->ofsFrames); - LL(mod->md3[lod]->ofsTags); - LL(mod->md3[lod]->ofsSurfaces); - LL(mod->md3[lod]->ofsEnd); - - if ( mod->md3[lod]->numFrames < 1 ) { - ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has no frames\n", mod_name ); - return qfalse; - } - - // swap all the frames - frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames ); - for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) { - frame->radius = LittleFloat( frame->radius ); - for ( j = 0 ; j < 3 ; j++ ) { - frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] ); - frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] ); - frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] ); - } - } - - // swap all the tags - tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags ); - for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) { - for ( j = 0 ; j < 3 ; j++ ) { - tag->origin[j] = LittleFloat( tag->origin[j] ); - tag->axis[0][j] = LittleFloat( tag->axis[0][j] ); - tag->axis[1][j] = LittleFloat( tag->axis[1][j] ); - tag->axis[2][j] = LittleFloat( tag->axis[2][j] ); - } - } - - // swap all the surfaces - surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces ); - for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) { - - LL(surf->ident); - LL(surf->flags); - LL(surf->numFrames); - LL(surf->numShaders); - LL(surf->numTriangles); - LL(surf->ofsTriangles); - LL(surf->numVerts); - LL(surf->ofsShaders); - LL(surf->ofsSt); - LL(surf->ofsXyzNormals); - LL(surf->ofsEnd); - - if ( surf->numVerts >= SHADER_MAX_VERTEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i verts on %s (%i).\n", - mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface", - surf->numVerts ); - return qfalse; - } - if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i triangles on %s (%i).\n", - mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface", - surf->numTriangles ); - return qfalse; - } - - // change to surface identifier - surf->ident = SF_MD3; - - // lowercase the surface name so skin compares are faster - Q_strlwr( surf->name ); - - // strip off a trailing _1 or _2 - // this is a crutch for q3data being a mess - j = strlen( surf->name ); - if ( j > 2 && surf->name[j-2] == '_' ) { - surf->name[j-2] = 0; - } - - // register the shaders - shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders ); - for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) { - shader_t *sh; - - sh = R_FindShader( shader->name, LIGHTMAP_NONE, qtrue ); - if ( sh->defaultShader ) { - shader->shaderIndex = 0; - } else { - shader->shaderIndex = sh->index; - } - } - - // swap all the triangles - tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles ); - for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) { - LL(tri->indexes[0]); - LL(tri->indexes[1]); - LL(tri->indexes[2]); - } - - // swap all the ST - st = (md3St_t *) ( (byte *)surf + surf->ofsSt ); - for ( j = 0 ; j < surf->numVerts ; j++, st++ ) { - st->st[0] = LittleFloat( st->st[0] ); - st->st[1] = LittleFloat( st->st[1] ); - } - - // swap all the XyzNormals - xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals ); - for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ ) - { - xyz->xyz[0] = LittleShort( xyz->xyz[0] ); - xyz->xyz[1] = LittleShort( xyz->xyz[1] ); - xyz->xyz[2] = LittleShort( xyz->xyz[2] ); - - xyz->normal = LittleShort( xyz->normal ); - } - - - // find the next surface - surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd ); - } - - return qtrue; -} - - - -/* -================= -R_LoadMDR -================= -*/ -static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char *mod_name ) -{ - int i, j, k, l; - mdrHeader_t *pinmodel, *mdr; - mdrFrame_t *frame; - mdrLOD_t *lod, *curlod; - mdrSurface_t *surf, *cursurf; - mdrTriangle_t *tri, *curtri; - mdrVertex_t *v, *curv; - mdrWeight_t *weight, *curweight; - mdrTag_t *tag, *curtag; - int size; - shader_t *sh; - - pinmodel = (mdrHeader_t *)buffer; - - pinmodel->version = LittleLong(pinmodel->version); - if (pinmodel->version != MDR_VERSION) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has wrong version (%i should be %i)\n", mod_name, pinmodel->version, MDR_VERSION); - return qfalse; - } - - size = LittleLong(pinmodel->ofsEnd); - - if(size > filesize) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: Header of %s is broken. Wrong filesize declared!\n", mod_name); - return qfalse; - } - - mod->type = MOD_MDR; - - LL(pinmodel->numFrames); - LL(pinmodel->numBones); - LL(pinmodel->ofsFrames); - - // This is a model that uses some type of compressed Bones. We don't want to uncompress every bone for each rendered frame - // over and over again, we'll uncompress it in this function already, so we must adjust the size of the target mdr. - if(pinmodel->ofsFrames < 0) - { - // mdrFrame_t is larger than mdrCompFrame_t: - size += pinmodel->numFrames * sizeof(frame->name); - // now add enough space for the uncompressed bones. - size += pinmodel->numFrames * pinmodel->numBones * ((sizeof(mdrBone_t) - sizeof(mdrCompBone_t))); - } - - // simple bounds check - if(pinmodel->numBones < 0 || - sizeof(*mdr) + pinmodel->numFrames * (sizeof(*frame) + (pinmodel->numBones - 1) * sizeof(*frame->bones)) > size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - mod->dataSize += size; - mod->modelData = mdr = ri.Hunk_Alloc( size, h_low ); - - // Copy all the values over from the file and fix endian issues in the process, if necessary. - - mdr->ident = LittleLong(pinmodel->ident); - mdr->version = pinmodel->version; // Don't need to swap byte order on this one, we already did above. - Q_strncpyz(mdr->name, pinmodel->name, sizeof(mdr->name)); - mdr->numFrames = pinmodel->numFrames; - mdr->numBones = pinmodel->numBones; - mdr->numLODs = LittleLong(pinmodel->numLODs); - mdr->numTags = LittleLong(pinmodel->numTags); - // We don't care about the other offset values, we'll generate them ourselves while loading. - - mod->numLods = mdr->numLODs; - - if ( mdr->numFrames < 1 ) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has no frames\n", mod_name); - return qfalse; - } - - /* The first frame will be put into the first free space after the header */ - frame = (mdrFrame_t *)(mdr + 1); - mdr->ofsFrames = (int)((byte *) frame - (byte *) mdr); - - if (pinmodel->ofsFrames < 0) - { - mdrCompFrame_t *cframe; - - // compressed model... - cframe = (mdrCompFrame_t *)((byte *) pinmodel - pinmodel->ofsFrames); - - for(i = 0; i < mdr->numFrames; i++) - { - for(j = 0; j < 3; j++) - { - frame->bounds[0][j] = LittleFloat(cframe->bounds[0][j]); - frame->bounds[1][j] = LittleFloat(cframe->bounds[1][j]); - frame->localOrigin[j] = LittleFloat(cframe->localOrigin[j]); - } - - frame->radius = LittleFloat(cframe->radius); - frame->name[0] = '\0'; // No name supplied in the compressed version. - - for(j = 0; j < mdr->numBones; j++) - { - for(k = 0; k < (sizeof(cframe->bones[j].Comp) / 2); k++) - { - // Do swapping for the uncompressing functions. They seem to use shorts - // values only, so I assume this will work. Never tested it on other - // platforms, though. - - ((unsigned short *)(cframe->bones[j].Comp))[k] = - LittleShort( ((unsigned short *)(cframe->bones[j].Comp))[k] ); - } - - /* Now do the actual uncompressing */ - MC_UnCompress(frame->bones[j].matrix, cframe->bones[j].Comp); - } - - // Next Frame... - cframe = (mdrCompFrame_t *) &cframe->bones[j]; - frame = (mdrFrame_t *) &frame->bones[j]; - } - } - else - { - mdrFrame_t *curframe; - - // uncompressed model... - // - - curframe = (mdrFrame_t *)((byte *) pinmodel + pinmodel->ofsFrames); - - // swap all the frames - for ( i = 0 ; i < mdr->numFrames ; i++) - { - for(j = 0; j < 3; j++) - { - frame->bounds[0][j] = LittleFloat(curframe->bounds[0][j]); - frame->bounds[1][j] = LittleFloat(curframe->bounds[1][j]); - frame->localOrigin[j] = LittleFloat(curframe->localOrigin[j]); - } - - frame->radius = LittleFloat(curframe->radius); - Q_strncpyz(frame->name, curframe->name, sizeof(frame->name)); - - for (j = 0; j < (int) (mdr->numBones * sizeof(mdrBone_t) / 4); j++) - { - ((float *)frame->bones)[j] = LittleFloat( ((float *)curframe->bones)[j] ); - } - - curframe = (mdrFrame_t *) &curframe->bones[mdr->numBones]; - frame = (mdrFrame_t *) &frame->bones[mdr->numBones]; - } - } - - // frame should now point to the first free address after all frames. - lod = (mdrLOD_t *) frame; - mdr->ofsLODs = (int) ((byte *) lod - (byte *)mdr); - - curlod = (mdrLOD_t *)((byte *) pinmodel + LittleLong(pinmodel->ofsLODs)); - - // swap all the LOD's - for ( l = 0 ; l < mdr->numLODs ; l++) - { - // simple bounds check - if((byte *) (lod + 1) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - lod->numSurfaces = LittleLong(curlod->numSurfaces); - - // swap all the surfaces - surf = (mdrSurface_t *) (lod + 1); - lod->ofsSurfaces = (int)((byte *) surf - (byte *) lod); - cursurf = (mdrSurface_t *) ((byte *)curlod + LittleLong(curlod->ofsSurfaces)); - - for ( i = 0 ; i < lod->numSurfaces ; i++) - { - // simple bounds check - if((byte *) (surf + 1) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - // first do some copying stuff - - surf->ident = SF_MDR; - Q_strncpyz(surf->name, cursurf->name, sizeof(surf->name)); - Q_strncpyz(surf->shader, cursurf->shader, sizeof(surf->shader)); - - surf->ofsHeader = (byte *) mdr - (byte *) surf; - - surf->numVerts = LittleLong(cursurf->numVerts); - surf->numTriangles = LittleLong(cursurf->numTriangles); - // numBoneReferences and BoneReferences generally seem to be unused - - // now do the checks that may fail. - if ( surf->numVerts >= SHADER_MAX_VERTEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on %s (%i).\n", - mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface", - surf->numVerts ); - return qfalse; - } - if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on %s (%i).\n", - mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface", - surf->numTriangles ); - return qfalse; - } - // lowercase the surface name so skin compares are faster - Q_strlwr( surf->name ); - - // register the shaders - sh = R_FindShader(surf->shader, LIGHTMAP_NONE, qtrue); - if ( sh->defaultShader ) { - surf->shaderIndex = 0; - } else { - surf->shaderIndex = sh->index; - } - - // now copy the vertexes. - v = (mdrVertex_t *) (surf + 1); - surf->ofsVerts = (int)((byte *) v - (byte *) surf); - curv = (mdrVertex_t *) ((byte *)cursurf + LittleLong(cursurf->ofsVerts)); - - for(j = 0; j < surf->numVerts; j++) - { - LL(curv->numWeights); - - // simple bounds check - if(curv->numWeights < 0 || (byte *) (v + 1) + (curv->numWeights - 1) * sizeof(*weight) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - v->normal[0] = LittleFloat(curv->normal[0]); - v->normal[1] = LittleFloat(curv->normal[1]); - v->normal[2] = LittleFloat(curv->normal[2]); - - v->texCoords[0] = LittleFloat(curv->texCoords[0]); - v->texCoords[1] = LittleFloat(curv->texCoords[1]); - - v->numWeights = curv->numWeights; - weight = &v->weights[0]; - curweight = &curv->weights[0]; - - // Now copy all the weights - for(k = 0; k < v->numWeights; k++) - { - weight->boneIndex = LittleLong(curweight->boneIndex); - weight->boneWeight = LittleFloat(curweight->boneWeight); - - weight->offset[0] = LittleFloat(curweight->offset[0]); - weight->offset[1] = LittleFloat(curweight->offset[1]); - weight->offset[2] = LittleFloat(curweight->offset[2]); - - weight++; - curweight++; - } - - v = (mdrVertex_t *) weight; - curv = (mdrVertex_t *) curweight; - } - - // we know the offset to the triangles now: - tri = (mdrTriangle_t *) v; - surf->ofsTriangles = (int)((byte *) tri - (byte *) surf); - curtri = (mdrTriangle_t *)((byte *) cursurf + LittleLong(cursurf->ofsTriangles)); - - // simple bounds check - if(surf->numTriangles < 0 || (byte *) (tri + surf->numTriangles) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - for(j = 0; j < surf->numTriangles; j++) - { - tri->indexes[0] = LittleLong(curtri->indexes[0]); - tri->indexes[1] = LittleLong(curtri->indexes[1]); - tri->indexes[2] = LittleLong(curtri->indexes[2]); - - tri++; - curtri++; - } - - // tri now points to the end of the surface. - surf->ofsEnd = (byte *) tri - (byte *) surf; - surf = (mdrSurface_t *) tri; - - // find the next surface. - cursurf = (mdrSurface_t *) ((byte *) cursurf + LittleLong(cursurf->ofsEnd)); - } - - // surf points to the next lod now. - lod->ofsEnd = (int)((byte *) surf - (byte *) lod); - lod = (mdrLOD_t *) surf; - - // find the next LOD. - curlod = (mdrLOD_t *)((byte *) curlod + LittleLong(curlod->ofsEnd)); - } - - // lod points to the first tag now, so update the offset too. - tag = (mdrTag_t *) lod; - mdr->ofsTags = (int)((byte *) tag - (byte *) mdr); - curtag = (mdrTag_t *) ((byte *)pinmodel + LittleLong(pinmodel->ofsTags)); - - // simple bounds check - if(mdr->numTags < 0 || (byte *) (tag + mdr->numTags) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - for (i = 0 ; i < mdr->numTags ; i++) - { - tag->boneIndex = LittleLong(curtag->boneIndex); - Q_strncpyz(tag->name, curtag->name, sizeof(tag->name)); - - tag++; - curtag++; - } - - // And finally we know the real offset to the end. - mdr->ofsEnd = (int)((byte *) tag - (byte *) mdr); - - // phew! we're done. - - return qtrue; -} - - - -//============================================================================= - -/* -** RE_BeginRegistration -*/ -void RE_BeginRegistration( glconfig_t *glconfigOut ) { - - R_Init(); - - *glconfigOut = glConfig; - - R_IssuePendingRenderCommands(); - - tr.viewCluster = -1; // force markleafs to regenerate - R_ClearFlares(); - RE_ClearScene(); - - tr.registered = qtrue; -} - -//============================================================================= - -/* -=============== -R_ModelInit -=============== -*/ -void R_ModelInit( void ) { - model_t *mod; - - // leave a space for NULL model - tr.numModels = 0; - - mod = R_AllocModel(); - mod->type = MOD_BAD; -} - - -/* -================ -R_Modellist_f -================ -*/ -void R_Modellist_f( void ) { - int i, j; - model_t *mod; - int total; - int lods; - - total = 0; - for ( i = 1 ; i < tr.numModels; i++ ) { - mod = tr.models[i]; - lods = 1; - for ( j = 1 ; j < MD3_MAX_LODS ; j++ ) { - if ( mod->md3[j] && mod->md3[j] != mod->md3[j-1] ) { - lods++; - } - } - ri.Printf( PRINT_ALL, "%8i : (%i) %s\n",mod->dataSize, lods, mod->name ); - total += mod->dataSize; - } - ri.Printf( PRINT_ALL, "%8i : Total models\n", total ); - -#if 0 // not working right with new hunk - if ( tr.world ) { - ri.Printf( PRINT_ALL, "\n%8i : %s\n", tr.world->dataSize, tr.world->name ); - } -#endif -} - - -//============================================================================= - - -/* -================ -R_GetTag -================ -*/ -static md3Tag_t *R_GetTag( md3Header_t *mod, int frame, const char *tagName ) { - md3Tag_t *tag; - int i; - - if ( frame >= mod->numFrames ) { - // it is possible to have a bad frame while changing models, so don't error - frame = mod->numFrames - 1; - } - - tag = (md3Tag_t *)((byte *)mod + mod->ofsTags) + frame * mod->numTags; - for ( i = 0 ; i < mod->numTags ; i++, tag++ ) { - if ( !strcmp( tag->name, tagName ) ) { - return tag; // found it - } - } - - return NULL; -} - -void R_GetAnimTag( mdrHeader_t *mod, int framenum, const char *tagName, md3Tag_t * dest) -{ - int i, j, k; - int frameSize; - mdrFrame_t *frame; - mdrTag_t *tag; - - if ( framenum >= mod->numFrames ) - { - // it is possible to have a bad frame while changing models, so don't error - framenum = mod->numFrames - 1; - } - - tag = (mdrTag_t *)((byte *)mod + mod->ofsTags); - for ( i = 0 ; i < mod->numTags ; i++, tag++ ) - { - if ( !strcmp( tag->name, tagName ) ) - { - Q_strncpyz(dest->name, tag->name, sizeof(dest->name)); - - // uncompressed model... - // - frameSize = (intptr_t)( &((mdrFrame_t *)0)->bones[ mod->numBones ] ); - frame = (mdrFrame_t *)((byte *)mod + mod->ofsFrames + framenum * frameSize ); - - for (j = 0; j < 3; j++) - { - for (k = 0; k < 3; k++) - dest->axis[j][k]=frame->bones[tag->boneIndex].matrix[k][j]; - } - - dest->origin[0]=frame->bones[tag->boneIndex].matrix[0][3]; - dest->origin[1]=frame->bones[tag->boneIndex].matrix[1][3]; - dest->origin[2]=frame->bones[tag->boneIndex].matrix[2][3]; - - return; - } - } - - AxisClear( dest->axis ); - VectorClear( dest->origin ); - strcpy(dest->name,""); -} - -/* -================ -R_LerpTag -================ -*/ -int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, - float frac, const char *tagName ) { - md3Tag_t *start, *end; - md3Tag_t start_space, end_space; - int i; - float frontLerp, backLerp; - model_t *model; - - model = R_GetModelByHandle( handle ); - if ( !model->md3[0] ) - { - if(model->type == MOD_MDR) - { - start = &start_space; - end = &end_space; - R_GetAnimTag((mdrHeader_t *) model->modelData, startFrame, tagName, start); - R_GetAnimTag((mdrHeader_t *) model->modelData, endFrame, tagName, end); - } - else if( model->type == MOD_IQM ) { - return R_IQMLerpTag( tag, model->modelData, - startFrame, endFrame, - frac, tagName ); - } else { - - AxisClear( tag->axis ); - VectorClear( tag->origin ); - return qfalse; - - } - } - else - { - start = R_GetTag( model->md3[0], startFrame, tagName ); - end = R_GetTag( model->md3[0], endFrame, tagName ); - if ( !start || !end ) { - AxisClear( tag->axis ); - VectorClear( tag->origin ); - return qfalse; - } - } - - frontLerp = frac; - backLerp = 1.0f - frac; - - for ( i = 0 ; i < 3 ; i++ ) { - tag->origin[i] = start->origin[i] * backLerp + end->origin[i] * frontLerp; - tag->axis[0][i] = start->axis[0][i] * backLerp + end->axis[0][i] * frontLerp; - tag->axis[1][i] = start->axis[1][i] * backLerp + end->axis[1][i] * frontLerp; - tag->axis[2][i] = start->axis[2][i] * backLerp + end->axis[2][i] * frontLerp; - } - VectorNormalize( tag->axis[0] ); - VectorNormalize( tag->axis[1] ); - VectorNormalize( tag->axis[2] ); - return qtrue; -} - - -/* -==================== -R_ModelBounds -==================== -*/ -void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) { - model_t *model; - - model = R_GetModelByHandle( handle ); - - if(model->type == MOD_BRUSH) { - VectorCopy( model->bmodel->bounds[0], mins ); - VectorCopy( model->bmodel->bounds[1], maxs ); - - return; - } else if (model->type == MOD_MESH) { - md3Header_t *header; - md3Frame_t *frame; - - header = model->md3[0]; - frame = (md3Frame_t *) ((byte *)header + header->ofsFrames); - - VectorCopy( frame->bounds[0], mins ); - VectorCopy( frame->bounds[1], maxs ); - - return; - } else if (model->type == MOD_MDR) { - mdrHeader_t *header; - mdrFrame_t *frame; - - header = (mdrHeader_t *)model->modelData; - frame = (mdrFrame_t *) ((byte *)header + header->ofsFrames); - - VectorCopy( frame->bounds[0], mins ); - VectorCopy( frame->bounds[1], maxs ); - - return; - } else if(model->type == MOD_IQM) { - iqmData_t *iqmData; - - iqmData = model->modelData; - - if(iqmData->bounds) - { - VectorCopy(iqmData->bounds, mins); - VectorCopy(iqmData->bounds + 3, maxs); - return; - } - } - - VectorClear( mins ); - VectorClear( maxs ); -} diff --git a/code/renderergl1/tr_model_iqm.c b/code/renderergl1/tr_model_iqm.c deleted file mode 100644 index 0f99f1605c..0000000000 --- a/code/renderergl1/tr_model_iqm.c +++ /dev/null @@ -1,1185 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2011 Thilo Schulz -Copyright (C) 2011 Matthias Bentrup - -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "tr_local.h" - -#define LL(x) x=LittleLong(x) - -// 3x4 identity matrix -static float identityMatrix[12] = { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0 -}; - -static qboolean IQM_CheckRange( iqmHeader_t *header, int offset, - int count,int size ) { - // return true if the range specified by offset, count and size - // doesn't fit into the file - return ( count <= 0 || - offset < 0 || - offset > header->filesize || - offset + count * size < 0 || - offset + count * size > header->filesize ); -} -// "multiply" 3x4 matrices, these are assumed to be the top 3 rows -// of a 4x4 matrix with the last row = (0 0 0 1) -static void Matrix34Multiply( float *a, float *b, float *out ) { - out[ 0] = a[0] * b[0] + a[1] * b[4] + a[ 2] * b[ 8]; - out[ 1] = a[0] * b[1] + a[1] * b[5] + a[ 2] * b[ 9]; - out[ 2] = a[0] * b[2] + a[1] * b[6] + a[ 2] * b[10]; - out[ 3] = a[0] * b[3] + a[1] * b[7] + a[ 2] * b[11] + a[ 3]; - out[ 4] = a[4] * b[0] + a[5] * b[4] + a[ 6] * b[ 8]; - out[ 5] = a[4] * b[1] + a[5] * b[5] + a[ 6] * b[ 9]; - out[ 6] = a[4] * b[2] + a[5] * b[6] + a[ 6] * b[10]; - out[ 7] = a[4] * b[3] + a[5] * b[7] + a[ 6] * b[11] + a[ 7]; - out[ 8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[ 8]; - out[ 9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[ 9]; - out[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10]; - out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11]; -} -static void Matrix34Multiply_OnlySetOrigin( float *a, float *b, float *out ) { - out[ 3] = a[0] * b[3] + a[1] * b[7] + a[ 2] * b[11] + a[ 3]; - out[ 7] = a[4] * b[3] + a[5] * b[7] + a[ 6] * b[11] + a[ 7]; - out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11]; -} -static void InterpolateMatrix( float *a, float *b, float lerp, float *mat ) { - float unLerp = 1.0f - lerp; - - mat[ 0] = a[ 0] * unLerp + b[ 0] * lerp; - mat[ 1] = a[ 1] * unLerp + b[ 1] * lerp; - mat[ 2] = a[ 2] * unLerp + b[ 2] * lerp; - mat[ 3] = a[ 3] * unLerp + b[ 3] * lerp; - mat[ 4] = a[ 4] * unLerp + b[ 4] * lerp; - mat[ 5] = a[ 5] * unLerp + b[ 5] * lerp; - mat[ 6] = a[ 6] * unLerp + b[ 6] * lerp; - mat[ 7] = a[ 7] * unLerp + b[ 7] * lerp; - mat[ 8] = a[ 8] * unLerp + b[ 8] * lerp; - mat[ 9] = a[ 9] * unLerp + b[ 9] * lerp; - mat[10] = a[10] * unLerp + b[10] * lerp; - mat[11] = a[11] * unLerp + b[11] * lerp; -} -static void JointToMatrix( vec4_t rot, vec3_t scale, vec3_t trans, - float *mat ) { - float xx = 2.0f * rot[0] * rot[0]; - float yy = 2.0f * rot[1] * rot[1]; - float zz = 2.0f * rot[2] * rot[2]; - float xy = 2.0f * rot[0] * rot[1]; - float xz = 2.0f * rot[0] * rot[2]; - float yz = 2.0f * rot[1] * rot[2]; - float wx = 2.0f * rot[3] * rot[0]; - float wy = 2.0f * rot[3] * rot[1]; - float wz = 2.0f * rot[3] * rot[2]; - - mat[ 0] = scale[0] * (1.0f - (yy + zz)); - mat[ 1] = scale[0] * (xy - wz); - mat[ 2] = scale[0] * (xz + wy); - mat[ 3] = trans[0]; - mat[ 4] = scale[1] * (xy + wz); - mat[ 5] = scale[1] * (1.0f - (xx + zz)); - mat[ 6] = scale[1] * (yz - wx); - mat[ 7] = trans[1]; - mat[ 8] = scale[2] * (xz - wy); - mat[ 9] = scale[2] * (yz + wx); - mat[10] = scale[2] * (1.0f - (xx + yy)); - mat[11] = trans[2]; -} -static void Matrix34Invert( float *inMat, float *outMat ) -{ - vec3_t trans; - float invSqrLen, *v; - - outMat[ 0] = inMat[ 0]; outMat[ 1] = inMat[ 4]; outMat[ 2] = inMat[ 8]; - outMat[ 4] = inMat[ 1]; outMat[ 5] = inMat[ 5]; outMat[ 6] = inMat[ 9]; - outMat[ 8] = inMat[ 2]; outMat[ 9] = inMat[ 6]; outMat[10] = inMat[10]; - - v = outMat + 0; invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v); - v = outMat + 4; invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v); - v = outMat + 8; invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v); - - trans[0] = inMat[ 3]; - trans[1] = inMat[ 7]; - trans[2] = inMat[11]; - - outMat[ 3] = -DotProduct(outMat + 0, trans); - outMat[ 7] = -DotProduct(outMat + 4, trans); - outMat[11] = -DotProduct(outMat + 8, trans); -} - -/* -================= -R_LoadIQM - -Load an IQM model and compute the joint matrices for every frame. -================= -*/ -qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_name ) { - iqmHeader_t *header; - iqmVertexArray_t *vertexarray; - iqmTriangle_t *triangle; - iqmMesh_t *mesh; - iqmJoint_t *joint; - iqmPose_t *pose; - iqmBounds_t *bounds; - unsigned short *framedata; - char *str; - int i, j; - float jointInvMats[IQM_MAX_JOINTS * 12]; - float *mat, *matInv; - size_t size, joint_names; - iqmData_t *iqmData; - srfIQModel_t *surface; - char meshName[MAX_QPATH]; - byte blendIndexesType, blendWeightsType; - - if( filesize < sizeof(iqmHeader_t) ) { - return qfalse; - } - - header = (iqmHeader_t *)buffer; - if( Q_strncmp( header->magic, IQM_MAGIC, sizeof(header->magic) ) ) { - return qfalse; - } - - LL( header->version ); - if( header->version != IQM_VERSION ) { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s is a unsupported IQM version (%d), only version %d is supported.\n", - mod_name, header->version, IQM_VERSION); - return qfalse; - } - - LL( header->filesize ); - if( header->filesize > filesize || header->filesize > 16<<20 ) { - return qfalse; - } - - LL( header->flags ); - LL( header->num_text ); - LL( header->ofs_text ); - LL( header->num_meshes ); - LL( header->ofs_meshes ); - LL( header->num_vertexarrays ); - LL( header->num_vertexes ); - LL( header->ofs_vertexarrays ); - LL( header->num_triangles ); - LL( header->ofs_triangles ); - LL( header->ofs_adjacency ); - LL( header->num_joints ); - LL( header->ofs_joints ); - LL( header->num_poses ); - LL( header->ofs_poses ); - LL( header->num_anims ); - LL( header->ofs_anims ); - LL( header->num_frames ); - LL( header->num_framechannels ); - LL( header->ofs_frames ); - LL( header->ofs_bounds ); - LL( header->num_comment ); - LL( header->ofs_comment ); - LL( header->num_extensions ); - LL( header->ofs_extensions ); - - // check ioq3 joint limit - if ( header->num_joints > IQM_MAX_JOINTS ) { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %d joints (%d).\n", - mod_name, IQM_MAX_JOINTS, header->num_joints); - return qfalse; - } - - blendIndexesType = blendWeightsType = IQM_UBYTE; - - // check and swap vertex arrays - if( IQM_CheckRange( header, header->ofs_vertexarrays, - header->num_vertexarrays, - sizeof(iqmVertexArray_t) ) ) { - return qfalse; - } - vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays); - for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) { - int n, *intPtr; - - if( vertexarray->size <= 0 || vertexarray->size > 4 ) { - return qfalse; - } - - // total number of values - n = header->num_vertexes * vertexarray->size; - - switch( vertexarray->format ) { - case IQM_BYTE: - case IQM_UBYTE: - // 1 byte, no swapping necessary - if( IQM_CheckRange( header, vertexarray->offset, - n, sizeof(byte) ) ) { - return qfalse; - } - break; - case IQM_INT: - case IQM_UINT: - case IQM_FLOAT: - // 4-byte swap - if( IQM_CheckRange( header, vertexarray->offset, - n, sizeof(float) ) ) { - return qfalse; - } - intPtr = (int *)((byte *)header + vertexarray->offset); - for( j = 0; j < n; j++, intPtr++ ) { - LL( *intPtr ); - } - break; - default: - // not supported - return qfalse; - break; - } - - switch( vertexarray->type ) { - case IQM_POSITION: - case IQM_NORMAL: - if( vertexarray->format != IQM_FLOAT || - vertexarray->size != 3 ) { - return qfalse; - } - break; - case IQM_TANGENT: - if( vertexarray->format != IQM_FLOAT || - vertexarray->size != 4 ) { - return qfalse; - } - break; - case IQM_TEXCOORD: - if( vertexarray->format != IQM_FLOAT || - vertexarray->size != 2 ) { - return qfalse; - } - break; - case IQM_BLENDINDEXES: - if( (vertexarray->format != IQM_INT && - vertexarray->format != IQM_UBYTE) || - vertexarray->size != 4 ) { - return qfalse; - } - blendIndexesType = vertexarray->format; - break; - case IQM_BLENDWEIGHTS: - if( (vertexarray->format != IQM_FLOAT && - vertexarray->format != IQM_UBYTE) || - vertexarray->size != 4 ) { - return qfalse; - } - blendWeightsType = vertexarray->format; - break; - case IQM_COLOR: - if( vertexarray->format != IQM_UBYTE || - vertexarray->size != 4 ) { - return qfalse; - } - break; - } - } - - // check and swap triangles - if( IQM_CheckRange( header, header->ofs_triangles, - header->num_triangles, sizeof(iqmTriangle_t) ) ) { - return qfalse; - } - triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles); - for( i = 0; i < header->num_triangles; i++, triangle++ ) { - LL( triangle->vertex[0] ); - LL( triangle->vertex[1] ); - LL( triangle->vertex[2] ); - - if( triangle->vertex[0] > header->num_vertexes || - triangle->vertex[1] > header->num_vertexes || - triangle->vertex[2] > header->num_vertexes ) { - return qfalse; - } - } - - // check and swap meshes - if( IQM_CheckRange( header, header->ofs_meshes, - header->num_meshes, sizeof(iqmMesh_t) ) ) { - return qfalse; - } - mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes); - for( i = 0; i < header->num_meshes; i++, mesh++) { - LL( mesh->name ); - LL( mesh->material ); - LL( mesh->first_vertex ); - LL( mesh->num_vertexes ); - LL( mesh->first_triangle ); - LL( mesh->num_triangles ); - - if ( mesh->name < header->num_text ) { - Q_strncpyz( meshName, (char*)header + header->ofs_text + mesh->name, sizeof (meshName) ); - } else { - meshName[0] = '\0'; - } - - // check ioq3 limits - if ( mesh->num_vertexes >= SHADER_MAX_VERTEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on %s (%i).\n", - mod_name, SHADER_MAX_VERTEXES - 1, meshName[0] ? meshName : "a surface", - mesh->num_vertexes ); - return qfalse; - } - if ( mesh->num_triangles*3 >= SHADER_MAX_INDEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on %s (%i).\n", - mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, meshName[0] ? meshName : "a surface", - mesh->num_triangles ); - return qfalse; - } - - if( mesh->first_vertex >= header->num_vertexes || - mesh->first_vertex + mesh->num_vertexes > header->num_vertexes || - mesh->first_triangle >= header->num_triangles || - mesh->first_triangle + mesh->num_triangles > header->num_triangles || - mesh->name >= header->num_text || - mesh->material >= header->num_text ) { - return qfalse; - } - } - - if( header->num_poses != header->num_joints && header->num_poses != 0 ) { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has %d poses and %d joints, must have the same number or 0 poses\n", - mod_name, header->num_poses, header->num_joints ); - return qfalse; - } - - joint_names = 0; - - if ( header->num_joints ) - { - // check and swap joints - if( IQM_CheckRange( header, header->ofs_joints, - header->num_joints, sizeof(iqmJoint_t) ) ) { - return qfalse; - } - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - LL( joint->name ); - LL( joint->parent ); - LL( joint->translate[0] ); - LL( joint->translate[1] ); - LL( joint->translate[2] ); - LL( joint->rotate[0] ); - LL( joint->rotate[1] ); - LL( joint->rotate[2] ); - LL( joint->rotate[3] ); - LL( joint->scale[0] ); - LL( joint->scale[1] ); - LL( joint->scale[2] ); - - if( joint->parent < -1 || - joint->parent >= (int)header->num_joints || - joint->name >= (int)header->num_text ) { - return qfalse; - } - joint_names += strlen( (char *)header + header->ofs_text + - joint->name ) + 1; - } - } - - if ( header->num_poses ) - { - // check and swap poses - if( IQM_CheckRange( header, header->ofs_poses, - header->num_poses, sizeof(iqmPose_t) ) ) { - return qfalse; - } - pose = (iqmPose_t *)((byte *)header + header->ofs_poses); - for( i = 0; i < header->num_poses; i++, pose++ ) { - LL( pose->parent ); - LL( pose->mask ); - LL( pose->channeloffset[0] ); - LL( pose->channeloffset[1] ); - LL( pose->channeloffset[2] ); - LL( pose->channeloffset[3] ); - LL( pose->channeloffset[4] ); - LL( pose->channeloffset[5] ); - LL( pose->channeloffset[6] ); - LL( pose->channeloffset[7] ); - LL( pose->channeloffset[8] ); - LL( pose->channeloffset[9] ); - LL( pose->channelscale[0] ); - LL( pose->channelscale[1] ); - LL( pose->channelscale[2] ); - LL( pose->channelscale[3] ); - LL( pose->channelscale[4] ); - LL( pose->channelscale[5] ); - LL( pose->channelscale[6] ); - LL( pose->channelscale[7] ); - LL( pose->channelscale[8] ); - LL( pose->channelscale[9] ); - } - } - - if (header->ofs_bounds) - { - // check and swap model bounds - if(IQM_CheckRange(header, header->ofs_bounds, - header->num_frames, sizeof(*bounds))) - { - return qfalse; - } - bounds = (iqmBounds_t *) ((byte *) header + header->ofs_bounds); - for(i = 0; i < header->num_frames; i++) - { - LL(bounds->bbmin[0]); - LL(bounds->bbmin[1]); - LL(bounds->bbmin[2]); - LL(bounds->bbmax[0]); - LL(bounds->bbmax[1]); - LL(bounds->bbmax[2]); - - bounds++; - } - } - - // allocate the model and copy the data - size = sizeof(iqmData_t); - size += header->num_meshes * sizeof( srfIQModel_t ); - size += header->num_joints * 12 * sizeof( float ); // joint mats - size += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats - if(header->ofs_bounds) - size += header->num_frames * 6 * sizeof(float); // model bounds - size += header->num_vertexes * 3 * sizeof(float); // positions - size += header->num_vertexes * 2 * sizeof(float); // texcoords - size += header->num_vertexes * 3 * sizeof(float); // normals - size += header->num_vertexes * 4 * sizeof(float); // tangents - size += header->num_vertexes * 4 * sizeof(byte); // blendIndexes - size += header->num_vertexes * 4 * sizeof(byte); // colors - size += header->num_joints * sizeof(int); // parents - size += header->num_triangles * 3 * sizeof(int); // triangles - size += joint_names; // joint names - - // blendWeights - if (blendWeightsType == IQM_FLOAT) { - size += header->num_vertexes * 4 * sizeof(float); - } else { - size += header->num_vertexes * 4 * sizeof(byte); - } - - mod->type = MOD_IQM; - iqmData = (iqmData_t *)ri.Hunk_Alloc( size, h_low ); - mod->modelData = iqmData; - - // fill header - iqmData->num_vertexes = header->num_vertexes; - iqmData->num_triangles = header->num_triangles; - iqmData->num_frames = header->num_frames; - iqmData->num_surfaces = header->num_meshes; - iqmData->num_joints = header->num_joints; - iqmData->num_poses = header->num_poses; - iqmData->blendWeightsType = blendWeightsType; - iqmData->surfaces = (srfIQModel_t *)(iqmData + 1); - iqmData->jointMats = (float *) (iqmData->surfaces + iqmData->num_surfaces); - iqmData->poseMats = iqmData->jointMats + 12 * header->num_joints; - if(header->ofs_bounds) - { - iqmData->bounds = iqmData->poseMats + 12 * header->num_poses * header->num_frames; - iqmData->positions = iqmData->bounds + 6 * header->num_frames; - } - else - iqmData->positions = iqmData->poseMats + 12 * header->num_poses * header->num_frames; - iqmData->texcoords = iqmData->positions + 3 * header->num_vertexes; - iqmData->normals = iqmData->texcoords + 2 * header->num_vertexes; - iqmData->tangents = iqmData->normals + 3 * header->num_vertexes; - iqmData->blendIndexes = (byte *)(iqmData->tangents + 4 * header->num_vertexes); - - if(blendWeightsType == IQM_FLOAT) { - iqmData->blendWeights.f = (float *)(iqmData->blendIndexes + 4 * header->num_vertexes); - iqmData->colors = (byte *)(iqmData->blendWeights.f + 4 * header->num_vertexes); - } else { - iqmData->blendWeights.b = iqmData->blendIndexes + 4 * header->num_vertexes; - iqmData->colors = iqmData->blendWeights.b + 4 * header->num_vertexes; - } - - iqmData->jointParents = (int *)(iqmData->colors + 4 * header->num_vertexes); - iqmData->triangles = iqmData->jointParents + header->num_joints; - iqmData->names = (char *)(iqmData->triangles + 3 * header->num_triangles); - - if ( header->num_joints == 0 ) - iqmData->jointMats = NULL; - - if ( header->num_poses == 0 ) - iqmData->poseMats = NULL; - - // calculate joint matrices and their inverses - // joint inverses are needed only until the pose matrices are calculated - mat = iqmData->jointMats; - matInv = jointInvMats; - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - float baseFrame[12], invBaseFrame[12]; - - JointToMatrix( joint->rotate, joint->scale, joint->translate, baseFrame ); - Matrix34Invert( baseFrame, invBaseFrame ); - - if ( joint->parent >= 0 ) - { - Matrix34Multiply( iqmData->jointMats + 12 * joint->parent, baseFrame, mat ); - mat += 12; - Matrix34Multiply( invBaseFrame, jointInvMats + 12 * joint->parent, matInv ); - matInv += 12; - } - else - { - Com_Memcpy( mat, baseFrame, sizeof(baseFrame) ); - mat += 12; - Com_Memcpy( matInv, invBaseFrame, sizeof(invBaseFrame) ); - matInv += 12; - } - } - - // calculate pose matrices - framedata = (unsigned short *)((byte *)header + header->ofs_frames); - mat = iqmData->poseMats; - for( i = 0; i < header->num_frames; i++ ) { - pose = (iqmPose_t *)((byte *)header + header->ofs_poses); - for( j = 0; j < header->num_poses; j++, pose++ ) { - vec3_t translate; - vec4_t rotate; - vec3_t scale; - float mat1[12], mat2[12]; - - translate[0] = pose->channeloffset[0]; - if( pose->mask & 0x001) - translate[0] += *framedata++ * pose->channelscale[0]; - translate[1] = pose->channeloffset[1]; - if( pose->mask & 0x002) - translate[1] += *framedata++ * pose->channelscale[1]; - translate[2] = pose->channeloffset[2]; - if( pose->mask & 0x004) - translate[2] += *framedata++ * pose->channelscale[2]; - - rotate[0] = pose->channeloffset[3]; - if( pose->mask & 0x008) - rotate[0] += *framedata++ * pose->channelscale[3]; - rotate[1] = pose->channeloffset[4]; - if( pose->mask & 0x010) - rotate[1] += *framedata++ * pose->channelscale[4]; - rotate[2] = pose->channeloffset[5]; - if( pose->mask & 0x020) - rotate[2] += *framedata++ * pose->channelscale[5]; - rotate[3] = pose->channeloffset[6]; - if( pose->mask & 0x040) - rotate[3] += *framedata++ * pose->channelscale[6]; - - scale[0] = pose->channeloffset[7]; - if( pose->mask & 0x080) - scale[0] += *framedata++ * pose->channelscale[7]; - scale[1] = pose->channeloffset[8]; - if( pose->mask & 0x100) - scale[1] += *framedata++ * pose->channelscale[8]; - scale[2] = pose->channeloffset[9]; - if( pose->mask & 0x200) - scale[2] += *framedata++ * pose->channelscale[9]; - - // construct transformation matrix - JointToMatrix( rotate, scale, translate, mat1 ); - - if( pose->parent >= 0 ) { - Matrix34Multiply( iqmData->jointMats + 12 * pose->parent, - mat1, mat2 ); - } else { - Com_Memcpy( mat2, mat1, sizeof(mat1) ); - } - - Matrix34Multiply( mat2, jointInvMats + 12 * j, mat ); - mat += 12; - } - } - - // register shaders - // overwrite the material offset with the shader index - mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes); - surface = iqmData->surfaces; - str = (char *)header + header->ofs_text; - for( i = 0; i < header->num_meshes; i++, mesh++, surface++ ) { - surface->surfaceType = SF_IQM; - Q_strncpyz(surface->name, str + mesh->name, sizeof (surface->name)); - Q_strlwr(surface->name); // lowercase the surface name so skin compares are faster - surface->shader = R_FindShader( str + mesh->material, LIGHTMAP_NONE, qtrue ); - if( surface->shader->defaultShader ) - surface->shader = tr.defaultShader; - surface->data = iqmData; - surface->first_vertex = mesh->first_vertex; - surface->num_vertexes = mesh->num_vertexes; - surface->first_triangle = mesh->first_triangle; - surface->num_triangles = mesh->num_triangles; - } - - // copy vertexarrays and indexes - vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays); - for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) { - int n; - - // total number of values - n = header->num_vertexes * vertexarray->size; - - switch( vertexarray->type ) { - case IQM_POSITION: - Com_Memcpy( iqmData->positions, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_NORMAL: - Com_Memcpy( iqmData->normals, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_TANGENT: - Com_Memcpy( iqmData->tangents, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_TEXCOORD: - Com_Memcpy( iqmData->texcoords, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_BLENDINDEXES: - if( blendIndexesType == IQM_INT ) { - int *data = (int*)((byte*)header + vertexarray->offset); - for ( j = 0; j < n; j++ ) { - iqmData->blendIndexes[j] = (byte)data[j]; - } - } else { - Com_Memcpy( iqmData->blendIndexes, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); - } - break; - case IQM_BLENDWEIGHTS: - if( blendWeightsType == IQM_FLOAT ) { - Com_Memcpy( iqmData->blendWeights.f, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - } else { - Com_Memcpy( iqmData->blendWeights.b, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); - } - break; - case IQM_COLOR: - Com_Memcpy( iqmData->colors, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); - break; - } - } - - // copy joint parents - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - iqmData->jointParents[i] = joint->parent; - } - - // copy triangles - triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles); - for( i = 0; i < header->num_triangles; i++, triangle++ ) { - iqmData->triangles[3*i+0] = triangle->vertex[0]; - iqmData->triangles[3*i+1] = triangle->vertex[1]; - iqmData->triangles[3*i+2] = triangle->vertex[2]; - } - - // copy joint names - str = iqmData->names; - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - char *name = (char *)header + header->ofs_text + - joint->name; - int len = strlen( name ) + 1; - Com_Memcpy( str, name, len ); - str += len; - } - - // copy model bounds - if(header->ofs_bounds) - { - mat = iqmData->bounds; - bounds = (iqmBounds_t *) ((byte *) header + header->ofs_bounds); - for(i = 0; i < header->num_frames; i++) - { - mat[0] = bounds->bbmin[0]; - mat[1] = bounds->bbmin[1]; - mat[2] = bounds->bbmin[2]; - mat[3] = bounds->bbmax[0]; - mat[4] = bounds->bbmax[1]; - mat[5] = bounds->bbmax[2]; - - mat += 6; - bounds++; - } - } - - return qtrue; -} - -/* -============= -R_CullIQM -============= -*/ -static int R_CullIQM( iqmData_t *data, trRefEntity_t *ent ) { - vec3_t bounds[2]; - vec_t *oldBounds, *newBounds; - int i; - - if (!data->bounds) { - tr.pc.c_box_cull_md3_clip++; - return CULL_CLIP; - } - - // compute bounds pointers - oldBounds = data->bounds + 6*ent->e.oldframe; - newBounds = data->bounds + 6*ent->e.frame; - - // calculate a bounding box in the current coordinate system - for (i = 0 ; i < 3 ; i++) { - bounds[0][i] = oldBounds[i] < newBounds[i] ? oldBounds[i] : newBounds[i]; - bounds[1][i] = oldBounds[i+3] > newBounds[i+3] ? oldBounds[i+3] : newBounds[i+3]; - } - - switch ( R_CullLocalBox( bounds ) ) - { - case CULL_IN: - tr.pc.c_box_cull_md3_in++; - return CULL_IN; - case CULL_CLIP: - tr.pc.c_box_cull_md3_clip++; - return CULL_CLIP; - case CULL_OUT: - default: - tr.pc.c_box_cull_md3_out++; - return CULL_OUT; - } -} - -/* -================= -R_ComputeIQMFogNum - -================= -*/ -int R_ComputeIQMFogNum( iqmData_t *data, trRefEntity_t *ent ) { - int i, j; - fog_t *fog; - const vec_t *bounds; - const vec_t defaultBounds[6] = { -8, -8, -8, 8, 8, 8 }; - vec3_t diag, center; - vec3_t localOrigin; - vec_t radius; - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return 0; - } - - // FIXME: non-normalized axis issues - if (data->bounds) { - bounds = data->bounds + 6*ent->e.frame; - } else { - bounds = defaultBounds; - } - VectorSubtract( bounds+3, bounds, diag ); - VectorMA( bounds, 0.5f, diag, center ); - VectorAdd( ent->e.origin, center, localOrigin ); - radius = 0.5f * VectorLength( diag ); - - for ( i = 1 ; i < tr.world->numfogs ; i++ ) { - fog = &tr.world->fogs[i]; - for ( j = 0 ; j < 3 ; j++ ) { - if ( localOrigin[j] - radius >= fog->bounds[1][j] ) { - break; - } - if ( localOrigin[j] + radius <= fog->bounds[0][j] ) { - break; - } - } - if ( j == 3 ) { - return i; - } - } - - return 0; -} - -/* -================= -R_AddIQMSurfaces - -Add all surfaces of this model -================= -*/ -void R_AddIQMSurfaces( trRefEntity_t *ent ) { - iqmData_t *data; - srfIQModel_t *surface; - int i, j; - qboolean personalModel; - int cull; - int fogNum; - shader_t *shader; - skin_t *skin; - - data = tr.currentModel->modelData; - surface = data->surfaces; - - // don't add third_person objects if not in a portal - personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; - - if ( ent->e.renderfx & RF_WRAP_FRAMES ) { - ent->e.frame %= data->num_frames; - ent->e.oldframe %= data->num_frames; - } - - // - // Validate the frames so there is no chance of a crash. - // This will write directly into the entity structure, so - // when the surfaces are rendered, they don't need to be - // range checked again. - // - if ( (ent->e.frame >= data->num_frames) - || (ent->e.frame < 0) - || (ent->e.oldframe >= data->num_frames) - || (ent->e.oldframe < 0) ) { - ri.Printf( PRINT_DEVELOPER, "R_AddIQMSurfaces: no such frame %d to %d for '%s'\n", - ent->e.oldframe, ent->e.frame, - tr.currentModel->name ); - ent->e.frame = 0; - ent->e.oldframe = 0; - } - - // - // cull the entire model if merged bounding box of both frames - // is outside the view frustum. - // - cull = R_CullIQM ( data, ent ); - if ( cull == CULL_OUT ) { - return; - } - - // - // set up lighting now that we know we aren't culled - // - if ( !personalModel || r_shadows->integer > 1 ) { - R_SetupEntityLighting( &tr.refdef, ent ); - } - - // - // see if we are in a fog volume - // - fogNum = R_ComputeIQMFogNum( data, ent ); - - for ( i = 0 ; i < data->num_surfaces ; i++ ) { - if(ent->e.customShader) - shader = R_GetShaderByHandle( ent->e.customShader ); - else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins) - { - skin = R_GetSkinByHandle(ent->e.customSkin); - shader = tr.defaultShader; - - for(j = 0; j < skin->numSurfaces; j++) - { - if (!strcmp(skin->surfaces[j]->name, surface->name)) - { - shader = skin->surfaces[j]->shader; - break; - } - } - } else { - shader = surface->shader; - } - - // we will add shadows even if the main object isn't visible in the view - - // stencil shadows can't do personal models unless I polyhedron clip - if ( !personalModel - && r_shadows->integer == 2 - && fogNum == 0 - && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) - && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, 0 ); - } - - // projection shadows work fine with personal models - if ( r_shadows->integer == 3 - && fogNum == 0 - && (ent->e.renderfx & RF_SHADOW_PLANE ) - && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, 0 ); - } - - if( !personalModel ) { - R_AddDrawSurf( (void *)surface, shader, fogNum, 0 ); - } - - surface++; - } -} - - -static void ComputePoseMats( iqmData_t *data, int frame, int oldframe, - float backlerp, float *mat ) { - float *mat1, *mat2; - int *joint = data->jointParents; - int i; - - if ( data->num_poses == 0 ) { - for( i = 0; i < data->num_joints; i++, joint++ ) { - if( *joint >= 0 ) { - Matrix34Multiply( mat + 12 * *joint, - identityMatrix, mat + 12*i ); - } else { - Com_Memcpy( mat + 12*i, identityMatrix, 12 * sizeof(float) ); - } - } - return; - } - - if ( oldframe == frame ) { - mat1 = data->poseMats + 12 * data->num_poses * frame; - for( i = 0; i < data->num_poses; i++, joint++ ) { - if( *joint >= 0 ) { - Matrix34Multiply( mat + 12 * *joint, - mat1 + 12*i, mat + 12*i ); - } else { - Com_Memcpy( mat + 12*i, mat1 + 12*i, 12 * sizeof(float) ); - } - } - } else { - mat1 = data->poseMats + 12 * data->num_poses * frame; - mat2 = data->poseMats + 12 * data->num_poses * oldframe; - - for( i = 0; i < data->num_poses; i++, joint++ ) { - if( *joint >= 0 ) { - float tmpMat[12]; - InterpolateMatrix( mat1 + 12*i, mat2 + 12*i, - backlerp, tmpMat ); - Matrix34Multiply( mat + 12 * *joint, - tmpMat, mat + 12*i ); - - } else { - InterpolateMatrix( mat1 + 12*i, mat2 + 12*i, - backlerp, mat ); - } - } - } -} - -static void ComputeJointMats( iqmData_t *data, int frame, int oldframe, - float backlerp, float *mat ) { - float *mat1; - int i; - - ComputePoseMats( data, frame, oldframe, backlerp, mat ); - - for( i = 0; i < data->num_joints; i++ ) { - float outmat[12]; - mat1 = mat + 12 * i; - - Com_Memcpy(outmat, mat1, sizeof(outmat)); - - Matrix34Multiply_OnlySetOrigin( outmat, data->jointMats + 12 * i, mat1 ); - } -} - - -/* -================= -RB_AddIQMSurfaces - -Compute vertices for this model surface -================= -*/ -void RB_IQMSurfaceAnim( surfaceType_t *surface ) { - srfIQModel_t *surf = (srfIQModel_t *)surface; - iqmData_t *data = surf->data; - float jointMats[IQM_MAX_JOINTS * 12]; - int i; - - vec4_t *outXYZ; - vec4_t *outNormal; - vec2_t (*outTexCoord)[2]; - color4ub_t *outColor; - - int frame = data->num_frames ? backEnd.currentEntity->e.frame % data->num_frames : 0; - int oldframe = data->num_frames ? backEnd.currentEntity->e.oldframe % data->num_frames : 0; - float backlerp = backEnd.currentEntity->e.backlerp; - - int *tri; - glIndex_t *ptr; - glIndex_t base; - - RB_CHECKOVERFLOW( surf->num_vertexes, surf->num_triangles * 3 ); - - outXYZ = &tess.xyz[tess.numVertexes]; - outNormal = &tess.normal[tess.numVertexes]; - outTexCoord = &tess.texCoords[tess.numVertexes]; - outColor = &tess.vertexColors[tess.numVertexes]; - - // compute interpolated joint matrices - if ( data->num_poses > 0 ) { - ComputePoseMats( data, frame, oldframe, backlerp, jointMats ); - } - - // transform vertexes and fill other data - for( i = 0; i < surf->num_vertexes; - i++, outXYZ++, outNormal++, outTexCoord++, outColor++ ) { - int j, k; - float vtxMat[12]; - float nrmMat[9]; - int vtx = i + surf->first_vertex; - float blendWeights[4]; - int numWeights; - - for ( numWeights = 0; numWeights < 4; numWeights++ ) { - if ( data->blendWeightsType == IQM_FLOAT ) - blendWeights[numWeights] = data->blendWeights.f[4*vtx + numWeights]; - else - blendWeights[numWeights] = (float)data->blendWeights.b[4*vtx + numWeights] / 255.0f; - - if ( blendWeights[numWeights] <= 0 ) - break; - } - - if ( data->num_poses == 0 || numWeights == 0 ) { - // no blend joint, use identity matrix. - Com_Memcpy( vtxMat, identityMatrix, 12 * sizeof (float) ); - } else { - // compute the vertex matrix by blending the up to - // four blend weights - Com_Memset( vtxMat, 0, 12 * sizeof (float) ); - for( j = 0; j < numWeights; j++ ) { - for( k = 0; k < 12; k++ ) { - vtxMat[k] += blendWeights[j] * jointMats[12*data->blendIndexes[4*vtx + j] + k]; - } - } - } - - // compute the normal matrix as transpose of the adjoint - // of the vertex matrix - nrmMat[ 0] = vtxMat[ 5]*vtxMat[10] - vtxMat[ 6]*vtxMat[ 9]; - nrmMat[ 1] = vtxMat[ 6]*vtxMat[ 8] - vtxMat[ 4]*vtxMat[10]; - nrmMat[ 2] = vtxMat[ 4]*vtxMat[ 9] - vtxMat[ 5]*vtxMat[ 8]; - nrmMat[ 3] = vtxMat[ 2]*vtxMat[ 9] - vtxMat[ 1]*vtxMat[10]; - nrmMat[ 4] = vtxMat[ 0]*vtxMat[10] - vtxMat[ 2]*vtxMat[ 8]; - nrmMat[ 5] = vtxMat[ 1]*vtxMat[ 8] - vtxMat[ 0]*vtxMat[ 9]; - nrmMat[ 6] = vtxMat[ 1]*vtxMat[ 6] - vtxMat[ 2]*vtxMat[ 5]; - nrmMat[ 7] = vtxMat[ 2]*vtxMat[ 4] - vtxMat[ 0]*vtxMat[ 6]; - nrmMat[ 8] = vtxMat[ 0]*vtxMat[ 5] - vtxMat[ 1]*vtxMat[ 4]; - - (*outTexCoord)[0][0] = data->texcoords[2*vtx + 0]; - (*outTexCoord)[0][1] = data->texcoords[2*vtx + 1]; - (*outTexCoord)[1][0] = (*outTexCoord)[0][0]; - (*outTexCoord)[1][1] = (*outTexCoord)[0][1]; - - (*outXYZ)[0] = - vtxMat[ 0] * data->positions[3*vtx+0] + - vtxMat[ 1] * data->positions[3*vtx+1] + - vtxMat[ 2] * data->positions[3*vtx+2] + - vtxMat[ 3]; - (*outXYZ)[1] = - vtxMat[ 4] * data->positions[3*vtx+0] + - vtxMat[ 5] * data->positions[3*vtx+1] + - vtxMat[ 6] * data->positions[3*vtx+2] + - vtxMat[ 7]; - (*outXYZ)[2] = - vtxMat[ 8] * data->positions[3*vtx+0] + - vtxMat[ 9] * data->positions[3*vtx+1] + - vtxMat[10] * data->positions[3*vtx+2] + - vtxMat[11]; - (*outXYZ)[3] = 1.0f; - - (*outNormal)[0] = - nrmMat[ 0] * data->normals[3*vtx+0] + - nrmMat[ 1] * data->normals[3*vtx+1] + - nrmMat[ 2] * data->normals[3*vtx+2]; - (*outNormal)[1] = - nrmMat[ 3] * data->normals[3*vtx+0] + - nrmMat[ 4] * data->normals[3*vtx+1] + - nrmMat[ 5] * data->normals[3*vtx+2]; - (*outNormal)[2] = - nrmMat[ 6] * data->normals[3*vtx+0] + - nrmMat[ 7] * data->normals[3*vtx+1] + - nrmMat[ 8] * data->normals[3*vtx+2]; - (*outNormal)[3] = 0.0f; - - (*outColor)[0] = data->colors[4*vtx+0]; - (*outColor)[1] = data->colors[4*vtx+1]; - (*outColor)[2] = data->colors[4*vtx+2]; - (*outColor)[3] = data->colors[4*vtx+3]; - } - - tri = data->triangles + 3 * surf->first_triangle; - ptr = &tess.indexes[tess.numIndexes]; - base = tess.numVertexes; - - for( i = 0; i < surf->num_triangles; i++ ) { - *ptr++ = base + (*tri++ - surf->first_vertex); - *ptr++ = base + (*tri++ - surf->first_vertex); - *ptr++ = base + (*tri++ - surf->first_vertex); - } - - tess.numIndexes += 3 * surf->num_triangles; - tess.numVertexes += surf->num_vertexes; -} - -int R_IQMLerpTag( orientation_t *tag, iqmData_t *data, - int startFrame, int endFrame, - float frac, const char *tagName ) { - float jointMats[IQM_MAX_JOINTS * 12]; - int joint; - char *names = data->names; - - // get joint number by reading the joint names - for( joint = 0; joint < data->num_joints; joint++ ) { - if( !strcmp( tagName, names ) ) - break; - names += strlen( names ) + 1; - } - if( joint >= data->num_joints ) { - AxisClear( tag->axis ); - VectorClear( tag->origin ); - return qfalse; - } - - ComputeJointMats( data, startFrame, endFrame, frac, jointMats ); - - tag->axis[0][0] = jointMats[12 * joint + 0]; - tag->axis[1][0] = jointMats[12 * joint + 1]; - tag->axis[2][0] = jointMats[12 * joint + 2]; - tag->origin[0] = jointMats[12 * joint + 3]; - tag->axis[0][1] = jointMats[12 * joint + 4]; - tag->axis[1][1] = jointMats[12 * joint + 5]; - tag->axis[2][1] = jointMats[12 * joint + 6]; - tag->origin[1] = jointMats[12 * joint + 7]; - tag->axis[0][2] = jointMats[12 * joint + 8]; - tag->axis[1][2] = jointMats[12 * joint + 9]; - tag->axis[2][2] = jointMats[12 * joint + 10]; - tag->origin[2] = jointMats[12 * joint + 11]; - - return qtrue; -} diff --git a/code/renderergl1/tr_scene.c b/code/renderergl1/tr_scene.c deleted file mode 100644 index 5d7a3dd1a5..0000000000 --- a/code/renderergl1/tr_scene.c +++ /dev/null @@ -1,411 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "tr_local.h" - -int r_firstSceneDrawSurf; - -int r_numdlights; -int r_firstSceneDlight; - -int r_numentities; -int r_firstSceneEntity; - -int r_numpolys; -int r_firstScenePoly; - -int r_numpolyverts; - - -/* -==================== -R_InitNextFrame - -==================== -*/ -void R_InitNextFrame( void ) { - backEndData->commands.used = 0; - - r_firstSceneDrawSurf = 0; - - r_numdlights = 0; - r_firstSceneDlight = 0; - - r_numentities = 0; - r_firstSceneEntity = 0; - - r_numpolys = 0; - r_firstScenePoly = 0; - - r_numpolyverts = 0; -} - - -/* -==================== -RE_ClearScene - -==================== -*/ -void RE_ClearScene( void ) { - r_firstSceneDlight = r_numdlights; - r_firstSceneEntity = r_numentities; - r_firstScenePoly = r_numpolys; -} - -/* -=========================================================================== - -DISCRETE POLYS - -=========================================================================== -*/ - -/* -===================== -R_AddPolygonSurfaces - -Adds all the scene's polys into this view's drawsurf list -===================== -*/ -void R_AddPolygonSurfaces( void ) { - int i; - shader_t *sh; - srfPoly_t *poly; - - tr.currentEntityNum = REFENTITYNUM_WORLD; - tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT; - - for ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) { - sh = R_GetShaderByHandle( poly->hShader ); - R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex, qfalse ); - } -} - -/* -===================== -RE_AddPolyToScene - -===================== -*/ -void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ) { - srfPoly_t *poly; - int i, j; - int fogIndex; - fog_t *fog; - vec3_t bounds[2]; - - if ( !tr.registered ) { - return; - } - - if ( !hShader ) { - ri.Printf( PRINT_WARNING, "WARNING: RE_AddPolyToScene: NULL poly shader\n"); - return; - } - - for ( j = 0; j < numPolys; j++ ) { - if ( r_numpolyverts + numVerts > max_polyverts || r_numpolys >= max_polys ) { - /* - NOTE TTimo this was initially a PRINT_WARNING - but it happens a lot with high fighting scenes and particles - since we don't plan on changing the const and making for room for those effects - simply cut this message to developer only - */ - ri.Printf( PRINT_DEVELOPER, "WARNING: RE_AddPolyToScene: r_max_polys or r_max_polyverts reached\n"); - return; - } - - poly = &backEndData->polys[r_numpolys]; - poly->surfaceType = SF_POLY; - poly->hShader = hShader; - poly->numVerts = numVerts; - poly->verts = &backEndData->polyVerts[r_numpolyverts]; - - Com_Memcpy( poly->verts, &verts[numVerts*j], numVerts * sizeof( *verts ) ); - - if ( glConfig.hardwareType == GLHW_RAGEPRO ) { - poly->verts->modulate[0] = 255; - poly->verts->modulate[1] = 255; - poly->verts->modulate[2] = 255; - poly->verts->modulate[3] = 255; - } - // done. - r_numpolys++; - r_numpolyverts += numVerts; - - // if no world is loaded - if ( tr.world == NULL ) { - fogIndex = 0; - } - // see if it is in a fog volume - else if ( tr.world->numfogs == 1 ) { - fogIndex = 0; - } else { - // find which fog volume the poly is in - VectorCopy( poly->verts[0].xyz, bounds[0] ); - VectorCopy( poly->verts[0].xyz, bounds[1] ); - for ( i = 1 ; i < poly->numVerts ; i++ ) { - AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] ); - } - for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) { - fog = &tr.world->fogs[fogIndex]; - if ( bounds[1][0] >= fog->bounds[0][0] - && bounds[1][1] >= fog->bounds[0][1] - && bounds[1][2] >= fog->bounds[0][2] - && bounds[0][0] <= fog->bounds[1][0] - && bounds[0][1] <= fog->bounds[1][1] - && bounds[0][2] <= fog->bounds[1][2] ) { - break; - } - } - if ( fogIndex == tr.world->numfogs ) { - fogIndex = 0; - } - } - poly->fogIndex = fogIndex; - } -} - - -//================================================================================= - - -/* -===================== -RE_AddRefEntityToScene - -===================== -*/ -void RE_AddRefEntityToScene( const refEntity_t *ent ) { - if ( !tr.registered ) { - return; - } - if ( r_numentities >= MAX_REFENTITIES ) { - ri.Printf(PRINT_DEVELOPER, "RE_AddRefEntityToScene: Dropping refEntity, reached MAX_REFENTITIES\n"); - return; - } - if ( Q_isnan(ent->origin[0]) || Q_isnan(ent->origin[1]) || Q_isnan(ent->origin[2]) ) { - static qboolean firstTime = qtrue; - if (firstTime) { - firstTime = qfalse; - ri.Printf( PRINT_WARNING, "RE_AddRefEntityToScene passed a refEntity which has an origin with a NaN component\n"); - } - return; - } - if ( (int)ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) { - ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType ); - } - - backEndData->entities[r_numentities].e = *ent; - backEndData->entities[r_numentities].lightingCalculated = qfalse; - - r_numentities++; -} - - -/* -===================== -RE_AddDynamicLightToScene - -===================== -*/ -void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, float g, float b, int additive ) { - dlight_t *dl; - - if ( !tr.registered ) { - return; - } - if ( r_numdlights >= MAX_DLIGHTS ) { - return; - } - if ( intensity <= 0 ) { - return; - } - // these cards don't have the correct blend mode - if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) { - return; - } - dl = &backEndData->dlights[r_numdlights++]; - VectorCopy (org, dl->origin); - dl->radius = intensity; - dl->color[0] = r; - dl->color[1] = g; - dl->color[2] = b; - dl->additive = additive; -} - -/* -===================== -RE_AddLightToScene - -===================== -*/ -void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) { - RE_AddDynamicLightToScene( org, intensity, r, g, b, qfalse ); -} - -/* -===================== -RE_AddAdditiveLightToScene - -===================== -*/ -void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) { - RE_AddDynamicLightToScene( org, intensity, r, g, b, qtrue ); -} - -/* -@@@@@@@@@@@@@@@@@@@@@ -RE_RenderScene - -Draw a 3D view into a part of the window, then return -to 2D drawing. - -Rendering a scene may require multiple views to be rendered -to handle mirrors, -@@@@@@@@@@@@@@@@@@@@@ -*/ -void RE_RenderScene( const refdef_t *fd ) { - viewParms_t parms; - int startTime; - - if ( !tr.registered ) { - return; - } - GLimp_LogComment( "====== RE_RenderScene =====\n" ); - - if ( r_norefresh->integer ) { - return; - } - - startTime = ri.Milliseconds(); - - if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) { - ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel"); - } - - Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) ); - - tr.refdef.x = fd->x; - tr.refdef.y = fd->y; - tr.refdef.width = fd->width; - tr.refdef.height = fd->height; - tr.refdef.fov_x = fd->fov_x; - tr.refdef.fov_y = fd->fov_y; - - VectorCopy( fd->vieworg, tr.refdef.vieworg ); - VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] ); - VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] ); - VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] ); - - tr.refdef.time = fd->time; - tr.refdef.rdflags = fd->rdflags; - - // copy the areamask data over and note if it has changed, which - // will force a reset of the visible leafs even if the view hasn't moved - tr.refdef.areamaskModified = qfalse; - if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) { - int areaDiff; - int i; - - // compare the area bits - areaDiff = 0; - for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) { - areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i]; - ((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i]; - } - - if ( areaDiff ) { - // a door just opened or something - tr.refdef.areamaskModified = qtrue; - } - } - - - // derived info - - tr.refdef.floatTime = tr.refdef.time * 0.001f; - - tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; - tr.refdef.drawSurfs = backEndData->drawSurfs; - - tr.refdef.num_entities = r_numentities - r_firstSceneEntity; - tr.refdef.entities = &backEndData->entities[r_firstSceneEntity]; - - tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight; - tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight]; - - tr.refdef.numPolys = r_numpolys - r_firstScenePoly; - tr.refdef.polys = &backEndData->polys[r_firstScenePoly]; - - // turn off dynamic lighting globally by clearing all the - // dlights if it needs to be disabled or if vertex lighting is enabled - if ( r_dynamiclight->integer == 0 || - r_vertexLight->integer == 1 || - glConfig.hardwareType == GLHW_PERMEDIA2 ) { - tr.refdef.num_dlights = 0; - } - - // a single frame may have multiple scenes draw inside it -- - // a 3D game view, 3D status bar renderings, 3D menus, etc. - // They need to be distinguished by the light flare code, because - // the visibility state for a given surface may be different in - // each scene / view. - tr.frameSceneNum++; - tr.sceneCount++; - - // setup view parms for the initial view - // - // set up viewport - // The refdef takes 0-at-the-top y coordinates, so - // convert to GL's 0-at-the-bottom space - // - Com_Memset( &parms, 0, sizeof( parms ) ); - parms.viewportX = tr.refdef.x; - parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height ); - parms.viewportWidth = tr.refdef.width; - parms.viewportHeight = tr.refdef.height; - parms.isPortal = qfalse; - - parms.fovX = tr.refdef.fov_x; - parms.fovY = tr.refdef.fov_y; - - parms.stereoFrame = tr.refdef.stereoFrame; - - VectorCopy( fd->vieworg, parms.or.origin ); - VectorCopy( fd->viewaxis[0], parms.or.axis[0] ); - VectorCopy( fd->viewaxis[1], parms.or.axis[1] ); - VectorCopy( fd->viewaxis[2], parms.or.axis[2] ); - - VectorCopy( fd->vieworg, parms.pvsOrigin ); - - R_RenderView( &parms ); - - // the next scene rendered in this frame will tack on after this one - r_firstSceneDrawSurf = tr.refdef.numDrawSurfs; - r_firstSceneEntity = r_numentities; - r_firstSceneDlight = r_numdlights; - r_firstScenePoly = r_numpolys; - - tr.frontEndMsec += ri.Milliseconds() - startTime; -} diff --git a/code/renderergl1/tr_shade.c b/code/renderergl1/tr_shade.c deleted file mode 100644 index 08648b2e8a..0000000000 --- a/code/renderergl1/tr_shade.c +++ /dev/null @@ -1,1522 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_shade.c - -#include "tr_local.h" -#if idppc_altivec && !defined(MACOS_X) -#include -#endif - -/* - - THIS ENTIRE FILE IS BACK END - - This file deals with applying shaders to surface data in the tess struct. -*/ - -/* -================ -R_ArrayElementDiscrete - -This is just for OpenGL conformance testing, it should never be the fastest -================ -*/ -static void APIENTRY R_ArrayElementDiscrete( GLint index ) { - qglColor4ubv( tess.svars.colors[ index ] ); - if ( glState.currenttmu ) { - qglMultiTexCoord2fARB( 0, tess.svars.texcoords[ 0 ][ index ][0], tess.svars.texcoords[ 0 ][ index ][1] ); - qglMultiTexCoord2fARB( 1, tess.svars.texcoords[ 1 ][ index ][0], tess.svars.texcoords[ 1 ][ index ][1] ); - } else { - qglTexCoord2fv( tess.svars.texcoords[ 0 ][ index ] ); - } - qglVertex3fv( tess.xyz[ index ] ); -} - -/* -=================== -R_DrawStripElements - -=================== -*/ -static int c_vertexes; // for seeing how long our average strips are -static int c_begins; -static void R_DrawStripElements( int numIndexes, const glIndex_t *indexes, void ( APIENTRY *element )(GLint) ) { - int i; - int last[3] = { -1, -1, -1 }; - qboolean even; - - c_begins++; - - if ( numIndexes <= 0 ) { - return; - } - - qglBegin( GL_TRIANGLE_STRIP ); - - // prime the strip - element( indexes[0] ); - element( indexes[1] ); - element( indexes[2] ); - c_vertexes += 3; - - last[0] = indexes[0]; - last[1] = indexes[1]; - last[2] = indexes[2]; - - even = qfalse; - - for ( i = 3; i < numIndexes; i += 3 ) - { - // odd numbered triangle in potential strip - if ( !even ) - { - // check previous triangle to see if we're continuing a strip - if ( ( indexes[i+0] == last[2] ) && ( indexes[i+1] == last[1] ) ) - { - element( indexes[i+2] ); - c_vertexes++; - assert( indexes[i+2] < tess.numVertexes ); - even = qtrue; - } - // otherwise we're done with this strip so finish it and start - // a new one - else - { - qglEnd(); - - qglBegin( GL_TRIANGLE_STRIP ); - c_begins++; - - element( indexes[i+0] ); - element( indexes[i+1] ); - element( indexes[i+2] ); - - c_vertexes += 3; - - even = qfalse; - } - } - else - { - // check previous triangle to see if we're continuing a strip - if ( ( last[2] == indexes[i+1] ) && ( last[0] == indexes[i+0] ) ) - { - element( indexes[i+2] ); - c_vertexes++; - - even = qfalse; - } - // otherwise we're done with this strip so finish it and start - // a new one - else - { - qglEnd(); - - qglBegin( GL_TRIANGLE_STRIP ); - c_begins++; - - element( indexes[i+0] ); - element( indexes[i+1] ); - element( indexes[i+2] ); - c_vertexes += 3; - - even = qfalse; - } - } - - // cache the last three vertices - last[0] = indexes[i+0]; - last[1] = indexes[i+1]; - last[2] = indexes[i+2]; - } - - qglEnd(); -} - - - -/* -================== -R_DrawElements - -Optionally performs our own glDrawElements that looks for strip conditions -instead of using the single glDrawElements call that may be inefficient -without compiled vertex arrays. -================== -*/ -static void R_DrawElements( int numIndexes, const glIndex_t *indexes ) { - int primitives; - - primitives = r_primitives->integer; - - // default is to use triangles if compiled vertex arrays are present - if ( primitives == 0 ) { - if ( qglLockArraysEXT ) { - primitives = 2; - } else { - primitives = 1; - } - } - - - if ( primitives == 2 ) { - qglDrawElements( GL_TRIANGLES, - numIndexes, - GL_INDEX_TYPE, - indexes ); - return; - } - - if ( primitives == 1 ) { - R_DrawStripElements( numIndexes, indexes, qglArrayElement ); - return; - } - - if ( primitives == 3 ) { - R_DrawStripElements( numIndexes, indexes, R_ArrayElementDiscrete ); - return; - } - - // anything else will cause no drawing -} - - -/* -============================================================= - -SURFACE SHADERS - -============================================================= -*/ - -shaderCommands_t tess; -static qboolean setArraysOnce; - -/* -================= -R_BindAnimatedImage - -================= -*/ -static void R_BindAnimatedImage( textureBundle_t *bundle ) { - int index; - - if ( bundle->isVideoMap ) { - ri.CIN_RunCinematic(bundle->videoMapHandle); - ri.CIN_UploadCinematic(bundle->videoMapHandle); - return; - } - - if ( bundle->numImageAnimations <= 1 ) { - GL_Bind( bundle->image[0] ); - return; - } - - // it is necessary to do this messy calc to make sure animations line up - // exactly with waveforms of the same frequency - index = ri.ftol(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE); - index >>= FUNCTABLE_SIZE2; - - if ( index < 0 ) { - index = 0; // may happen with shader time offsets - } - index %= bundle->numImageAnimations; - - GL_Bind( bundle->image[ index ] ); -} - -/* -================ -DrawTris - -Draws triangle outlines for debugging -================ -*/ -static void DrawTris (shaderCommands_t *input) { - GL_Bind( tr.whiteImage ); - qglColor3f (1,1,1); - - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ); - qglDepthRange( 0, 0 ); - - qglDisableClientState (GL_COLOR_ARRAY); - qglDisableClientState (GL_TEXTURE_COORD_ARRAY); - - qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD - - if (qglLockArraysEXT) { - qglLockArraysEXT(0, input->numVertexes); - GLimp_LogComment( "glLockArraysEXT\n" ); - } - - R_DrawElements( input->numIndexes, input->indexes ); - - if (qglUnlockArraysEXT) { - qglUnlockArraysEXT(); - GLimp_LogComment( "glUnlockArraysEXT\n" ); - } - qglDepthRange( 0, 1 ); -} - - -/* -================ -DrawNormals - -Draws vertex normals for debugging -================ -*/ -static void DrawNormals (shaderCommands_t *input) { - int i; - vec3_t temp; - - GL_Bind( tr.whiteImage ); - qglColor3f (1,1,1); - qglDepthRange( 0, 0 ); // never occluded - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ); - - qglBegin (GL_LINES); - for (i = 0 ; i < input->numVertexes ; i++) { - qglVertex3fv (input->xyz[i]); - VectorMA (input->xyz[i], 2, input->normal[i], temp); - qglVertex3fv (temp); - } - qglEnd (); - - qglDepthRange( 0, 1 ); -} - -/* -============== -RB_BeginSurface - -We must set some things up before beginning any tesselation, -because a surface may be forced to perform a RB_End due -to overflow. -============== -*/ -void RB_BeginSurface( shader_t *shader, int fogNum ) { - - shader_t *state = (shader->remappedShader) ? shader->remappedShader : shader; - - tess.numIndexes = 0; - tess.numVertexes = 0; - tess.shader = state; - tess.fogNum = fogNum; - tess.dlightBits = 0; // will be OR'd in by surface functions - tess.xstages = state->stages; - tess.numPasses = state->numUnfoggedPasses; - tess.currentStageIteratorFunc = state->optimalStageIteratorFunc; - - tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; - if (tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime) { - tess.shaderTime = tess.shader->clampTime; - } - - -} - -/* -=================== -DrawMultitextured - -output = t0 * t1 or t0 + t1 - -t0 = most upstream according to spec -t1 = most downstream according to spec -=================== -*/ -static void DrawMultitextured( shaderCommands_t *input, int stage ) { - shaderStage_t *pStage; - - pStage = tess.xstages[stage]; - - GL_State( pStage->stateBits ); - - // this is an ugly hack to work around a GeForce driver - // bug with multitexture and clip planes - if ( backEnd.viewParms.isPortal ) { - qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); - } - - // - // base - // - GL_SelectTexture( 0 ); - qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] ); - R_BindAnimatedImage( &pStage->bundle[0] ); - - // - // lightmap/secondary pass - // - GL_SelectTexture( 1 ); - qglEnable( GL_TEXTURE_2D ); - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - - if ( r_lightmap->integer ) { - GL_TexEnv( GL_REPLACE ); - } else { - GL_TexEnv( tess.shader->multitextureEnv ); - } - - qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[1] ); - - R_BindAnimatedImage( &pStage->bundle[1] ); - - R_DrawElements( input->numIndexes, input->indexes ); - - // - // disable texturing on TEXTURE1, then select TEXTURE0 - // - //qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); - qglDisable( GL_TEXTURE_2D ); - - GL_SelectTexture( 0 ); -} - - - -/* -=================== -ProjectDlightTexture - -Perform dynamic lighting with another rendering pass -=================== -*/ -#if idppc_altivec -static void ProjectDlightTexture_altivec( void ) { - int i, l; - vec_t origin0, origin1, origin2; - float texCoords0, texCoords1; - vector float floatColorVec0, floatColorVec1; - vector float modulateVec, colorVec, zero; - vector short colorShort; - vector signed int colorInt; - vector unsigned char floatColorVecPerm, modulatePerm, colorChar; - vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff); - float *texCoords; - byte *colors; - byte clipBits[SHADER_MAX_VERTEXES]; - float texCoordsArray[SHADER_MAX_VERTEXES][2]; - byte colorArray[SHADER_MAX_VERTEXES][4]; - unsigned hitIndexes[SHADER_MAX_INDEXES]; - int numIndexes; - float scale; - float radius; - vec3_t floatColor; - float modulate = 0.0f; - - if ( !backEnd.refdef.num_dlights ) { - return; - } - - // There has to be a better way to do this so that floatColor - // and/or modulate are already 16-byte aligned. - floatColorVecPerm = vec_lvsl(0,(float *)floatColor); - modulatePerm = vec_lvsl(0,(float *)&modulate); - modulatePerm = (vector unsigned char)vec_splat((vector unsigned int)modulatePerm,0); - zero = (vector float)vec_splat_s8(0); - - for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { - dlight_t *dl; - - if ( !( tess.dlightBits & ( 1 << l ) ) ) { - continue; // this surface definately doesn't have any of this light - } - texCoords = texCoordsArray[0]; - colors = colorArray[0]; - - dl = &backEnd.refdef.dlights[l]; - origin0 = dl->transformed[0]; - origin1 = dl->transformed[1]; - origin2 = dl->transformed[2]; - radius = dl->radius; - scale = 1.0f / radius; - - if(r_greyscale->integer) - { - float luminance; - - luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; - floatColor[0] = floatColor[1] = floatColor[2] = luminance; - } - else if(r_greyscale->value) - { - float luminance; - - luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; - floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value); - floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value); - floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value); - } - else - { - floatColor[0] = dl->color[0] * 255.0f; - floatColor[1] = dl->color[1] * 255.0f; - floatColor[2] = dl->color[2] * 255.0f; - } - floatColorVec0 = vec_ld(0, floatColor); - floatColorVec1 = vec_ld(11, floatColor); - floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm); - for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) { - int clip = 0; - vec_t dist0, dist1, dist2; - - dist0 = origin0 - tess.xyz[i][0]; - dist1 = origin1 - tess.xyz[i][1]; - dist2 = origin2 - tess.xyz[i][2]; - - backEnd.pc.c_dlightVertexes++; - - texCoords0 = 0.5f + dist0 * scale; - texCoords1 = 0.5f + dist1 * scale; - - if( !r_dlightBacks->integer && - // dist . tess.normal[i] - ( dist0 * tess.normal[i][0] + - dist1 * tess.normal[i][1] + - dist2 * tess.normal[i][2] ) < 0.0f ) { - clip = 63; - } else { - if ( texCoords0 < 0.0f ) { - clip |= 1; - } else if ( texCoords0 > 1.0f ) { - clip |= 2; - } - if ( texCoords1 < 0.0f ) { - clip |= 4; - } else if ( texCoords1 > 1.0f ) { - clip |= 8; - } - texCoords[0] = texCoords0; - texCoords[1] = texCoords1; - - // modulate the strength based on the height and color - if ( dist2 > radius ) { - clip |= 16; - modulate = 0.0f; - } else if ( dist2 < -radius ) { - clip |= 32; - modulate = 0.0f; - } else { - dist2 = Q_fabs(dist2); - if ( dist2 < radius * 0.5f ) { - modulate = 1.0f; - } else { - modulate = 2.0f * (radius - dist2) * scale; - } - } - } - clipBits[i] = clip; - - modulateVec = vec_ld(0,(float *)&modulate); - modulateVec = vec_perm(modulateVec,modulateVec,modulatePerm); - colorVec = vec_madd(floatColorVec0,modulateVec,zero); - colorInt = vec_cts(colorVec,0); // RGBx - colorShort = vec_pack(colorInt,colorInt); // RGBxRGBx - colorChar = vec_packsu(colorShort,colorShort); // RGBxRGBxRGBxRGBx - colorChar = vec_sel(colorChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255 - vec_ste((vector unsigned int)colorChar,0,(unsigned int *)colors); // store color - } - - // build a list of triangles that need light - numIndexes = 0; - for ( i = 0 ; i < tess.numIndexes ; i += 3 ) { - int a, b, c; - - a = tess.indexes[i]; - b = tess.indexes[i+1]; - c = tess.indexes[i+2]; - if ( clipBits[a] & clipBits[b] & clipBits[c] ) { - continue; // not lighted - } - hitIndexes[numIndexes] = a; - hitIndexes[numIndexes+1] = b; - hitIndexes[numIndexes+2] = c; - numIndexes += 3; - } - - if ( !numIndexes ) { - continue; - } - - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); - - qglEnableClientState( GL_COLOR_ARRAY ); - qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); - - GL_Bind( tr.dlightImage ); - // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light - // where they aren't rendered - if ( dl->additive ) { - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); - } - else { - GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); - } - R_DrawElements( numIndexes, hitIndexes ); - backEnd.pc.c_totalIndexes += numIndexes; - backEnd.pc.c_dlightIndexes += numIndexes; - } -} -#endif - - -static void ProjectDlightTexture_scalar( void ) { - int i, l; - vec3_t origin; - float *texCoords; - byte *colors; - byte clipBits[SHADER_MAX_VERTEXES]; - float texCoordsArray[SHADER_MAX_VERTEXES][2]; - byte colorArray[SHADER_MAX_VERTEXES][4]; - unsigned hitIndexes[SHADER_MAX_INDEXES]; - int numIndexes; - float scale; - float radius; - vec3_t floatColor; - float modulate = 0.0f; - - if ( !backEnd.refdef.num_dlights ) { - return; - } - - for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { - dlight_t *dl; - - if ( !( tess.dlightBits & ( 1 << l ) ) ) { - continue; // this surface definately doesn't have any of this light - } - texCoords = texCoordsArray[0]; - colors = colorArray[0]; - - dl = &backEnd.refdef.dlights[l]; - VectorCopy( dl->transformed, origin ); - radius = dl->radius; - scale = 1.0f / radius; - - if(r_greyscale->integer) - { - float luminance; - - luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; - floatColor[0] = floatColor[1] = floatColor[2] = luminance; - } - else if(r_greyscale->value) - { - float luminance; - - luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; - floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value); - floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value); - floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value); - } - else - { - floatColor[0] = dl->color[0] * 255.0f; - floatColor[1] = dl->color[1] * 255.0f; - floatColor[2] = dl->color[2] * 255.0f; - } - - for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) { - int clip = 0; - vec3_t dist; - - VectorSubtract( origin, tess.xyz[i], dist ); - - backEnd.pc.c_dlightVertexes++; - - texCoords[0] = 0.5f + dist[0] * scale; - texCoords[1] = 0.5f + dist[1] * scale; - - if( !r_dlightBacks->integer && - // dist . tess.normal[i] - ( dist[0] * tess.normal[i][0] + - dist[1] * tess.normal[i][1] + - dist[2] * tess.normal[i][2] ) < 0.0f ) { - clip = 63; - } else { - if ( texCoords[0] < 0.0f ) { - clip |= 1; - } else if ( texCoords[0] > 1.0f ) { - clip |= 2; - } - if ( texCoords[1] < 0.0f ) { - clip |= 4; - } else if ( texCoords[1] > 1.0f ) { - clip |= 8; - } - texCoords[0] = texCoords[0]; - texCoords[1] = texCoords[1]; - - // modulate the strength based on the height and color - if ( dist[2] > radius ) { - clip |= 16; - modulate = 0.0f; - } else if ( dist[2] < -radius ) { - clip |= 32; - modulate = 0.0f; - } else { - dist[2] = Q_fabs(dist[2]); - if ( dist[2] < radius * 0.5f ) { - modulate = 1.0f; - } else { - modulate = 2.0f * (radius - dist[2]) * scale; - } - } - } - clipBits[i] = clip; - colors[0] = ri.ftol(floatColor[0] * modulate); - colors[1] = ri.ftol(floatColor[1] * modulate); - colors[2] = ri.ftol(floatColor[2] * modulate); - colors[3] = 255; - } - - // build a list of triangles that need light - numIndexes = 0; - for ( i = 0 ; i < tess.numIndexes ; i += 3 ) { - int a, b, c; - - a = tess.indexes[i]; - b = tess.indexes[i+1]; - c = tess.indexes[i+2]; - if ( clipBits[a] & clipBits[b] & clipBits[c] ) { - continue; // not lighted - } - hitIndexes[numIndexes] = a; - hitIndexes[numIndexes+1] = b; - hitIndexes[numIndexes+2] = c; - numIndexes += 3; - } - - if ( !numIndexes ) { - continue; - } - - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); - - qglEnableClientState( GL_COLOR_ARRAY ); - qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); - - GL_Bind( tr.dlightImage ); - // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light - // where they aren't rendered - if ( dl->additive ) { - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); - } - else { - GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); - } - R_DrawElements( numIndexes, hitIndexes ); - backEnd.pc.c_totalIndexes += numIndexes; - backEnd.pc.c_dlightIndexes += numIndexes; - } -} - -static void ProjectDlightTexture( void ) { -#if idppc_altivec - if (com_altivec->integer) { - // must be in a seperate function or G3 systems will crash. - ProjectDlightTexture_altivec(); - return; - } -#endif - ProjectDlightTexture_scalar(); -} - - -/* -=================== -RB_FogPass - -Blends a fog texture on top of everything else -=================== -*/ -static void RB_FogPass( void ) { - fog_t *fog; - int i; - - qglEnableClientState( GL_COLOR_ARRAY ); - qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors ); - - qglEnableClientState( GL_TEXTURE_COORD_ARRAY); - qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] ); - - fog = tr.world->fogs + tess.fogNum; - - for ( i = 0; i < tess.numVertexes; i++ ) { - * ( int * )&tess.svars.colors[i] = fog->colorInt; - } - - RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[0] ); - - GL_Bind( tr.fogImage ); - - if ( tess.shader->fogPass == FP_EQUAL ) { - GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); - } else { - GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); - } - - R_DrawElements( tess.numIndexes, tess.indexes ); -} - -/* -=============== -ComputeColors -=============== -*/ -static void ComputeColors( shaderStage_t *pStage ) -{ - int i; - - // - // rgbGen - // - switch ( pStage->rgbGen ) - { - case CGEN_IDENTITY: - Com_Memset( tess.svars.colors, 0xff, tess.numVertexes * 4 ); - break; - default: - case CGEN_IDENTITY_LIGHTING: - Com_Memset( tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 ); - break; - case CGEN_LIGHTING_DIFFUSE: - RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors ); - break; - case CGEN_EXACT_VERTEX: - Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) ); - break; - case CGEN_CONST: - for ( i = 0; i < tess.numVertexes; i++ ) { - *(int *)tess.svars.colors[i] = *(int *)pStage->constantColor; - } - break; - case CGEN_VERTEX: - if ( tr.identityLight == 1 ) - { - Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) ); - } - else - { - for ( i = 0; i < tess.numVertexes; i++ ) - { - tess.svars.colors[i][0] = tess.vertexColors[i][0] * tr.identityLight; - tess.svars.colors[i][1] = tess.vertexColors[i][1] * tr.identityLight; - tess.svars.colors[i][2] = tess.vertexColors[i][2] * tr.identityLight; - tess.svars.colors[i][3] = tess.vertexColors[i][3]; - } - } - break; - case CGEN_ONE_MINUS_VERTEX: - if ( tr.identityLight == 1 ) - { - for ( i = 0; i < tess.numVertexes; i++ ) - { - tess.svars.colors[i][0] = 255 - tess.vertexColors[i][0]; - tess.svars.colors[i][1] = 255 - tess.vertexColors[i][1]; - tess.svars.colors[i][2] = 255 - tess.vertexColors[i][2]; - } - } - else - { - for ( i = 0; i < tess.numVertexes; i++ ) - { - tess.svars.colors[i][0] = ( 255 - tess.vertexColors[i][0] ) * tr.identityLight; - tess.svars.colors[i][1] = ( 255 - tess.vertexColors[i][1] ) * tr.identityLight; - tess.svars.colors[i][2] = ( 255 - tess.vertexColors[i][2] ) * tr.identityLight; - } - } - break; - case CGEN_FOG: - { - fog_t *fog; - - fog = tr.world->fogs + tess.fogNum; - - for ( i = 0; i < tess.numVertexes; i++ ) { - * ( int * )&tess.svars.colors[i] = fog->colorInt; - } - } - break; - case CGEN_WAVEFORM: - RB_CalcWaveColor( &pStage->rgbWave, ( unsigned char * ) tess.svars.colors ); - break; - case CGEN_ENTITY: - RB_CalcColorFromEntity( ( unsigned char * ) tess.svars.colors ); - break; - case CGEN_ONE_MINUS_ENTITY: - RB_CalcColorFromOneMinusEntity( ( unsigned char * ) tess.svars.colors ); - break; - } - - // - // alphaGen - // - switch ( pStage->alphaGen ) - { - case AGEN_SKIP: - break; - case AGEN_IDENTITY: - if ( pStage->rgbGen != CGEN_IDENTITY ) { - if ( ( pStage->rgbGen == CGEN_VERTEX && tr.identityLight != 1 ) || - pStage->rgbGen != CGEN_VERTEX ) { - for ( i = 0; i < tess.numVertexes; i++ ) { - tess.svars.colors[i][3] = 0xff; - } - } - } - break; - case AGEN_CONST: - if ( pStage->rgbGen != CGEN_CONST ) { - for ( i = 0; i < tess.numVertexes; i++ ) { - tess.svars.colors[i][3] = pStage->constantColor[3]; - } - } - break; - case AGEN_WAVEFORM: - RB_CalcWaveAlpha( &pStage->alphaWave, ( unsigned char * ) tess.svars.colors ); - break; - case AGEN_LIGHTING_SPECULAR: - RB_CalcSpecularAlpha( ( unsigned char * ) tess.svars.colors ); - break; - case AGEN_ENTITY: - RB_CalcAlphaFromEntity( ( unsigned char * ) tess.svars.colors ); - break; - case AGEN_ONE_MINUS_ENTITY: - RB_CalcAlphaFromOneMinusEntity( ( unsigned char * ) tess.svars.colors ); - break; - case AGEN_VERTEX: - if ( pStage->rgbGen != CGEN_VERTEX ) { - for ( i = 0; i < tess.numVertexes; i++ ) { - tess.svars.colors[i][3] = tess.vertexColors[i][3]; - } - } - break; - case AGEN_ONE_MINUS_VERTEX: - for ( i = 0; i < tess.numVertexes; i++ ) - { - tess.svars.colors[i][3] = 255 - tess.vertexColors[i][3]; - } - break; - case AGEN_PORTAL: - { - unsigned char alpha; - - for ( i = 0; i < tess.numVertexes; i++ ) - { - float len; - vec3_t v; - - VectorSubtract( tess.xyz[i], backEnd.viewParms.or.origin, v ); - len = VectorLength( v ); - - len /= tess.shader->portalRange; - - if ( len < 0 ) - { - alpha = 0; - } - else if ( len > 1 ) - { - alpha = 0xff; - } - else - { - alpha = len * 0xff; - } - - tess.svars.colors[i][3] = alpha; - } - } - break; - } - - // - // fog adjustment for colors to fade out as fog increases - // - if ( tess.fogNum ) - { - switch ( pStage->adjustColorsForFog ) - { - case ACFF_MODULATE_RGB: - RB_CalcModulateColorsByFog( ( unsigned char * ) tess.svars.colors ); - break; - case ACFF_MODULATE_ALPHA: - RB_CalcModulateAlphasByFog( ( unsigned char * ) tess.svars.colors ); - break; - case ACFF_MODULATE_RGBA: - RB_CalcModulateRGBAsByFog( ( unsigned char * ) tess.svars.colors ); - break; - case ACFF_NONE: - break; - } - } - - // if in greyscale rendering mode turn all color values into greyscale. - if(r_greyscale->integer) - { - int scale; - for(i = 0; i < tess.numVertexes; i++) - { - scale = LUMA(tess.svars.colors[i][0], tess.svars.colors[i][1], tess.svars.colors[i][2]); - tess.svars.colors[i][0] = tess.svars.colors[i][1] = tess.svars.colors[i][2] = scale; - } - } - else if(r_greyscale->value) - { - float scale; - - for(i = 0; i < tess.numVertexes; i++) - { - scale = LUMA(tess.svars.colors[i][0], tess.svars.colors[i][1], tess.svars.colors[i][2]); - tess.svars.colors[i][0] = LERP(tess.svars.colors[i][0], scale, r_greyscale->value); - tess.svars.colors[i][1] = LERP(tess.svars.colors[i][1], scale, r_greyscale->value); - tess.svars.colors[i][2] = LERP(tess.svars.colors[i][2], scale, r_greyscale->value); - } - } -} - -/* -=============== -ComputeTexCoords -=============== -*/ -static void ComputeTexCoords( shaderStage_t *pStage ) { - int i; - int b; - - for ( b = 0; b < NUM_TEXTURE_BUNDLES; b++ ) { - int tm; - - // - // generate the texture coordinates - // - switch ( pStage->bundle[b].tcGen ) - { - case TCGEN_IDENTITY: - Com_Memset( tess.svars.texcoords[b], 0, sizeof( float ) * 2 * tess.numVertexes ); - break; - case TCGEN_TEXTURE: - for ( i = 0 ; i < tess.numVertexes ; i++ ) { - tess.svars.texcoords[b][i][0] = tess.texCoords[i][0][0]; - tess.svars.texcoords[b][i][1] = tess.texCoords[i][0][1]; - } - break; - case TCGEN_LIGHTMAP: - for ( i = 0 ; i < tess.numVertexes ; i++ ) { - tess.svars.texcoords[b][i][0] = tess.texCoords[i][1][0]; - tess.svars.texcoords[b][i][1] = tess.texCoords[i][1][1]; - } - break; - case TCGEN_VECTOR: - for ( i = 0 ; i < tess.numVertexes ; i++ ) { - tess.svars.texcoords[b][i][0] = DotProduct( tess.xyz[i], pStage->bundle[b].tcGenVectors[0] ); - tess.svars.texcoords[b][i][1] = DotProduct( tess.xyz[i], pStage->bundle[b].tcGenVectors[1] ); - } - break; - case TCGEN_FOG: - RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[b] ); - break; - case TCGEN_ENVIRONMENT_MAPPED: - RB_CalcEnvironmentTexCoords( ( float * ) tess.svars.texcoords[b] ); - break; - case TCGEN_BAD: - return; - } - - // - // alter texture coordinates - // - for ( tm = 0; tm < pStage->bundle[b].numTexMods ; tm++ ) { - switch ( pStage->bundle[b].texMods[tm].type ) - { - case TMOD_NONE: - tm = TR_MAX_TEXMODS; // break out of for loop - break; - - case TMOD_TURBULENT: - RB_CalcTurbulentTexCoords( &pStage->bundle[b].texMods[tm].wave, - ( float * ) tess.svars.texcoords[b] ); - break; - - case TMOD_ENTITY_TRANSLATE: - RB_CalcScrollTexCoords( backEnd.currentEntity->e.shaderTexCoord, - ( float * ) tess.svars.texcoords[b] ); - break; - - case TMOD_SCROLL: - RB_CalcScrollTexCoords( pStage->bundle[b].texMods[tm].scroll, - ( float * ) tess.svars.texcoords[b] ); - break; - - case TMOD_SCALE: - RB_CalcScaleTexCoords( pStage->bundle[b].texMods[tm].scale, - ( float * ) tess.svars.texcoords[b] ); - break; - - case TMOD_STRETCH: - RB_CalcStretchTexCoords( &pStage->bundle[b].texMods[tm].wave, - ( float * ) tess.svars.texcoords[b] ); - break; - - case TMOD_TRANSFORM: - RB_CalcTransformTexCoords( &pStage->bundle[b].texMods[tm], - ( float * ) tess.svars.texcoords[b] ); - break; - - case TMOD_ROTATE: - RB_CalcRotateTexCoords( pStage->bundle[b].texMods[tm].rotateSpeed, - ( float * ) tess.svars.texcoords[b] ); - break; - - default: - ri.Error( ERR_DROP, "ERROR: unknown texmod '%d' in shader '%s'", pStage->bundle[b].texMods[tm].type, tess.shader->name ); - break; - } - } - } -} - -/* -** RB_IterateStagesGeneric -*/ -static void RB_IterateStagesGeneric( shaderCommands_t *input ) -{ - int stage; - - for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) - { - shaderStage_t *pStage = tess.xstages[stage]; - - if ( !pStage ) - { - break; - } - - ComputeColors( pStage ); - ComputeTexCoords( pStage ); - - if ( !setArraysOnce ) - { - qglEnableClientState( GL_COLOR_ARRAY ); - qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, input->svars.colors ); - } - - // - // do multitexture - // - if ( pStage->bundle[1].image[0] != 0 ) - { - DrawMultitextured( input, stage ); - } - else - { - if ( !setArraysOnce ) - { - qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] ); - } - - // - // set state - // - R_BindAnimatedImage( &pStage->bundle[0] ); - - GL_State( pStage->stateBits ); - - // - // draw - // - R_DrawElements( input->numIndexes, input->indexes ); - } - // allow skipping out to show just lightmaps during development - if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap ) ) - { - break; - } - } -} - - -/* -** RB_StageIteratorGeneric -*/ -void RB_StageIteratorGeneric( void ) -{ - shaderCommands_t *input; - shader_t *shader; - - input = &tess; - shader = input->shader; - - RB_DeformTessGeometry(); - - // - // log this call - // - if ( r_logFile->integer ) - { - // don't just call LogComment, or we will get - // a call to va() every frame! - GLimp_LogComment( va("--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name) ); - } - - // - // set face culling appropriately - // - GL_Cull( shader->cullType ); - - // set polygon offset if necessary - if ( shader->polygonOffset ) - { - qglEnable( GL_POLYGON_OFFSET_FILL ); - qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); - } - - // - // if there is only a single pass then we can enable color - // and texture arrays before we compile, otherwise we need - // to avoid compiling those arrays since they will change - // during multipass rendering - // - if ( tess.numPasses > 1 || shader->multitextureEnv ) - { - setArraysOnce = qfalse; - qglDisableClientState (GL_COLOR_ARRAY); - qglDisableClientState (GL_TEXTURE_COORD_ARRAY); - } - else - { - setArraysOnce = qtrue; - - qglEnableClientState( GL_COLOR_ARRAY); - qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors ); - - qglEnableClientState( GL_TEXTURE_COORD_ARRAY); - qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] ); - } - - // - // lock XYZ - // - qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD - if (qglLockArraysEXT) - { - qglLockArraysEXT(0, input->numVertexes); - GLimp_LogComment( "glLockArraysEXT\n" ); - } - - // - // enable color and texcoord arrays after the lock if necessary - // - if ( !setArraysOnce ) - { - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - qglEnableClientState( GL_COLOR_ARRAY ); - } - - // - // call shader function - // - RB_IterateStagesGeneric( input ); - - // - // now do any dynamic lighting needed - // - if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE - && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { - ProjectDlightTexture(); - } - - // - // now do fog - // - if ( tess.fogNum && tess.shader->fogPass ) { - RB_FogPass(); - } - - // - // unlock arrays - // - if (qglUnlockArraysEXT) - { - qglUnlockArraysEXT(); - GLimp_LogComment( "glUnlockArraysEXT\n" ); - } - - // - // reset polygon offset - // - if ( shader->polygonOffset ) - { - qglDisable( GL_POLYGON_OFFSET_FILL ); - } -} - - -/* -** RB_StageIteratorVertexLitTexture -*/ -void RB_StageIteratorVertexLitTexture( void ) -{ - shaderCommands_t *input; - shader_t *shader; - - input = &tess; - shader = input->shader; - - // - // compute colors - // - RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors ); - - // - // log this call - // - if ( r_logFile->integer ) - { - // don't just call LogComment, or we will get - // a call to va() every frame! - GLimp_LogComment( va("--- RB_StageIteratorVertexLitTexturedUnfogged( %s ) ---\n", tess.shader->name) ); - } - - // - // set face culling appropriately - // - GL_Cull( shader->cullType ); - - // - // set arrays and lock - // - qglEnableClientState( GL_COLOR_ARRAY); - qglEnableClientState( GL_TEXTURE_COORD_ARRAY); - - qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors ); - qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] ); - qglVertexPointer (3, GL_FLOAT, 16, input->xyz); - - if ( qglLockArraysEXT ) - { - qglLockArraysEXT(0, input->numVertexes); - GLimp_LogComment( "glLockArraysEXT\n" ); - } - - // - // call special shade routine - // - R_BindAnimatedImage( &tess.xstages[0]->bundle[0] ); - GL_State( tess.xstages[0]->stateBits ); - R_DrawElements( input->numIndexes, input->indexes ); - - // - // now do any dynamic lighting needed - // - if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) { - ProjectDlightTexture(); - } - - // - // now do fog - // - if ( tess.fogNum && tess.shader->fogPass ) { - RB_FogPass(); - } - - // - // unlock arrays - // - if (qglUnlockArraysEXT) - { - qglUnlockArraysEXT(); - GLimp_LogComment( "glUnlockArraysEXT\n" ); - } -} - -//define REPLACE_MODE - -void RB_StageIteratorLightmappedMultitexture( void ) { - shaderCommands_t *input; - shader_t *shader; - - input = &tess; - shader = input->shader; - - // - // log this call - // - if ( r_logFile->integer ) { - // don't just call LogComment, or we will get - // a call to va() every frame! - GLimp_LogComment( va("--- RB_StageIteratorLightmappedMultitexture( %s ) ---\n", tess.shader->name) ); - } - - // - // set face culling appropriately - // - GL_Cull( shader->cullType ); - - // - // set color, pointers, and lock - // - GL_State( GLS_DEFAULT ); - qglVertexPointer( 3, GL_FLOAT, 16, input->xyz ); - -#ifdef REPLACE_MODE - qglDisableClientState( GL_COLOR_ARRAY ); - qglColor3f( 1, 1, 1 ); - qglShadeModel( GL_FLAT ); -#else - qglEnableClientState( GL_COLOR_ARRAY ); - qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.constantColor255 ); -#endif - - // - // select base stage - // - GL_SelectTexture( 0 ); - - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - R_BindAnimatedImage( &tess.xstages[0]->bundle[0] ); - qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] ); - - // - // configure second stage - // - GL_SelectTexture( 1 ); - qglEnable( GL_TEXTURE_2D ); - if ( r_lightmap->integer ) { - GL_TexEnv( GL_REPLACE ); - } else { - GL_TexEnv( GL_MODULATE ); - } - R_BindAnimatedImage( &tess.xstages[0]->bundle[1] ); - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][1] ); - - // - // lock arrays - // - if ( qglLockArraysEXT ) { - qglLockArraysEXT(0, input->numVertexes); - GLimp_LogComment( "glLockArraysEXT\n" ); - } - - R_DrawElements( input->numIndexes, input->indexes ); - - // - // disable texturing on TEXTURE1, then select TEXTURE0 - // - qglDisable( GL_TEXTURE_2D ); - qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); - - GL_SelectTexture( 0 ); -#ifdef REPLACE_MODE - GL_TexEnv( GL_MODULATE ); - qglShadeModel( GL_SMOOTH ); -#endif - - // - // now do any dynamic lighting needed - // - if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) { - ProjectDlightTexture(); - } - - // - // now do fog - // - if ( tess.fogNum && tess.shader->fogPass ) { - RB_FogPass(); - } - - // - // unlock arrays - // - if ( qglUnlockArraysEXT ) { - qglUnlockArraysEXT(); - GLimp_LogComment( "glUnlockArraysEXT\n" ); - } -} - -/* -** RB_EndSurface -*/ -void RB_EndSurface( void ) { - shaderCommands_t *input; - - input = &tess; - - if (input->numIndexes == 0) { - return; - } - - if (input->indexes[SHADER_MAX_INDEXES-1] != 0) { - ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_INDEXES hit"); - } - if (input->xyz[SHADER_MAX_VERTEXES-1][0] != 0) { - ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_VERTEXES hit"); - } - - if ( tess.shader == tr.shadowShader ) { - RB_ShadowTessEnd(); - return; - } - - // for debugging of sort order issues, stop rendering after a given sort value - if ( r_debugSort->integer && r_debugSort->integer < tess.shader->sort ) { - return; - } - - // - // update performance counters - // - backEnd.pc.c_shaders++; - backEnd.pc.c_vertexes += tess.numVertexes; - backEnd.pc.c_indexes += tess.numIndexes; - backEnd.pc.c_totalIndexes += tess.numIndexes * tess.numPasses; - - // - // call off to shader specific tess end function - // - tess.currentStageIteratorFunc(); - - // - // draw debugging stuff - // - if ( r_showtris->integer ) { - DrawTris (input); - } - if ( r_shownormals->integer ) { - DrawNormals (input); - } - // clear shader so we can tell we don't have any unclosed surfaces - tess.numIndexes = 0; - - GLimp_LogComment( "----------\n" ); -} - diff --git a/code/renderergl1/tr_shade_calc.c b/code/renderergl1/tr_shade_calc.c deleted file mode 100644 index e8f43e4f1f..0000000000 --- a/code/renderergl1/tr_shade_calc.c +++ /dev/null @@ -1,1216 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_shade_calc.c - -#include "tr_local.h" -#if idppc_altivec && !defined(MACOS_X) -#include -#endif - - -#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ ri.ftol( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude)) - -static float *TableForFunc( genFunc_t func ) -{ - switch ( func ) - { - case GF_SIN: - return tr.sinTable; - case GF_TRIANGLE: - return tr.triangleTable; - case GF_SQUARE: - return tr.squareTable; - case GF_SAWTOOTH: - return tr.sawToothTable; - case GF_INVERSE_SAWTOOTH: - return tr.inverseSawToothTable; - case GF_NONE: - default: - break; - } - - ri.Error( ERR_DROP, "TableForFunc called with invalid function '%d' in shader '%s'", func, tess.shader->name ); - return NULL; -} - -/* -** EvalWaveForm -** -** Evaluates a given waveForm_t, referencing backEnd.refdef.time directly -*/ -static float EvalWaveForm( const waveForm_t *wf ) -{ - float *table; - - table = TableForFunc( wf->func ); - - return WAVEVALUE( table, wf->base, wf->amplitude, wf->phase, wf->frequency ); -} - -static float EvalWaveFormClamped( const waveForm_t *wf ) -{ - float glow = EvalWaveForm( wf ); - - if ( glow < 0 ) - { - return 0; - } - - if ( glow > 1 ) - { - return 1; - } - - return glow; -} - -/* -** RB_CalcStretchTexCoords -*/ -void RB_CalcStretchTexCoords( const waveForm_t *wf, float *st ) -{ - float p; - texModInfo_t tmi; - - p = 1.0f / EvalWaveForm( wf ); - - tmi.matrix[0][0] = p; - tmi.matrix[1][0] = 0; - tmi.translate[0] = 0.5f - 0.5f * p; - - tmi.matrix[0][1] = 0; - tmi.matrix[1][1] = p; - tmi.translate[1] = 0.5f - 0.5f * p; - - RB_CalcTransformTexCoords( &tmi, st ); -} - -/* -==================================================================== - -DEFORMATIONS - -==================================================================== -*/ - -/* -======================== -RB_CalcDeformVertexes - -======================== -*/ -void RB_CalcDeformVertexes( deformStage_t *ds ) -{ - int i; - vec3_t offset; - float scale; - float *xyz = ( float * ) tess.xyz; - float *normal = ( float * ) tess.normal; - float *table; - - if ( ds->deformationWave.frequency == 0 ) - { - scale = EvalWaveForm( &ds->deformationWave ); - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) - { - VectorScale( normal, scale, offset ); - - xyz[0] += offset[0]; - xyz[1] += offset[1]; - xyz[2] += offset[2]; - } - } - else - { - table = TableForFunc( ds->deformationWave.func ); - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) - { - float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread; - - scale = WAVEVALUE( table, ds->deformationWave.base, - ds->deformationWave.amplitude, - ds->deformationWave.phase + off, - ds->deformationWave.frequency ); - - VectorScale( normal, scale, offset ); - - xyz[0] += offset[0]; - xyz[1] += offset[1]; - xyz[2] += offset[2]; - } - } -} - -/* -========================= -RB_CalcDeformNormals - -Wiggle the normals for wavy environment mapping -========================= -*/ -void RB_CalcDeformNormals( deformStage_t *ds ) { - int i; - float scale; - float *xyz = ( float * ) tess.xyz; - float *normal = ( float * ) tess.normal; - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) { - scale = 0.98f; - scale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, - tess.shaderTime * ds->deformationWave.frequency ); - normal[ 0 ] += ds->deformationWave.amplitude * scale; - - scale = 0.98f; - scale = R_NoiseGet4f( 100 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, - tess.shaderTime * ds->deformationWave.frequency ); - normal[ 1 ] += ds->deformationWave.amplitude * scale; - - scale = 0.98f; - scale = R_NoiseGet4f( 200 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, - tess.shaderTime * ds->deformationWave.frequency ); - normal[ 2 ] += ds->deformationWave.amplitude * scale; - - VectorNormalizeFast( normal ); - } -} - -/* -======================== -RB_CalcBulgeVertexes - -======================== -*/ -void RB_CalcBulgeVertexes( deformStage_t *ds ) { - int i; - const float *st = ( const float * ) tess.texCoords[0]; - float *xyz = ( float * ) tess.xyz; - float *normal = ( float * ) tess.normal; - float now; - - now = backEnd.refdef.time * ds->bulgeSpeed * 0.001f; - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal += 4 ) { - int off; - float scale; - - off = (float)( FUNCTABLE_SIZE / (M_PI*2) ) * ( st[0] * ds->bulgeWidth + now ); - - scale = tr.sinTable[ off & FUNCTABLE_MASK ] * ds->bulgeHeight; - - xyz[0] += normal[0] * scale; - xyz[1] += normal[1] * scale; - xyz[2] += normal[2] * scale; - } -} - - -/* -====================== -RB_CalcMoveVertexes - -A deformation that can move an entire surface along a wave path -====================== -*/ -void RB_CalcMoveVertexes( deformStage_t *ds ) { - int i; - float *xyz; - float *table; - float scale; - vec3_t offset; - - table = TableForFunc( ds->deformationWave.func ); - - scale = WAVEVALUE( table, ds->deformationWave.base, - ds->deformationWave.amplitude, - ds->deformationWave.phase, - ds->deformationWave.frequency ); - - VectorScale( ds->moveVector, scale, offset ); - - xyz = ( float * ) tess.xyz; - for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) { - VectorAdd( xyz, offset, xyz ); - } -} - - -/* -============= -DeformText - -Change a polygon into a bunch of text polygons -============= -*/ -void DeformText( const char *text ) { - int i; - vec3_t origin, width, height; - int len; - int ch; - byte color[4]; - float bottom, top; - vec3_t mid; - - height[0] = 0; - height[1] = 0; - height[2] = -1; - CrossProduct( tess.normal[0], height, width ); - - // find the midpoint of the box - VectorClear( mid ); - bottom = 999999; - top = -999999; - for ( i = 0 ; i < 4 ; i++ ) { - VectorAdd( tess.xyz[i], mid, mid ); - if ( tess.xyz[i][2] < bottom ) { - bottom = tess.xyz[i][2]; - } - if ( tess.xyz[i][2] > top ) { - top = tess.xyz[i][2]; - } - } - VectorScale( mid, 0.25f, origin ); - - // determine the individual character size - height[0] = 0; - height[1] = 0; - height[2] = ( top - bottom ) * 0.5f; - - VectorScale( width, height[2] * -0.75f, width ); - - // determine the starting position - len = strlen( text ); - VectorMA( origin, (len-1), width, origin ); - - // clear the shader indexes - tess.numIndexes = 0; - tess.numVertexes = 0; - - color[0] = color[1] = color[2] = color[3] = 255; - - // draw each character - for ( i = 0 ; i < len ; i++ ) { - ch = text[i]; - ch &= 255; - - if ( ch != ' ' ) { - int row, col; - float frow, fcol, size; - - row = ch>>4; - col = ch&15; - - frow = row*0.0625f; - fcol = col*0.0625f; - size = 0.0625f; - - RB_AddQuadStampExt( origin, width, height, color, fcol, frow, fcol + size, frow + size ); - } - VectorMA( origin, -2, width, origin ); - } -} - -/* -================== -GlobalVectorToLocal -================== -*/ -static void GlobalVectorToLocal( const vec3_t in, vec3_t out ) { - out[0] = DotProduct( in, backEnd.or.axis[0] ); - out[1] = DotProduct( in, backEnd.or.axis[1] ); - out[2] = DotProduct( in, backEnd.or.axis[2] ); -} - -/* -===================== -AutospriteDeform - -Assuming all the triangles for this shader are independant -quads, rebuild them as forward facing sprites -===================== -*/ -static void AutospriteDeform( void ) { - int i; - int oldVerts; - float *xyz; - vec3_t mid, delta; - float radius; - vec3_t left, up; - vec3_t leftDir, upDir; - - if ( tess.numVertexes & 3 ) { - ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd vertex count\n", tess.shader->name ); - } - if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) { - ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd index count\n", tess.shader->name ); - } - - oldVerts = tess.numVertexes; - tess.numVertexes = 0; - tess.numIndexes = 0; - - if ( backEnd.currentEntity != &tr.worldEntity ) { - GlobalVectorToLocal( backEnd.viewParms.or.axis[1], leftDir ); - GlobalVectorToLocal( backEnd.viewParms.or.axis[2], upDir ); - } else { - VectorCopy( backEnd.viewParms.or.axis[1], leftDir ); - VectorCopy( backEnd.viewParms.or.axis[2], upDir ); - } - - for ( i = 0 ; i < oldVerts ; i+=4 ) { - // find the midpoint - xyz = tess.xyz[i]; - - mid[0] = 0.25f * (xyz[0] + xyz[4] + xyz[8] + xyz[12]); - mid[1] = 0.25f * (xyz[1] + xyz[5] + xyz[9] + xyz[13]); - mid[2] = 0.25f * (xyz[2] + xyz[6] + xyz[10] + xyz[14]); - - VectorSubtract( xyz, mid, delta ); - radius = VectorLength( delta ) * 0.707f; // / sqrt(2) - - VectorScale( leftDir, radius, left ); - VectorScale( upDir, radius, up ); - - if ( backEnd.viewParms.isMirror ) { - VectorSubtract( vec3_origin, left, left ); - } - - // compensate for scale in the axes if necessary - if ( backEnd.currentEntity->e.nonNormalizedAxes ) { - float axisLength; - axisLength = VectorLength( backEnd.currentEntity->e.axis[0] ); - if ( !axisLength ) { - axisLength = 0; - } else { - axisLength = 1.0f / axisLength; - } - VectorScale(left, axisLength, left); - VectorScale(up, axisLength, up); - } - - RB_AddQuadStamp( mid, left, up, tess.vertexColors[i] ); - } -} - - -/* -===================== -Autosprite2Deform - -Autosprite2 will pivot a rectangular quad along the center of its long axis -===================== -*/ -int edgeVerts[6][2] = { - { 0, 1 }, - { 0, 2 }, - { 0, 3 }, - { 1, 2 }, - { 1, 3 }, - { 2, 3 } -}; - -static void Autosprite2Deform( void ) { - int i, j, k; - int indexes; - float *xyz; - vec3_t forward; - - if ( tess.numVertexes & 3 ) { - ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd vertex count", tess.shader->name ); - } - if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) { - ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd index count", tess.shader->name ); - } - - if ( backEnd.currentEntity != &tr.worldEntity ) { - GlobalVectorToLocal( backEnd.viewParms.or.axis[0], forward ); - } else { - VectorCopy( backEnd.viewParms.or.axis[0], forward ); - } - - // this is a lot of work for two triangles... - // we could precalculate a lot of it is an issue, but it would mess up - // the shader abstraction - for ( i = 0, indexes = 0 ; i < tess.numVertexes ; i+=4, indexes+=6 ) { - float lengths[2]; - int nums[2]; - vec3_t mid[2]; - vec3_t major, minor; - float *v1, *v2; - - // find the midpoint - xyz = tess.xyz[i]; - - // identify the two shortest edges - nums[0] = nums[1] = 0; - lengths[0] = lengths[1] = 999999; - - for ( j = 0 ; j < 6 ; j++ ) { - float l; - vec3_t temp; - - v1 = xyz + 4 * edgeVerts[j][0]; - v2 = xyz + 4 * edgeVerts[j][1]; - - VectorSubtract( v1, v2, temp ); - - l = DotProduct( temp, temp ); - if ( l < lengths[0] ) { - nums[1] = nums[0]; - lengths[1] = lengths[0]; - nums[0] = j; - lengths[0] = l; - } else if ( l < lengths[1] ) { - nums[1] = j; - lengths[1] = l; - } - } - - for ( j = 0 ; j < 2 ; j++ ) { - v1 = xyz + 4 * edgeVerts[nums[j]][0]; - v2 = xyz + 4 * edgeVerts[nums[j]][1]; - - mid[j][0] = 0.5f * (v1[0] + v2[0]); - mid[j][1] = 0.5f * (v1[1] + v2[1]); - mid[j][2] = 0.5f * (v1[2] + v2[2]); - } - - // find the vector of the major axis - VectorSubtract( mid[1], mid[0], major ); - - // cross this with the view direction to get minor axis - CrossProduct( major, forward, minor ); - VectorNormalize( minor ); - - // re-project the points - for ( j = 0 ; j < 2 ; j++ ) { - float l; - - v1 = xyz + 4 * edgeVerts[nums[j]][0]; - v2 = xyz + 4 * edgeVerts[nums[j]][1]; - - l = 0.5 * sqrt( lengths[j] ); - - // we need to see which direction this edge - // is used to determine direction of projection - for ( k = 0 ; k < 5 ; k++ ) { - if ( tess.indexes[ indexes + k ] == i + edgeVerts[nums[j]][0] - && tess.indexes[ indexes + k + 1 ] == i + edgeVerts[nums[j]][1] ) { - break; - } - } - - if ( k == 5 ) { - VectorMA( mid[j], l, minor, v1 ); - VectorMA( mid[j], -l, minor, v2 ); - } else { - VectorMA( mid[j], -l, minor, v1 ); - VectorMA( mid[j], l, minor, v2 ); - } - } - } -} - - -/* -===================== -RB_DeformTessGeometry - -===================== -*/ -void RB_DeformTessGeometry( void ) { - int i; - deformStage_t *ds; - - for ( i = 0 ; i < tess.shader->numDeforms ; i++ ) { - ds = &tess.shader->deforms[ i ]; - - switch ( ds->deformation ) { - case DEFORM_NONE: - break; - case DEFORM_NORMALS: - RB_CalcDeformNormals( ds ); - break; - case DEFORM_WAVE: - RB_CalcDeformVertexes( ds ); - break; - case DEFORM_BULGE: - RB_CalcBulgeVertexes( ds ); - break; - case DEFORM_MOVE: - RB_CalcMoveVertexes( ds ); - break; - case DEFORM_PROJECTION_SHADOW: - RB_ProjectionShadowDeform(); - break; - case DEFORM_AUTOSPRITE: - AutospriteDeform(); - break; - case DEFORM_AUTOSPRITE2: - Autosprite2Deform(); - break; - case DEFORM_TEXT0: - case DEFORM_TEXT1: - case DEFORM_TEXT2: - case DEFORM_TEXT3: - case DEFORM_TEXT4: - case DEFORM_TEXT5: - case DEFORM_TEXT6: - case DEFORM_TEXT7: - DeformText( backEnd.refdef.text[ds->deformation - DEFORM_TEXT0] ); - break; - } - } -} - -/* -==================================================================== - -COLORS - -==================================================================== -*/ - - -/* -** RB_CalcColorFromEntity -*/ -void RB_CalcColorFromEntity( unsigned char *dstColors ) -{ - int i; - int *pColors = ( int * ) dstColors; - int c; - - if ( !backEnd.currentEntity ) - return; - - c = * ( int * ) backEnd.currentEntity->e.shaderRGBA; - - for ( i = 0; i < tess.numVertexes; i++, pColors++ ) - { - *pColors = c; - } -} - -/* -** RB_CalcColorFromOneMinusEntity -*/ -void RB_CalcColorFromOneMinusEntity( unsigned char *dstColors ) -{ - int i; - int *pColors = ( int * ) dstColors; - unsigned char invModulate[4]; - int c; - - if ( !backEnd.currentEntity ) - return; - - invModulate[0] = 255 - backEnd.currentEntity->e.shaderRGBA[0]; - invModulate[1] = 255 - backEnd.currentEntity->e.shaderRGBA[1]; - invModulate[2] = 255 - backEnd.currentEntity->e.shaderRGBA[2]; - invModulate[3] = 255 - backEnd.currentEntity->e.shaderRGBA[3]; // this trashes alpha, but the AGEN block fixes it - - c = * ( int * ) invModulate; - - for ( i = 0; i < tess.numVertexes; i++, pColors++ ) - { - *pColors = c; - } -} - -/* -** RB_CalcAlphaFromEntity -*/ -void RB_CalcAlphaFromEntity( unsigned char *dstColors ) -{ - int i; - - if ( !backEnd.currentEntity ) - return; - - dstColors += 3; - - for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 ) - { - *dstColors = backEnd.currentEntity->e.shaderRGBA[3]; - } -} - -/* -** RB_CalcAlphaFromOneMinusEntity -*/ -void RB_CalcAlphaFromOneMinusEntity( unsigned char *dstColors ) -{ - int i; - - if ( !backEnd.currentEntity ) - return; - - dstColors += 3; - - for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 ) - { - *dstColors = 0xff - backEnd.currentEntity->e.shaderRGBA[3]; - } -} - -/* -** RB_CalcWaveColor -*/ -void RB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors ) -{ - int i; - int v; - float glow; - int *colors = ( int * ) dstColors; - byte color[4]; - - - if ( wf->func == GF_NOISE ) { - glow = wf->base + R_NoiseGet4f( 0, 0, 0, ( tess.shaderTime + wf->phase ) * wf->frequency ) * wf->amplitude; - } else { - glow = EvalWaveForm( wf ) * tr.identityLight; - } - - if ( glow < 0 ) { - glow = 0; - } - else if ( glow > 1 ) { - glow = 1; - } - - v = ri.ftol(255 * glow); - color[0] = color[1] = color[2] = v; - color[3] = 255; - v = *(int *)color; - - for ( i = 0; i < tess.numVertexes; i++, colors++ ) { - *colors = v; - } -} - -/* -** RB_CalcWaveAlpha -*/ -void RB_CalcWaveAlpha( const waveForm_t *wf, unsigned char *dstColors ) -{ - int i; - int v; - float glow; - - glow = EvalWaveFormClamped( wf ); - - v = 255 * glow; - - for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 ) - { - dstColors[3] = v; - } -} - -/* -** RB_CalcModulateColorsByFog -*/ -void RB_CalcModulateColorsByFog( unsigned char *colors ) { - int i; - float texCoords[SHADER_MAX_VERTEXES][2]; - - // calculate texcoords so we can derive density - // this is not wasted, because it would only have - // been previously called if the surface was opaque - RB_CalcFogTexCoords( texCoords[0] ); - - for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) { - float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] ); - colors[0] *= f; - colors[1] *= f; - colors[2] *= f; - } -} - -/* -** RB_CalcModulateAlphasByFog -*/ -void RB_CalcModulateAlphasByFog( unsigned char *colors ) { - int i; - float texCoords[SHADER_MAX_VERTEXES][2]; - - // calculate texcoords so we can derive density - // this is not wasted, because it would only have - // been previously called if the surface was opaque - RB_CalcFogTexCoords( texCoords[0] ); - - for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) { - float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] ); - colors[3] *= f; - } -} - -/* -** RB_CalcModulateRGBAsByFog -*/ -void RB_CalcModulateRGBAsByFog( unsigned char *colors ) { - int i; - float texCoords[SHADER_MAX_VERTEXES][2]; - - // calculate texcoords so we can derive density - // this is not wasted, because it would only have - // been previously called if the surface was opaque - RB_CalcFogTexCoords( texCoords[0] ); - - for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) { - float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] ); - colors[0] *= f; - colors[1] *= f; - colors[2] *= f; - colors[3] *= f; - } -} - - -/* -==================================================================== - -TEX COORDS - -==================================================================== -*/ - -/* -======================== -RB_CalcFogTexCoords - -To do the clipped fog plane really correctly, we should use -projected textures, but I don't trust the drivers and it -doesn't fit our shader data. -======================== -*/ -void RB_CalcFogTexCoords( float *st ) { - int i; - float *v; - float s, t; - float eyeT; - qboolean eyeOutside; - fog_t *fog; - vec3_t local; - vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; - - fog = tr.world->fogs + tess.fogNum; - - // all fogging distance is based on world Z units - VectorSubtract( backEnd.or.origin, backEnd.viewParms.or.origin, local ); - fogDistanceVector[0] = -backEnd.or.modelMatrix[2]; - fogDistanceVector[1] = -backEnd.or.modelMatrix[6]; - fogDistanceVector[2] = -backEnd.or.modelMatrix[10]; - fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.or.axis[0] ); - - // scale the fog vectors based on the fog's thickness - fogDistanceVector[0] *= fog->tcScale; - fogDistanceVector[1] *= fog->tcScale; - fogDistanceVector[2] *= fog->tcScale; - fogDistanceVector[3] *= fog->tcScale; - - // rotate the gradient vector for this orientation - if ( fog->hasSurface ) { - fogDepthVector[0] = fog->surface[0] * backEnd.or.axis[0][0] + - fog->surface[1] * backEnd.or.axis[0][1] + fog->surface[2] * backEnd.or.axis[0][2]; - fogDepthVector[1] = fog->surface[0] * backEnd.or.axis[1][0] + - fog->surface[1] * backEnd.or.axis[1][1] + fog->surface[2] * backEnd.or.axis[1][2]; - fogDepthVector[2] = fog->surface[0] * backEnd.or.axis[2][0] + - fog->surface[1] * backEnd.or.axis[2][1] + fog->surface[2] * backEnd.or.axis[2][2]; - fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.or.origin, fog->surface ); - - eyeT = DotProduct( backEnd.or.viewOrigin, fogDepthVector ) + fogDepthVector[3]; - } else { - eyeT = 1; // non-surface fog always has eye inside - } - - // see if the viewpoint is outside - // this is needed for clipping distance even for constant fog - - if ( eyeT < 0 ) { - eyeOutside = qtrue; - } else { - eyeOutside = qfalse; - } - - fogDistanceVector[3] += 1.0/512; - - // calculate density for each point - for (i = 0, v = tess.xyz[0] ; i < tess.numVertexes ; i++, v += 4) { - // calculate the length in fog - s = DotProduct( v, fogDistanceVector ) + fogDistanceVector[3]; - t = DotProduct( v, fogDepthVector ) + fogDepthVector[3]; - - // partially clipped fogs use the T axis - if ( eyeOutside ) { - if ( t < 1.0 ) { - t = 1.0/32; // point is outside, so no fogging - } else { - t = 1.0/32 + 30.0/32 * t / ( t - eyeT ); // cut the distance at the fog plane - } - } else { - if ( t < 0 ) { - t = 1.0/32; // point is outside, so no fogging - } else { - t = 31.0/32; - } - } - - st[0] = s; - st[1] = t; - st += 2; - } -} - - - -/* -** RB_CalcEnvironmentTexCoords -*/ -void RB_CalcEnvironmentTexCoords( float *st ) -{ - int i; - float *v, *normal; - vec3_t viewer, reflected; - float d; - - v = tess.xyz[0]; - normal = tess.normal[0]; - - for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 ) - { - VectorSubtract (backEnd.or.viewOrigin, 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; - } -} - -/* -** RB_CalcTurbulentTexCoords -*/ -void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *st ) -{ - int i; - float now; - - now = ( wf->phase + tess.shaderTime * wf->frequency ); - - for ( i = 0; i < tess.numVertexes; i++, st += 2 ) - { - float s = st[0]; - float t = st[1]; - - st[0] = s + tr.sinTable[ ( ( int ) ( ( ( tess.xyz[i][0] + tess.xyz[i][2] )* 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude; - st[1] = t + tr.sinTable[ ( ( int ) ( ( tess.xyz[i][1] * 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude; - } -} - -/* -** RB_CalcScaleTexCoords -*/ -void RB_CalcScaleTexCoords( const float scale[2], float *st ) -{ - int i; - - for ( i = 0; i < tess.numVertexes; i++, st += 2 ) - { - st[0] *= scale[0]; - st[1] *= scale[1]; - } -} - -/* -** RB_CalcScrollTexCoords -*/ -void RB_CalcScrollTexCoords( const float scrollSpeed[2], float *st ) -{ - int i; - float timeScale = tess.shaderTime; - float adjustedScrollS, adjustedScrollT; - - adjustedScrollS = scrollSpeed[0] * timeScale; - adjustedScrollT = scrollSpeed[1] * timeScale; - - // clamp so coordinates don't continuously get larger, causing problems - // with hardware limits - adjustedScrollS = adjustedScrollS - floor( adjustedScrollS ); - adjustedScrollT = adjustedScrollT - floor( adjustedScrollT ); - - for ( i = 0; i < tess.numVertexes; i++, st += 2 ) - { - st[0] += adjustedScrollS; - st[1] += adjustedScrollT; - } -} - -/* -** RB_CalcTransformTexCoords -*/ -void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *st ) -{ - int i; - - for ( i = 0; i < tess.numVertexes; i++, st += 2 ) - { - float s = st[0]; - float t = st[1]; - - st[0] = s * tmi->matrix[0][0] + t * tmi->matrix[1][0] + tmi->translate[0]; - st[1] = s * tmi->matrix[0][1] + t * tmi->matrix[1][1] + tmi->translate[1]; - } -} - -/* -** RB_CalcRotateTexCoords -*/ -void RB_CalcRotateTexCoords( float degsPerSecond, float *st ) -{ - float timeScale = tess.shaderTime; - float degs; - int index; - float sinValue, cosValue; - texModInfo_t tmi; - - degs = -degsPerSecond * timeScale; - index = degs * ( FUNCTABLE_SIZE / 360.0f ); - - sinValue = tr.sinTable[ index & FUNCTABLE_MASK ]; - cosValue = tr.sinTable[ ( index + FUNCTABLE_SIZE / 4 ) & FUNCTABLE_MASK ]; - - tmi.matrix[0][0] = cosValue; - tmi.matrix[1][0] = -sinValue; - tmi.translate[0] = 0.5 - 0.5 * cosValue + 0.5 * sinValue; - - tmi.matrix[0][1] = sinValue; - tmi.matrix[1][1] = cosValue; - tmi.translate[1] = 0.5 - 0.5 * sinValue - 0.5 * cosValue; - - RB_CalcTransformTexCoords( &tmi, st ); -} - - -/* -** RB_CalcSpecularAlpha -** -** Calculates specular coefficient and places it in the alpha channel -*/ -vec3_t lightOrigin = { -960, 1980, 96 }; // FIXME: track dynamically - -void RB_CalcSpecularAlpha( unsigned char *alphas ) { - int i; - float *v, *normal; - vec3_t viewer, reflected; - float l, d; - int b; - vec3_t lightDir; - int numVertexes; - - v = tess.xyz[0]; - normal = tess.normal[0]; - - alphas += 3; - - numVertexes = tess.numVertexes; - for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4, alphas += 4) { - float ilength; - - VectorSubtract( lightOrigin, v, lightDir ); -// ilength = Q_rsqrt( DotProduct( lightDir, lightDir ) ); - VectorNormalizeFast( lightDir ); - - // calculate the specular color - d = DotProduct (normal, lightDir); -// d *= ilength; - - // we don't optimize for the d < 0 case since this tends to - // cause visual artifacts such as faceted "snapping" - reflected[0] = normal[0]*2*d - lightDir[0]; - reflected[1] = normal[1]*2*d - lightDir[1]; - reflected[2] = normal[2]*2*d - lightDir[2]; - - VectorSubtract (backEnd.or.viewOrigin, v, viewer); - ilength = Q_rsqrt( DotProduct( viewer, viewer ) ); - l = DotProduct (reflected, viewer); - l *= ilength; - - if (l < 0) { - b = 0; - } else { - l = l*l; - l = l*l; - b = l * 255; - if (b > 255) { - b = 255; - } - } - - *alphas = b; - } -} - -/* -** RB_CalcDiffuseColor -** -** The basic vertex lighting calc -*/ -#if idppc_altivec -static void RB_CalcDiffuseColor_altivec( unsigned char *colors ) -{ - int i; - float *v, *normal; - trRefEntity_t *ent; - int ambientLightInt; - vec3_t lightDir; - int numVertexes; - vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff); - vector float ambientLightVec; - vector float directedLightVec; - vector float lightDirVec; - vector float normalVec0, normalVec1; - vector float incomingVec0, incomingVec1, incomingVec2; - vector float zero, jVec; - vector signed int jVecInt; - vector signed short jVecShort; - vector unsigned char jVecChar, normalPerm; - ent = backEnd.currentEntity; - ambientLightInt = ent->ambientLightInt; - // A lot of this could be simplified if we made sure - // entities light info was 16-byte aligned. - jVecChar = vec_lvsl(0, ent->ambientLight); - ambientLightVec = vec_ld(0, (vector float *)ent->ambientLight); - jVec = vec_ld(11, (vector float *)ent->ambientLight); - ambientLightVec = vec_perm(ambientLightVec,jVec,jVecChar); - - jVecChar = vec_lvsl(0, ent->directedLight); - directedLightVec = vec_ld(0,(vector float *)ent->directedLight); - jVec = vec_ld(11,(vector float *)ent->directedLight); - directedLightVec = vec_perm(directedLightVec,jVec,jVecChar); - - jVecChar = vec_lvsl(0, ent->lightDir); - lightDirVec = vec_ld(0,(vector float *)ent->lightDir); - jVec = vec_ld(11,(vector float *)ent->lightDir); - lightDirVec = vec_perm(lightDirVec,jVec,jVecChar); - - zero = (vector float)vec_splat_s8(0); - VectorCopy( ent->lightDir, lightDir ); - - v = tess.xyz[0]; - normal = tess.normal[0]; - - normalPerm = vec_lvsl(0,normal); - numVertexes = tess.numVertexes; - for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) { - normalVec0 = vec_ld(0,(vector float *)normal); - normalVec1 = vec_ld(11,(vector float *)normal); - normalVec0 = vec_perm(normalVec0,normalVec1,normalPerm); - incomingVec0 = vec_madd(normalVec0, lightDirVec, zero); - incomingVec1 = vec_sld(incomingVec0,incomingVec0,4); - incomingVec2 = vec_add(incomingVec0,incomingVec1); - incomingVec1 = vec_sld(incomingVec1,incomingVec1,4); - incomingVec2 = vec_add(incomingVec2,incomingVec1); - incomingVec0 = vec_splat(incomingVec2,0); - incomingVec0 = vec_max(incomingVec0,zero); - normalPerm = vec_lvsl(12,normal); - jVec = vec_madd(incomingVec0, directedLightVec, ambientLightVec); - jVecInt = vec_cts(jVec,0); // RGBx - jVecShort = vec_pack(jVecInt,jVecInt); // RGBxRGBx - jVecChar = vec_packsu(jVecShort,jVecShort); // RGBxRGBxRGBxRGBx - jVecChar = vec_sel(jVecChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255 - vec_ste((vector unsigned int)jVecChar,0,(unsigned int *)&colors[i*4]); // store color - } -} -#endif - -static void RB_CalcDiffuseColor_scalar( unsigned char *colors ) -{ - int i, j; - float *v, *normal; - float incoming; - trRefEntity_t *ent; - int ambientLightInt; - vec3_t ambientLight; - vec3_t lightDir; - vec3_t directedLight; - int numVertexes; - ent = backEnd.currentEntity; - ambientLightInt = ent->ambientLightInt; - VectorCopy( ent->ambientLight, ambientLight ); - VectorCopy( ent->directedLight, directedLight ); - VectorCopy( ent->lightDir, lightDir ); - - v = tess.xyz[0]; - normal = tess.normal[0]; - - numVertexes = tess.numVertexes; - for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) { - incoming = DotProduct (normal, lightDir); - if ( incoming <= 0 ) { - *(int *)&colors[i*4] = ambientLightInt; - continue; - } - j = ri.ftol(ambientLight[0] + incoming * directedLight[0]); - if ( j > 255 ) { - j = 255; - } - colors[i*4+0] = j; - - j = ri.ftol(ambientLight[1] + incoming * directedLight[1]); - if ( j > 255 ) { - j = 255; - } - colors[i*4+1] = j; - - j = ri.ftol(ambientLight[2] + incoming * directedLight[2]); - if ( j > 255 ) { - j = 255; - } - colors[i*4+2] = j; - - colors[i*4+3] = 255; - } -} - -void RB_CalcDiffuseColor( unsigned char *colors ) -{ -#if idppc_altivec - if (com_altivec->integer) { - // must be in a seperate function or G3 systems will crash. - RB_CalcDiffuseColor_altivec( colors ); - return; - } -#endif - RB_CalcDiffuseColor_scalar( colors ); -} - diff --git a/code/renderergl1/tr_shader.c b/code/renderergl1/tr_shader.c deleted file mode 100644 index 877c619123..0000000000 --- a/code/renderergl1/tr_shader.c +++ /dev/null @@ -1,3122 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - -// tr_shader.c -- this file deals with the parsing and definition of shaders - -static char *s_shaderText; - -// the shader is parsed into these global variables, then copied into -// dynamically allocated memory if it is valid. -static shaderStage_t stages[MAX_SHADER_STAGES]; -static shader_t shader; -static texModInfo_t texMods[MAX_SHADER_STAGES][TR_MAX_TEXMODS]; - -#define FILE_HASH_SIZE 1024 -static shader_t* hashTable[FILE_HASH_SIZE]; - -#define MAX_SHADERTEXT_HASH 2048 -static char **shaderTextHashTable[MAX_SHADERTEXT_HASH]; - -/* -================ -return a hash value for the filename -================ -*/ -#ifdef __GNUCC__ - #warning TODO: check if long is ok here -#endif -static long generateHashValue( const char *fname, const int size ) { - int i; - long hash; - char letter; - - hash = 0; - i = 0; - while (fname[i] != '\0') { - letter = tolower(fname[i]); - if (letter =='.') break; // don't include extension - if (letter =='\\') letter = '/'; // damn path names - if (letter == PATH_SEP) letter = '/'; // damn path names - hash+=(long)(letter)*(i+119); - i++; - } - hash = (hash ^ (hash >> 10) ^ (hash >> 20)); - hash &= (size-1); - return hash; -} - -void R_RemapShader(const char *shaderName, const char *newShaderName, const char *timeOffset) { - char strippedName[MAX_QPATH]; - int hash; - shader_t *sh, *sh2; - qhandle_t h; - - sh = R_FindShaderByName( shaderName ); - if (sh == NULL || sh == tr.defaultShader) { - h = RE_RegisterShaderLightMap(shaderName, 0); - sh = R_GetShaderByHandle(h); - } - if (sh == NULL || sh == tr.defaultShader) { - ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: shader %s not found\n", shaderName ); - return; - } - - sh2 = R_FindShaderByName( newShaderName ); - if (sh2 == NULL || sh2 == tr.defaultShader) { - h = RE_RegisterShaderLightMap(newShaderName, 0); - sh2 = R_GetShaderByHandle(h); - } - - if (sh2 == NULL || sh2 == tr.defaultShader) { - ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: new shader %s not found\n", newShaderName ); - return; - } - - // remap all the shaders with the given name - // even tho they might have different lightmaps - COM_StripExtension(shaderName, strippedName, sizeof(strippedName)); - hash = generateHashValue(strippedName, FILE_HASH_SIZE); - for (sh = hashTable[hash]; sh; sh = sh->next) { - if (Q_stricmp(sh->name, strippedName) == 0) { - if (sh != sh2) { - sh->remappedShader = sh2; - } else { - sh->remappedShader = NULL; - } - } - } - if (timeOffset) { - sh2->timeOffset = atof(timeOffset); - } -} - -/* -=============== -ParseVector -=============== -*/ -static qboolean ParseVector( char **text, int count, float *v ) { - char *token; - int i; - - // FIXME: spaces are currently required after parens, should change parseext... - token = COM_ParseExt( text, qfalse ); - if ( strcmp( token, "(" ) ) { - ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name ); - return qfalse; - } - - for ( i = 0 ; i < count ; i++ ) { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) { - ri.Printf( PRINT_WARNING, "WARNING: missing vector element in shader '%s'\n", shader.name ); - return qfalse; - } - v[i] = atof( token ); - } - - token = COM_ParseExt( text, qfalse ); - if ( strcmp( token, ")" ) ) { - ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name ); - return qfalse; - } - - return qtrue; -} - - -/* -=============== -NameToAFunc -=============== -*/ -static unsigned NameToAFunc( const char *funcname ) -{ - if ( !Q_stricmp( funcname, "GT0" ) ) - { - return GLS_ATEST_GT_0; - } - else if ( !Q_stricmp( funcname, "LT128" ) ) - { - return GLS_ATEST_LT_80; - } - else if ( !Q_stricmp( funcname, "GE128" ) ) - { - return GLS_ATEST_GE_80; - } - - ri.Printf( PRINT_WARNING, "WARNING: invalid alphaFunc name '%s' in shader '%s'\n", funcname, shader.name ); - return 0; -} - - -/* -=============== -NameToSrcBlendMode -=============== -*/ -static int NameToSrcBlendMode( const char *name ) -{ - if ( !Q_stricmp( name, "GL_ONE" ) ) - { - return GLS_SRCBLEND_ONE; - } - else if ( !Q_stricmp( name, "GL_ZERO" ) ) - { - return GLS_SRCBLEND_ZERO; - } - else if ( !Q_stricmp( name, "GL_DST_COLOR" ) ) - { - return GLS_SRCBLEND_DST_COLOR; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_COLOR" ) ) - { - return GLS_SRCBLEND_ONE_MINUS_DST_COLOR; - } - else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) ) - { - return GLS_SRCBLEND_SRC_ALPHA; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) ) - { - return GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA; - } - else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) ) - { - return GLS_SRCBLEND_DST_ALPHA; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) ) - { - return GLS_SRCBLEND_ONE_MINUS_DST_ALPHA; - } - else if ( !Q_stricmp( name, "GL_SRC_ALPHA_SATURATE" ) ) - { - return GLS_SRCBLEND_ALPHA_SATURATE; - } - - ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name ); - return GLS_SRCBLEND_ONE; -} - -/* -=============== -NameToDstBlendMode -=============== -*/ -static int NameToDstBlendMode( const char *name ) -{ - if ( !Q_stricmp( name, "GL_ONE" ) ) - { - return GLS_DSTBLEND_ONE; - } - else if ( !Q_stricmp( name, "GL_ZERO" ) ) - { - return GLS_DSTBLEND_ZERO; - } - else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) ) - { - return GLS_DSTBLEND_SRC_ALPHA; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) ) - { - return GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } - else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) ) - { - return GLS_DSTBLEND_DST_ALPHA; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) ) - { - return GLS_DSTBLEND_ONE_MINUS_DST_ALPHA; - } - else if ( !Q_stricmp( name, "GL_SRC_COLOR" ) ) - { - return GLS_DSTBLEND_SRC_COLOR; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_COLOR" ) ) - { - return GLS_DSTBLEND_ONE_MINUS_SRC_COLOR; - } - - ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name ); - return GLS_DSTBLEND_ONE; -} - -/* -=============== -NameToGenFunc -=============== -*/ -static genFunc_t NameToGenFunc( const char *funcname ) -{ - if ( !Q_stricmp( funcname, "sin" ) ) - { - return GF_SIN; - } - else if ( !Q_stricmp( funcname, "square" ) ) - { - return GF_SQUARE; - } - else if ( !Q_stricmp( funcname, "triangle" ) ) - { - return GF_TRIANGLE; - } - else if ( !Q_stricmp( funcname, "sawtooth" ) ) - { - return GF_SAWTOOTH; - } - else if ( !Q_stricmp( funcname, "inversesawtooth" ) ) - { - return GF_INVERSE_SAWTOOTH; - } - else if ( !Q_stricmp( funcname, "noise" ) ) - { - return GF_NOISE; - } - - ri.Printf( PRINT_WARNING, "WARNING: invalid genfunc name '%s' in shader '%s'\n", funcname, shader.name ); - return GF_SIN; -} - - -/* -=================== -ParseWaveForm -=================== -*/ -static void ParseWaveForm( char **text, waveForm_t *wave ) -{ - char *token; - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->func = NameToGenFunc( token ); - - // BASE, AMP, PHASE, FREQ - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->base = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->amplitude = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->phase = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->frequency = atof( token ); -} - - -/* -=================== -ParseTexMod -=================== -*/ -static void ParseTexMod( char *_text, shaderStage_t *stage ) -{ - const char *token; - char **text = &_text; - texModInfo_t *tmi; - - if ( stage->bundle[0].numTexMods == TR_MAX_TEXMODS ) { - ri.Error( ERR_DROP, "ERROR: too many tcMod stages in shader '%s'", shader.name ); - return; - } - - tmi = &stage->bundle[0].texMods[stage->bundle[0].numTexMods]; - stage->bundle[0].numTexMods++; - - token = COM_ParseExt( text, qfalse ); - - // - // turb - // - if ( !Q_stricmp( token, "turb" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.base = atof( token ); - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name ); - return; - } - tmi->wave.amplitude = atof( token ); - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name ); - return; - } - tmi->wave.phase = atof( token ); - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name ); - return; - } - tmi->wave.frequency = atof( token ); - - tmi->type = TMOD_TURBULENT; - } - // - // scale - // - else if ( !Q_stricmp( token, "scale" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name ); - return; - } - tmi->scale[0] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name ); - return; - } - tmi->scale[1] = atof( token ); - tmi->type = TMOD_SCALE; - } - // - // scroll - // - else if ( !Q_stricmp( token, "scroll" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name ); - return; - } - tmi->scroll[0] = atof( token ); - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name ); - return; - } - tmi->scroll[1] = atof( token ); - tmi->type = TMOD_SCROLL; - } - // - // stretch - // - else if ( !Q_stricmp( token, "stretch" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.func = NameToGenFunc( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.base = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.amplitude = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.phase = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.frequency = atof( token ); - - tmi->type = TMOD_STRETCH; - } - // - // transform - // - else if ( !Q_stricmp( token, "transform" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->matrix[0][0] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->matrix[0][1] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->matrix[1][0] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->matrix[1][1] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->translate[0] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->translate[1] = atof( token ); - - tmi->type = TMOD_TRANSFORM; - } - // - // rotate - // - else if ( !Q_stricmp( token, "rotate" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod rotate parms in shader '%s'\n", shader.name ); - return; - } - tmi->rotateSpeed = atof( token ); - tmi->type = TMOD_ROTATE; - } - // - // entityTranslate - // - else if ( !Q_stricmp( token, "entityTranslate" ) ) - { - tmi->type = TMOD_ENTITY_TRANSLATE; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown tcMod '%s' in shader '%s'\n", token, shader.name ); - } -} - - -/* -=================== -ParseStage -=================== -*/ -static qboolean ParseStage( shaderStage_t *stage, char **text ) -{ - char *token; - int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0; - qboolean depthMaskExplicit = qfalse; - - stage->active = qtrue; - - while ( 1 ) - { - token = COM_ParseExt( text, qtrue ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: no matching '}' found\n" ); - return qfalse; - } - - if ( token[0] == '}' ) - { - break; - } - // - // map - // - else if ( !Q_stricmp( token, "map" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'map' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - if ( !Q_stricmp( token, "$whiteimage" ) ) - { - stage->bundle[0].image[0] = tr.whiteImage; - continue; - } - else if ( !Q_stricmp( token, "$lightmap" ) ) - { - stage->bundle[0].isLightmap = qtrue; - if ( shader.lightmapIndex < 0 || !tr.lightmaps ) { - stage->bundle[0].image[0] = tr.whiteImage; - } else { - stage->bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; - } - continue; - } - else - { - imgType_t type = IMGTYPE_COLORALPHA; - imgFlags_t flags = IMGFLAG_NONE; - - if (!shader.noMipMaps) - flags |= IMGFLAG_MIPMAP; - - if (!shader.noPicMip) - flags |= IMGFLAG_PICMIP; - - stage->bundle[0].image[0] = R_FindImageFile( token, type, flags ); - - if ( !stage->bundle[0].image[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - } - } - // - // clampmap - // - else if ( !Q_stricmp( token, "clampmap" ) ) - { - imgType_t type = IMGTYPE_COLORALPHA; - imgFlags_t flags = IMGFLAG_CLAMPTOEDGE; - - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampmap' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - if (!shader.noMipMaps) - flags |= IMGFLAG_MIPMAP; - - if (!shader.noPicMip) - flags |= IMGFLAG_PICMIP; - - stage->bundle[0].image[0] = R_FindImageFile( token, type, flags ); - if ( !stage->bundle[0].image[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - } - // - // animMap .... - // - else if ( !Q_stricmp( token, "animMap" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'animMmap' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - stage->bundle[0].imageAnimationSpeed = atof( token ); - - // parse up to MAX_IMAGE_ANIMATIONS animations - while ( 1 ) { - int num; - - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) { - break; - } - num = stage->bundle[0].numImageAnimations; - if ( num < MAX_IMAGE_ANIMATIONS ) { - imgFlags_t flags = IMGFLAG_NONE; - - if (!shader.noMipMaps) - flags |= IMGFLAG_MIPMAP; - - if (!shader.noPicMip) - flags |= IMGFLAG_PICMIP; - - stage->bundle[0].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags ); - if ( !stage->bundle[0].image[num] ) - { - ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - stage->bundle[0].numImageAnimations++; - } - } - } - else if ( !Q_stricmp( token, "videoMap" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMmap' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - stage->bundle[0].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); - if (stage->bundle[0].videoMapHandle != -1) { - stage->bundle[0].isVideoMap = qtrue; - stage->bundle[0].image[0] = tr.scratchImage[stage->bundle[0].videoMapHandle]; - } - } - // - // alphafunc - // - else if ( !Q_stricmp( token, "alphaFunc" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'alphaFunc' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - atestBits = NameToAFunc( token ); - } - // - // depthFunc - // - else if ( !Q_stricmp( token, "depthfunc" ) ) - { - token = COM_ParseExt( text, qfalse ); - - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'depthfunc' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - if ( !Q_stricmp( token, "lequal" ) ) - { - depthFuncBits = 0; - } - else if ( !Q_stricmp( token, "equal" ) ) - { - depthFuncBits = GLS_DEPTHFUNC_EQUAL; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown depthfunc '%s' in shader '%s'\n", token, shader.name ); - continue; - } - } - // - // detail - // - else if ( !Q_stricmp( token, "detail" ) ) - { - stage->isDetail = qtrue; - } - // - // blendfunc - // or blendfunc - // - else if ( !Q_stricmp( token, "blendfunc" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name ); - continue; - } - // check for "simple" blends first - if ( !Q_stricmp( token, "add" ) ) { - blendSrcBits = GLS_SRCBLEND_ONE; - blendDstBits = GLS_DSTBLEND_ONE; - } else if ( !Q_stricmp( token, "filter" ) ) { - blendSrcBits = GLS_SRCBLEND_DST_COLOR; - blendDstBits = GLS_DSTBLEND_ZERO; - } else if ( !Q_stricmp( token, "blend" ) ) { - blendSrcBits = GLS_SRCBLEND_SRC_ALPHA; - blendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } else { - // complex double blends - blendSrcBits = NameToSrcBlendMode( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name ); - continue; - } - blendDstBits = NameToDstBlendMode( token ); - } - - // clear depth mask for blended surfaces - if ( !depthMaskExplicit ) - { - depthMaskBits = 0; - } - } - // - // rgbGen - // - else if ( !Q_stricmp( token, "rgbGen" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameters for rgbGen in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "wave" ) ) - { - ParseWaveForm( text, &stage->rgbWave ); - stage->rgbGen = CGEN_WAVEFORM; - } - else if ( !Q_stricmp( token, "const" ) ) - { - vec3_t color; - - ParseVector( text, 3, color ); - stage->constantColor[0] = 255 * color[0]; - stage->constantColor[1] = 255 * color[1]; - stage->constantColor[2] = 255 * color[2]; - - stage->rgbGen = CGEN_CONST; - } - else if ( !Q_stricmp( token, "identity" ) ) - { - stage->rgbGen = CGEN_IDENTITY; - } - else if ( !Q_stricmp( token, "identityLighting" ) ) - { - stage->rgbGen = CGEN_IDENTITY_LIGHTING; - } - else if ( !Q_stricmp( token, "entity" ) ) - { - stage->rgbGen = CGEN_ENTITY; - } - else if ( !Q_stricmp( token, "oneMinusEntity" ) ) - { - stage->rgbGen = CGEN_ONE_MINUS_ENTITY; - } - else if ( !Q_stricmp( token, "vertex" ) ) - { - stage->rgbGen = CGEN_VERTEX; - if ( stage->alphaGen == 0 ) { - stage->alphaGen = AGEN_VERTEX; - } - } - else if ( !Q_stricmp( token, "exactVertex" ) ) - { - stage->rgbGen = CGEN_EXACT_VERTEX; - } - else if ( !Q_stricmp( token, "lightingDiffuse" ) ) - { - stage->rgbGen = CGEN_LIGHTING_DIFFUSE; - } - else if ( !Q_stricmp( token, "oneMinusVertex" ) ) - { - stage->rgbGen = CGEN_ONE_MINUS_VERTEX; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown rgbGen parameter '%s' in shader '%s'\n", token, shader.name ); - continue; - } - } - // - // alphaGen - // - else if ( !Q_stricmp( token, "alphaGen" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameters for alphaGen in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "wave" ) ) - { - ParseWaveForm( text, &stage->alphaWave ); - stage->alphaGen = AGEN_WAVEFORM; - } - else if ( !Q_stricmp( token, "const" ) ) - { - token = COM_ParseExt( text, qfalse ); - stage->constantColor[3] = 255 * atof( token ); - stage->alphaGen = AGEN_CONST; - } - else if ( !Q_stricmp( token, "identity" ) ) - { - stage->alphaGen = AGEN_IDENTITY; - } - else if ( !Q_stricmp( token, "entity" ) ) - { - stage->alphaGen = AGEN_ENTITY; - } - else if ( !Q_stricmp( token, "oneMinusEntity" ) ) - { - stage->alphaGen = AGEN_ONE_MINUS_ENTITY; - } - else if ( !Q_stricmp( token, "vertex" ) ) - { - stage->alphaGen = AGEN_VERTEX; - } - else if ( !Q_stricmp( token, "lightingSpecular" ) ) - { - stage->alphaGen = AGEN_LIGHTING_SPECULAR; - } - else if ( !Q_stricmp( token, "oneMinusVertex" ) ) - { - stage->alphaGen = AGEN_ONE_MINUS_VERTEX; - } - else if ( !Q_stricmp( token, "portal" ) ) - { - stage->alphaGen = AGEN_PORTAL; - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - shader.portalRange = 256; - ri.Printf( PRINT_WARNING, "WARNING: missing range parameter for alphaGen portal in shader '%s', defaulting to 256\n", shader.name ); - } - else - { - shader.portalRange = atof( token ); - } - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown alphaGen parameter '%s' in shader '%s'\n", token, shader.name ); - continue; - } - } - // - // tcGen - // - else if ( !Q_stricmp(token, "texgen") || !Q_stricmp( token, "tcGen" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing texgen parm in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "environment" ) ) - { - stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED; - } - else if ( !Q_stricmp( token, "lightmap" ) ) - { - stage->bundle[0].tcGen = TCGEN_LIGHTMAP; - } - else if ( !Q_stricmp( token, "texture" ) || !Q_stricmp( token, "base" ) ) - { - stage->bundle[0].tcGen = TCGEN_TEXTURE; - } - else if ( !Q_stricmp( token, "vector" ) ) - { - ParseVector( text, 3, stage->bundle[0].tcGenVectors[0] ); - ParseVector( text, 3, stage->bundle[0].tcGenVectors[1] ); - - stage->bundle[0].tcGen = TCGEN_VECTOR; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown texgen parm in shader '%s'\n", shader.name ); - } - } - // - // tcMod <...> - // - else if ( !Q_stricmp( token, "tcMod" ) ) - { - char buffer[1024] = ""; - - while ( 1 ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - break; - strcat( buffer, token ); - strcat( buffer, " " ); - } - - ParseTexMod( buffer, stage ); - - continue; - } - // - // depthmask - // - else if ( !Q_stricmp( token, "depthwrite" ) ) - { - depthMaskBits = GLS_DEPTHMASK_TRUE; - depthMaskExplicit = qtrue; - - continue; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - } - - // - // if cgen isn't explicitly specified, use either identity or identitylighting - // - if ( stage->rgbGen == CGEN_BAD ) { - if ( blendSrcBits == 0 || - blendSrcBits == GLS_SRCBLEND_ONE || - blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) { - stage->rgbGen = CGEN_IDENTITY_LIGHTING; - } else { - stage->rgbGen = CGEN_IDENTITY; - } - } - - - // - // implicitly assume that a GL_ONE GL_ZERO blend mask disables blending - // - if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && - ( blendDstBits == GLS_DSTBLEND_ZERO ) ) - { - blendDstBits = blendSrcBits = 0; - depthMaskBits = GLS_DEPTHMASK_TRUE; - } - - // decide which agens we can skip - if ( stage->alphaGen == AGEN_IDENTITY ) { - if ( stage->rgbGen == CGEN_IDENTITY - || stage->rgbGen == CGEN_LIGHTING_DIFFUSE ) { - stage->alphaGen = AGEN_SKIP; - } - } - - // - // compute state bits - // - stage->stateBits = depthMaskBits | - blendSrcBits | blendDstBits | - atestBits | - depthFuncBits; - - return qtrue; -} - -/* -=============== -ParseDeform - -deformVertexes wave -deformVertexes normal -deformVertexes move -deformVertexes bulge -deformVertexes projectionShadow -deformVertexes autoSprite -deformVertexes autoSprite2 -deformVertexes text[0-7] -=============== -*/ -static void ParseDeform( char **text ) { - char *token; - deformStage_t *ds; - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deform parm in shader '%s'\n", shader.name ); - return; - } - - if ( shader.numDeforms == MAX_SHADER_DEFORMS ) { - ri.Printf( PRINT_WARNING, "WARNING: MAX_SHADER_DEFORMS in '%s'\n", shader.name ); - return; - } - - ds = &shader.deforms[ shader.numDeforms ]; - shader.numDeforms++; - - if ( !Q_stricmp( token, "projectionShadow" ) ) { - ds->deformation = DEFORM_PROJECTION_SHADOW; - return; - } - - if ( !Q_stricmp( token, "autosprite" ) ) { - ds->deformation = DEFORM_AUTOSPRITE; - return; - } - - if ( !Q_stricmp( token, "autosprite2" ) ) { - ds->deformation = DEFORM_AUTOSPRITE2; - return; - } - - if ( !Q_stricmpn( token, "text", 4 ) ) { - int n; - - n = token[4] - '0'; - if ( n < 0 || n > 7 ) { - n = 0; - } - ds->deformation = DEFORM_TEXT0 + n; - return; - } - - if ( !Q_stricmp( token, "bulge" ) ) { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name ); - return; - } - ds->bulgeWidth = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name ); - return; - } - ds->bulgeHeight = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name ); - return; - } - ds->bulgeSpeed = atof( token ); - - ds->deformation = DEFORM_BULGE; - return; - } - - if ( !Q_stricmp( token, "wave" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); - return; - } - - if ( atof( token ) != 0 ) - { - ds->deformationSpread = 1.0f / atof( token ); - } - else - { - ds->deformationSpread = 100.0f; - ri.Printf( PRINT_WARNING, "WARNING: illegal div value of 0 in deformVertexes command for shader '%s'\n", shader.name ); - } - - ParseWaveForm( text, &ds->deformationWave ); - ds->deformation = DEFORM_WAVE; - return; - } - - if ( !Q_stricmp( token, "normal" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); - return; - } - ds->deformationWave.amplitude = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); - return; - } - ds->deformationWave.frequency = atof( token ); - - ds->deformation = DEFORM_NORMALS; - return; - } - - if ( !Q_stricmp( token, "move" ) ) { - int i; - - for ( i = 0 ; i < 3 ; i++ ) { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); - return; - } - ds->moveVector[i] = atof( token ); - } - - ParseWaveForm( text, &ds->deformationWave ); - ds->deformation = DEFORM_MOVE; - return; - } - - ri.Printf( PRINT_WARNING, "WARNING: unknown deformVertexes subtype '%s' found in shader '%s'\n", token, shader.name ); -} - - -/* -=============== -ParseSkyParms - -skyParms -=============== -*/ -static void ParseSkyParms( char **text ) { - char *token; - static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"}; - char pathname[MAX_QPATH]; - int i; - imgFlags_t imgFlags = IMGFLAG_MIPMAP | IMGFLAG_PICMIP; - - // outerbox - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name ); - return; - } - if ( strcmp( token, "-" ) ) { - for (i=0 ; i<6 ; i++) { - Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga" - , token, suf[i] ); - shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, imgFlags | IMGFLAG_CLAMPTOEDGE ); - - if ( !shader.sky.outerbox[i] ) { - shader.sky.outerbox[i] = tr.defaultImage; - } - } - } - - // cloudheight - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name ); - return; - } - shader.sky.cloudHeight = atof( token ); - if ( !shader.sky.cloudHeight ) { - shader.sky.cloudHeight = 512; - } - R_InitSkyTexCoords( shader.sky.cloudHeight ); - - - // innerbox - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name ); - return; - } - if ( strcmp( token, "-" ) ) { - for (i=0 ; i<6 ; i++) { - Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga" - , token, suf[i] ); - shader.sky.innerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, imgFlags ); - if ( !shader.sky.innerbox[i] ) { - shader.sky.innerbox[i] = tr.defaultImage; - } - } - } - - shader.isSky = qtrue; -} - - -/* -================= -ParseSort -================= -*/ -void ParseSort( char **text ) { - char *token; - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: missing sort parameter in shader '%s'\n", shader.name ); - return; - } - - if ( !Q_stricmp( token, "portal" ) ) { - shader.sort = SS_PORTAL; - } else if ( !Q_stricmp( token, "sky" ) ) { - shader.sort = SS_ENVIRONMENT; - } else if ( !Q_stricmp( token, "opaque" ) ) { - shader.sort = SS_OPAQUE; - }else if ( !Q_stricmp( token, "decal" ) ) { - shader.sort = SS_DECAL; - } else if ( !Q_stricmp( token, "seeThrough" ) ) { - shader.sort = SS_SEE_THROUGH; - } else if ( !Q_stricmp( token, "banner" ) ) { - shader.sort = SS_BANNER; - } else if ( !Q_stricmp( token, "additive" ) ) { - shader.sort = SS_BLEND1; - } else if ( !Q_stricmp( token, "nearest" ) ) { - shader.sort = SS_NEAREST; - } else if ( !Q_stricmp( token, "underwater" ) ) { - shader.sort = SS_UNDERWATER; - } else { - shader.sort = atof( token ); - } -} - - - -// this table is also present in q3map - -typedef struct { - char *name; - int clearSolid, surfaceFlags, contents; -} infoParm_t; - -infoParm_t infoParms[] = { - // server relevant contents - {"water", 1, 0, CONTENTS_WATER }, - {"slime", 1, 0, CONTENTS_SLIME }, // mildly damaging - {"lava", 1, 0, CONTENTS_LAVA }, // very damaging - {"playerclip", 1, 0, CONTENTS_PLAYERCLIP }, - {"monsterclip", 1, 0, CONTENTS_MONSTERCLIP }, - {"nodrop", 1, 0, CONTENTS_NODROP }, // don't drop items or leave bodies (death fog, lava, etc) - {"nonsolid", 1, SURF_NONSOLID, 0}, // clears the solid flag - - // utility relevant attributes - {"origin", 1, 0, CONTENTS_ORIGIN }, // center of rotating brushes - {"trans", 0, 0, CONTENTS_TRANSLUCENT }, // don't eat contained surfaces - {"detail", 0, 0, CONTENTS_DETAIL }, // don't include in structural bsp - {"structural", 0, 0, CONTENTS_STRUCTURAL }, // force into structural bsp even if trnas - {"areaportal", 1, 0, CONTENTS_AREAPORTAL }, // divides areas - {"clusterportal", 1,0, CONTENTS_CLUSTERPORTAL }, // for bots - {"donotenter", 1, 0, CONTENTS_DONOTENTER }, // for bots - - {"fog", 1, 0, CONTENTS_FOG}, // carves surfaces entering - {"sky", 0, SURF_SKY, 0 }, // emit light from an environment map - {"lightfilter", 0, SURF_LIGHTFILTER, 0 }, // filter light going through it - {"alphashadow", 0, SURF_ALPHASHADOW, 0 }, // test light on a per-pixel basis - {"hint", 0, SURF_HINT, 0 }, // use as a primary splitter - - // server attributes - {"slick", 0, SURF_SLICK, 0 }, - {"noimpact", 0, SURF_NOIMPACT, 0 }, // don't make impact explosions or marks - {"nomarks", 0, SURF_NOMARKS, 0 }, // don't make impact marks, but still explode - {"ladder", 0, SURF_LADDER, 0 }, - {"nodamage", 0, SURF_NODAMAGE, 0 }, - {"metalsteps", 0, SURF_METALSTEPS,0 }, - {"flesh", 0, SURF_FLESH, 0 }, - {"nosteps", 0, SURF_NOSTEPS, 0 }, - - // drawsurf attributes - {"nodraw", 0, SURF_NODRAW, 0 }, // don't generate a drawsurface (or a lightmap) - {"pointlight", 0, SURF_POINTLIGHT, 0 }, // sample lighting at vertexes - {"nolightmap", 0, SURF_NOLIGHTMAP,0 }, // don't generate a lightmap - {"nodlight", 0, SURF_NODLIGHT, 0 }, // don't ever add dynamic lights - {"dust", 0, SURF_DUST, 0} // leave a dust trail when walking on this surface -}; - - -/* -=============== -ParseSurfaceParm - -surfaceparm -=============== -*/ -static void ParseSurfaceParm( char **text ) { - char *token; - int numInfoParms = ARRAY_LEN( infoParms ); - int i; - - token = COM_ParseExt( text, qfalse ); - for ( i = 0 ; i < numInfoParms ; i++ ) { - if ( !Q_stricmp( token, infoParms[i].name ) ) { - shader.surfaceFlags |= infoParms[i].surfaceFlags; - shader.contentFlags |= infoParms[i].contents; -#if 0 - if ( infoParms[i].clearSolid ) { - si->contents &= ~CONTENTS_SOLID; - } -#endif - break; - } - } -} - -/* -================= -ParseShader - -The current text pointer is at the explicit text definition of the -shader. Parse it into the global shader variable. Later functions -will optimize it. -================= -*/ -static qboolean ParseShader( char **text ) -{ - char *token; - int s; - - s = 0; - - token = COM_ParseExt( text, qtrue ); - if ( token[0] != '{' ) - { - ri.Printf( PRINT_WARNING, "WARNING: expecting '{', found '%s' instead in shader '%s'\n", token, shader.name ); - return qfalse; - } - - while ( 1 ) - { - token = COM_ParseExt( text, qtrue ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: no concluding '}' in shader %s\n", shader.name ); - return qfalse; - } - - // end of shader definition - if ( token[0] == '}' ) - { - break; - } - // stage definition - else if ( token[0] == '{' ) - { - if ( s >= MAX_SHADER_STAGES ) { - ri.Printf( PRINT_WARNING, "WARNING: too many stages in shader %s\n", shader.name ); - return qfalse; - } - - if ( !ParseStage( &stages[s], text ) ) - { - return qfalse; - } - stages[s].active = qtrue; - s++; - - continue; - } - // skip stuff that only the QuakeEdRadient needs - else if ( !Q_stricmpn( token, "qer", 3 ) ) { - SkipRestOfLine( text ); - continue; - } - // sun parms - else if ( !Q_stricmp( token, "q3map_sun" ) ) { - float a, b; - - token = COM_ParseExt( text, qfalse ); - tr.sunLight[0] = atof( token ); - token = COM_ParseExt( text, qfalse ); - tr.sunLight[1] = atof( token ); - token = COM_ParseExt( text, qfalse ); - tr.sunLight[2] = atof( token ); - - VectorNormalize( tr.sunLight ); - - token = COM_ParseExt( text, qfalse ); - a = atof( token ); - VectorScale( tr.sunLight, a, tr.sunLight); - - token = COM_ParseExt( text, qfalse ); - a = atof( token ); - a = a / 180 * M_PI; - - token = COM_ParseExt( text, qfalse ); - b = atof( token ); - b = b / 180 * M_PI; - - tr.sunDirection[0] = cos( a ) * cos( b ); - tr.sunDirection[1] = sin( a ) * cos( b ); - tr.sunDirection[2] = sin( b ); - } - else if ( !Q_stricmp( token, "deformVertexes" ) ) { - ParseDeform( text ); - continue; - } - else if ( !Q_stricmp( token, "tesssize" ) ) { - SkipRestOfLine( text ); - continue; - } - else if ( !Q_stricmp( token, "clampTime" ) ) { - token = COM_ParseExt( text, qfalse ); - if (token[0]) { - shader.clampTime = atof(token); - } - } - // skip stuff that only the q3map needs - else if ( !Q_stricmpn( token, "q3map", 5 ) ) { - SkipRestOfLine( text ); - continue; - } - // skip stuff that only q3map or the server needs - else if ( !Q_stricmp( token, "surfaceParm" ) ) { - ParseSurfaceParm( text ); - continue; - } - // no mip maps - else if ( !Q_stricmp( token, "nomipmaps" ) ) - { - shader.noMipMaps = qtrue; - shader.noPicMip = qtrue; - continue; - } - // no picmip adjustment - else if ( !Q_stricmp( token, "nopicmip" ) ) - { - shader.noPicMip = qtrue; - continue; - } - // polygonOffset - else if ( !Q_stricmp( token, "polygonOffset" ) ) - { - shader.polygonOffset = qtrue; - continue; - } - // entityMergable, allowing sprite surfaces from multiple entities - // to be merged into one batch. This is a savings for smoke - // puffs and blood, but can't be used for anything where the - // shader calcs (not the surface function) reference the entity color or scroll - else if ( !Q_stricmp( token, "entityMergable" ) ) - { - shader.entityMergable = qtrue; - continue; - } - // fogParms - else if ( !Q_stricmp( token, "fogParms" ) ) - { - if ( !ParseVector( text, 3, shader.fogParms.color ) ) { - return qfalse; - } - - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parm for 'fogParms' keyword in shader '%s'\n", shader.name ); - continue; - } - shader.fogParms.depthForOpaque = atof( token ); - - // skip any old gradient directions - SkipRestOfLine( text ); - continue; - } - // portal - else if ( !Q_stricmp(token, "portal") ) - { - shader.sort = SS_PORTAL; - continue; - } - // skyparms - else if ( !Q_stricmp( token, "skyparms" ) ) - { - ParseSkyParms( text ); - continue; - } - // light determines flaring in q3map, not needed here - else if ( !Q_stricmp(token, "light") ) - { - (void)COM_ParseExt( text, qfalse ); - continue; - } - // cull - else if ( !Q_stricmp( token, "cull") ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing cull parms in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "none" ) || !Q_stricmp( token, "twosided" ) || !Q_stricmp( token, "disable" ) ) - { - shader.cullType = CT_TWO_SIDED; - } - else if ( !Q_stricmp( token, "back" ) || !Q_stricmp( token, "backside" ) || !Q_stricmp( token, "backsided" ) ) - { - shader.cullType = CT_BACK_SIDED; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: invalid cull parm '%s' in shader '%s'\n", token, shader.name ); - } - continue; - } - // sort - else if ( !Q_stricmp( token, "sort" ) ) - { - ParseSort( text ); - continue; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown general shader parameter '%s' in '%s'\n", token, shader.name ); - return qfalse; - } - } - - // - // ignore shaders that don't have any stages, unless it is a sky or fog - // - if ( s == 0 && !shader.isSky && !(shader.contentFlags & CONTENTS_FOG ) ) { - return qfalse; - } - - shader.explicitlyDefined = qtrue; - - return qtrue; -} - -/* -======================================================================================== - -SHADER OPTIMIZATION AND FOGGING - -======================================================================================== -*/ - -/* -=================== -ComputeStageIteratorFunc - -See if we can use on of the simple fastpath stage functions, -otherwise set to the generic stage function -=================== -*/ -static void ComputeStageIteratorFunc( void ) -{ - shader.optimalStageIteratorFunc = RB_StageIteratorGeneric; - - // - // see if this should go into the sky path - // - if ( shader.isSky ) - { - shader.optimalStageIteratorFunc = RB_StageIteratorSky; - return; - } - - if ( r_ignoreFastPath->integer ) - { - return; - } - - // - // see if this can go into the vertex lit fast path - // - if ( shader.numUnfoggedPasses == 1 ) - { - if ( stages[0].rgbGen == CGEN_LIGHTING_DIFFUSE ) - { - if ( stages[0].alphaGen == AGEN_IDENTITY ) - { - if ( stages[0].bundle[0].tcGen == TCGEN_TEXTURE ) - { - if ( !shader.polygonOffset ) - { - if ( !shader.multitextureEnv ) - { - if ( !shader.numDeforms ) - { - shader.optimalStageIteratorFunc = RB_StageIteratorVertexLitTexture; - return; - } - } - } - } - } - } - } - - // - // see if this can go into an optimized LM, multitextured path - // - if ( shader.numUnfoggedPasses == 1 ) - { - if ( ( stages[0].rgbGen == CGEN_IDENTITY ) && ( stages[0].alphaGen == AGEN_IDENTITY ) ) - { - if ( stages[0].bundle[0].tcGen == TCGEN_TEXTURE && - stages[0].bundle[1].tcGen == TCGEN_LIGHTMAP ) - { - if ( !shader.polygonOffset ) - { - if ( !shader.numDeforms ) - { - if ( shader.multitextureEnv ) - { - shader.optimalStageIteratorFunc = RB_StageIteratorLightmappedMultitexture; - } - } - } - } - } - } -} - -typedef struct { - int blendA; - int blendB; - - int multitextureEnv; - int multitextureBlend; -} collapse_t; - -static collapse_t collapse[] = { - { 0, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, - GL_MODULATE, 0 }, - - { 0, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, - GL_MODULATE, 0 }, - - { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, - GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, - - { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, - GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, - - { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, - GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, - - { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, - GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, - - { 0, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, - GL_ADD, 0 }, - - { GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, - GL_ADD, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE }, -#if 0 - { 0, GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_SRCBLEND_SRC_ALPHA, - GL_DECAL, 0 }, -#endif - { -1 } -}; - -/* -================ -CollapseMultitexture - -Attempt to combine two stages into a single multitexture stage -FIXME: I think modulated add + modulated add collapses incorrectly -================= -*/ -static qboolean CollapseMultitexture( void ) { - int abits, bbits; - int i; - textureBundle_t tmpBundle; - - if ( !qglActiveTextureARB ) { - return qfalse; - } - - // make sure both stages are active - if ( !stages[0].active || !stages[1].active ) { - return qfalse; - } - - // on voodoo2, don't combine different tmus - if ( glConfig.driverType == GLDRV_VOODOO ) { - if ( stages[0].bundle[0].image[0]->TMU == - stages[1].bundle[0].image[0]->TMU ) { - return qfalse; - } - } - - abits = stages[0].stateBits; - bbits = stages[1].stateBits; - - // make sure that both stages have identical state other than blend modes - if ( ( abits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) != - ( bbits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) ) { - return qfalse; - } - - abits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - bbits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - - // search for a valid multitexture blend function - for ( i = 0; collapse[i].blendA != -1 ; i++ ) { - if ( abits == collapse[i].blendA - && bbits == collapse[i].blendB ) { - break; - } - } - - // nothing found - if ( collapse[i].blendA == -1 ) { - return qfalse; - } - - // GL_ADD is a separate extension - if ( collapse[i].multitextureEnv == GL_ADD && !glConfig.textureEnvAddAvailable ) { - return qfalse; - } - - // make sure waveforms have identical parameters - if ( ( stages[0].rgbGen != stages[1].rgbGen ) || - ( stages[0].alphaGen != stages[1].alphaGen ) ) { - return qfalse; - } - - // an add collapse can only have identity colors - if ( collapse[i].multitextureEnv == GL_ADD && stages[0].rgbGen != CGEN_IDENTITY ) { - return qfalse; - } - - if ( stages[0].rgbGen == CGEN_WAVEFORM ) - { - if ( memcmp( &stages[0].rgbWave, - &stages[1].rgbWave, - sizeof( stages[0].rgbWave ) ) ) - { - return qfalse; - } - } - if ( stages[0].alphaGen == AGEN_WAVEFORM ) - { - if ( memcmp( &stages[0].alphaWave, - &stages[1].alphaWave, - sizeof( stages[0].alphaWave ) ) ) - { - return qfalse; - } - } - - - // make sure that lightmaps are in bundle 1 for 3dfx - if ( stages[0].bundle[0].isLightmap ) - { - tmpBundle = stages[0].bundle[0]; - stages[0].bundle[0] = stages[1].bundle[0]; - stages[0].bundle[1] = tmpBundle; - } - else - { - stages[0].bundle[1] = stages[1].bundle[0]; - } - - // set the new blend state bits - shader.multitextureEnv = collapse[i].multitextureEnv; - stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - stages[0].stateBits |= collapse[i].multitextureBlend; - - // - // move down subsequent shaders - // - memmove( &stages[1], &stages[2], sizeof( stages[0] ) * ( MAX_SHADER_STAGES - 2 ) ); - Com_Memset( &stages[MAX_SHADER_STAGES-1], 0, sizeof( stages[0] ) ); - - return qtrue; -} - -/* -============= - -FixRenderCommandList -https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493 -Arnout: this is a nasty issue. Shaders can be registered after drawsurfaces are generated -but before the frame is rendered. This will, for the duration of one frame, cause drawsurfaces -to be rendered with bad shaders. To fix this, need to go through all render commands and fix -sortedIndex. -============== -*/ -static void FixRenderCommandList( int newShader ) { - renderCommandList_t *cmdList = &backEndData->commands; - - if( cmdList ) { - const void *curCmd = cmdList->cmds; - - while ( 1 ) { - curCmd = PADP(curCmd, sizeof(void *)); - - switch ( *(const int *)curCmd ) { - case RC_SET_COLOR: - { - const setColorCommand_t *sc_cmd = (const setColorCommand_t *)curCmd; - curCmd = (const void *)(sc_cmd + 1); - break; - } - case RC_STRETCH_PIC: - { - const stretchPicCommand_t *sp_cmd = (const stretchPicCommand_t *)curCmd; - curCmd = (const void *)(sp_cmd + 1); - break; - } - case RC_DRAW_SURFS: - { - int i; - drawSurf_t *drawSurf; - shader_t *shader; - int fogNum; - int entityNum; - int dlightMap; - int sortedIndex; - const drawSurfsCommand_t *ds_cmd = (const drawSurfsCommand_t *)curCmd; - - for( i = 0, drawSurf = ds_cmd->drawSurfs; i < ds_cmd->numDrawSurfs; i++, drawSurf++ ) { - R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlightMap ); - sortedIndex = (( drawSurf->sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1)); - if( sortedIndex >= newShader ) { - sortedIndex++; - drawSurf->sort = (sortedIndex << QSORT_SHADERNUM_SHIFT) | entityNum | ( fogNum << QSORT_FOGNUM_SHIFT ) | (int)dlightMap; - } - } - curCmd = (const void *)(ds_cmd + 1); - break; - } - case RC_DRAW_BUFFER: - { - const drawBufferCommand_t *db_cmd = (const drawBufferCommand_t *)curCmd; - curCmd = (const void *)(db_cmd + 1); - break; - } - case RC_SWAP_BUFFERS: - { - const swapBuffersCommand_t *sb_cmd = (const swapBuffersCommand_t *)curCmd; - curCmd = (const void *)(sb_cmd + 1); - break; - } - case RC_END_OF_LIST: - default: - return; - } - } - } -} - -/* -============== -SortNewShader - -Positions the most recently created shader in the tr.sortedShaders[] -array so that the shader->sort key is sorted relative to the other -shaders. - -Sets shader->sortedIndex -============== -*/ -static void SortNewShader( void ) { - int i; - float sort; - shader_t *newShader; - - newShader = tr.shaders[ tr.numShaders - 1 ]; - sort = newShader->sort; - - for ( i = tr.numShaders - 2 ; i >= 0 ; i-- ) { - if ( tr.sortedShaders[ i ]->sort <= sort ) { - break; - } - tr.sortedShaders[i+1] = tr.sortedShaders[i]; - tr.sortedShaders[i+1]->sortedIndex++; - } - - // Arnout: fix rendercommandlist - // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493 - FixRenderCommandList( i+1 ); - - newShader->sortedIndex = i+1; - tr.sortedShaders[i+1] = newShader; -} - - -/* -==================== -GeneratePermanentShader -==================== -*/ -static shader_t *GeneratePermanentShader( void ) { - shader_t *newShader; - int i, b; - int size, hash; - - if ( tr.numShaders == MAX_SHADERS ) { - ri.Printf( PRINT_WARNING, "WARNING: GeneratePermanentShader - MAX_SHADERS hit\n"); - return tr.defaultShader; - } - - newShader = ri.Hunk_Alloc( sizeof( shader_t ), h_low ); - - *newShader = shader; - - if ( shader.sort <= SS_OPAQUE ) { - newShader->fogPass = FP_EQUAL; - } else if ( shader.contentFlags & CONTENTS_FOG ) { - newShader->fogPass = FP_LE; - } - - tr.shaders[ tr.numShaders ] = newShader; - newShader->index = tr.numShaders; - - tr.sortedShaders[ tr.numShaders ] = newShader; - newShader->sortedIndex = tr.numShaders; - - tr.numShaders++; - - for ( i = 0 ; i < newShader->numUnfoggedPasses ; i++ ) { - if ( !stages[i].active ) { - break; - } - newShader->stages[i] = ri.Hunk_Alloc( sizeof( stages[i] ), h_low ); - *newShader->stages[i] = stages[i]; - - for ( b = 0 ; b < NUM_TEXTURE_BUNDLES ; b++ ) { - size = newShader->stages[i]->bundle[b].numTexMods * sizeof( texModInfo_t ); - newShader->stages[i]->bundle[b].texMods = ri.Hunk_Alloc( size, h_low ); - Com_Memcpy( newShader->stages[i]->bundle[b].texMods, stages[i].bundle[b].texMods, size ); - } - } - - SortNewShader(); - - hash = generateHashValue(newShader->name, FILE_HASH_SIZE); - newShader->next = hashTable[hash]; - hashTable[hash] = newShader; - - return newShader; -} - -/* -================= -VertexLightingCollapse - -If vertex lighting is enabled, only render a single -pass, trying to guess which is the correct one to best aproximate -what it is supposed to look like. -================= -*/ -static void VertexLightingCollapse( void ) { - int stage; - shaderStage_t *bestStage; - int bestImageRank; - int rank; - - // if we aren't opaque, just use the first pass - if ( shader.sort == SS_OPAQUE ) { - - // pick the best texture for the single pass - bestStage = &stages[0]; - bestImageRank = -999999; - - for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) { - shaderStage_t *pStage = &stages[stage]; - - if ( !pStage->active ) { - break; - } - rank = 0; - - if ( pStage->bundle[0].isLightmap ) { - rank -= 100; - } - if ( pStage->bundle[0].tcGen != TCGEN_TEXTURE ) { - rank -= 5; - } - if ( pStage->bundle[0].numTexMods ) { - rank -= 5; - } - if ( pStage->rgbGen != CGEN_IDENTITY && pStage->rgbGen != CGEN_IDENTITY_LIGHTING ) { - rank -= 3; - } - - if ( rank > bestImageRank ) { - bestImageRank = rank; - bestStage = pStage; - } - } - - stages[0].bundle[0] = bestStage->bundle[0]; - stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - stages[0].stateBits |= GLS_DEPTHMASK_TRUE; - if ( shader.lightmapIndex == LIGHTMAP_NONE ) { - stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE; - } else { - stages[0].rgbGen = CGEN_EXACT_VERTEX; - } - stages[0].alphaGen = AGEN_SKIP; - } else { - // don't use a lightmap (tesla coils) - if ( stages[0].bundle[0].isLightmap ) { - stages[0] = stages[1]; - } - - // if we were in a cross-fade cgen, hack it to normal - if ( stages[0].rgbGen == CGEN_ONE_MINUS_ENTITY || stages[1].rgbGen == CGEN_ONE_MINUS_ENTITY ) { - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - } - if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_SAWTOOTH ) - && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_INVERSE_SAWTOOTH ) ) { - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - } - if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_INVERSE_SAWTOOTH ) - && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_SAWTOOTH ) ) { - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - } - } - - for ( stage = 1; stage < MAX_SHADER_STAGES; stage++ ) { - shaderStage_t *pStage = &stages[stage]; - - if ( !pStage->active ) { - break; - } - - Com_Memset( pStage, 0, sizeof( *pStage ) ); - } -} - -/* -========================= -FinishShader - -Returns a freshly allocated shader with all the needed info -from the current global working shader -========================= -*/ -static shader_t *FinishShader( void ) { - int stage; - qboolean hasLightmapStage; - qboolean vertexLightmap; - - hasLightmapStage = qfalse; - vertexLightmap = qfalse; - - // - // set sky stuff appropriate - // - if ( shader.isSky ) { - shader.sort = SS_ENVIRONMENT; - } - - // - // set polygon offset - // - if ( shader.polygonOffset && !shader.sort ) { - shader.sort = SS_DECAL; - } - - // - // set appropriate stage information - // - for ( stage = 0; stage < MAX_SHADER_STAGES; ) { - shaderStage_t *pStage = &stages[stage]; - - if ( !pStage->active ) { - break; - } - - // check for a missing texture - if ( !pStage->bundle[0].image[0] ) { - ri.Printf( PRINT_WARNING, "Shader %s has a stage with no image\n", shader.name ); - pStage->active = qfalse; - stage++; - continue; - } - - // - // ditch this stage if it's detail and detail textures are disabled - // - if ( pStage->isDetail && !r_detailTextures->integer ) - { - int index; - - for(index = stage + 1; index < MAX_SHADER_STAGES; index++) - { - if(!stages[index].active) - break; - } - - if(index < MAX_SHADER_STAGES) - memmove(pStage, pStage + 1, sizeof(*pStage) * (index - stage)); - else - { - if(stage + 1 < MAX_SHADER_STAGES) - memmove(pStage, pStage + 1, sizeof(*pStage) * (index - stage - 1)); - - Com_Memset(&stages[index - 1], 0, sizeof(*stages)); - } - - continue; - } - - // - // default texture coordinate generation - // - if ( pStage->bundle[0].isLightmap ) { - if ( pStage->bundle[0].tcGen == TCGEN_BAD ) { - pStage->bundle[0].tcGen = TCGEN_LIGHTMAP; - } - hasLightmapStage = qtrue; - } else { - if ( pStage->bundle[0].tcGen == TCGEN_BAD ) { - pStage->bundle[0].tcGen = TCGEN_TEXTURE; - } - } - - - // not a true lightmap but we want to leave existing - // behaviour in place and not print out a warning - //if (pStage->rgbGen == CGEN_VERTEX) { - // vertexLightmap = qtrue; - //} - - - - // - // determine sort order and fog color adjustment - // - if ( ( pStage->stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) && - ( stages[0].stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) ) { - int blendSrcBits = pStage->stateBits & GLS_SRCBLEND_BITS; - int blendDstBits = pStage->stateBits & GLS_DSTBLEND_BITS; - - // fog color adjustment only works for blend modes that have a contribution - // that aproaches 0 as the modulate values aproach 0 -- - // GL_ONE, GL_ONE - // GL_ZERO, GL_ONE_MINUS_SRC_COLOR - // GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA - - // modulate, additive - if ( ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE ) ) || - ( ( blendSrcBits == GLS_SRCBLEND_ZERO ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR ) ) ) { - pStage->adjustColorsForFog = ACFF_MODULATE_RGB; - } - // strict blend - else if ( ( blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) ) - { - pStage->adjustColorsForFog = ACFF_MODULATE_ALPHA; - } - // premultiplied alpha - else if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) ) - { - pStage->adjustColorsForFog = ACFF_MODULATE_RGBA; - } else { - // we can't adjust this one correctly, so it won't be exactly correct in fog - } - - // don't screw with sort order if this is a portal or environment - if ( !shader.sort ) { - // see through item, like a grill or grate - if ( pStage->stateBits & GLS_DEPTHMASK_TRUE ) { - shader.sort = SS_SEE_THROUGH; - } else { - shader.sort = SS_BLEND0; - } - } - } - - stage++; - } - - // there are times when you will need to manually apply a sort to - // opaque alpha tested shaders that have later blend passes - if ( !shader.sort ) { - shader.sort = SS_OPAQUE; - } - - // - // if we are in r_vertexLight mode, never use a lightmap texture - // - if ( stage > 1 && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) ) { - VertexLightingCollapse(); - stage = 1; - hasLightmapStage = qfalse; - } - - // - // look for multitexture potential - // - if ( stage > 1 && CollapseMultitexture() ) { - stage--; - } - - if ( shader.lightmapIndex >= 0 && !hasLightmapStage ) { - if (vertexLightmap) { - ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has VERTEX forced lightmap!\n", shader.name ); - } else { - ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has lightmap but no lightmap stage!\n", shader.name ); - shader.lightmapIndex = LIGHTMAP_NONE; - } - } - - - // - // compute number of passes - // - shader.numUnfoggedPasses = stage; - - // fogonly shaders don't have any normal passes - if (stage == 0 && !shader.isSky) - shader.sort = SS_FOG; - - // determine which stage iterator function is appropriate - ComputeStageIteratorFunc(); - - return GeneratePermanentShader(); -} - -//======================================================================================== - -/* -==================== -FindShaderInShaderText - -Scans the combined text description of all the shader files for -the given shader name. - -return NULL if not found - -If found, it will return a valid shader -===================== -*/ -static char *FindShaderInShaderText( const char *shadername ) { - - char *token, *p; - - int i, hash; - - hash = generateHashValue(shadername, MAX_SHADERTEXT_HASH); - - if(shaderTextHashTable[hash]) - { - for (i = 0; shaderTextHashTable[hash][i]; i++) - { - p = shaderTextHashTable[hash][i]; - token = COM_ParseExt(&p, qtrue); - - if(!Q_stricmp(token, shadername)) - return p; - } - } - - p = s_shaderText; - - if ( !p ) { - return NULL; - } - - // look for label - while ( 1 ) { - token = COM_ParseExt( &p, qtrue ); - if ( token[0] == 0 ) { - break; - } - - if ( !Q_stricmp( token, shadername ) ) { - return p; - } - else { - // skip the definition - SkipBracedSection( &p, 0 ); - } - } - - return NULL; -} - - -/* -================== -R_FindShaderByName - -Will always return a valid shader, but it might be the -default shader if the real one can't be found. -================== -*/ -shader_t *R_FindShaderByName( const char *name ) { - char strippedName[MAX_QPATH]; - int hash; - shader_t *sh; - - if ( (name==NULL) || (name[0] == 0) ) { - return tr.defaultShader; - } - - COM_StripExtension(name, strippedName, sizeof(strippedName)); - - hash = generateHashValue(strippedName, FILE_HASH_SIZE); - - // - // see if the shader is already loaded - // - for (sh=hashTable[hash]; sh; sh=sh->next) { - // NOTE: if there was no shader or image available with the name strippedName - // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we - // have to check all default shaders otherwise for every call to R_FindShader - // with that same strippedName a new default shader is created. - if (Q_stricmp(sh->name, strippedName) == 0) { - // match found - return sh; - } - } - - return tr.defaultShader; -} - - -/* -=============== -R_FindShader - -Will always return a valid shader, but it might be the -default shader if the real one can't be found. - -In the interest of not requiring an explicit shader text entry to -be defined for every single image used in the game, three default -shader behaviors can be auto-created for any image: - -If lightmapIndex == LIGHTMAP_NONE, then the image will have -dynamic diffuse lighting applied to it, as apropriate for most -entity skin surfaces. - -If lightmapIndex == LIGHTMAP_2D, then the image will be used -for 2D rendering unless an explicit shader is found - -If lightmapIndex == LIGHTMAP_BY_VERTEX, then the image will use -the vertex rgba modulate values, as apropriate for misc_model -pre-lit surfaces. - -Other lightmapIndex values will have a lightmap stage created -and src*dest blending applied with the texture, as apropriate for -most world construction surfaces. - -=============== -*/ -shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ) { - char strippedName[MAX_QPATH]; - int i, hash; - char *shaderText; - image_t *image; - shader_t *sh; - - if ( name[0] == 0 ) { - return tr.defaultShader; - } - - // use (fullbright) vertex lighting if the bsp file doesn't have - // lightmaps - if ( lightmapIndex >= 0 && lightmapIndex >= tr.numLightmaps ) { - lightmapIndex = LIGHTMAP_BY_VERTEX; - } else if ( lightmapIndex < LIGHTMAP_2D ) { - // negative lightmap indexes cause stray pointers (think tr.lightmaps[lightmapIndex]) - ri.Printf( PRINT_WARNING, "WARNING: shader '%s' has invalid lightmap index of %d\n", name, lightmapIndex ); - lightmapIndex = LIGHTMAP_BY_VERTEX; - } - - COM_StripExtension(name, strippedName, sizeof(strippedName)); - - hash = generateHashValue(strippedName, FILE_HASH_SIZE); - - // - // see if the shader is already loaded - // - for (sh = hashTable[hash]; sh; sh = sh->next) { - // NOTE: if there was no shader or image available with the name strippedName - // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we - // have to check all default shaders otherwise for every call to R_FindShader - // with that same strippedName a new default shader is created. - if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) && - !Q_stricmp(sh->name, strippedName)) { - // match found - return sh; - } - } - - // clear the global shader - Com_Memset( &shader, 0, sizeof( shader ) ); - Com_Memset( &stages, 0, sizeof( stages ) ); - Q_strncpyz(shader.name, strippedName, sizeof(shader.name)); - shader.lightmapIndex = lightmapIndex; - for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) { - stages[i].bundle[0].texMods = texMods[i]; - } - - // FIXME: set these "need" values apropriately - shader.needsNormal = qtrue; - shader.needsST1 = qtrue; - shader.needsST2 = qtrue; - shader.needsColor = qtrue; - - // - // attempt to define shader from an explicit parameter file - // - shaderText = FindShaderInShaderText( strippedName ); - if ( shaderText ) { - // enable this when building a pak file to get a global list - // of all explicit shaders - if ( r_printShaders->integer ) { - ri.Printf( PRINT_ALL, "*SHADER* %s\n", name ); - } - - if ( !ParseShader( &shaderText ) ) { - // had errors, so use default shader - shader.defaultShader = qtrue; - } - sh = FinishShader(); - return sh; - } - - - // - // if not defined in the in-memory shader descriptions, - // look for a single supported image file - // - { - imgFlags_t flags; - - flags = IMGFLAG_NONE; - - if (mipRawImage) - { - flags |= IMGFLAG_MIPMAP | IMGFLAG_PICMIP; - } - else - { - flags |= IMGFLAG_CLAMPTOEDGE; - } - - image = R_FindImageFile( name, IMGTYPE_COLORALPHA, flags ); - if ( !image ) { - ri.Printf( PRINT_DEVELOPER, "Couldn't find image file for shader %s\n", name ); - shader.defaultShader = qtrue; - return FinishShader(); - } - } - - // - // create the default shading commands - // - if ( shader.lightmapIndex == LIGHTMAP_NONE ) { - // dynamic colors at vertexes - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE; - stages[0].stateBits = GLS_DEFAULT; - } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) { - // explicit colors at vertexes - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_EXACT_VERTEX; - stages[0].alphaGen = AGEN_SKIP; - stages[0].stateBits = GLS_DEFAULT; - } else if ( shader.lightmapIndex == LIGHTMAP_2D ) { - // GUI elements - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_VERTEX; - stages[0].alphaGen = AGEN_VERTEX; - stages[0].stateBits = GLS_DEPTHTEST_DISABLE | - GLS_SRCBLEND_SRC_ALPHA | - GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) { - // fullbright level - stages[0].bundle[0].image[0] = tr.whiteImage; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - stages[0].stateBits = GLS_DEFAULT; - - stages[1].bundle[0].image[0] = image; - stages[1].active = qtrue; - stages[1].rgbGen = CGEN_IDENTITY; - stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; - } else { - // two pass lightmap - stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; - stages[0].bundle[0].isLightmap = qtrue; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation - // for identitylight - stages[0].stateBits = GLS_DEFAULT; - - stages[1].bundle[0].image[0] = image; - stages[1].active = qtrue; - stages[1].rgbGen = CGEN_IDENTITY; - stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; - } - - return FinishShader(); -} - - -qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage) { - int i, hash; - shader_t *sh; - - hash = generateHashValue(name, FILE_HASH_SIZE); - - // probably not necessary since this function - // only gets called from tr_font.c with lightmapIndex == LIGHTMAP_2D - // but better safe than sorry. - if ( lightmapIndex >= tr.numLightmaps ) { - lightmapIndex = LIGHTMAP_WHITEIMAGE; - } - - // - // see if the shader is already loaded - // - for (sh=hashTable[hash]; sh; sh=sh->next) { - // NOTE: if there was no shader or image available with the name strippedName - // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we - // have to check all default shaders otherwise for every call to R_FindShader - // with that same strippedName a new default shader is created. - if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) && - // index by name - !Q_stricmp(sh->name, name)) { - // match found - return sh->index; - } - } - - // clear the global shader - Com_Memset( &shader, 0, sizeof( shader ) ); - Com_Memset( &stages, 0, sizeof( stages ) ); - Q_strncpyz(shader.name, name, sizeof(shader.name)); - shader.lightmapIndex = lightmapIndex; - for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) { - stages[i].bundle[0].texMods = texMods[i]; - } - - // FIXME: set these "need" values apropriately - shader.needsNormal = qtrue; - shader.needsST1 = qtrue; - shader.needsST2 = qtrue; - shader.needsColor = qtrue; - - // - // create the default shading commands - // - if ( shader.lightmapIndex == LIGHTMAP_NONE ) { - // dynamic colors at vertexes - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE; - stages[0].stateBits = GLS_DEFAULT; - } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) { - // explicit colors at vertexes - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_EXACT_VERTEX; - stages[0].alphaGen = AGEN_SKIP; - stages[0].stateBits = GLS_DEFAULT; - } else if ( shader.lightmapIndex == LIGHTMAP_2D ) { - // GUI elements - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_VERTEX; - stages[0].alphaGen = AGEN_VERTEX; - stages[0].stateBits = GLS_DEPTHTEST_DISABLE | - GLS_SRCBLEND_SRC_ALPHA | - GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) { - // fullbright level - stages[0].bundle[0].image[0] = tr.whiteImage; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - stages[0].stateBits = GLS_DEFAULT; - - stages[1].bundle[0].image[0] = image; - stages[1].active = qtrue; - stages[1].rgbGen = CGEN_IDENTITY; - stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; - } else { - // two pass lightmap - stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; - stages[0].bundle[0].isLightmap = qtrue; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation - // for identitylight - stages[0].stateBits = GLS_DEFAULT; - - stages[1].bundle[0].image[0] = image; - stages[1].active = qtrue; - stages[1].rgbGen = CGEN_IDENTITY; - stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; - } - - sh = FinishShader(); - return sh->index; -} - - -/* -==================== -RE_RegisterShader - -This is the exported shader entry point for the rest of the system -It will always return an index that will be valid. - -This should really only be used for explicit shaders, because there is no -way to ask for different implicit lighting modes (vertex, lightmap, etc) -==================== -*/ -qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex ) { - shader_t *sh; - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" ); - return 0; - } - - sh = R_FindShader( name, lightmapIndex, qtrue ); - - // we want to return 0 if the shader failed to - // load for some reason, but R_FindShader should - // still keep a name allocated for it, so if - // something calls RE_RegisterShader again with - // the same name, we don't try looking for it again - if ( sh->defaultShader ) { - return 0; - } - - return sh->index; -} - - -/* -==================== -RE_RegisterShader - -This is the exported shader entry point for the rest of the system -It will always return an index that will be valid. - -This should really only be used for explicit shaders, because there is no -way to ask for different implicit lighting modes (vertex, lightmap, etc) -==================== -*/ -qhandle_t RE_RegisterShader( const char *name ) { - shader_t *sh; - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" ); - return 0; - } - - sh = R_FindShader( name, LIGHTMAP_2D, qtrue ); - - // we want to return 0 if the shader failed to - // load for some reason, but R_FindShader should - // still keep a name allocated for it, so if - // something calls RE_RegisterShader again with - // the same name, we don't try looking for it again - if ( sh->defaultShader ) { - return 0; - } - - return sh->index; -} - - -/* -==================== -RE_RegisterShaderNoMip - -For menu graphics that should never be picmiped -==================== -*/ -qhandle_t RE_RegisterShaderNoMip( const char *name ) { - shader_t *sh; - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" ); - return 0; - } - - sh = R_FindShader( name, LIGHTMAP_2D, qfalse ); - - // we want to return 0 if the shader failed to - // load for some reason, but R_FindShader should - // still keep a name allocated for it, so if - // something calls RE_RegisterShader again with - // the same name, we don't try looking for it again - if ( sh->defaultShader ) { - return 0; - } - - return sh->index; -} - -/* -==================== -R_GetShaderByHandle - -When a handle is passed in by another module, this range checks -it and returns a valid (possibly default) shader_t to be used internally. -==================== -*/ -shader_t *R_GetShaderByHandle( qhandle_t hShader ) { - if ( hShader < 0 ) { - ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader ); - return tr.defaultShader; - } - if ( hShader >= tr.numShaders ) { - ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader ); - return tr.defaultShader; - } - return tr.shaders[hShader]; -} - -/* -=============== -R_ShaderList_f - -Dump information on all valid shaders to the console -A second parameter will cause it to print in sorted order -=============== -*/ -void R_ShaderList_f (void) { - int i; - int count; - shader_t *shader; - - ri.Printf (PRINT_ALL, "-----------------------\n"); - - count = 0; - for ( i = 0 ; i < tr.numShaders ; i++ ) { - if ( ri.Cmd_Argc() > 1 ) { - shader = tr.sortedShaders[i]; - } else { - shader = tr.shaders[i]; - } - - ri.Printf( PRINT_ALL, "%i ", shader->numUnfoggedPasses ); - - if (shader->lightmapIndex >= 0 ) { - ri.Printf (PRINT_ALL, "L "); - } else { - ri.Printf (PRINT_ALL, " "); - } - if ( shader->multitextureEnv == GL_ADD ) { - ri.Printf( PRINT_ALL, "MT(a) " ); - } else if ( shader->multitextureEnv == GL_MODULATE ) { - ri.Printf( PRINT_ALL, "MT(m) " ); - } else if ( shader->multitextureEnv == GL_DECAL ) { - ri.Printf( PRINT_ALL, "MT(d) " ); - } else { - ri.Printf( PRINT_ALL, " " ); - } - if ( shader->explicitlyDefined ) { - ri.Printf( PRINT_ALL, "E " ); - } else { - ri.Printf( PRINT_ALL, " " ); - } - - if ( shader->optimalStageIteratorFunc == RB_StageIteratorGeneric ) { - ri.Printf( PRINT_ALL, "gen " ); - } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorSky ) { - ri.Printf( PRINT_ALL, "sky " ); - } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorLightmappedMultitexture ) { - ri.Printf( PRINT_ALL, "lmmt" ); - } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorVertexLitTexture ) { - ri.Printf( PRINT_ALL, "vlt " ); - } else { - ri.Printf( PRINT_ALL, " " ); - } - - if ( shader->defaultShader ) { - ri.Printf (PRINT_ALL, ": %s (DEFAULTED)\n", shader->name); - } else { - ri.Printf (PRINT_ALL, ": %s\n", shader->name); - } - count++; - } - ri.Printf (PRINT_ALL, "%i total shaders\n", count); - ri.Printf (PRINT_ALL, "------------------\n"); -} - -/* -==================== -ScanAndLoadShaderFiles - -Finds and loads all .shader files, combining them into -a single large text block that can be scanned for shader names -===================== -*/ -#define MAX_SHADER_FILES 4096 -static void ScanAndLoadShaderFiles( void ) -{ - char **shaderFiles; - char *buffers[MAX_SHADER_FILES]; - char *p; - int numShaderFiles; - int i; - char *oldp, *token, *hashMem, *textEnd; - int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size; - char shaderName[MAX_QPATH]; - int shaderLine; - - long sum = 0, summand; - // scan for shader files - shaderFiles = ri.FS_ListFiles( "scripts", ".shader", &numShaderFiles ); - - if ( !shaderFiles || !numShaderFiles ) - { - ri.Printf( PRINT_WARNING, "WARNING: no shader files found\n" ); - return; - } - - if ( numShaderFiles > MAX_SHADER_FILES ) { - numShaderFiles = MAX_SHADER_FILES; - } - - // load and parse shader files - for ( i = 0; i < numShaderFiles; i++ ) - { - char filename[MAX_QPATH]; - - Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] ); - ri.Printf( PRINT_DEVELOPER, "...loading '%s'\n", filename ); - summand = ri.FS_ReadFile( filename, (void **)&buffers[i] ); - - if ( !buffers[i] ) - ri.Error( ERR_DROP, "Couldn't load %s", filename ); - - // Do a simple check on the shader structure in that file to make sure one bad shader file cannot fuck up all other shaders. - p = buffers[i]; - COM_BeginParseSession(filename); - while(1) - { - token = COM_ParseExt(&p, qtrue); - - if(!*token) - break; - - Q_strncpyz(shaderName, token, sizeof(shaderName)); - shaderLine = COM_GetCurrentParseLine(); - - token = COM_ParseExt(&p, qtrue); - if(token[0] != '{' || token[1] != '\0') - { - ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing opening brace", - filename, shaderName, shaderLine); - if (token[0]) - { - ri.Printf(PRINT_WARNING, " (found \"%s\" on line %d)", token, COM_GetCurrentParseLine()); - } - ri.Printf(PRINT_WARNING, ".\n"); - ri.FS_FreeFile(buffers[i]); - buffers[i] = NULL; - break; - } - - if(!SkipBracedSection(&p, 1)) - { - ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing closing brace.\n", - filename, shaderName, shaderLine); - ri.FS_FreeFile(buffers[i]); - buffers[i] = NULL; - break; - } - } - - - if (buffers[i]) - sum += summand; - } - - // build single large buffer - s_shaderText = ri.Hunk_Alloc( sum + numShaderFiles*2, h_low ); - s_shaderText[ 0 ] = '\0'; - textEnd = s_shaderText; - - // free in reverse order, so the temp files are all dumped - for ( i = numShaderFiles - 1; i >= 0 ; i-- ) - { - if ( !buffers[i] ) - continue; - - strcat( textEnd, buffers[i] ); - strcat( textEnd, "\n" ); - textEnd += strlen( textEnd ); - ri.FS_FreeFile( buffers[i] ); - } - - COM_Compress( s_shaderText ); - - // free up memory - ri.FS_FreeFileList( shaderFiles ); - - Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes)); - size = 0; - - p = s_shaderText; - // look for shader names - while ( 1 ) { - token = COM_ParseExt( &p, qtrue ); - if ( token[0] == 0 ) { - break; - } - - hash = generateHashValue(token, MAX_SHADERTEXT_HASH); - shaderTextHashTableSizes[hash]++; - size++; - SkipBracedSection(&p, 0); - } - - size += MAX_SHADERTEXT_HASH; - - hashMem = ri.Hunk_Alloc( size * sizeof(char *), h_low ); - - for (i = 0; i < MAX_SHADERTEXT_HASH; i++) { - shaderTextHashTable[i] = (char **) hashMem; - hashMem = ((char *) hashMem) + ((shaderTextHashTableSizes[i] + 1) * sizeof(char *)); - } - - Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes)); - - p = s_shaderText; - // look for shader names - while ( 1 ) { - oldp = p; - token = COM_ParseExt( &p, qtrue ); - if ( token[0] == 0 ) { - break; - } - - hash = generateHashValue(token, MAX_SHADERTEXT_HASH); - shaderTextHashTable[hash][shaderTextHashTableSizes[hash]++] = oldp; - - SkipBracedSection(&p, 0); - } - - return; - -} - - -/* -==================== -CreateInternalShaders -==================== -*/ -static void CreateInternalShaders( void ) { - tr.numShaders = 0; - - // init the default shader - Com_Memset( &shader, 0, sizeof( shader ) ); - Com_Memset( &stages, 0, sizeof( stages ) ); - - Q_strncpyz( shader.name, "", sizeof( shader.name ) ); - - shader.lightmapIndex = LIGHTMAP_NONE; - stages[0].bundle[0].image[0] = tr.defaultImage; - stages[0].active = qtrue; - stages[0].stateBits = GLS_DEFAULT; - tr.defaultShader = FinishShader(); - - // shadow shader is just a marker - Q_strncpyz( shader.name, "", sizeof( shader.name ) ); - shader.sort = SS_STENCIL_SHADOW; - tr.shadowShader = FinishShader(); -} - -static void CreateExternalShaders( void ) { - tr.projectionShadowShader = R_FindShader( "projectionShadow", LIGHTMAP_NONE, qtrue ); - tr.flareShader = R_FindShader( "flareShader", LIGHTMAP_NONE, qtrue ); - - // Hack to make fogging work correctly on flares. Fog colors are calculated - // in tr_flare.c already. - if(!tr.flareShader->defaultShader) - { - int index; - - for(index = 0; index < tr.flareShader->numUnfoggedPasses; index++) - { - tr.flareShader->stages[index]->adjustColorsForFog = ACFF_NONE; - tr.flareShader->stages[index]->stateBits |= GLS_DEPTHTEST_DISABLE; - } - } - - tr.sunShader = R_FindShader( "sun", LIGHTMAP_NONE, qtrue ); -} - -/* -================== -R_InitShaders -================== -*/ -void R_InitShaders( void ) { - ri.Printf( PRINT_ALL, "Initializing Shaders\n" ); - - Com_Memset(hashTable, 0, sizeof(hashTable)); - - CreateInternalShaders(); - - ScanAndLoadShaderFiles(); - - CreateExternalShaders(); -} diff --git a/code/renderergl1/tr_shadows.c b/code/renderergl1/tr_shadows.c deleted file mode 100644 index f412b00d3e..0000000000 --- a/code/renderergl1/tr_shadows.c +++ /dev/null @@ -1,343 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - - -/* - - for a projection shadow: - - point[x] += light vector * ( z - shadow plane ) - point[y] += - point[z] = shadow plane - - 1 0 light[x] / light[z] - -*/ - -typedef struct { - int i2; - int facing; -} edgeDef_t; - -#define MAX_EDGE_DEFS 32 - -static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS]; -static int numEdgeDefs[SHADER_MAX_VERTEXES]; -static int facing[SHADER_MAX_INDEXES/3]; - -void R_AddEdgeDef( int i1, int i2, int facing ) { - int c; - - c = numEdgeDefs[ i1 ]; - if ( c == MAX_EDGE_DEFS ) { - return; // overflow - } - edgeDefs[ i1 ][ c ].i2 = i2; - edgeDefs[ i1 ][ c ].facing = facing; - - numEdgeDefs[ i1 ]++; -} - -void R_RenderShadowEdges( void ) { - int i; - -#if 0 - int numTris; - - // dumb way -- render every triangle's edges - numTris = tess.numIndexes / 3; - - for ( i = 0 ; i < numTris ; i++ ) { - int i1, i2, i3; - - if ( !facing[i] ) { - continue; - } - - i1 = tess.indexes[ i*3 + 0 ]; - i2 = tess.indexes[ i*3 + 1 ]; - i3 = tess.indexes[ i*3 + 2 ]; - - qglBegin( GL_TRIANGLE_STRIP ); - qglVertex3fv( tess.xyz[ i1 ] ); - qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); - qglVertex3fv( tess.xyz[ i2 ] ); - qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); - qglVertex3fv( tess.xyz[ i3 ] ); - qglVertex3fv( tess.xyz[ i3 + tess.numVertexes ] ); - qglVertex3fv( tess.xyz[ i1 ] ); - qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); - qglEnd(); - } -#else - int c, c2; - int j, k; - int i2; - int c_edges, c_rejected; - int hit[2]; - - // an edge is NOT a silhouette edge if its face doesn't face the light, - // or if it has a reverse paired edge that also faces the light. - // A well behaved polyhedron would have exactly two faces for each edge, - // but lots of models have dangling edges or overfanned edges - c_edges = 0; - c_rejected = 0; - - for ( i = 0 ; i < tess.numVertexes ; i++ ) { - c = numEdgeDefs[ i ]; - for ( j = 0 ; j < c ; j++ ) { - if ( !edgeDefs[ i ][ j ].facing ) { - continue; - } - - hit[0] = 0; - hit[1] = 0; - - i2 = edgeDefs[ i ][ j ].i2; - c2 = numEdgeDefs[ i2 ]; - for ( k = 0 ; k < c2 ; k++ ) { - if ( edgeDefs[ i2 ][ k ].i2 == i ) { - hit[ edgeDefs[ i2 ][ k ].facing ]++; - } - } - - // if it doesn't share the edge with another front facing - // triangle, it is a sil edge - if ( hit[ 1 ] == 0 ) { - qglBegin( GL_TRIANGLE_STRIP ); - qglVertex3fv( tess.xyz[ i ] ); - qglVertex3fv( tess.xyz[ i + tess.numVertexes ] ); - qglVertex3fv( tess.xyz[ i2 ] ); - qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); - qglEnd(); - c_edges++; - } else { - c_rejected++; - } - } - } -#endif -} - -/* -================= -RB_ShadowTessEnd - -triangleFromEdge[ v1 ][ v2 ] - - - set triangle from edge( v1, v2, tri ) - if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) { - } -================= -*/ -void RB_ShadowTessEnd( void ) { - int i; - int numTris; - vec3_t lightDir; - GLboolean rgba[4]; - - // we can only do this if we have enough space in the vertex buffers - if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) { - return; - } - - if ( glConfig.stencilBits < 4 ) { - return; - } - - VectorCopy( backEnd.currentEntity->lightDir, lightDir ); - - // project vertexes away from light direction - for ( i = 0 ; i < tess.numVertexes ; i++ ) { - VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] ); - } - - // decide which triangles face the light - Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes ); - - numTris = tess.numIndexes / 3; - for ( i = 0 ; i < numTris ; i++ ) { - int i1, i2, i3; - vec3_t d1, d2, normal; - float *v1, *v2, *v3; - float d; - - i1 = tess.indexes[ i*3 + 0 ]; - i2 = tess.indexes[ i*3 + 1 ]; - i3 = tess.indexes[ i*3 + 2 ]; - - v1 = tess.xyz[ i1 ]; - v2 = tess.xyz[ i2 ]; - v3 = tess.xyz[ i3 ]; - - VectorSubtract( v2, v1, d1 ); - VectorSubtract( v3, v1, d2 ); - CrossProduct( d1, d2, normal ); - - d = DotProduct( normal, lightDir ); - if ( d > 0 ) { - facing[ i ] = 1; - } else { - facing[ i ] = 0; - } - - // create the edges - R_AddEdgeDef( i1, i2, facing[ i ] ); - R_AddEdgeDef( i2, i3, facing[ i ] ); - R_AddEdgeDef( i3, i1, facing[ i ] ); - } - - // draw the silhouette edges - - GL_Bind( tr.whiteImage ); - qglEnable( GL_CULL_FACE ); - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - qglColor3f( 0.2f, 0.2f, 0.2f ); - - // don't write to the color buffer - qglGetBooleanv(GL_COLOR_WRITEMASK, rgba); - qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); - - qglEnable( GL_STENCIL_TEST ); - qglStencilFunc( GL_ALWAYS, 1, 255 ); - - // mirrors have the culling order reversed - if ( backEnd.viewParms.isMirror ) { - qglCullFace( GL_FRONT ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); - - R_RenderShadowEdges(); - - qglCullFace( GL_BACK ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); - - R_RenderShadowEdges(); - } else { - qglCullFace( GL_BACK ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); - - R_RenderShadowEdges(); - - qglCullFace( GL_FRONT ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); - - R_RenderShadowEdges(); - } - - - // reenable writing to the color buffer - qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]); -} - - -/* -================= -RB_ShadowFinish - -Darken everything that is is a shadow volume. -We have to delay this until everything has been shadowed, -because otherwise shadows from different body parts would -overlap and double darken. -================= -*/ -void RB_ShadowFinish( void ) { - if ( r_shadows->integer != 2 ) { - return; - } - if ( glConfig.stencilBits < 4 ) { - return; - } - qglEnable( GL_STENCIL_TEST ); - qglStencilFunc( GL_NOTEQUAL, 0, 255 ); - - qglDisable (GL_CLIP_PLANE0); - qglDisable (GL_CULL_FACE); - - GL_Bind( tr.whiteImage ); - - qglLoadIdentity (); - - qglColor3f( 0.6f, 0.6f, 0.6f ); - GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO ); - -// qglColor3f( 1, 0, 0 ); -// GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - - qglBegin( GL_QUADS ); - qglVertex3f( -100, 100, -10 ); - qglVertex3f( 100, 100, -10 ); - qglVertex3f( 100, -100, -10 ); - qglVertex3f( -100, -100, -10 ); - qglEnd (); - - qglColor4f(1,1,1,1); - qglDisable( GL_STENCIL_TEST ); -} - - -/* -================= -RB_ProjectionShadowDeform - -================= -*/ -void RB_ProjectionShadowDeform( void ) { - float *xyz; - int i; - float h; - vec3_t ground; - vec3_t light; - float groundDist; - float d; - vec3_t lightDir; - - xyz = ( float * ) tess.xyz; - - ground[0] = backEnd.or.axis[0][2]; - ground[1] = backEnd.or.axis[1][2]; - ground[2] = backEnd.or.axis[2][2]; - - groundDist = backEnd.or.origin[2] - backEnd.currentEntity->e.shadowPlane; - - VectorCopy( backEnd.currentEntity->lightDir, lightDir ); - d = DotProduct( lightDir, ground ); - // don't let the shadows get too long or go negative - if ( d < 0.5 ) { - VectorMA( lightDir, (0.5 - d), ground, lightDir ); - d = DotProduct( lightDir, ground ); - } - d = 1.0 / d; - - light[0] = lightDir[0] * d; - light[1] = lightDir[1] * d; - light[2] = lightDir[2] * d; - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) { - h = DotProduct( xyz, ground ) + groundDist; - - xyz[0] -= light[0] * h; - xyz[1] -= light[1] * h; - xyz[2] -= light[2] * h; - } -} diff --git a/code/renderergl1/tr_sky.c b/code/renderergl1/tr_sky.c deleted file mode 100644 index daa5ff12d6..0000000000 --- a/code/renderergl1/tr_sky.c +++ /dev/null @@ -1,794 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_sky.c -#include "tr_local.h" - -#define SKY_SUBDIVISIONS 8 -#define HALF_SKY_SUBDIVISIONS (SKY_SUBDIVISIONS/2) - -static float s_cloudTexCoords[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2]; -static float s_cloudTexP[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1]; - -/* -=================================================================================== - -POLYGON TO BOX SIDE PROJECTION - -=================================================================================== -*/ - -static vec3_t sky_clip[6] = -{ - {1,1,0}, - {1,-1,0}, - {0,-1,1}, - {0,1,1}, - {1,0,1}, - {-1,0,1} -}; - -static float sky_mins[2][6], sky_maxs[2][6]; -static float sky_min, sky_max; - -/* -================ -AddSkyPolygon -================ -*/ -static void AddSkyPolygon (int nump, vec3_t vecs) -{ - int i,j; - vec3_t v, av; - float s, t, dv; - int axis; - float *vp; - // s = [0]/[2], t = [1]/[2] - static int vec_to_st[6][3] = - { - {-2,3,1}, - {2,3,-1}, - - {1,3,2}, - {-1,3,-2}, - - {-2,-1,3}, - {-2,1,-3} - - // {-1,2,3}, - // {1,2,-3} - }; - - // decide which face it maps to - VectorCopy (vec3_origin, v); - for (i=0, vp=vecs ; i av[1] && av[0] > av[2]) - { - if (v[0] < 0) - axis = 1; - else - axis = 0; - } - else if (av[1] > av[2] && av[1] > av[0]) - { - if (v[1] < 0) - axis = 3; - else - axis = 2; - } - else - { - if (v[2] < 0) - axis = 5; - else - axis = 4; - } - - // project new texture coords - for (i=0 ; i 0) - dv = vecs[j - 1]; - else - dv = -vecs[-j - 1]; - if (dv < 0.001) - continue; // don't divide by zero - j = vec_to_st[axis][0]; - if (j < 0) - s = -vecs[-j -1] / dv; - else - s = vecs[j-1] / dv; - j = vec_to_st[axis][1]; - if (j < 0) - t = -vecs[-j -1] / dv; - else - t = vecs[j-1] / dv; - - if (s < sky_mins[0][axis]) - sky_mins[0][axis] = s; - if (t < sky_mins[1][axis]) - sky_mins[1][axis] = t; - if (s > sky_maxs[0][axis]) - sky_maxs[0][axis] = s; - if (t > sky_maxs[1][axis]) - sky_maxs[1][axis] = t; - } -} - -#define ON_EPSILON 0.1f // point on plane side epsilon -#define MAX_CLIP_VERTS 64 -/* -================ -ClipSkyPolygon -================ -*/ -static void ClipSkyPolygon (int nump, vec3_t vecs, int stage) -{ - float *norm; - float *v; - qboolean front, back; - float d, e; - float dists[MAX_CLIP_VERTS]; - int sides[MAX_CLIP_VERTS]; - vec3_t newv[2][MAX_CLIP_VERTS]; - int newc[2]; - int i, j; - - if (nump > MAX_CLIP_VERTS-2) - ri.Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS"); - if (stage == 6) - { // fully clipped, so draw it - AddSkyPolygon (nump, vecs); - return; - } - - front = back = qfalse; - norm = sky_clip[stage]; - for (i=0, v = vecs ; i ON_EPSILON) - { - front = qtrue; - sides[i] = SIDE_FRONT; - } - else if (d < -ON_EPSILON) - { - back = qtrue; - sides[i] = SIDE_BACK; - } - else - sides[i] = SIDE_ON; - dists[i] = d; - } - - if (!front || !back) - { // not clipped - ClipSkyPolygon (nump, vecs, stage+1); - return; - } - - // clip it - sides[i] = sides[0]; - dists[i] = dists[0]; - VectorCopy (vecs, (vecs+(i*3)) ); - newc[0] = newc[1] = 0; - - for (i=0, v = vecs ; inumIndexes; i += 3 ) - { - for (j = 0 ; j < 3 ; j++) - { - VectorSubtract( input->xyz[input->indexes[i+j]], - backEnd.viewParms.or.origin, - p[j] ); - } - ClipSkyPolygon( 3, p[0], 0 ); - } -} - -/* -=================================================================================== - -CLOUD VERTEX GENERATION - -=================================================================================== -*/ - -/* -** MakeSkyVec -** -** Parms: s, t range from -1 to 1 -*/ -static void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXYZ ) -{ - // 1 = s, 2 = t, 3 = 2048 - static int st_to_vec[6][3] = - { - {3,-1,2}, - {-3,1,2}, - - {1,3,2}, - {-1,-3,2}, - - {-2,-1,3}, // 0 degrees yaw, look straight up - {2,-1,-3} // look straight down - }; - - vec3_t b; - int j, k; - float boxSize; - - boxSize = backEnd.viewParms.zFar / 1.75; // div sqrt(3) - b[0] = s*boxSize; - b[1] = t*boxSize; - b[2] = boxSize; - - for (j=0 ; j<3 ; j++) - { - k = st_to_vec[axis][j]; - if (k < 0) - { - outXYZ[j] = -b[-k - 1]; - } - else - { - outXYZ[j] = b[k - 1]; - } - } - - // avoid bilerp seam - s = (s+1)*0.5; - t = (t+1)*0.5; - if (s < sky_min) - { - s = sky_min; - } - else if (s > sky_max) - { - s = sky_max; - } - - if (t < sky_min) - { - t = sky_min; - } - else if (t > sky_max) - { - t = sky_max; - } - - t = 1.0 - t; - - - if ( outSt ) - { - outSt[0] = s; - outSt[1] = t; - } -} - -static int sky_texorder[6] = {0,2,1,3,4,5}; -static vec3_t s_skyPoints[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1]; -static float s_skyTexCoords[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2]; - -static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] ) -{ - int s, t; - - GL_Bind( image ); - - for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) - { - qglBegin( GL_TRIANGLE_STRIP ); - - for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) - { - qglTexCoord2fv( s_skyTexCoords[t][s] ); - qglVertex3fv( s_skyPoints[t][s] ); - - qglTexCoord2fv( s_skyTexCoords[t+1][s] ); - qglVertex3fv( s_skyPoints[t+1][s] ); - } - - qglEnd(); - } -} - -static void DrawSkyBox( shader_t *shader ) -{ - int i; - - sky_min = 0; - sky_max = 1; - - Com_Memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) ); - - for (i=0 ; i<6 ; i++) - { - int sky_mins_subd[2], sky_maxs_subd[2]; - int s, t; - - sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - - if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) || - ( sky_mins[1][i] >= sky_maxs[1][i] ) ) - { - continue; - } - - sky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS; - sky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS; - sky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS; - sky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS; - - if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS; - if ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS; - - if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS; - if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS; - - // - // iterate through the subdivisions - // - for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ ) - { - for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ ) - { - MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - i, - s_skyTexCoords[t][s], - s_skyPoints[t][s] ); - } - } - - DrawSkySide( shader->sky.outerbox[sky_texorder[i]], - sky_mins_subd, - sky_maxs_subd ); - } - -} - -static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean addIndexes ) -{ - int s, t; - int vertexStart = tess.numVertexes; - int tHeight, sWidth; - - tHeight = maxs[1] - mins[1] + 1; - sWidth = maxs[0] - mins[0] + 1; - - for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) - { - for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) - { - VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0]; - tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1]; - - tess.numVertexes++; - - if ( tess.numVertexes >= SHADER_MAX_VERTEXES ) - { - ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()" ); - } - } - } - - // only add indexes for one pass, otherwise it would draw multiple times for each pass - if ( addIndexes ) { - for ( t = 0; t < tHeight-1; t++ ) - { - for ( s = 0; s < sWidth-1; s++ ) - { - tess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth ); - tess.numIndexes++; - tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth ); - tess.numIndexes++; - tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth ); - tess.numIndexes++; - - tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth ); - tess.numIndexes++; - tess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth ); - tess.numIndexes++; - tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth ); - tess.numIndexes++; - } - } - } -} - -static void FillCloudBox( const shader_t *shader, int stage ) -{ - int i; - - for ( i =0; i < 6; i++ ) - { - int sky_mins_subd[2], sky_maxs_subd[2]; - int s, t; - float MIN_T; - - if ( 1 ) // FIXME? shader->sky.fullClouds ) - { - MIN_T = -HALF_SKY_SUBDIVISIONS; - - // still don't want to draw the bottom, even if fullClouds - if ( i == 5 ) - continue; - } - else - { - switch( i ) - { - case 0: - case 1: - case 2: - case 3: - MIN_T = -1; - break; - case 5: - // don't draw clouds beneath you - continue; - case 4: // top - default: - MIN_T = -HALF_SKY_SUBDIVISIONS; - break; - } - } - - sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - - if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) || - ( sky_mins[1][i] >= sky_maxs[1][i] ) ) - { - continue; - } - - sky_mins_subd[0] = ri.ftol(sky_mins[0][i] * HALF_SKY_SUBDIVISIONS); - sky_mins_subd[1] = ri.ftol(sky_mins[1][i] * HALF_SKY_SUBDIVISIONS); - sky_maxs_subd[0] = ri.ftol(sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS); - sky_maxs_subd[1] = ri.ftol(sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS); - - if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS; - if ( sky_mins_subd[1] < MIN_T ) - sky_mins_subd[1] = MIN_T; - else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS; - - if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS; - if ( sky_maxs_subd[1] < MIN_T ) - sky_maxs_subd[1] = MIN_T; - else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS; - - // - // iterate through the subdivisions - // - for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ ) - { - for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ ) - { - MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - i, - NULL, - s_skyPoints[t][s] ); - - s_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0]; - s_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1]; - } - } - - // only add indexes for first stage - FillCloudySkySide( sky_mins_subd, sky_maxs_subd, ( stage == 0 ) ); - } -} - -/* -** R_BuildCloudData -*/ -void R_BuildCloudData( shaderCommands_t *input ) -{ - int i; - shader_t *shader; - - shader = input->shader; - - assert( shader->isSky ); - - sky_min = 1.0 / 256.0f; // FIXME: not correct? - sky_max = 255.0 / 256.0f; - - // set up for drawing - tess.numIndexes = 0; - tess.numVertexes = 0; - - if ( shader->sky.cloudHeight ) - { - for ( i = 0; i < MAX_SHADER_STAGES; i++ ) - { - if ( !tess.xstages[i] ) { - break; - } - FillCloudBox( shader, i ); - } - } -} - -/* -** R_InitSkyTexCoords -** Called when a sky shader is parsed -*/ -#define SQR( a ) ((a)*(a)) -void R_InitSkyTexCoords( float heightCloud ) -{ - int i, s, t; - float radiusWorld = 4096; - float p; - float sRad, tRad; - vec3_t skyVec; - vec3_t v; - - // init zfar so MakeSkyVec works even though - // a world hasn't been bounded - backEnd.viewParms.zFar = 1024; - - for ( i = 0; i < 6; i++ ) - { - for ( t = 0; t <= SKY_SUBDIVISIONS; t++ ) - { - for ( s = 0; s <= SKY_SUBDIVISIONS; s++ ) - { - // compute vector from view origin to sky side integral point - MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - i, - NULL, - skyVec ); - - // compute parametric value 'p' that intersects with cloud layer - p = ( 1.0f / ( 2 * DotProduct( skyVec, skyVec ) ) ) * - ( -2 * skyVec[2] * radiusWorld + - 2 * sqrt( SQR( skyVec[2] ) * SQR( radiusWorld ) + - 2 * SQR( skyVec[0] ) * radiusWorld * heightCloud + - SQR( skyVec[0] ) * SQR( heightCloud ) + - 2 * SQR( skyVec[1] ) * radiusWorld * heightCloud + - SQR( skyVec[1] ) * SQR( heightCloud ) + - 2 * SQR( skyVec[2] ) * radiusWorld * heightCloud + - SQR( skyVec[2] ) * SQR( heightCloud ) ) ); - - s_cloudTexP[i][t][s] = p; - - // compute intersection point based on p - VectorScale( skyVec, p, v ); - v[2] += radiusWorld; - - // compute vector from world origin to intersection point 'v' - VectorNormalize( v ); - - sRad = Q_acos( v[0] ); - tRad = Q_acos( v[1] ); - - s_cloudTexCoords[i][t][s][0] = sRad; - s_cloudTexCoords[i][t][s][1] = tRad; - } - } - } -} - -//====================================================================================== - -/* -** RB_DrawSun -*/ -void RB_DrawSun( float scale, shader_t *shader ) { - float size; - float dist; - vec3_t origin, vec1, vec2; - byte sunColor[4] = { 255, 255, 255, 255 }; - - if ( !backEnd.skyRenderedThisView ) { - return; - } - - qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); - qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); - - dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) - size = dist * scale; - - VectorScale( tr.sunDirection, dist, origin ); - PerpendicularVector( vec1, tr.sunDirection ); - CrossProduct( tr.sunDirection, vec1, vec2 ); - - VectorScale( vec1, size, vec1 ); - VectorScale( vec2, size, vec2 ); - - // farthest depth range - qglDepthRange( 1.0, 1.0 ); - - RB_BeginSurface( shader, 0 ); - - RB_AddQuadStamp(origin, vec1, vec2, sunColor); - - RB_EndSurface(); - - // back to normal depth range - qglDepthRange( 0.0, 1.0 ); -} - - - - -/* -================ -RB_StageIteratorSky - -All of the visible sky triangles are in tess - -Other things could be stuck in here, like birds in the sky, etc -================ -*/ -void RB_StageIteratorSky( void ) { - if ( r_fastsky->integer ) { - return; - } - - // go through all the polygons and project them onto - // the sky box to see which blocks on each side need - // to be drawn - RB_ClipSkyPolygons( &tess ); - - // r_showsky will let all the sky blocks be drawn in - // front of everything to allow developers to see how - // much sky is getting sucked in - if ( r_showsky->integer ) { - qglDepthRange( 0.0, 0.0 ); - } else { - qglDepthRange( 1.0, 1.0 ); - } - - // draw the outer skybox - if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) { - qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); - - qglPushMatrix (); - GL_State( 0 ); - qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); - - DrawSkyBox( tess.shader ); - - qglPopMatrix(); - } - - // generate the vertexes for all the clouds, which will be drawn - // by the generic shader routine - R_BuildCloudData( &tess ); - - RB_StageIteratorGeneric(); - - // draw the inner skybox - - - // back to normal depth range - qglDepthRange( 0.0, 1.0 ); - - // note that sky was drawn so we will draw a sun later - backEnd.skyRenderedThisView = qtrue; -} - diff --git a/code/renderergl1/tr_subs.c b/code/renderergl1/tr_subs.c deleted file mode 100644 index 6f4901287c..0000000000 --- a/code/renderergl1/tr_subs.c +++ /dev/null @@ -1,48 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2010 James Canete (use.less01@gmail.com) - -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_subs.c - common function replacements for modular renderer - -#include "tr_local.h" - -void QDECL Com_Printf( const char *msg, ... ) -{ - va_list argptr; - char text[1024]; - - va_start(argptr, msg); - Q_vsnprintf(text, sizeof(text), msg, argptr); - va_end(argptr); - - ri.Printf(PRINT_ALL, "%s", text); -} - -void QDECL Com_Error( int level, const char *error, ... ) -{ - va_list argptr; - char text[1024]; - - va_start(argptr, error); - Q_vsnprintf(text, sizeof(text), error, argptr); - va_end(argptr); - - ri.Error(level, "%s", text); -} diff --git a/code/renderergl1/tr_surface.c b/code/renderergl1/tr_surface.c deleted file mode 100644 index 1879fe2c02..0000000000 --- a/code/renderergl1/tr_surface.c +++ /dev/null @@ -1,1243 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; 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" -#if idppc_altivec && !defined(MACOS_X) -#include -#endif - -/* - - 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, tess.fogNum ); -} - - -/* -============== -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.or.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.or.axis[1], radius, left ); - VectorScale( backEnd.viewParms.or.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.or.axis[1], c * radius, left ); - VectorMA( left, -s * radius, backEnd.viewParms.or.axis[2], left ); - - VectorScale( backEnd.viewParms.or.axis[2], c * radius, up ); - VectorMA( up, s * radius, backEnd.viewParms.or.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 -============= -*/ -static 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.numVertexes = numv; -} - - -/* -============= -RB_SurfaceTriangles -============= -*/ -static void RB_SurfaceTriangles( srfTriangles_t *srf ) { - int i; - drawVert_t *dv; - float *xyz, *normal, *texCoords; - byte *color; - int dlightBits; - qboolean needsNormal; - - dlightBits = srf->dlightBits; - 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 -============== -*/ -static 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(); -} - -//================================================================================ - -static void DoRailCore( const vec3_t start, const vec3_t end, const vec3_t up, float len, float spanWidth ) -{ - float spanWidth2; - int vbase; - float t = len / 256.0f; - - RB_CHECKOVERFLOW( 4, 6 ); - - vbase = tess.numVertexes; - - spanWidth2 = -spanWidth; - - // FIXME: use quad stamp? - VectorMA( start, spanWidth, up, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 0.25; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 0.25; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 0.25; - tess.numVertexes++; - - VectorMA( start, spanWidth2, up, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0]; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1]; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2]; - tess.numVertexes++; - - VectorMA( end, spanWidth, up, tess.xyz[tess.numVertexes] ); - - tess.texCoords[tess.numVertexes][0][0] = t; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0]; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1]; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2]; - tess.numVertexes++; - - VectorMA( end, spanWidth2, up, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = t; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0]; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1]; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2]; - tess.numVertexes++; - - tess.indexes[tess.numIndexes++] = vbase; - tess.indexes[tess.numIndexes++] = vbase + 1; - tess.indexes[tess.numIndexes++] = vbase + 2; - - tess.indexes[tess.numIndexes++] = vbase + 2; - tess.indexes[tess.numIndexes++] = vbase + 1; - tess.indexes[tess.numIndexes++] = vbase + 3; -} - -static void DoRailDiscs( int numSegs, const vec3_t start, const vec3_t dir, const vec3_t right, const vec3_t up ) -{ - int i; - vec3_t pos[4]; - vec3_t v; - int spanWidth = r_railWidth->integer; - float c, s; - float scale; - - if ( numSegs > 1 ) - numSegs--; - if ( !numSegs ) - return; - - scale = 0.25; - - for ( i = 0; i < 4; i++ ) - { - c = cos( DEG2RAD( 45 + i * 90 ) ); - s = sin( DEG2RAD( 45 + i * 90 ) ); - v[0] = ( right[0] * c + up[0] * s ) * scale * spanWidth; - v[1] = ( right[1] * c + up[1] * s ) * scale * spanWidth; - v[2] = ( right[2] * c + up[2] * s ) * scale * spanWidth; - VectorAdd( start, v, pos[i] ); - - if ( numSegs > 1 ) - { - // offset by 1 segment if we're doing a long distance shot - VectorAdd( pos[i], dir, pos[i] ); - } - } - - for ( i = 0; i < numSegs; i++ ) - { - int j; - - RB_CHECKOVERFLOW( 4, 6 ); - - for ( j = 0; j < 4; j++ ) - { - VectorCopy( pos[j], tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = ( j < 2 ); - tess.texCoords[tess.numVertexes][0][1] = ( j && j != 3 ); - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0]; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1]; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2]; - tess.numVertexes++; - - VectorAdd( pos[j], dir, pos[j] ); - } - - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 0; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 2; - } -} - -/* -** RB_SurfaceRailRinges -*/ -static void RB_SurfaceRailRings( void ) { - refEntity_t *e; - int numSegs; - int len; - vec3_t vec; - vec3_t right, up; - vec3_t start, end; - - e = &backEnd.currentEntity->e; - - VectorCopy( e->oldorigin, start ); - VectorCopy( e->origin, end ); - - // compute variables - VectorSubtract( end, start, vec ); - len = VectorNormalize( vec ); - MakeNormalVectors( vec, right, up ); - numSegs = ( len ) / r_railSegmentLength->value; - if ( numSegs <= 0 ) { - numSegs = 1; - } - - VectorScale( vec, r_railSegmentLength->value, vec ); - - DoRailDiscs( numSegs, start, vec, right, up ); -} - -/* -** RB_SurfaceRailCore -*/ -static void RB_SurfaceRailCore( void ) { - refEntity_t *e; - int len; - vec3_t right; - vec3_t vec; - vec3_t start, end; - vec3_t v1, v2; - - e = &backEnd.currentEntity->e; - - VectorCopy( e->oldorigin, start ); - VectorCopy( e->origin, end ); - - VectorSubtract( end, start, vec ); - len = VectorNormalize( vec ); - - // compute side vector - VectorSubtract( start, backEnd.viewParms.or.origin, v1 ); - VectorNormalize( v1 ); - VectorSubtract( end, backEnd.viewParms.or.origin, v2 ); - VectorNormalize( v2 ); - CrossProduct( v1, v2, right ); - VectorNormalize( right ); - - DoRailCore( start, end, right, len, r_railCoreWidth->integer ); -} - -/* -** RB_SurfaceLightningBolt -*/ -static void RB_SurfaceLightningBolt( void ) { - refEntity_t *e; - int len; - vec3_t right; - vec3_t vec; - vec3_t start, end; - vec3_t v1, v2; - int i; - - e = &backEnd.currentEntity->e; - - VectorCopy( e->oldorigin, end ); - VectorCopy( e->origin, start ); - - // compute variables - VectorSubtract( end, start, vec ); - len = VectorNormalize( vec ); - - // compute side vector - VectorSubtract( start, backEnd.viewParms.or.origin, v1 ); - VectorNormalize( v1 ); - VectorSubtract( end, backEnd.viewParms.or.origin, v2 ); - VectorNormalize( v2 ); - CrossProduct( v1, v2, right ); - VectorNormalize( right ); - - for ( i = 0 ; i < 4 ; i++ ) { - vec3_t temp; - - DoRailCore( start, end, right, len, 8 ); - RotatePointAroundVector( temp, vec, right, 45 ); - VectorCopy( temp, right ); - } -} - -/* -** VectorArrayNormalize -* -* The inputs to this routing seem to always be close to length = 1.0 (about 0.6 to 2.0) -* This means that we don't have to worry about zero length or enormously long vectors. -*/ -static void VectorArrayNormalize(vec4_t *normals, unsigned int count) -{ -// assert(count); - -#if idppc - { - register float half = 0.5; - register float one = 1.0; - float *components = (float *)normals; - - // Vanilla PPC code, but since PPC has a reciprocal square root estimate instruction, - // runs *much* faster than calling sqrt(). We'll use a single Newton-Raphson - // refinement step to get a little more precision. This seems to yeild results - // that are correct to 3 decimal places and usually correct to at least 4 (sometimes 5). - // (That is, for the given input range of about 0.6 to 2.0). - do { - float x, y, z; - float B, y0, y1; - - x = components[0]; - y = components[1]; - z = components[2]; - components += 4; - B = x*x + y*y + z*z; - -#ifdef __GNUC__ - asm("frsqrte %0,%1" : "=f" (y0) : "f" (B)); -#else - y0 = __frsqrte(B); -#endif - y1 = y0 + half*y0*(one - B*y0*y0); - - x = x * y1; - y = y * y1; - components[-4] = x; - z = z * y1; - components[-3] = y; - components[-2] = z; - } while(count--); - } -#else // No assembly version for this architecture, or C_ONLY defined - // given the input, it's safe to call VectorNormalizeFast - while (count--) { - VectorNormalizeFast(normals[0]); - normals++; - } -#endif - -} - - - -/* -** LerpMeshVertexes -*/ -#if idppc_altivec -static void LerpMeshVertexes_altivec(md3Surface_t *surf, float backlerp) -{ - short *oldXyz, *newXyz, *oldNormals, *newNormals; - float *outXyz, *outNormal; - float oldXyzScale QALIGN(16); - float newXyzScale QALIGN(16); - float oldNormalScale QALIGN(16); - float newNormalScale QALIGN(16); - int vertNum; - unsigned lat, lng; - int numVerts; - - outXyz = tess.xyz[tess.numVertexes]; - outNormal = tess.normal[tess.numVertexes]; - - newXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.frame * surf->numVerts * 4); - newNormals = newXyz + 3; - - newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp); - newNormalScale = 1.0 - backlerp; - - numVerts = surf->numVerts; - - if ( backlerp == 0 ) { - vector signed short newNormalsVec0; - vector signed short newNormalsVec1; - vector signed int newNormalsIntVec; - vector float newNormalsFloatVec; - vector float newXyzScaleVec; - vector unsigned char newNormalsLoadPermute; - vector unsigned char newNormalsStorePermute; - vector float zero; - - newNormalsStorePermute = vec_lvsl(0,(float *)&newXyzScaleVec); - newXyzScaleVec = *(vector float *)&newXyzScale; - newXyzScaleVec = vec_perm(newXyzScaleVec,newXyzScaleVec,newNormalsStorePermute); - newXyzScaleVec = vec_splat(newXyzScaleVec,0); - newNormalsLoadPermute = vec_lvsl(0,newXyz); - newNormalsStorePermute = vec_lvsr(0,outXyz); - zero = (vector float)vec_splat_s8(0); - // - // just copy the vertexes - // - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - newXyz += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - newNormalsLoadPermute = vec_lvsl(0,newXyz); - newNormalsStorePermute = vec_lvsr(0,outXyz); - newNormalsVec0 = vec_ld(0,newXyz); - newNormalsVec1 = vec_ld(16,newXyz); - newNormalsVec0 = vec_perm(newNormalsVec0,newNormalsVec1,newNormalsLoadPermute); - newNormalsIntVec = vec_unpackh(newNormalsVec0); - newNormalsFloatVec = vec_ctf(newNormalsIntVec,0); - newNormalsFloatVec = vec_madd(newNormalsFloatVec,newXyzScaleVec,zero); - newNormalsFloatVec = vec_perm(newNormalsFloatVec,newNormalsFloatVec,newNormalsStorePermute); - //outXyz[0] = newXyz[0] * newXyzScale; - //outXyz[1] = newXyz[1] * newXyzScale; - //outXyz[2] = newXyz[2] * newXyzScale; - - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - vec_ste(newNormalsFloatVec,0,outXyz); - vec_ste(newNormalsFloatVec,4,outXyz); - vec_ste(newNormalsFloatVec,8,outXyz); - } - } else { - // - // interpolate and copy the vertex and normal - // - oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.oldframe * surf->numVerts * 4); - oldNormals = oldXyz + 3; - - oldXyzScale = MD3_XYZ_SCALE * backlerp; - oldNormalScale = backlerp; - - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - vec3_t uncompressedOldNormal, uncompressedNewNormal; - - // interpolate the xyz - outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale; - outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale; - outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale; - - // FIXME: interpolate lat/long instead? - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - lat = ( oldNormals[0] >> 8 ) & 0xff; - lng = ( oldNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - - uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale; - outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale; - outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale; - -// VectorNormalize (outNormal); - } - VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts); - } -} -#endif - -static void LerpMeshVertexes_scalar(md3Surface_t *surf, float backlerp) -{ - short *oldXyz, *newXyz, *oldNormals, *newNormals; - float *outXyz, *outNormal; - float oldXyzScale, newXyzScale; - float oldNormalScale, newNormalScale; - int vertNum; - unsigned lat, lng; - int numVerts; - - outXyz = tess.xyz[tess.numVertexes]; - outNormal = tess.normal[tess.numVertexes]; - - newXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.frame * surf->numVerts * 4); - newNormals = newXyz + 3; - - newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp); - newNormalScale = 1.0 - backlerp; - - numVerts = surf->numVerts; - - if ( backlerp == 0 ) { - // - // just copy the vertexes - // - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - newXyz += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - - outXyz[0] = newXyz[0] * newXyzScale; - outXyz[1] = newXyz[1] * newXyzScale; - outXyz[2] = newXyz[2] * newXyzScale; - - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - } - } else { - // - // interpolate and copy the vertex and normal - // - oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.oldframe * surf->numVerts * 4); - oldNormals = oldXyz + 3; - - oldXyzScale = MD3_XYZ_SCALE * backlerp; - oldNormalScale = backlerp; - - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - vec3_t uncompressedOldNormal, uncompressedNewNormal; - - // interpolate the xyz - outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale; - outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale; - outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale; - - // FIXME: interpolate lat/long instead? - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - lat = ( oldNormals[0] >> 8 ) & 0xff; - lng = ( oldNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - - uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale; - outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale; - outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale; - -// VectorNormalize (outNormal); - } - VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts); - } -} - -static void LerpMeshVertexes(md3Surface_t *surf, float backlerp) -{ -#if idppc_altivec - if (com_altivec->integer) { - // must be in a seperate function or G3 systems will crash. - LerpMeshVertexes_altivec( surf, backlerp ); - return; - } -#endif // idppc_altivec - LerpMeshVertexes_scalar( surf, backlerp ); -} - - -/* -============= -RB_SurfaceMesh -============= -*/ -static void RB_SurfaceMesh(md3Surface_t *surface) { - int j; - float backlerp; - int *triangles; - float *texCoords; - int indexes; - int Bob, Doug; - int numVerts; - - if ( backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) { - backlerp = 0; - } else { - backlerp = backEnd.currentEntity->e.backlerp; - } - - RB_CHECKOVERFLOW( surface->numVerts, surface->numTriangles*3 ); - - LerpMeshVertexes (surface, backlerp); - - triangles = (int *) ((byte *)surface + surface->ofsTriangles); - indexes = surface->numTriangles * 3; - Bob = tess.numIndexes; - Doug = tess.numVertexes; - for (j = 0 ; j < indexes ; j++) { - tess.indexes[Bob + j] = Doug + triangles[j]; - } - tess.numIndexes += indexes; - - texCoords = (float *) ((byte *)surface + surface->ofsSt); - - numVerts = surface->numVerts; - for ( j = 0; j < numVerts; j++ ) { - tess.texCoords[Doug + j][0][0] = texCoords[j*2+0]; - tess.texCoords[Doug + j][0][1] = texCoords[j*2+1]; - // FIXME: fill in lightmapST for completeness? - } - - tess.numVertexes += surface->numVerts; - -} - - -/* -============== -RB_SurfaceFace -============== -*/ -static void RB_SurfaceFace( srfSurfaceFace_t *surf ) { - int i; - unsigned *indices, *tessIndexes; - float *v; - float *normal; - int ndx; - int Bob; - int numPoints; - int dlightBits; - - RB_CHECKOVERFLOW( surf->numPoints, surf->numIndices ); - - dlightBits = surf->dlightBits; - 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; - - if ( tess.shader->needsNormal ) { - normal = surf->plane.normal; - for ( i = 0, ndx = tess.numVertexes; i < numPoints; i++, ndx++ ) { - VectorCopy( normal, tess.normal[ndx] ); - } - } - - 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.or.axis[0][0] + local[1] * backEnd.or.axis[1][0] + - local[2] * backEnd.or.axis[2][0] + backEnd.or.origin[0]; - world[1] = local[0] * backEnd.or.axis[0][1] + local[1] * backEnd.or.axis[1][1] + - local[2] * backEnd.or.axis[2][1] + backEnd.or.origin[1]; - world[2] = local[0] * backEnd.or.axis[0][2] + local[1] * backEnd.or.axis[1][2] + - local[2] * backEnd.or.axis[2][2] + backEnd.or.origin[2]; - - VectorSubtract( world, backEnd.viewParms.or.origin, world ); - d = DotProduct( world, backEnd.viewParms.or.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 -============= -*/ -static 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; - 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; - 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, tess.fogNum ); - } 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 ) { - 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 -=================== -*/ -static void RB_SurfaceAxis( void ) { - GL_Bind( tr.whiteImage ); - GL_State( GLS_DEFAULT ); - 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 -==================== -*/ -static void RB_SurfaceEntity( surfaceType_t *surfType ) { - switch( backEnd.currentEntity->e.reType ) { - case RT_SPRITE: - RB_SurfaceSprite(); - break; - case RT_BEAM: - RB_SurfaceBeam(); - break; - case RT_RAIL_CORE: - RB_SurfaceRailCore(); - break; - case RT_RAIL_RINGS: - RB_SurfaceRailRings(); - break; - case RT_LIGHTNING: - RB_SurfaceLightningBolt(); - break; - default: - RB_SurfaceAxis(); - break; - } -} - -static void RB_SurfaceBad( surfaceType_t *surfType ) { - ri.Printf( PRINT_ALL, "Bad surface tesselated.\n" ); -} - -static void RB_SurfaceFlare(srfFlare_t *surf) -{ - if (r_flares->integer) - RB_AddFlare(surf, tess.fogNum, surf->origin, surf->color, surf->normal); -} - -static void RB_SurfaceDisplayList( srfDisplayList_t *surf ) { - // all apropriate state must be set in RB_BeginSurface - // this isn't implemented yet... - qglCallList( surf->listNum ); -} - -static void RB_SurfaceSkip( void *surf ) { -} - - -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_SurfaceTriangles, // SF_TRIANGLES, - (void(*)(void*))RB_SurfacePolychain, // SF_POLY, - (void(*)(void*))RB_SurfaceMesh, // SF_MD3, - (void(*)(void*))RB_MDRSurfaceAnim, // SF_MDR, - (void(*)(void*))RB_IQMSurfaceAnim, // SF_IQM, - (void(*)(void*))RB_SurfaceFlare, // SF_FLARE, - (void(*)(void*))RB_SurfaceEntity, // SF_ENTITY - (void(*)(void*))RB_SurfaceDisplayList // SF_DISPLAY_LIST -}; diff --git a/code/renderergl1/tr_world.c b/code/renderergl1/tr_world.c deleted file mode 100644 index 0a2743f927..0000000000 --- a/code/renderergl1/tr_world.c +++ /dev/null @@ -1,668 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - - - -/* -================= -R_CullTriSurf - -Returns true if the grid is completely culled away. -Also sets the clipped hint bit in tess -================= -*/ -static qboolean R_CullTriSurf( srfTriangles_t *cv ) { - int boxCull; - - boxCull = R_CullLocalBox( cv->bounds ); - - if ( boxCull == CULL_OUT ) { - return qtrue; - } - return qfalse; -} - -/* -================= -R_CullGrid - -Returns true if the grid is completely culled away. -Also sets the clipped hint bit in tess -================= -*/ -static qboolean R_CullGrid( srfGridMesh_t *cv ) { - int boxCull; - int sphereCull; - - if ( r_nocurves->integer ) { - return qtrue; - } - - if ( tr.currentEntityNum != REFENTITYNUM_WORLD ) { - sphereCull = R_CullLocalPointAndRadius( cv->localOrigin, cv->meshRadius ); - } else { - sphereCull = R_CullPointAndRadius( cv->localOrigin, cv->meshRadius ); - } - - // check for trivial reject - if ( sphereCull == CULL_OUT ) - { - tr.pc.c_sphere_cull_patch_out++; - return qtrue; - } - // check bounding box if necessary - else if ( sphereCull == CULL_CLIP ) - { - tr.pc.c_sphere_cull_patch_clip++; - - boxCull = R_CullLocalBox( cv->meshBounds ); - - if ( boxCull == CULL_OUT ) - { - tr.pc.c_box_cull_patch_out++; - return qtrue; - } - else if ( boxCull == CULL_IN ) - { - tr.pc.c_box_cull_patch_in++; - } - else - { - tr.pc.c_box_cull_patch_clip++; - } - } - else - { - tr.pc.c_sphere_cull_patch_in++; - } - - return qfalse; -} - - -/* -================ -R_CullSurface - -Tries to back face cull surfaces before they are lighted or -added to the sorting list. - -This will also allow mirrors on both sides of a model without recursion. -================ -*/ -static qboolean R_CullSurface( surfaceType_t *surface, shader_t *shader ) { - srfSurfaceFace_t *sface; - float d; - - if ( r_nocull->integer ) { - return qfalse; - } - - if ( *surface == SF_GRID ) { - return R_CullGrid( (srfGridMesh_t *)surface ); - } - - if ( *surface == SF_TRIANGLES ) { - return R_CullTriSurf( (srfTriangles_t *)surface ); - } - - if ( *surface != SF_FACE ) { - return qfalse; - } - - if ( shader->cullType == CT_TWO_SIDED ) { - return qfalse; - } - - // face culling - if ( !r_facePlaneCull->integer ) { - return qfalse; - } - - sface = ( srfSurfaceFace_t * ) surface; - d = DotProduct (tr.or.viewOrigin, sface->plane.normal); - - // don't cull exactly on the plane, because there are levels of rounding - // through the BSP, ICD, and hardware that may cause pixel gaps if an - // epsilon isn't allowed here - if ( shader->cullType == CT_FRONT_SIDED ) { - if ( d < sface->plane.dist - 8 ) { - return qtrue; - } - } else { - if ( d > sface->plane.dist + 8 ) { - return qtrue; - } - } - - return qfalse; -} - - -static int R_DlightFace( srfSurfaceFace_t *face, int dlightBits ) { - float d; - int i; - dlight_t *dl; - - for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { - if ( ! ( dlightBits & ( 1 << i ) ) ) { - continue; - } - dl = &tr.refdef.dlights[i]; - d = DotProduct( dl->origin, face->plane.normal ) - face->plane.dist; - if ( d < -dl->radius || d > dl->radius ) { - // dlight doesn't reach the plane - dlightBits &= ~( 1 << i ); - } - } - - if ( !dlightBits ) { - tr.pc.c_dlightSurfacesCulled++; - } - - face->dlightBits = dlightBits; - return dlightBits; -} - -static int R_DlightGrid( srfGridMesh_t *grid, int dlightBits ) { - int i; - dlight_t *dl; - - for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { - if ( ! ( dlightBits & ( 1 << i ) ) ) { - continue; - } - dl = &tr.refdef.dlights[i]; - if ( dl->origin[0] - dl->radius > grid->meshBounds[1][0] - || dl->origin[0] + dl->radius < grid->meshBounds[0][0] - || dl->origin[1] - dl->radius > grid->meshBounds[1][1] - || dl->origin[1] + dl->radius < grid->meshBounds[0][1] - || dl->origin[2] - dl->radius > grid->meshBounds[1][2] - || dl->origin[2] + dl->radius < grid->meshBounds[0][2] ) { - // dlight doesn't reach the bounds - dlightBits &= ~( 1 << i ); - } - } - - if ( !dlightBits ) { - tr.pc.c_dlightSurfacesCulled++; - } - - grid->dlightBits = dlightBits; - return dlightBits; -} - - -static int R_DlightTrisurf( srfTriangles_t *surf, int dlightBits ) { - // FIXME: more dlight culling to trisurfs... - surf->dlightBits = dlightBits; - return dlightBits; -#if 0 - int i; - dlight_t *dl; - - for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { - if ( ! ( dlightBits & ( 1 << i ) ) ) { - continue; - } - dl = &tr.refdef.dlights[i]; - if ( dl->origin[0] - dl->radius > grid->meshBounds[1][0] - || dl->origin[0] + dl->radius < grid->meshBounds[0][0] - || dl->origin[1] - dl->radius > grid->meshBounds[1][1] - || dl->origin[1] + dl->radius < grid->meshBounds[0][1] - || dl->origin[2] - dl->radius > grid->meshBounds[1][2] - || dl->origin[2] + dl->radius < grid->meshBounds[0][2] ) { - // dlight doesn't reach the bounds - dlightBits &= ~( 1 << i ); - } - } - - if ( !dlightBits ) { - tr.pc.c_dlightSurfacesCulled++; - } - - grid->dlightBits = dlightBits; - return dlightBits; -#endif -} - -/* -==================== -R_DlightSurface - -The given surface is going to be drawn, and it touches a leaf -that is touched by one or more dlights, so try to throw out -more dlights if possible. -==================== -*/ -static int R_DlightSurface( msurface_t *surf, int dlightBits ) { - if ( *surf->data == SF_FACE ) { - dlightBits = R_DlightFace( (srfSurfaceFace_t *)surf->data, dlightBits ); - } else if ( *surf->data == SF_GRID ) { - dlightBits = R_DlightGrid( (srfGridMesh_t *)surf->data, dlightBits ); - } else if ( *surf->data == SF_TRIANGLES ) { - dlightBits = R_DlightTrisurf( (srfTriangles_t *)surf->data, dlightBits ); - } else { - dlightBits = 0; - } - - if ( dlightBits ) { - tr.pc.c_dlightSurfaces++; - } - - return dlightBits; -} - - - -/* -====================== -R_AddWorldSurface -====================== -*/ -static void R_AddWorldSurface( msurface_t *surf, int dlightBits ) { - if ( surf->viewCount == tr.viewCount ) { - return; // already in this view - } - - surf->viewCount = tr.viewCount; - // FIXME: bmodel fog? - - // try to cull before dlighting or adding - if ( R_CullSurface( surf->data, surf->shader ) ) { - return; - } - - // check for dlighting - if ( dlightBits ) { - dlightBits = R_DlightSurface( surf, dlightBits ); - dlightBits = ( dlightBits != 0 ); - } - - R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits ); -} - -/* -============================================================= - - BRUSH MODELS - -============================================================= -*/ - -/* -================= -R_AddBrushModelSurfaces -================= -*/ -void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) { - bmodel_t *bmodel; - int clip; - model_t *pModel; - int i; - - pModel = R_GetModelByHandle( ent->e.hModel ); - - bmodel = pModel->bmodel; - - clip = R_CullLocalBox( bmodel->bounds ); - if ( clip == CULL_OUT ) { - return; - } - - R_SetupEntityLighting( &tr.refdef, ent ); - R_DlightBmodel( bmodel ); - - for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) { - R_AddWorldSurface( bmodel->firstSurface + i, tr.currentEntity->needDlights ); - } -} - - -/* -============================================================= - - WORLD MODEL - -============================================================= -*/ - - -/* -================ -R_RecursiveWorldNode -================ -*/ -static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits ) { - - do { - int newDlights[2]; - - // if the node wasn't marked as potentially visible, exit - if (node->visframe != tr.visCount) { - return; - } - - // if the bounding volume is outside the frustum, nothing - // inside can be visible OPTIMIZE: don't do this all the way to leafs? - - if ( !r_nocull->integer ) { - int r; - - if ( planeBits & 1 ) { - r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[0]); - if (r == 2) { - return; // culled - } - if ( r == 1 ) { - planeBits &= ~1; // all descendants will also be in front - } - } - - if ( planeBits & 2 ) { - r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[1]); - if (r == 2) { - return; // culled - } - if ( r == 1 ) { - planeBits &= ~2; // all descendants will also be in front - } - } - - if ( planeBits & 4 ) { - r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[2]); - if (r == 2) { - return; // culled - } - if ( r == 1 ) { - planeBits &= ~4; // all descendants will also be in front - } - } - - if ( planeBits & 8 ) { - r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[3]); - if (r == 2) { - return; // culled - } - if ( r == 1 ) { - planeBits &= ~8; // all descendants will also be in front - } - } - - } - - if ( node->contents != -1 ) { - break; - } - - // node is just a decision point, so go down both sides - // since we don't care about sort orders, just go positive to negative - - // determine which dlights are needed - newDlights[0] = 0; - newDlights[1] = 0; - if ( dlightBits ) { - int i; - - for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { - dlight_t *dl; - float dist; - - if ( dlightBits & ( 1 << i ) ) { - dl = &tr.refdef.dlights[i]; - dist = DotProduct( dl->origin, node->plane->normal ) - node->plane->dist; - - if ( dist > -dl->radius ) { - newDlights[0] |= ( 1 << i ); - } - if ( dist < dl->radius ) { - newDlights[1] |= ( 1 << i ); - } - } - } - } - - // recurse down the children, front side first - R_RecursiveWorldNode (node->children[0], planeBits, newDlights[0] ); - - // tail recurse - node = node->children[1]; - dlightBits = newDlights[1]; - } while ( 1 ); - - { - // leaf node, so add mark surfaces - int c; - msurface_t *surf, **mark; - - tr.pc.c_leafs++; - - // add to z buffer bounds - if ( node->mins[0] < tr.viewParms.visBounds[0][0] ) { - tr.viewParms.visBounds[0][0] = node->mins[0]; - } - if ( node->mins[1] < tr.viewParms.visBounds[0][1] ) { - tr.viewParms.visBounds[0][1] = node->mins[1]; - } - if ( node->mins[2] < tr.viewParms.visBounds[0][2] ) { - tr.viewParms.visBounds[0][2] = node->mins[2]; - } - - if ( node->maxs[0] > tr.viewParms.visBounds[1][0] ) { - tr.viewParms.visBounds[1][0] = node->maxs[0]; - } - if ( node->maxs[1] > tr.viewParms.visBounds[1][1] ) { - tr.viewParms.visBounds[1][1] = node->maxs[1]; - } - if ( node->maxs[2] > tr.viewParms.visBounds[1][2] ) { - tr.viewParms.visBounds[1][2] = node->maxs[2]; - } - - // add the individual surfaces - mark = node->firstmarksurface; - c = node->nummarksurfaces; - while (c--) { - // the surface may have already been added if it - // spans multiple leafs - surf = *mark; - R_AddWorldSurface( surf, dlightBits ); - mark++; - } - } - -} - - -/* -=============== -R_PointInLeaf -=============== -*/ -static mnode_t *R_PointInLeaf( const vec3_t p ) { - mnode_t *node; - float d; - cplane_t *plane; - - if ( !tr.world ) { - ri.Error (ERR_DROP, "R_PointInLeaf: bad model"); - } - - node = tr.world->nodes; - while( 1 ) { - if (node->contents != -1) { - break; - } - plane = node->plane; - d = DotProduct (p,plane->normal) - plane->dist; - if (d > 0) { - node = node->children[0]; - } else { - node = node->children[1]; - } - } - - return node; -} - -/* -============== -R_ClusterPVS -============== -*/ -static const byte *R_ClusterPVS (int cluster) { - if (!tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) { - return tr.world->novis; - } - - return tr.world->vis + cluster * tr.world->clusterBytes; -} - -/* -================= -R_inPVS -================= -*/ -qboolean R_inPVS( const vec3_t p1, const vec3_t p2 ) { - mnode_t *leaf; - byte *vis; - - leaf = R_PointInLeaf( p1 ); - vis = ri.CM_ClusterPVS( leaf->cluster ); // why not R_ClusterPVS ?? - leaf = R_PointInLeaf( p2 ); - - if ( !(vis[leaf->cluster>>3] & (1<<(leaf->cluster&7))) ) { - return qfalse; - } - return qtrue; -} - -/* -=============== -R_MarkLeaves - -Mark the leaves and nodes that are in the PVS for the current -cluster -=============== -*/ -static void R_MarkLeaves (void) { - const byte *vis; - mnode_t *leaf, *parent; - int i; - int cluster; - - // lockpvs lets designers walk around to determine the - // extent of the current pvs - if ( r_lockpvs->integer ) { - return; - } - - // current viewcluster - leaf = R_PointInLeaf( tr.viewParms.pvsOrigin ); - cluster = leaf->cluster; - - // if the cluster is the same and the area visibility matrix - // hasn't changed, we don't need to mark everything again - - // if r_showcluster was just turned on, remark everything - if ( tr.viewCluster == cluster && !tr.refdef.areamaskModified - && !r_showcluster->modified ) { - return; - } - - if ( r_showcluster->modified || r_showcluster->integer ) { - r_showcluster->modified = qfalse; - if ( r_showcluster->integer ) { - ri.Printf( PRINT_ALL, "cluster:%i area:%i\n", cluster, leaf->area ); - } - } - - tr.visCount++; - tr.viewCluster = cluster; - - if ( r_novis->integer || tr.viewCluster == -1 ) { - for (i=0 ; inumnodes ; i++) { - if (tr.world->nodes[i].contents != CONTENTS_SOLID) { - tr.world->nodes[i].visframe = tr.visCount; - } - } - return; - } - - vis = R_ClusterPVS (tr.viewCluster); - - for (i=0,leaf=tr.world->nodes ; inumnodes ; i++, leaf++) { - cluster = leaf->cluster; - if ( cluster < 0 || cluster >= tr.world->numClusters ) { - continue; - } - - // check general pvs - if ( !(vis[cluster>>3] & (1<<(cluster&7))) ) { - continue; - } - - // check for door connection - if ( (tr.refdef.areamask[leaf->area>>3] & (1<<(leaf->area&7)) ) ) { - continue; // not visible - } - - parent = leaf; - do { - if (parent->visframe == tr.visCount) - break; - parent->visframe = tr.visCount; - parent = parent->parent; - } while (parent); - } -} - - -/* -============= -R_AddWorldSurfaces -============= -*/ -void R_AddWorldSurfaces (void) { - if ( !r_drawworld->integer ) { - return; - } - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return; - } - - tr.currentEntityNum = REFENTITYNUM_WORLD; - tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT; - - // determine which leaves are in the PVS / areamask - R_MarkLeaves (); - - // clear out the visible min/max - ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] ); - - // perform frustum culling and add all the potentially visible surfaces - if ( tr.refdef.num_dlights > 32 ) { - tr.refdef.num_dlights = 32 ; - } - R_RecursiveWorldNode( tr.world->nodes, 15, ( 1 << tr.refdef.num_dlights ) - 1 ); -} diff --git a/code/renderergl2/glsl/bokeh_fp.glsl b/code/renderergl2/glsl/bokeh_fp.glsl deleted file mode 100644 index d08816aeff..0000000000 --- a/code/renderergl2/glsl/bokeh_fp.glsl +++ /dev/null @@ -1,70 +0,0 @@ -uniform sampler2D u_TextureMap; - -uniform vec4 u_Color; - -uniform vec2 u_InvTexRes; -varying vec2 var_TexCoords; - -void main() -{ - vec4 color; - vec2 tc; - -#if 0 - float c[7] = float[7](1.0, 0.9659258263, 0.8660254038, 0.7071067812, 0.5, 0.2588190451, 0.0); - - tc = var_TexCoords + u_InvTexRes * vec2( c[0], c[6]); color = texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[1], c[5]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[2], c[4]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[3], c[3]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[4], c[2]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[5], c[1]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[6], c[0]); color += texture2D(u_TextureMap, tc); - - tc = var_TexCoords + u_InvTexRes * vec2( c[1], -c[5]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[2], -c[4]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[3], -c[3]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[4], -c[2]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[5], -c[1]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[6], -c[0]); color += texture2D(u_TextureMap, tc); - - tc = var_TexCoords + u_InvTexRes * vec2( -c[0], c[6]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[1], c[5]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[2], c[4]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[3], c[3]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[4], c[2]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[5], c[1]); color += texture2D(u_TextureMap, tc); - - tc = var_TexCoords + u_InvTexRes * vec2( -c[1], -c[5]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[2], -c[4]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[3], -c[3]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[4], -c[2]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[5], -c[1]); color += texture2D(u_TextureMap, tc); - - gl_FragColor = color * 0.04166667 * u_Color; -#endif - - float c[5] = float[5](1.0, 0.9238795325, 0.7071067812, 0.3826834324, 0.0); - - tc = var_TexCoords + u_InvTexRes * vec2( c[0], c[4]); color = texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[1], c[3]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[2], c[2]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[3], c[1]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[4], c[0]); color += texture2D(u_TextureMap, tc); - - tc = var_TexCoords + u_InvTexRes * vec2( c[1], -c[3]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[2], -c[2]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[3], -c[1]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( c[4], -c[0]); color += texture2D(u_TextureMap, tc); - - tc = var_TexCoords + u_InvTexRes * vec2( -c[0], c[4]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[1], c[3]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[2], c[2]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[3], c[1]); color += texture2D(u_TextureMap, tc); - - tc = var_TexCoords + u_InvTexRes * vec2( -c[1], -c[3]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[2], -c[2]); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( -c[3], -c[1]); color += texture2D(u_TextureMap, tc); - - gl_FragColor = color * 0.0625 * u_Color; -} diff --git a/code/renderergl2/glsl/bokeh_vp.glsl b/code/renderergl2/glsl/bokeh_vp.glsl deleted file mode 100644 index bdaa74af8e..0000000000 --- a/code/renderergl2/glsl/bokeh_vp.glsl +++ /dev/null @@ -1,13 +0,0 @@ -attribute vec3 attr_Position; -attribute vec4 attr_TexCoord0; - -uniform mat4 u_ModelViewProjectionMatrix; - -varying vec2 var_TexCoords; - - -void main() -{ - gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); - var_TexCoords = attr_TexCoord0.st; -} diff --git a/code/renderergl2/glsl/calclevels4x_fp.glsl b/code/renderergl2/glsl/calclevels4x_fp.glsl deleted file mode 100644 index c8cf06c710..0000000000 --- a/code/renderergl2/glsl/calclevels4x_fp.glsl +++ /dev/null @@ -1,55 +0,0 @@ -uniform sampler2D u_TextureMap; - -uniform vec4 u_Color; - -uniform vec2 u_InvTexRes; -varying vec2 var_TexCoords; - -const vec3 LUMINANCE_VECTOR = vec3(0.2125, 0.7154, 0.0721); //vec3(0.299, 0.587, 0.114); - -vec3 GetValues(vec2 offset, vec3 current) -{ - vec3 minAvgMax; - vec2 tc = var_TexCoords + u_InvTexRes * offset; minAvgMax = texture2D(u_TextureMap, tc).rgb; - -#ifdef FIRST_PASS - float lumi = max(dot(LUMINANCE_VECTOR, minAvgMax), 0.000001); - float loglumi = clamp(log2(lumi), -10.0, 10.0); - minAvgMax = vec3(loglumi * 0.05 + 0.5); -#endif - - return vec3(min(current.x, minAvgMax.x), current.y + minAvgMax.y, max(current.z, minAvgMax.z)); -} - -void main() -{ - vec3 current = vec3(1.0, 0.0, 0.0); - -#ifdef FIRST_PASS - current = GetValues(vec2( 0.0, 0.0), current); -#else - current = GetValues(vec2(-1.5, -1.5), current); - current = GetValues(vec2(-0.5, -1.5), current); - current = GetValues(vec2( 0.5, -1.5), current); - current = GetValues(vec2( 1.5, -1.5), current); - - current = GetValues(vec2(-1.5, -0.5), current); - current = GetValues(vec2(-0.5, -0.5), current); - current = GetValues(vec2( 0.5, -0.5), current); - current = GetValues(vec2( 1.5, -0.5), current); - - current = GetValues(vec2(-1.5, 0.5), current); - current = GetValues(vec2(-0.5, 0.5), current); - current = GetValues(vec2( 0.5, 0.5), current); - current = GetValues(vec2( 1.5, 0.5), current); - - current = GetValues(vec2(-1.5, 1.5), current); - current = GetValues(vec2(-0.5, 1.5), current); - current = GetValues(vec2( 0.5, 1.5), current); - current = GetValues(vec2( 1.5, 1.5), current); - - current.y *= 0.0625; -#endif - - gl_FragColor = vec4(current, 1.0f); -} diff --git a/code/renderergl2/glsl/calclevels4x_vp.glsl b/code/renderergl2/glsl/calclevels4x_vp.glsl deleted file mode 100644 index bdaa74af8e..0000000000 --- a/code/renderergl2/glsl/calclevels4x_vp.glsl +++ /dev/null @@ -1,13 +0,0 @@ -attribute vec3 attr_Position; -attribute vec4 attr_TexCoord0; - -uniform mat4 u_ModelViewProjectionMatrix; - -varying vec2 var_TexCoords; - - -void main() -{ - gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); - var_TexCoords = attr_TexCoord0.st; -} diff --git a/code/renderergl2/glsl/depthblur_fp.glsl b/code/renderergl2/glsl/depthblur_fp.glsl deleted file mode 100644 index 93895b4e17..0000000000 --- a/code/renderergl2/glsl/depthblur_fp.glsl +++ /dev/null @@ -1,58 +0,0 @@ -uniform sampler2D u_ScreenImageMap; -uniform sampler2D u_ScreenDepthMap; - -uniform vec4 u_ViewInfo; // zfar / znear, zfar -varying vec2 var_ScreenTex; - -//float gauss[5] = float[5](0.30, 0.23, 0.097, 0.024, 0.0033); -float gauss[4] = float[4](0.40, 0.24, 0.054, 0.0044); -//float gauss[3] = float[3](0.60, 0.19, 0.0066); -#define GAUSS_SIZE 4 - -float getLinearDepth(sampler2D depthMap, const vec2 tex, const float zFarDivZNear) -{ - float sampleZDivW = texture2D(depthMap, tex).r; - return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW); -} - -vec4 depthGaussian1D(sampler2D imageMap, sampler2D depthMap, vec2 tex, float zFarDivZNear, float zFar) -{ - float scale = 1.0 / 256.0; - -#if defined(USE_HORIZONTAL_BLUR) - vec2 direction = vec2(1.0, 0.0) * scale; -#else // if defined(USE_VERTICAL_BLUR) - vec2 direction = vec2(0.0, 1.0) * scale; -#endif - - float depthCenter = zFar * getLinearDepth(depthMap, tex, zFarDivZNear); - vec2 centerSlope = vec2(dFdx(depthCenter), dFdy(depthCenter)) / vec2(dFdx(tex.x), dFdy(tex.y)); - - vec4 result = texture2D(imageMap, tex) * gauss[0]; - float total = gauss[0]; - - int i, j; - for (i = 0; i < 2; i++) - { - for (j = 1; j < GAUSS_SIZE; j++) - { - vec2 offset = direction * j; - float depthSample = zFar * getLinearDepth(depthMap, tex + offset, zFarDivZNear); - float depthExpected = depthCenter + dot(centerSlope, offset); - if(abs(depthSample - depthExpected) < 5.0) - { - result += texture2D(imageMap, tex + offset) * gauss[j]; - total += gauss[j]; - } - } - - direction = -direction; - } - - return result / total; -} - -void main() -{ - gl_FragColor = depthGaussian1D(u_ScreenImageMap, u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y); -} diff --git a/code/renderergl2/glsl/depthblur_vp.glsl b/code/renderergl2/glsl/depthblur_vp.glsl deleted file mode 100644 index 9c46a79f26..0000000000 --- a/code/renderergl2/glsl/depthblur_vp.glsl +++ /dev/null @@ -1,12 +0,0 @@ -attribute vec4 attr_Position; -attribute vec4 attr_TexCoord0; - -varying vec2 var_ScreenTex; - -void main() -{ - gl_Position = attr_Position; - var_ScreenTex = attr_TexCoord0.xy; - //vec2 screenCoords = gl_Position.xy / gl_Position.w; - //var_ScreenTex = screenCoords * 0.5 + 0.5; -} diff --git a/code/renderergl2/glsl/dlight_fp.glsl b/code/renderergl2/glsl/dlight_fp.glsl deleted file mode 100644 index 8ffca5b98d..0000000000 --- a/code/renderergl2/glsl/dlight_fp.glsl +++ /dev/null @@ -1,12 +0,0 @@ -uniform sampler2D u_DiffuseMap; - -varying vec2 var_Tex1; -varying vec4 var_Color; - - -void main() -{ - vec4 color = texture2D(u_DiffuseMap, var_Tex1); - - gl_FragColor = color * var_Color; -} diff --git a/code/renderergl2/glsl/dlight_vp.glsl b/code/renderergl2/glsl/dlight_vp.glsl deleted file mode 100644 index 9566a04c26..0000000000 --- a/code/renderergl2/glsl/dlight_vp.glsl +++ /dev/null @@ -1,92 +0,0 @@ -attribute vec3 attr_Position; -attribute vec4 attr_TexCoord0; -attribute vec3 attr_Normal; - -uniform vec4 u_DlightInfo; - -#if defined(USE_DEFORM_VERTEXES) -uniform int u_DeformGen; -uniform float u_DeformParams[5]; -uniform float u_Time; -#endif - -uniform vec4 u_Color; -uniform mat4 u_ModelViewProjectionMatrix; - -varying vec2 var_Tex1; -varying vec4 var_Color; - -#if defined(USE_DEFORM_VERTEXES) -vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) -{ - if (u_DeformGen == 0) - { - return pos; - } - - float base = u_DeformParams[0]; - float amplitude = u_DeformParams[1]; - float phase = u_DeformParams[2]; - float frequency = u_DeformParams[3]; - float spread = u_DeformParams[4]; - - if (u_DeformGen == DGEN_BULGE) - { - phase *= st.x; - } - else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH) - { - phase += dot(pos.xyz, vec3(spread)); - } - - float value = phase + (u_Time * frequency); - float func; - - if (u_DeformGen == DGEN_WAVE_SIN) - { - func = sin(value * 2.0 * M_PI); - } - else if (u_DeformGen == DGEN_WAVE_SQUARE) - { - func = sign(0.5 - fract(value)); - } - else if (u_DeformGen == DGEN_WAVE_TRIANGLE) - { - func = abs(fract(value + 0.75) - 0.5) * 4.0 - 1.0; - } - else if (u_DeformGen == DGEN_WAVE_SAWTOOTH) - { - func = fract(value); - } - else if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH) - { - func = (1.0 - fract(value)); - } - else // if (u_DeformGen == DGEN_BULGE) - { - func = sin(value); - } - - return pos + normal * (base + func * amplitude); -} -#endif - -void main() -{ - vec3 position = attr_Position; - vec3 normal = attr_Normal * 2.0 - vec3(1.0); - -#if defined(USE_DEFORM_VERTEXES) - position = DeformPosition(position, normal, attr_TexCoord0.st); -#endif - - gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0); - - vec3 dist = u_DlightInfo.xyz - position; - - var_Tex1 = dist.xy * u_DlightInfo.a + vec2(0.5); - float dlightmod = step(0.0, dot(dist, normal)); - dlightmod *= clamp(2.0 * (1.0 - abs(dist.z) * u_DlightInfo.a), 0.0, 1.0); - - var_Color = u_Color * dlightmod; -} diff --git a/code/renderergl2/glsl/down4x_fp.glsl b/code/renderergl2/glsl/down4x_fp.glsl deleted file mode 100644 index 0f88fb2e34..0000000000 --- a/code/renderergl2/glsl/down4x_fp.glsl +++ /dev/null @@ -1,34 +0,0 @@ -uniform sampler2D u_TextureMap; - -uniform vec2 u_InvTexRes; -varying vec2 var_TexCoords; - -void main() -{ - vec4 color; - vec2 tc; - - tc = var_TexCoords + u_InvTexRes * vec2(-1.5, -1.5); color = texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2(-0.5, -1.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( 0.5, -1.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( 1.5, -1.5); color += texture2D(u_TextureMap, tc); - - tc = var_TexCoords + u_InvTexRes * vec2(-1.5, -0.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2(-0.5, -0.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( 0.5, -0.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( 1.5, -0.5); color += texture2D(u_TextureMap, tc); - - tc = var_TexCoords + u_InvTexRes * vec2(-1.5, 0.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2(-0.5, 0.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( 0.5, 0.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( 1.5, 0.5); color += texture2D(u_TextureMap, tc); - - tc = var_TexCoords + u_InvTexRes * vec2(-1.5, 1.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2(-0.5, 1.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( 0.5, 1.5); color += texture2D(u_TextureMap, tc); - tc = var_TexCoords + u_InvTexRes * vec2( 1.5, 1.5); color += texture2D(u_TextureMap, tc); - - color *= 0.0625; - - gl_FragColor = color; -} diff --git a/code/renderergl2/glsl/down4x_vp.glsl b/code/renderergl2/glsl/down4x_vp.glsl deleted file mode 100644 index bdaa74af8e..0000000000 --- a/code/renderergl2/glsl/down4x_vp.glsl +++ /dev/null @@ -1,13 +0,0 @@ -attribute vec3 attr_Position; -attribute vec4 attr_TexCoord0; - -uniform mat4 u_ModelViewProjectionMatrix; - -varying vec2 var_TexCoords; - - -void main() -{ - gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); - var_TexCoords = attr_TexCoord0.st; -} diff --git a/code/renderergl2/glsl/fogpass_fp.glsl b/code/renderergl2/glsl/fogpass_fp.glsl deleted file mode 100644 index e2ad465ba3..0000000000 --- a/code/renderergl2/glsl/fogpass_fp.glsl +++ /dev/null @@ -1,9 +0,0 @@ -uniform vec4 u_Color; - -varying float var_Scale; - -void main() -{ - gl_FragColor = u_Color; - gl_FragColor.a = sqrt(clamp(var_Scale, 0.0, 1.0)); -} diff --git a/code/renderergl2/glsl/fogpass_vp.glsl b/code/renderergl2/glsl/fogpass_vp.glsl deleted file mode 100644 index 8f7bc72879..0000000000 --- a/code/renderergl2/glsl/fogpass_vp.glsl +++ /dev/null @@ -1,118 +0,0 @@ -attribute vec3 attr_Position; -attribute vec3 attr_Normal; - -attribute vec4 attr_TexCoord0; - -#if defined(USE_VERTEX_ANIMATION) -attribute vec3 attr_Position2; -attribute vec3 attr_Normal2; -#endif - -uniform vec4 u_FogDistance; -uniform vec4 u_FogDepth; -uniform float u_FogEyeT; - -#if defined(USE_DEFORM_VERTEXES) -uniform int u_DeformGen; -uniform float u_DeformParams[5]; -#endif - -uniform float u_Time; -uniform mat4 u_ModelViewProjectionMatrix; - -#if defined(USE_VERTEX_ANIMATION) -uniform float u_VertexLerp; -#endif - -uniform vec4 u_Color; - -varying float var_Scale; - -#if defined(USE_DEFORM_VERTEXES) -vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) -{ - if (u_DeformGen == 0) - { - return pos; - } - - float base = u_DeformParams[0]; - float amplitude = u_DeformParams[1]; - float phase = u_DeformParams[2]; - float frequency = u_DeformParams[3]; - float spread = u_DeformParams[4]; - - if (u_DeformGen == DGEN_BULGE) - { - phase *= st.x; - } - else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH) - { - phase += dot(pos.xyz, vec3(spread)); - } - - float value = phase + (u_Time * frequency); - float func; - - if (u_DeformGen == DGEN_WAVE_SIN) - { - func = sin(value * 2.0 * M_PI); - } - else if (u_DeformGen == DGEN_WAVE_SQUARE) - { - func = sign(0.5 - fract(value)); - } - else if (u_DeformGen == DGEN_WAVE_TRIANGLE) - { - func = abs(fract(value + 0.75) - 0.5) * 4.0 - 1.0; - } - else if (u_DeformGen == DGEN_WAVE_SAWTOOTH) - { - func = fract(value); - } - else if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH) - { - func = (1.0 - fract(value)); - } - else // if (u_DeformGen == DGEN_BULGE) - { - func = sin(value); - } - - return pos + normal * (base + func * amplitude); -} -#endif - -float CalcFog(vec3 position) -{ - float s = dot(vec4(position, 1.0), u_FogDistance) * 8.0; - float t = dot(vec4(position, 1.0), u_FogDepth); - - float eyeOutside = float(u_FogEyeT < 0.0); - float fogged = float(t >= eyeOutside); - - t += 1e-6; - t *= fogged / (t - u_FogEyeT * eyeOutside); - - return s * t; -} - -void main() -{ -#if defined(USE_VERTEX_ANIMATION) - vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp); - vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp); - normal = normalize(normal - vec3(0.5)); -#else - vec3 position = attr_Position; - vec3 normal = attr_Normal * 2.0 - vec3(1.0); -#endif - -#if defined(USE_DEFORM_VERTEXES) - position.xyz = DeformPosition(position.xyz, normal, attr_TexCoord0.st); -#endif - - gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0); - - var_Scale = CalcFog(position) * u_Color.a * u_Color.a; -} diff --git a/code/renderergl2/glsl/generic_fp.glsl b/code/renderergl2/glsl/generic_fp.glsl deleted file mode 100644 index aefa33c3fa..0000000000 --- a/code/renderergl2/glsl/generic_fp.glsl +++ /dev/null @@ -1,45 +0,0 @@ -uniform sampler2D u_DiffuseMap; - -#if defined(USE_LIGHTMAP) -uniform sampler2D u_LightMap; - -uniform int u_Texture1Env; -#endif - -varying vec2 var_DiffuseTex; - -#if defined(USE_LIGHTMAP) -varying vec2 var_LightTex; -#endif - -varying vec4 var_Color; - - -void main() -{ - vec4 color = texture2D(u_DiffuseMap, var_DiffuseTex); -#if defined(USE_LIGHTMAP) - vec4 color2 = texture2D(u_LightMap, var_LightTex); - #if defined(RGBM_LIGHTMAP) - color2.rgb *= color2.a; - color2.a = 1.0; - #endif - - if (u_Texture1Env == TEXENV_MODULATE) - { - color *= color2; - } - else if (u_Texture1Env == TEXENV_ADD) - { - color += color2; - } - else if (u_Texture1Env == TEXENV_REPLACE) - { - color = color2; - } - - //color = color * (u_Texture1Env.xxxx + color2 * u_Texture1Env.z) + color2 * u_Texture1Env.y; -#endif - - gl_FragColor = color * var_Color; -} diff --git a/code/renderergl2/glsl/generic_vp.glsl b/code/renderergl2/glsl/generic_vp.glsl deleted file mode 100644 index 0e5b38b41b..0000000000 --- a/code/renderergl2/glsl/generic_vp.glsl +++ /dev/null @@ -1,247 +0,0 @@ -attribute vec3 attr_Position; -attribute vec3 attr_Normal; - -#if defined(USE_VERTEX_ANIMATION) -attribute vec3 attr_Position2; -attribute vec3 attr_Normal2; -#endif - -attribute vec4 attr_Color; -attribute vec4 attr_TexCoord0; - -#if defined(USE_LIGHTMAP) || defined(USE_TCGEN) -attribute vec4 attr_TexCoord1; -#endif - -uniform vec4 u_DiffuseTexMatrix; -uniform vec4 u_DiffuseTexOffTurb; - -#if defined(USE_TCGEN) || defined(USE_RGBAGEN) -uniform vec3 u_LocalViewOrigin; -#endif - -#if defined(USE_TCGEN) -uniform int u_TCGen0; -uniform vec3 u_TCGen0Vector0; -uniform vec3 u_TCGen0Vector1; -#endif - -#if defined(USE_FOG) -uniform vec4 u_FogDistance; -uniform vec4 u_FogDepth; -uniform float u_FogEyeT; -uniform vec4 u_FogColorMask; -#endif - -#if defined(USE_DEFORM_VERTEXES) -uniform int u_DeformGen; -uniform float u_DeformParams[5]; -uniform float u_Time; -#endif - -uniform mat4 u_ModelViewProjectionMatrix; -uniform vec4 u_BaseColor; -uniform vec4 u_VertColor; - -#if defined(USE_RGBAGEN) -uniform int u_ColorGen; -uniform int u_AlphaGen; -uniform vec3 u_AmbientLight; -uniform vec3 u_DirectedLight; -uniform vec3 u_ModelLightDir; -uniform float u_PortalRange; -#endif - -#if defined(USE_VERTEX_ANIMATION) -uniform float u_VertexLerp; -#endif - -varying vec2 var_DiffuseTex; -#if defined(USE_LIGHTMAP) -varying vec2 var_LightTex; -#endif -varying vec4 var_Color; - -#if defined(USE_DEFORM_VERTEXES) -vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) -{ - float base = u_DeformParams[0]; - float amplitude = u_DeformParams[1]; - float phase = u_DeformParams[2]; - float frequency = u_DeformParams[3]; - float spread = u_DeformParams[4]; - - if (u_DeformGen == DGEN_BULGE) - { - phase *= st.x; - } - else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH) - { - phase += dot(pos.xyz, vec3(spread)); - } - - float value = phase + (u_Time * frequency); - float func; - - if (u_DeformGen == DGEN_WAVE_SIN) - { - func = sin(value * 2.0 * M_PI); - } - else if (u_DeformGen == DGEN_WAVE_SQUARE) - { - func = sign(fract(0.5 - value)); - } - else if (u_DeformGen == DGEN_WAVE_TRIANGLE) - { - func = abs(fract(value + 0.75) - 0.5) * 4.0 - 1.0; - } - else if (u_DeformGen == DGEN_WAVE_SAWTOOTH) - { - func = fract(value); - } - else if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH) - { - func = (1.0 - fract(value)); - } - else // if (u_DeformGen == DGEN_BULGE) - { - func = sin(value); - } - - return pos + normal * (base + func * amplitude); -} -#endif - -#if defined(USE_TCGEN) -vec2 GenTexCoords(int TCGen, vec3 position, vec3 normal, vec3 TCGenVector0, vec3 TCGenVector1) -{ - vec2 tex = attr_TexCoord0.st; - - if (TCGen == TCGEN_LIGHTMAP) - { - tex = attr_TexCoord1.st; - } - else if (TCGen == TCGEN_ENVIRONMENT_MAPPED) - { - vec3 viewer = normalize(u_LocalViewOrigin - position); - vec2 ref = reflect(viewer, normal).yz; - tex.s = ref.x * -0.5 + 0.5; - tex.t = ref.y * 0.5 + 0.5; - } - else if (TCGen == TCGEN_VECTOR) - { - tex = vec2(dot(position, TCGenVector0), dot(position, TCGenVector1)); - } - - return tex; -} -#endif - -#if defined(USE_TCMOD) -vec2 ModTexCoords(vec2 st, vec3 position, vec4 texMatrix, vec4 offTurb) -{ - float amplitude = offTurb.z; - float phase = offTurb.w * 2.0 * M_PI; - vec2 st2; - st2.x = st.x * texMatrix.x + (st.y * texMatrix.z + offTurb.x); - st2.y = st.x * texMatrix.y + (st.y * texMatrix.w + offTurb.y); - - vec2 offsetPos = vec2(position.x + position.z, position.y); - - vec2 texOffset = sin(offsetPos * (2.0 * M_PI / 1024.0) + vec2(phase)); - - return st2 + texOffset * amplitude; -} -#endif - -#if defined(USE_RGBAGEN) -vec4 CalcColor(vec3 position, vec3 normal) -{ - vec4 color = u_VertColor * attr_Color + u_BaseColor; - - if (u_ColorGen == CGEN_LIGHTING_DIFFUSE) - { - float incoming = clamp(dot(normal, u_ModelLightDir), 0.0, 1.0); - - color.rgb = clamp(u_DirectedLight * incoming + u_AmbientLight, 0.0, 1.0); - } - - vec3 viewer = u_LocalViewOrigin - position; - - if (u_AlphaGen == AGEN_LIGHTING_SPECULAR) - { - vec3 lightDir = normalize(vec3(-960.0, 1980.0, 96.0) - position); - vec3 reflected = -reflect(lightDir, normal); - - color.a = clamp(dot(reflected, normalize(viewer)), 0.0, 1.0); - color.a *= color.a; - color.a *= color.a; - } - else if (u_AlphaGen == AGEN_PORTAL) - { - color.a = clamp(length(viewer) / u_PortalRange, 0.0, 1.0); - } - - return color; -} -#endif - -#if defined(USE_FOG) -float CalcFog(vec3 position) -{ - float s = dot(vec4(position, 1.0), u_FogDistance) * 8.0; - float t = dot(vec4(position, 1.0), u_FogDepth); - - float eyeOutside = float(u_FogEyeT < 0.0); - float fogged = float(t < eyeOutside); - - t += 1e-6; - t *= fogged / (t - u_FogEyeT * eyeOutside); - - return s * t; -} -#endif - -void main() -{ -#if defined(USE_VERTEX_ANIMATION) - vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp); - vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp); - normal = normalize(normal - vec3(0.5)); -#else - vec3 position = attr_Position; - vec3 normal = attr_Normal * 2.0 - vec3(1.0); -#endif - -#if defined(USE_DEFORM_VERTEXES) - position = DeformPosition(position, normal, attr_TexCoord0.st); -#endif - - gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0); - -#if defined(USE_TCGEN) - vec2 tex = GenTexCoords(u_TCGen0, position, normal, u_TCGen0Vector0, u_TCGen0Vector1); -#else - vec2 tex = attr_TexCoord0.st; -#endif - -#if defined(USE_TCMOD) - var_DiffuseTex = ModTexCoords(tex, position, u_DiffuseTexMatrix, u_DiffuseTexOffTurb); -#else - var_DiffuseTex = tex; -#endif - -#if defined(USE_LIGHTMAP) - var_LightTex = attr_TexCoord1.st; -#endif - -#if defined(USE_RGBAGEN) - var_Color = CalcColor(position, normal); -#else - var_Color = u_VertColor * attr_Color + u_BaseColor; -#endif - -#if defined(USE_FOG) - var_Color *= vec4(1.0) - u_FogColorMask * sqrt(clamp(CalcFog(position), 0.0, 1.0)); -#endif -} diff --git a/code/renderergl2/glsl/lightall_fp.glsl b/code/renderergl2/glsl/lightall_fp.glsl deleted file mode 100644 index b983d6fef6..0000000000 --- a/code/renderergl2/glsl/lightall_fp.glsl +++ /dev/null @@ -1,537 +0,0 @@ -uniform sampler2D u_DiffuseMap; - -#if defined(USE_LIGHTMAP) -uniform sampler2D u_LightMap; -#endif - -#if defined(USE_NORMALMAP) -uniform sampler2D u_NormalMap; -#endif - -#if defined(USE_DELUXEMAP) -uniform sampler2D u_DeluxeMap; -#endif - -#if defined(USE_SPECULARMAP) -uniform sampler2D u_SpecularMap; -#endif - -#if defined(USE_SHADOWMAP) -uniform sampler2D u_ShadowMap; -#endif - -#if defined(USE_CUBEMAP) -uniform samplerCube u_CubeMap; -#endif - -#if defined(USE_NORMALMAP) || defined(USE_DELUXEMAP) || defined(USE_SPECULARMAP) || defined(USE_CUBEMAP) -uniform vec4 u_EnableTextures; // x = normal, y = deluxe, z = specular, w = cube -#endif - -#if defined(USE_LIGHT_VECTOR) && !defined(USE_FAST_LIGHT) -uniform vec3 u_DirectedLight; -uniform vec3 u_AmbientLight; -#endif - -#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) -uniform vec3 u_PrimaryLightColor; -uniform vec3 u_PrimaryLightAmbient; -#endif - -#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) -uniform vec2 u_MaterialInfo; -#endif - -varying vec4 var_TexCoords; - -varying vec4 var_Color; - -#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) - #if defined(USE_VERT_TANGENT_SPACE) -varying vec4 var_Normal; -varying vec4 var_Tangent; -varying vec4 var_Bitangent; - #else -varying vec3 var_Normal; -varying vec3 var_ViewDir; - #endif -#endif - -#if defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT) -varying vec3 var_LightColor; -#endif - -#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) -varying vec4 var_LightDir; -#endif - -#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) -varying vec4 var_PrimaryLightDir; -#endif - - -#define EPSILON 0.00000001 - -#if defined(USE_PARALLAXMAP) -float SampleDepth(sampler2D normalMap, vec2 t) -{ - #if defined(SWIZZLE_NORMALMAP) - return 1.0 - texture2D(normalMap, t).r; - #else - return 1.0 - texture2D(normalMap, t).a; - #endif -} - -float RayIntersectDisplaceMap(vec2 dp, vec2 ds, sampler2D normalMap) -{ - const int linearSearchSteps = 16; - const int binarySearchSteps = 6; - - // current size of search window - float size = 1.0 / float(linearSearchSteps); - - // current depth position - float depth = 0.0; - - // best match found (starts with last position 1.0) - float bestDepth = 1.0; - - // search front to back for first point inside object - for(int i = 0; i < linearSearchSteps - 1; ++i) - { - depth += size; - - float t = SampleDepth(normalMap, dp + ds * depth); - - if(bestDepth > 0.996) // if no depth found yet - if(depth >= t) - bestDepth = depth; // store best depth - } - - depth = bestDepth; - - // recurse around first point (depth) for closest match - for(int i = 0; i < binarySearchSteps; ++i) - { - size *= 0.5; - - float t = SampleDepth(normalMap, dp + ds * depth); - - if(depth >= t) - { - bestDepth = depth; - depth -= 2.0 * size; - } - - depth += size; - } - - return bestDepth; -} -#endif - -vec3 CalcDiffuse(vec3 diffuseAlbedo, vec3 N, vec3 L, vec3 E, float NE, float NL, float shininess) -{ - #if defined(USE_OREN_NAYAR) || defined(USE_TRIACE_OREN_NAYAR) - float gamma = dot(E, L) - NE * NL; - float B = 2.22222 + 0.1 * shininess; - - #if defined(USE_OREN_NAYAR) - float A = 1.0 - 1.0 / (2.0 + 0.33 * shininess); - gamma = clamp(gamma, 0.0, 1.0); - #endif - - #if defined(USE_TRIACE_OREN_NAYAR) - float A = 1.0 - 1.0 / (2.0 + 0.65 * shininess); - - if (gamma >= 0.0) - #endif - { - B = max(B * max(NL, NE), EPSILON); - } - - return diffuseAlbedo * (A + gamma / B); - #else - return diffuseAlbedo; - #endif -} - -vec3 EnvironmentBRDF(float gloss, float NE, vec3 specular) -{ - #if 1 - // from http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf - vec4 t = vec4( 1/0.96, 0.475, (0.0275 - 0.25 * 0.04)/0.96,0.25 ) * gloss; - t += vec4( 0.0, 0.0, (0.015 - 0.75 * 0.04)/0.96,0.75 ); - float a0 = t.x * min( t.y, exp2( -9.28 * NE ) ) + t.z; - float a1 = t.w; - return clamp( a0 + specular * ( a1 - a0 ), 0.0, 1.0 ); - #elif 0 - // from http://seblagarde.wordpress.com/2011/08/17/hello-world/ - return mix(specular.rgb, max(specular.rgb, vec3(gloss)), CalcFresnel(NE)); - #else - // from http://advances.realtimerendering.com/s2011/Lazarov-Physically-Based-Lighting-in-Black-Ops%20%28Siggraph%202011%20Advances%20in%20Real-Time%20Rendering%20Course%29.pptx - return mix(specular.rgb, vec3(1.0), CalcFresnel(NE) / (4.0 - 3.0 * gloss)); - #endif -} - -float CalcBlinn(float NH, float shininess) -{ -#if defined(USE_BLINN) || defined(USE_BLINN_FRESNEL) - // Normalized Blinn-Phong - float norm = shininess * 0.125 + 1.0; -#elif defined(USE_MCAULEY) - // Cook-Torrance as done by Stephen McAuley - // http://blog.selfshadow.com/publications/s2012-shading-course/mcauley/s2012_pbs_farcry3_notes_v2.pdf - float norm = shininess * 0.25 + 0.125; -#elif defined(USE_GOTANDA) - // Neumann-Neumann as done by Yoshiharu Gotanda - // http://research.tri-ace.com/Data/s2012_beyond_CourseNotes.pdf - float norm = shininess * 0.124858 + 0.269182; -#elif defined(USE_LAZAROV) - // Cook-Torrance as done by Dimitar Lazarov - // http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf - float norm = shininess * 0.125 + 0.25; -#else - float norm = 1.0; -#endif - -#if 0 - // from http://seblagarde.wordpress.com/2012/06/03/spherical-gaussien-approximation-for-blinn-phong-phong-and-fresnel/ - float a = shininess + 0.775; - return norm * exp(a * NH - a); -#else - return norm * pow(NH, shininess); -#endif -} - -float CalcGGX(float NH, float gloss) -{ - // from http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf - float a_sq = exp2(gloss * -13.0 + 1.0); - float d = ((NH * NH) * (a_sq - 1.0) + 1.0); - return a_sq / (d * d); -} - -float CalcFresnel(float EH) -{ -#if 1 - // From http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf - // not accurate, but fast - return exp2(-10.0 * EH); -#elif 0 - // From http://seblagarde.wordpress.com/2012/06/03/spherical-gaussien-approximation-for-blinn-phong-phong-and-fresnel/ - return exp2((-5.55473 * EH - 6.98316) * EH); -#elif 0 - float blend = 1.0 - EH; - float blend2 = blend * blend; - blend *= blend2 * blend2; - - return blend; -#else - return pow(1.0 - EH, 5.0); -#endif -} - -float CalcVisibility(float NH, float NL, float NE, float EH, float gloss) -{ -#if defined(USE_GOTANDA) - // Neumann-Neumann as done by Yoshiharu Gotanda - // http://research.tri-ace.com/Data/s2012_beyond_CourseNotes.pdf - return 1.0 / max(max(NL, NE), EPSILON); -#elif defined(USE_LAZAROV) - // Cook-Torrance as done by Dimitar Lazarov - // http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf - float k = min(1.0, gloss + 0.545); - return 1.0 / (k * (EH * EH - 1.0) + 1.0); -#elif defined(USE_GGX) - float roughness = exp2(gloss * -6.5); - - // Modified from http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf - // NL, NE in numerator factored out from cook-torrance - float k = roughness + 1.0; - k *= k * 0.125; - - float k2 = 1.0 - k; - - float invGeo1 = NL * k2 + k; - float invGeo2 = NE * k2 + k; - - return 1.0 / (invGeo1 * invGeo2); -#else - return 1.0; -#endif -} - - -vec3 CalcSpecular(vec3 specular, float NH, float NL, float NE, float EH, float gloss, float shininess) -{ -#if defined(USE_GGX) - float distrib = CalcGGX(NH, gloss); -#else - float distrib = CalcBlinn(NH, shininess); -#endif - -#if defined(USE_BLINN) - vec3 fSpecular = specular; -#else - vec3 fSpecular = mix(specular, vec3(1.0), CalcFresnel(EH)); -#endif - - float vis = CalcVisibility(NH, NL, NE, EH, gloss); - - return fSpecular * (distrib * vis); -} - - -float CalcLightAttenuation(float point, float normDist) -{ - // zero light at 1.0, approximating q3 style - // also don't attenuate directional light - float attenuation = (0.5 * normDist - 1.5) * point + 1.0; - - // clamp attenuation - #if defined(NO_LIGHT_CLAMP) - attenuation = max(attenuation, 0.0); - #else - attenuation = clamp(attenuation, 0.0, 1.0); - #endif - - return attenuation; -} - -// from http://www.thetenthplanet.de/archives/1180 -mat3 cotangent_frame( vec3 N, vec3 p, vec2 uv ) -{ - // get edge vectors of the pixel triangle - vec3 dp1 = dFdx( p ); - vec3 dp2 = dFdy( p ); - vec2 duv1 = dFdx( uv ); - vec2 duv2 = dFdy( uv ); - - // solve the linear system - vec3 dp2perp = cross( dp2, N ); - vec3 dp1perp = cross( N, dp1 ); - vec3 T = dp2perp * duv1.x + dp1perp * duv2.x; - vec3 B = dp2perp * duv1.y + dp1perp * duv2.y; - - // construct a scale-invariant frame - float invmax = inversesqrt( max( dot(T,T), dot(B,B) ) ); - return mat3( T * invmax, B * invmax, N ); -} - -void main() -{ - vec3 L, N, E, H; - float NL, NH, NE, EH; - -#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - #if defined(USE_VERT_TANGENT_SPACE) - mat3 tangentToWorld = mat3(var_Tangent.xyz, var_Bitangent.xyz, var_Normal.xyz); - E = vec3(var_Normal.w, var_Tangent.w, var_Bitangent.w); - #else - mat3 tangentToWorld = cotangent_frame(var_Normal, -var_ViewDir, var_TexCoords.xy); - E = var_ViewDir; - #endif - - E = normalize(E); - - L = var_LightDir.xyz; - #if defined(USE_DELUXEMAP) - L += (texture2D(u_DeluxeMap, var_TexCoords.zw).xyz - vec3(0.5)) * u_EnableTextures.y; - #endif - float sqrLightDist = dot(L, L); -#endif - -#if defined(USE_LIGHTMAP) - vec4 lightSample = texture2D(u_LightMap, var_TexCoords.zw); - vec3 lightColor = lightSample.rgb; - #if defined(RGBM_LIGHTMAP) - lightColor *= lightSample.a; - #endif -#elif defined(USE_LIGHT_VECTOR) && !defined(USE_FAST_LIGHT) - vec3 lightColor = u_DirectedLight * CalcLightAttenuation(float(var_LightDir.w > 0.0), var_LightDir.w / sqrLightDist); - vec3 ambientColor = u_AmbientLight; -#elif defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT) - vec3 lightColor = var_LightColor; -#endif - - vec2 texCoords = var_TexCoords.xy; - -#if defined(USE_PARALLAXMAP) - vec3 offsetDir = normalize(E * tangentToWorld); - - offsetDir.xy *= -0.05 / offsetDir.z; - - texCoords += offsetDir.xy * RayIntersectDisplaceMap(texCoords, offsetDir.xy, u_NormalMap); -#endif - - vec4 diffuse = texture2D(u_DiffuseMap, texCoords); -#if defined(USE_GAMMA2_TEXTURES) - diffuse.rgb *= diffuse.rgb; -#endif - - -#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - #if defined(USE_NORMALMAP) - #if defined(SWIZZLE_NORMALMAP) - N.xy = texture2D(u_NormalMap, texCoords).ag - vec2(0.5); - #else - N.xy = texture2D(u_NormalMap, texCoords).rg - vec2(0.5); - #endif - N.xy *= u_EnableTextures.x; - N.z = sqrt((0.25 - N.x * N.x) - N.y * N.y); - N = tangentToWorld * N; - #else - N = var_Normal.xyz; - #endif - - N = normalize(N); - L /= sqrt(sqrLightDist); - - #if defined(USE_SHADOWMAP) - vec2 shadowTex = gl_FragCoord.xy * r_FBufScale; - float shadowValue = texture2D(u_ShadowMap, shadowTex).r; - - // surfaces not facing the light are always shadowed - shadowValue *= float(dot(var_Normal.xyz, var_PrimaryLightDir.xyz) > 0.0); - - #if defined(SHADOWMAP_MODULATE) - //vec3 shadowColor = min(u_PrimaryLightAmbient, lightColor); - vec3 shadowColor = u_PrimaryLightAmbient * lightColor; - - #if 0 - // Only shadow when the world light is parallel to the primary light - shadowValue = 1.0 + (shadowValue - 1.0) * clamp(dot(L, var_PrimaryLightDir.xyz), 0.0, 1.0); - #endif - lightColor = mix(shadowColor, lightColor, shadowValue); - #endif - #endif - - #if defined(USE_LIGHTMAP) || defined(USE_LIGHT_VERTEX) - vec3 ambientColor = lightColor; - float surfNL = clamp(dot(var_Normal.xyz, L), 0.0, 1.0); - - // Scale the incoming light to compensate for the baked-in light angle - // attenuation. - lightColor /= max(surfNL, 0.25); - - // Recover any unused light as ambient, in case attenuation is over 4x or - // light is below the surface - ambientColor -= lightColor * surfNL; - #endif - - vec3 reflectance; - - NL = clamp(dot(N, L), 0.0, 1.0); - NE = clamp(dot(N, E), 0.0, 1.0); - - vec4 specular = vec4(1.0); - #if defined(USE_SPECULARMAP) - specular += texture2D(u_SpecularMap, texCoords) * u_EnableTextures.z - u_EnableTextures.zzzz; - #if defined(USE_GAMMA2_TEXTURES) - specular.rgb *= specular.rgb; - #endif - #endif - - specular *= u_MaterialInfo.xxxy; - - float gloss = specular.a; - float shininess = exp2(gloss * 13.0); - - #if defined(SPECULAR_IS_METALLIC) - // diffuse is actually base color, and red of specular is metallicness - float metallic = specular.r; - - specular.rgb = (0.96 * metallic) * diffuse.rgb + vec3(0.04); - diffuse.rgb *= 1.0 - metallic; - #else - // adjust diffuse by specular reflectance, to maintain energy conservation - diffuse.rgb *= vec3(1.0) - specular.rgb; - #endif - - reflectance = CalcDiffuse(diffuse.rgb, N, L, E, NE, NL, shininess); - - #if defined(r_deluxeSpecular) || defined(USE_LIGHT_VECTOR) - float adjGloss = gloss; - float adjShininess = shininess; - - #if !defined(USE_LIGHT_VECTOR) - adjGloss *= r_deluxeSpecular; - adjShininess = exp2(adjGloss * 13.0); - #endif - - H = normalize(L + E); - - EH = clamp(dot(E, H), 0.0, 1.0); - NH = clamp(dot(N, H), 0.0, 1.0); - - #if !defined(USE_LIGHT_VECTOR) - reflectance += CalcSpecular(specular.rgb, NH, NL, NE, EH, adjGloss, adjShininess) * r_deluxeSpecular; - #else - reflectance += CalcSpecular(specular.rgb, NH, NL, NE, EH, adjGloss, adjShininess); - #endif - #endif - - gl_FragColor.rgb = lightColor * reflectance * NL; - gl_FragColor.rgb += ambientColor * (diffuse.rgb + specular.rgb); - - #if defined(USE_CUBEMAP) - reflectance = EnvironmentBRDF(gloss, NE, specular.rgb); - - vec3 R = reflect(E, N); - - vec3 cubeLightColor = textureCubeLod(u_CubeMap, R, 7.0 - gloss * 7.0).rgb * u_EnableTextures.w; - - #if defined(USE_LIGHTMAP) - cubeLightColor *= lightSample.rgb; - #elif defined (USE_LIGHT_VERTEX) - cubeLightColor *= var_LightColor; - #else - cubeLightColor *= lightColor * NL + ambientColor; - #endif - - //gl_FragColor.rgb += diffuse.rgb * textureCubeLod(u_CubeMap, N, 7.0).rgb * u_EnableTextures.w; - gl_FragColor.rgb += cubeLightColor * reflectance; - #endif - - #if defined(USE_PRIMARY_LIGHT) - vec3 L2, H2; - float NL2, EH2, NH2; - - L2 = var_PrimaryLightDir.xyz; - - // enable when point lights are supported as primary lights - //sqrLightDist = dot(L2, L2); - //L2 /= sqrt(sqrLightDist); - - NL2 = clamp(dot(N, L2), 0.0, 1.0); - - H2 = normalize(L2 + E); - EH2 = clamp(dot(E, H2), 0.0, 1.0); - NH2 = clamp(dot(N, H2), 0.0, 1.0); - - reflectance = CalcDiffuse(diffuse.rgb, N, L2, E, NE, NL2, shininess); - reflectance += CalcSpecular(specular.rgb, NH2, NL2, NE, EH2, gloss, shininess); - - lightColor = u_PrimaryLightColor; - - // enable when point lights are supported as primary lights - //lightColor *= CalcLightAttenuation(float(u_PrimaryLightDir.w > 0.0), u_PrimaryLightDir.w / sqrLightDist); - - #if defined(USE_SHADOWMAP) - lightColor *= shadowValue; - #endif - - gl_FragColor.rgb += lightColor * reflectance * NL2; - #endif - - gl_FragColor.a = diffuse.a; -#else - gl_FragColor = diffuse; - #if defined(USE_LIGHTMAP) - gl_FragColor.rgb *= lightColor; - #endif -#endif - - gl_FragColor *= var_Color; -} diff --git a/code/renderergl2/glsl/lightall_vp.glsl b/code/renderergl2/glsl/lightall_vp.glsl deleted file mode 100644 index 2e1c899cae..0000000000 --- a/code/renderergl2/glsl/lightall_vp.glsl +++ /dev/null @@ -1,260 +0,0 @@ -attribute vec4 attr_TexCoord0; -#if defined(USE_LIGHTMAP) || defined(USE_TCGEN) -attribute vec4 attr_TexCoord1; -#endif -attribute vec4 attr_Color; - -attribute vec3 attr_Position; -attribute vec3 attr_Normal; -#if defined(USE_VERT_TANGENT_SPACE) -attribute vec4 attr_Tangent; -#endif - -#if defined(USE_VERTEX_ANIMATION) -attribute vec3 attr_Position2; -attribute vec3 attr_Normal2; - #if defined(USE_VERT_TANGENT_SPACE) -attribute vec4 attr_Tangent2; - #endif -#endif - -#if defined(USE_LIGHT) && !defined(USE_LIGHT_VECTOR) -attribute vec3 attr_LightDirection; -#endif - -#if defined(USE_DELUXEMAP) -uniform vec4 u_EnableTextures; // x = normal, y = deluxe, z = specular, w = cube -#endif - -#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) -uniform vec3 u_ViewOrigin; -#endif - -#if defined(USE_TCGEN) -uniform int u_TCGen0; -uniform vec3 u_TCGen0Vector0; -uniform vec3 u_TCGen0Vector1; -uniform vec3 u_LocalViewOrigin; -#endif - -#if defined(USE_TCMOD) -uniform vec4 u_DiffuseTexMatrix; -uniform vec4 u_DiffuseTexOffTurb; -#endif - -uniform mat4 u_ModelViewProjectionMatrix; -uniform vec4 u_BaseColor; -uniform vec4 u_VertColor; - -#if defined(USE_MODELMATRIX) -uniform mat4 u_ModelMatrix; -#endif - -#if defined(USE_VERTEX_ANIMATION) -uniform float u_VertexLerp; -#endif - -#if defined(USE_LIGHT_VECTOR) -uniform vec4 u_LightOrigin; -uniform float u_LightRadius; - #if defined(USE_FAST_LIGHT) -uniform vec3 u_DirectedLight; -uniform vec3 u_AmbientLight; - #endif -#endif - -#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) -uniform vec4 u_PrimaryLightOrigin; -uniform float u_PrimaryLightRadius; -#endif - -varying vec4 var_TexCoords; - -varying vec4 var_Color; - -#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - #if defined(USE_VERT_TANGENT_SPACE) -varying vec4 var_Normal; -varying vec4 var_Tangent; -varying vec4 var_Bitangent; - #else -varying vec3 var_Normal; -varying vec3 var_ViewDir; - #endif -#endif - -#if defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT) -varying vec3 var_LightColor; -#endif - -#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) -varying vec4 var_LightDir; -#endif - -#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) -varying vec4 var_PrimaryLightDir; -#endif - -#if defined(USE_TCGEN) -vec2 GenTexCoords(int TCGen, vec3 position, vec3 normal, vec3 TCGenVector0, vec3 TCGenVector1) -{ - vec2 tex = attr_TexCoord0.st; - - if (TCGen == TCGEN_LIGHTMAP) - { - tex = attr_TexCoord1.st; - } - else if (TCGen == TCGEN_ENVIRONMENT_MAPPED) - { - vec3 viewer = normalize(u_LocalViewOrigin - position); - vec2 ref = reflect(viewer, normal).yz; - tex.s = ref.x * -0.5 + 0.5; - tex.t = ref.y * 0.5 + 0.5; - } - else if (TCGen == TCGEN_VECTOR) - { - tex = vec2(dot(position, TCGenVector0), dot(position, TCGenVector1)); - } - - return tex; -} -#endif - -#if defined(USE_TCMOD) -vec2 ModTexCoords(vec2 st, vec3 position, vec4 texMatrix, vec4 offTurb) -{ - float amplitude = offTurb.z; - float phase = offTurb.w * 2.0 * M_PI; - vec2 st2; - st2.x = st.x * texMatrix.x + (st.y * texMatrix.z + offTurb.x); - st2.y = st.x * texMatrix.y + (st.y * texMatrix.w + offTurb.y); - - vec2 offsetPos = vec2(position.x + position.z, position.y); - - vec2 texOffset = sin(offsetPos * (2.0 * M_PI / 1024.0) + vec2(phase)); - - return st2 + texOffset * amplitude; -} -#endif - - -float CalcLightAttenuation(float point, float normDist) -{ - // zero light at 1.0, approximating q3 style - // also don't attenuate directional light - float attenuation = (0.5 * normDist - 1.5) * point + 1.0; - - // clamp attenuation - #if defined(NO_LIGHT_CLAMP) - attenuation = max(attenuation, 0.0); - #else - attenuation = clamp(attenuation, 0.0, 1.0); - #endif - - return attenuation; -} - - -void main() -{ -#if defined(USE_VERTEX_ANIMATION) - vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp); - vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp); - #if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - vec3 tangent = mix(attr_Tangent.xyz, attr_Tangent2.xyz, u_VertexLerp); - #endif -#else - vec3 position = attr_Position; - vec3 normal = attr_Normal; - #if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - vec3 tangent = attr_Tangent.xyz; - #endif -#endif - - normal = normal * 2.0 - vec3(1.0); -#if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - tangent = tangent * 2.0 - vec3(1.0); -#endif - -#if defined(USE_TCGEN) - vec2 texCoords = GenTexCoords(u_TCGen0, position, normal, u_TCGen0Vector0, u_TCGen0Vector1); -#else - vec2 texCoords = attr_TexCoord0.st; -#endif - -#if defined(USE_TCMOD) - var_TexCoords.xy = ModTexCoords(texCoords, position, u_DiffuseTexMatrix, u_DiffuseTexOffTurb); -#else - var_TexCoords.xy = texCoords; -#endif - - gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0); - -#if defined(USE_MODELMATRIX) - position = (u_ModelMatrix * vec4(position, 1.0)).xyz; - normal = (u_ModelMatrix * vec4(normal, 0.0)).xyz; - #if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - tangent = (u_ModelMatrix * vec4(tangent, 0.0)).xyz; - #endif -#endif - -#if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - vec3 bitangent = cross(normal, tangent) * (attr_Tangent.w * 2.0 - 1.0); -#endif - -#if defined(USE_LIGHT_VECTOR) - vec3 L = u_LightOrigin.xyz - (position * u_LightOrigin.w); -#elif defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - vec3 L = attr_LightDirection * 2.0 - vec3(1.0); - #if defined(USE_MODELMATRIX) - L = (u_ModelMatrix * vec4(L, 0.0)).xyz; - #endif -#endif - -#if defined(USE_LIGHTMAP) - var_TexCoords.zw = attr_TexCoord1.st; -#endif - - var_Color = u_VertColor * attr_Color + u_BaseColor; -#if defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT) - var_LightColor = var_Color.rgb; - var_Color.rgb = vec3(1.0); -#endif - -#if defined(USE_LIGHT_VECTOR) && defined(USE_FAST_LIGHT) - float sqrLightDist = dot(L, L); - float attenuation = CalcLightAttenuation(u_LightOrigin.w, u_LightRadius * u_LightRadius / sqrLightDist); - float NL = clamp(dot(normalize(normal), L) / sqrt(sqrLightDist), 0.0, 1.0); - - var_Color.rgb *= u_DirectedLight * (attenuation * NL) + u_AmbientLight; -#endif - -#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) - var_PrimaryLightDir.xyz = u_PrimaryLightOrigin.xyz - (position * u_PrimaryLightOrigin.w); - var_PrimaryLightDir.w = u_PrimaryLightRadius * u_PrimaryLightRadius; -#endif - -#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - #if defined(USE_LIGHT_VECTOR) - var_LightDir = vec4(L, u_LightRadius * u_LightRadius); - #else - var_LightDir = vec4(L, 0.0); - #endif - #if defined(USE_DELUXEMAP) - var_LightDir -= u_EnableTextures.y * var_LightDir; - #endif -#endif - -#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - vec3 viewDir = u_ViewOrigin - position; - #if defined(USE_VERT_TANGENT_SPACE) - // store view direction in tangent space to save on varyings - var_Normal = vec4(normal, viewDir.x); - var_Tangent = vec4(tangent, viewDir.y); - var_Bitangent = vec4(bitangent, viewDir.z); - #else - var_Normal = normal; - var_ViewDir = viewDir; - #endif -#endif -} diff --git a/code/renderergl2/glsl/pshadow_fp.glsl b/code/renderergl2/glsl/pshadow_fp.glsl deleted file mode 100644 index b152971af6..0000000000 --- a/code/renderergl2/glsl/pshadow_fp.glsl +++ /dev/null @@ -1,98 +0,0 @@ -uniform sampler2D u_ShadowMap; - -uniform vec3 u_LightForward; -uniform vec3 u_LightUp; -uniform vec3 u_LightRight; -uniform vec4 u_LightOrigin; -uniform float u_LightRadius; -varying vec3 var_Position; -varying vec3 var_Normal; - -float sampleDistMap(sampler2D texMap, vec2 uv, float scale) -{ - vec3 distv = texture2D(texMap, uv).xyz; - return dot(distv, vec3(1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0)) * scale; -} - -void main() -{ - vec3 lightToPos = var_Position - u_LightOrigin.xyz; - vec2 st = vec2(-dot(u_LightRight, lightToPos), dot(u_LightUp, lightToPos)); - - float fade = length(st); - -#if defined(USE_DISCARD) - if (fade >= 1.0) - { - discard; - } -#endif - - fade = clamp(8.0 - fade * 8.0, 0.0, 1.0); - - st = st * 0.5 + vec2(0.5); - -#if defined(USE_SOLID_PSHADOWS) - float intensity = max(sign(u_LightRadius - length(lightToPos)), 0.0); -#else - float intensity = clamp((1.0 - dot(lightToPos, lightToPos) / (u_LightRadius * u_LightRadius)) * 2.0, 0.0, 1.0); -#endif - - float lightDist = length(lightToPos); - float dist; - -#if defined(USE_DISCARD) - if (dot(u_LightForward, lightToPos) <= 0.0) - { - discard; - } - - if (dot(var_Normal, lightToPos) > 0.0) - { - discard; - } -#else - intensity *= max(sign(dot(u_LightForward, lightToPos)), 0.0); - intensity *= max(sign(-dot(var_Normal, lightToPos)), 0.0); -#endif - - intensity *= fade; -#if defined(USE_PCF) - float part; - - dist = sampleDistMap(u_ShadowMap, st + vec2(-1.0/512.0, -1.0/512.0), u_LightRadius); - part = max(sign(lightDist - dist), 0.0); - - dist = sampleDistMap(u_ShadowMap, st + vec2( 1.0/512.0, -1.0/512.0), u_LightRadius); - part += max(sign(lightDist - dist), 0.0); - - dist = sampleDistMap(u_ShadowMap, st + vec2(-1.0/512.0, 1.0/512.0), u_LightRadius); - part += max(sign(lightDist - dist), 0.0); - - dist = sampleDistMap(u_ShadowMap, st + vec2( 1.0/512.0, 1.0/512.0), u_LightRadius); - part += max(sign(lightDist - dist), 0.0); - - #if defined(USE_DISCARD) - if (part <= 0.0) - { - discard; - } - #endif - - intensity *= part * 0.25; -#else - dist = sampleDistMap(u_ShadowMap, st, u_LightRadius); - - #if defined(USE_DISCARD) - if (lightDist - dist <= 0.0) - { - discard; - } - #endif - - intensity *= max(sign(lightDist - dist), 0.0); -#endif - - gl_FragColor.rgb = vec3(0); - gl_FragColor.a = clamp(intensity, 0.0, 0.75); -} diff --git a/code/renderergl2/glsl/pshadow_vp.glsl b/code/renderergl2/glsl/pshadow_vp.glsl deleted file mode 100644 index 0f9940cd4e..0000000000 --- a/code/renderergl2/glsl/pshadow_vp.glsl +++ /dev/null @@ -1,15 +0,0 @@ -attribute vec3 attr_Position; -attribute vec3 attr_Normal; - -uniform mat4 u_ModelViewProjectionMatrix; -varying vec3 var_Position; -varying vec3 var_Normal; - - -void main() -{ - gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); - - var_Position = attr_Position; - var_Normal = attr_Normal * 2.0 - vec3(1.0); -} diff --git a/code/renderergl2/glsl/shadowfill_fp.glsl b/code/renderergl2/glsl/shadowfill_fp.glsl deleted file mode 100644 index 150f3d1229..0000000000 --- a/code/renderergl2/glsl/shadowfill_fp.glsl +++ /dev/null @@ -1,41 +0,0 @@ -uniform vec4 u_LightOrigin; -uniform float u_LightRadius; - -varying vec3 var_Position; - -void main() -{ -#if defined(USE_DEPTH) - float depth = length(u_LightOrigin.xyz - var_Position) / u_LightRadius; - #if 0 - // 32 bit precision - const vec4 bitSh = vec4( 256 * 256 * 256, 256 * 256, 256, 1); - const vec4 bitMsk = vec4( 0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); - - vec4 comp; - comp = depth * bitSh; - comp.xyz = fract(comp.xyz); - comp -= comp.xxyz * bitMsk; - gl_FragColor = comp; - #endif - - #if 1 - // 24 bit precision - const vec3 bitSh = vec3( 256 * 256, 256, 1); - const vec3 bitMsk = vec3( 0, 1.0 / 256.0, 1.0 / 256.0); - - vec3 comp; - comp = depth * bitSh; - comp.xy = fract(comp.xy); - comp -= comp.xxy * bitMsk; - gl_FragColor = vec4(comp, 1.0); - #endif - - #if 0 - // 8 bit precision - gl_FragColor = vec4(depth, depth, depth, 1); - #endif -#else - gl_FragColor = vec4(0, 0, 0, 1); -#endif -} diff --git a/code/renderergl2/glsl/shadowfill_vp.glsl b/code/renderergl2/glsl/shadowfill_vp.glsl deleted file mode 100644 index 7a5cc571a1..0000000000 --- a/code/renderergl2/glsl/shadowfill_vp.glsl +++ /dev/null @@ -1,90 +0,0 @@ -attribute vec3 attr_Position; -attribute vec3 attr_Normal; -attribute vec4 attr_TexCoord0; - -//#if defined(USE_VERTEX_ANIMATION) -attribute vec3 attr_Position2; -attribute vec3 attr_Normal2; -//#endif - -//#if defined(USE_DEFORM_VERTEXES) -uniform int u_DeformGen; -uniform float u_DeformParams[5]; -//#endif - -uniform float u_Time; -uniform mat4 u_ModelViewProjectionMatrix; - -uniform mat4 u_ModelMatrix; - -//#if defined(USE_VERTEX_ANIMATION) -uniform float u_VertexLerp; -//#endif - -varying vec3 var_Position; - -vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) -{ - if (u_DeformGen == 0) - { - return pos; - } - - float base = u_DeformParams[0]; - float amplitude = u_DeformParams[1]; - float phase = u_DeformParams[2]; - float frequency = u_DeformParams[3]; - float spread = u_DeformParams[4]; - - if (u_DeformGen == DGEN_BULGE) - { - phase *= st.x; - } - else // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH) - { - phase += dot(pos.xyz, vec3(spread)); - } - - float value = phase + (u_Time * frequency); - float func; - - if (u_DeformGen == DGEN_WAVE_SIN) - { - func = sin(value * 2.0 * M_PI); - } - else if (u_DeformGen == DGEN_WAVE_SQUARE) - { - func = sign(0.5 - fract(value)); - } - else if (u_DeformGen == DGEN_WAVE_TRIANGLE) - { - func = abs(fract(value + 0.75) - 0.5) * 4.0 - 1.0; - } - else if (u_DeformGen == DGEN_WAVE_SAWTOOTH) - { - func = fract(value); - } - else if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH) - { - func = (1.0 - fract(value)); - } - else // if (u_DeformGen == DGEN_BULGE) - { - func = sin(value); - } - - return pos + normal * (base + func * amplitude); -} - -void main() -{ - vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp); - vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp); - normal = normalize(normal - vec3(0.5)); - - position = DeformPosition(position, normal, attr_TexCoord0.st); - - gl_Position = u_ModelViewProjectionMatrix * vec4(position, 1.0); - - var_Position = (u_ModelMatrix * vec4(position, 1.0)).xyz; -} diff --git a/code/renderergl2/glsl/shadowmask_fp.glsl b/code/renderergl2/glsl/shadowmask_fp.glsl deleted file mode 100644 index 4bac5ccdd8..0000000000 --- a/code/renderergl2/glsl/shadowmask_fp.glsl +++ /dev/null @@ -1,127 +0,0 @@ -uniform sampler2D u_ScreenDepthMap; - -uniform sampler2D u_ShadowMap; -#if defined(USE_SHADOW_CASCADE) -uniform sampler2D u_ShadowMap2; -uniform sampler2D u_ShadowMap3; -#endif - -uniform mat4 u_ShadowMvp; -#if defined(USE_SHADOW_CASCADE) -uniform mat4 u_ShadowMvp2; -uniform mat4 u_ShadowMvp3; -#endif - -uniform vec3 u_ViewOrigin; -uniform vec4 u_ViewInfo; // zfar / znear, zfar - -varying vec2 var_DepthTex; -varying vec3 var_ViewDir; - -// Input: It uses texture coords as the random number seed. -// Output: Random number: [0,1), that is between 0.0 and 0.999999... inclusive. -// Author: Michael Pohoreski -// Copyright: Copyleft 2012 :-) -// Source: http://stackoverflow.com/questions/5149544/can-i-generate-a-random-number-inside-a-pixel-shader - -float random( const vec2 p ) -{ - // We need irrationals for pseudo randomness. - // Most (all?) known transcendental numbers will (generally) work. - const vec2 r = vec2( - 23.1406926327792690, // e^pi (Gelfond's constant) - 2.6651441426902251); // 2^sqrt(2) (Gelfond-Schneider constant) - //return fract( cos( mod( 123456789., 1e-7 + 256. * dot(p,r) ) ) ); - return mod( 123456789., 1e-7 + 256. * dot(p,r) ); -} - -float PCF(const sampler2D shadowmap, const vec2 st, const float dist) -{ - float mult; - float scale = 2.0 / r_shadowMapSize; - -#if defined(USE_SHADOW_FILTER) - float r = random(var_DepthTex.xy); - float sinr = sin(r) * scale; - float cosr = cos(r) * scale; - mat2 rmat = mat2(cosr, sinr, -sinr, cosr); - - mult = step(dist, texture2D(shadowmap, st + rmat * vec2(-0.7055767, 0.196515)).r); - mult += step(dist, texture2D(shadowmap, st + rmat * vec2(0.3524343, -0.7791386)).r); - mult += step(dist, texture2D(shadowmap, st + rmat * vec2(0.2391056, 0.9189604)).r); - #if defined(USE_SHADOW_FILTER2) - mult += step(dist, texture2D(shadowmap, st + rmat * vec2(-0.07580382, -0.09224417)).r); - mult += step(dist, texture2D(shadowmap, st + rmat * vec2(0.5784913, -0.002528916)).r); - mult += step(dist, texture2D(shadowmap, st + rmat * vec2(0.192888, 0.4064181)).r); - mult += step(dist, texture2D(shadowmap, st + rmat * vec2(-0.6335801, -0.5247476)).r); - mult += step(dist, texture2D(shadowmap, st + rmat * vec2(-0.5579782, 0.7491854)).r); - mult += step(dist, texture2D(shadowmap, st + rmat * vec2(0.7320465, 0.6317794)).r); - - mult *= 0.11111; - #else - mult *= 0.33333; - #endif -#else - mult = step(dist, texture2D(shadowmap, st).r); -#endif - - return mult; -} - -float getLinearDepth(sampler2D depthMap, vec2 tex, float zFarDivZNear) -{ - float sampleZDivW = texture2D(depthMap, tex).r; - return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW); -} - -void main() -{ - float result; - - float depth = getLinearDepth(u_ScreenDepthMap, var_DepthTex, u_ViewInfo.x); - float sampleZ = u_ViewInfo.y * depth; - - vec4 biasPos = vec4(u_ViewOrigin + var_ViewDir * depth * 0.99, 1.0); - - vec4 shadowpos = u_ShadowMvp * biasPos; - -#if defined(USE_SHADOW_CASCADE) - const float fadeTo = 1.0; - result = fadeTo; -#else - result = 0.0; -#endif - - if (all(lessThanEqual(abs(shadowpos.xyz), vec3(abs(shadowpos.w))))) - { - shadowpos.xyz = shadowpos.xyz / shadowpos.w * 0.5 + 0.5; - result = PCF(u_ShadowMap, shadowpos.xy, shadowpos.z); - } -#if defined(USE_SHADOW_CASCADE) - else - { - shadowpos = u_ShadowMvp2 * biasPos; - - if (all(lessThanEqual(abs(shadowpos.xyz), vec3(abs(shadowpos.w))))) - { - shadowpos.xyz = shadowpos.xyz / shadowpos.w * 0.5 + 0.5; - result = PCF(u_ShadowMap2, shadowpos.xy, shadowpos.z); - } - else - { - shadowpos = u_ShadowMvp3 * biasPos; - - if (all(lessThanEqual(abs(shadowpos.xyz), vec3(abs(shadowpos.w))))) - { - shadowpos.xyz = shadowpos.xyz / shadowpos.w * 0.5 + 0.5; - result = PCF(u_ShadowMap3, shadowpos.xy, shadowpos.z); - - float fade = clamp(sampleZ / r_shadowCascadeZFar * 10.0 - 9.0, 0.0, 1.0); - result = mix(result, fadeTo, fade); - } - } - } -#endif - - gl_FragColor = vec4(vec3(result), 1.0); -} diff --git a/code/renderergl2/glsl/shadowmask_vp.glsl b/code/renderergl2/glsl/shadowmask_vp.glsl deleted file mode 100644 index 13166a2400..0000000000 --- a/code/renderergl2/glsl/shadowmask_vp.glsl +++ /dev/null @@ -1,18 +0,0 @@ -attribute vec4 attr_Position; -attribute vec4 attr_TexCoord0; - -uniform vec3 u_ViewForward; -uniform vec3 u_ViewLeft; -uniform vec3 u_ViewUp; -uniform vec4 u_ViewInfo; // zfar / znear - -varying vec2 var_DepthTex; -varying vec3 var_ViewDir; - -void main() -{ - gl_Position = attr_Position; - vec2 screenCoords = gl_Position.xy / gl_Position.w; - var_DepthTex = attr_TexCoord0.xy; - var_ViewDir = u_ViewForward + u_ViewLeft * -screenCoords.x + u_ViewUp * screenCoords.y; -} diff --git a/code/renderergl2/glsl/ssao_fp.glsl b/code/renderergl2/glsl/ssao_fp.glsl deleted file mode 100644 index 6263284c56..0000000000 --- a/code/renderergl2/glsl/ssao_fp.glsl +++ /dev/null @@ -1,86 +0,0 @@ -uniform sampler2D u_ScreenDepthMap; - -uniform vec4 u_ViewInfo; // zfar / znear, zfar - -varying vec2 var_ScreenTex; - -vec2 poissonDisc[9] = vec2[9]( -vec2(-0.7055767, 0.196515), vec2(0.3524343, -0.7791386), -vec2(0.2391056, 0.9189604), vec2(-0.07580382, -0.09224417), -vec2(0.5784913, -0.002528916), vec2(0.192888, 0.4064181), -vec2(-0.6335801, -0.5247476), vec2(-0.5579782, 0.7491854), -vec2(0.7320465, 0.6317794) -); - -// Input: It uses texture coords as the random number seed. -// Output: Random number: [0,1), that is between 0.0 and 0.999999... inclusive. -// Author: Michael Pohoreski -// Copyright: Copyleft 2012 :-) -// Source: http://stackoverflow.com/questions/5149544/can-i-generate-a-random-number-inside-a-pixel-shader - -float random( const vec2 p ) -{ - // We need irrationals for pseudo randomness. - // Most (all?) known transcendental numbers will (generally) work. - const vec2 r = vec2( - 23.1406926327792690, // e^pi (Gelfond's constant) - 2.6651441426902251); // 2^sqrt(2) (Gelfond-Schneider constant) - //return fract( cos( mod( 123456789., 1e-7 + 256. * dot(p,r) ) ) ); - return mod( 123456789., 1e-7 + 256. * dot(p,r) ); -} - -mat2 randomRotation( const vec2 p ) -{ - float r = random(p); - float sinr = sin(r); - float cosr = cos(r); - return mat2(cosr, sinr, -sinr, cosr); -} - -float getLinearDepth(sampler2D depthMap, const vec2 tex, const float zFarDivZNear) -{ - float sampleZDivW = texture2D(depthMap, tex).r; - return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW); -} - -float ambientOcclusion(sampler2D depthMap, const vec2 tex, const float zFarDivZNear, const float zFar) -{ - float result = 0; - - float sampleZ = zFar * getLinearDepth(depthMap, tex, zFarDivZNear); - - vec2 expectedSlope = vec2(dFdx(sampleZ), dFdy(sampleZ)) / vec2(dFdx(tex.x), dFdy(tex.y)); - - if (length(expectedSlope) > 5000.0) - return 1.0; - - vec2 offsetScale = vec2(3.0 / sampleZ); - - mat2 rmat = randomRotation(tex); - - int i; - for (i = 0; i < 3; i++) - { - vec2 offset = rmat * poissonDisc[i] * offsetScale; - float sampleZ2 = zFar * getLinearDepth(depthMap, tex + offset, zFarDivZNear); - - if (abs(sampleZ - sampleZ2) > 20.0) - result += 1.0; - else - { - float expectedZ = sampleZ + dot(expectedSlope, offset); - result += step(expectedZ - 1.0, sampleZ2); - } - } - - result *= 0.33333; - - return result; -} - -void main() -{ - float result = ambientOcclusion(u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y); - - gl_FragColor = vec4(vec3(result), 1.0); -} diff --git a/code/renderergl2/glsl/ssao_vp.glsl b/code/renderergl2/glsl/ssao_vp.glsl deleted file mode 100644 index 9c46a79f26..0000000000 --- a/code/renderergl2/glsl/ssao_vp.glsl +++ /dev/null @@ -1,12 +0,0 @@ -attribute vec4 attr_Position; -attribute vec4 attr_TexCoord0; - -varying vec2 var_ScreenTex; - -void main() -{ - gl_Position = attr_Position; - var_ScreenTex = attr_TexCoord0.xy; - //vec2 screenCoords = gl_Position.xy / gl_Position.w; - //var_ScreenTex = screenCoords * 0.5 + 0.5; -} diff --git a/code/renderergl2/glsl/texturecolor_fp.glsl b/code/renderergl2/glsl/texturecolor_fp.glsl deleted file mode 100644 index e077e7daf2..0000000000 --- a/code/renderergl2/glsl/texturecolor_fp.glsl +++ /dev/null @@ -1,12 +0,0 @@ -#version 120 - -uniform sampler2D u_DiffuseMap; -uniform vec4 u_Color; - -varying vec2 var_Tex1; - - -void main() -{ - gl_FragColor = texture2D(u_DiffuseMap, var_Tex1) * u_Color; -} diff --git a/code/renderergl2/glsl/texturecolor_vp.glsl b/code/renderergl2/glsl/texturecolor_vp.glsl deleted file mode 100644 index 7a5750a564..0000000000 --- a/code/renderergl2/glsl/texturecolor_vp.glsl +++ /dev/null @@ -1,15 +0,0 @@ -#version 120 - -attribute vec3 attr_Position; -attribute vec4 attr_TexCoord0; - -uniform mat4 u_ModelViewProjectionMatrix; - -varying vec2 var_Tex1; - - -void main() -{ - gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); - var_Tex1 = attr_TexCoord0.st; -} diff --git a/code/renderergl2/glsl/tonemap_fp.glsl b/code/renderergl2/glsl/tonemap_fp.glsl deleted file mode 100644 index 9b18de8a1c..0000000000 --- a/code/renderergl2/glsl/tonemap_fp.glsl +++ /dev/null @@ -1,48 +0,0 @@ -uniform sampler2D u_TextureMap; -uniform sampler2D u_LevelsMap; - -uniform vec4 u_Color; - -uniform vec2 u_AutoExposureMinMax; -uniform vec3 u_ToneMinAvgMaxLinear; - -varying vec2 var_TexCoords; - -const vec3 LUMINANCE_VECTOR = vec3(0.2125, 0.7154, 0.0721); //vec3(0.299, 0.587, 0.114); - -vec3 FilmicTonemap(vec3 x) -{ - const float SS = 0.22; // Shoulder Strength - const float LS = 0.30; // Linear Strength - const float LA = 0.10; // Linear Angle - const float TS = 0.20; // Toe Strength - const float TAN = 0.01; // Toe Angle Numerator - const float TAD = 0.30; // Toe Angle Denominator - - vec3 SSxx = SS * x * x; - vec3 LSx = LS * x; - vec3 LALSx = LSx * LA; - - return ((SSxx + LALSx + TS * TAN) / (SSxx + LSx + TS * TAD)) - TAN / TAD; - - //return ((x*(SS*x+LA*LS)+TS*TAN)/(x*(SS*x+LS)+TS*TAD)) - TAN/TAD; - -} - -void main() -{ - vec4 color = texture2D(u_TextureMap, var_TexCoords) * u_Color; - vec3 minAvgMax = texture2D(u_LevelsMap, var_TexCoords).rgb; - vec3 logMinAvgMaxLum = clamp(minAvgMax * 20.0 - 10.0, -u_AutoExposureMinMax.y, -u_AutoExposureMinMax.x); - - float avgLum = exp2(logMinAvgMaxLum.y); - //float maxLum = exp2(logMinAvgMaxLum.z); - - color.rgb *= u_ToneMinAvgMaxLinear.y / avgLum; - color.rgb = max(vec3(0.0), color.rgb - vec3(u_ToneMinAvgMaxLinear.x)); - - vec3 fWhite = 1.0 / FilmicTonemap(vec3(u_ToneMinAvgMaxLinear.z - u_ToneMinAvgMaxLinear.x)); - color.rgb = FilmicTonemap(color.rgb) * fWhite; - - gl_FragColor = clamp(color, 0.0, 1.0); -} diff --git a/code/renderergl2/glsl/tonemap_vp.glsl b/code/renderergl2/glsl/tonemap_vp.glsl deleted file mode 100644 index bdaa74af8e..0000000000 --- a/code/renderergl2/glsl/tonemap_vp.glsl +++ /dev/null @@ -1,13 +0,0 @@ -attribute vec3 attr_Position; -attribute vec4 attr_TexCoord0; - -uniform mat4 u_ModelViewProjectionMatrix; - -varying vec2 var_TexCoords; - - -void main() -{ - gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); - var_TexCoords = attr_TexCoord0.st; -} diff --git a/code/renderergl2/tr_animation.c b/code/renderergl2/tr_animation.c deleted file mode 100644 index a5f08986b6..0000000000 --- a/code/renderergl2/tr_animation.c +++ /dev/null @@ -1,522 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "tr_local.h" - -/* - -All bones should be an identity orientation to display the mesh exactly -as it is specified. - -For all other frames, the bones represent the transformation from the -orientation of the bone in the base frame to the orientation in this -frame. - -*/ - - -// copied and adapted from tr_mesh.c - -/* -============= -R_MDRCullModel -============= -*/ - -static int R_MDRCullModel( mdrHeader_t *header, trRefEntity_t *ent ) { - vec3_t bounds[2]; - mdrFrame_t *oldFrame, *newFrame; - int i, frameSize; - - frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); - - // compute frame pointers - newFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame); - oldFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.oldframe); - - // cull bounding sphere ONLY if this is not an upscaled entity - if ( !ent->e.nonNormalizedAxes ) - { - if ( ent->e.frame == ent->e.oldframe ) - { - switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) ) - { - // Ummm... yeah yeah I know we don't really have an md3 here.. but we pretend - // we do. After all, the purpose of mdrs are not that different, are they? - - case CULL_OUT: - tr.pc.c_sphere_cull_md3_out++; - return CULL_OUT; - - case CULL_IN: - tr.pc.c_sphere_cull_md3_in++; - return CULL_IN; - - case CULL_CLIP: - tr.pc.c_sphere_cull_md3_clip++; - break; - } - } - else - { - int sphereCull, sphereCullB; - - sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ); - if ( newFrame == oldFrame ) { - sphereCullB = sphereCull; - } else { - sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius ); - } - - if ( sphereCull == sphereCullB ) - { - if ( sphereCull == CULL_OUT ) - { - tr.pc.c_sphere_cull_md3_out++; - return CULL_OUT; - } - else if ( sphereCull == CULL_IN ) - { - tr.pc.c_sphere_cull_md3_in++; - return CULL_IN; - } - else - { - tr.pc.c_sphere_cull_md3_clip++; - } - } - } - } - - // calculate a bounding box in the current coordinate system - for (i = 0 ; i < 3 ; i++) { - bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; - bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; - } - - switch ( R_CullLocalBox( bounds ) ) - { - case CULL_IN: - tr.pc.c_box_cull_md3_in++; - return CULL_IN; - case CULL_CLIP: - tr.pc.c_box_cull_md3_clip++; - return CULL_CLIP; - case CULL_OUT: - default: - tr.pc.c_box_cull_md3_out++; - return CULL_OUT; - } -} - -/* -================= -R_MDRComputeFogNum - -================= -*/ - -int R_MDRComputeFogNum( mdrHeader_t *header, trRefEntity_t *ent ) { - int i, j; - fog_t *fog; - mdrFrame_t *mdrFrame; - vec3_t localOrigin; - int frameSize; - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return 0; - } - - frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); - - // FIXME: non-normalized axis issues - mdrFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame); - VectorAdd( ent->e.origin, mdrFrame->localOrigin, localOrigin ); - for ( i = 1 ; i < tr.world->numfogs ; i++ ) { - fog = &tr.world->fogs[i]; - for ( j = 0 ; j < 3 ; j++ ) { - if ( localOrigin[j] - mdrFrame->radius >= fog->bounds[1][j] ) { - break; - } - if ( localOrigin[j] + mdrFrame->radius <= fog->bounds[0][j] ) { - break; - } - } - if ( j == 3 ) { - return i; - } - } - - return 0; -} - - -/* -============== -R_MDRAddAnimSurfaces -============== -*/ - -// much stuff in there is just copied from R_AddMd3Surfaces in tr_mesh.c - -void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { - mdrHeader_t *header; - mdrSurface_t *surface; - mdrLOD_t *lod; - shader_t *shader; - skin_t *skin; - int i, j; - int lodnum = 0; - int fogNum = 0; - int cull; - int cubemapIndex; - qboolean personalModel; - - header = (mdrHeader_t *) tr.currentModel->modelData; - - personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; - - if ( ent->e.renderfx & RF_WRAP_FRAMES ) - { - ent->e.frame %= header->numFrames; - ent->e.oldframe %= header->numFrames; - } - - // - // Validate the frames so there is no chance of a crash. - // This will write directly into the entity structure, so - // when the surfaces are rendered, they don't need to be - // range checked again. - // - if ((ent->e.frame >= header->numFrames) - || (ent->e.frame < 0) - || (ent->e.oldframe >= header->numFrames) - || (ent->e.oldframe < 0) ) - { - ri.Printf( PRINT_DEVELOPER, "R_MDRAddAnimSurfaces: no such frame %d to %d for '%s'\n", - ent->e.oldframe, ent->e.frame, tr.currentModel->name ); - ent->e.frame = 0; - ent->e.oldframe = 0; - } - - // - // cull the entire model if merged bounding box of both frames - // is outside the view frustum. - // - cull = R_MDRCullModel (header, ent); - if ( cull == CULL_OUT ) { - return; - } - - // figure out the current LOD of the model we're rendering, and set the lod pointer respectively. - lodnum = R_ComputeLOD(ent); - // check whether this model has as that many LODs at all. If not, try the closest thing we got. - if(header->numLODs <= 0) - return; - if(header->numLODs <= lodnum) - lodnum = header->numLODs - 1; - - lod = (mdrLOD_t *)( (byte *)header + header->ofsLODs); - for(i = 0; i < lodnum; i++) - { - lod = (mdrLOD_t *) ((byte *) lod + lod->ofsEnd); - } - - // set up lighting - if ( !personalModel || r_shadows->integer > 1 ) - { - R_SetupEntityLighting( &tr.refdef, ent ); - } - - // fogNum? - fogNum = R_MDRComputeFogNum( header, ent ); - - cubemapIndex = R_CubemapForPoint(ent->e.origin); - - surface = (mdrSurface_t *)( (byte *)lod + lod->ofsSurfaces ); - - for ( i = 0 ; i < lod->numSurfaces ; i++ ) - { - - if(ent->e.customShader) - shader = R_GetShaderByHandle(ent->e.customShader); - else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins) - { - skin = R_GetSkinByHandle(ent->e.customSkin); - shader = tr.defaultShader; - - for(j = 0; j < skin->numSurfaces; j++) - { - if (!strcmp(skin->surfaces[j]->name, surface->name)) - { - shader = skin->surfaces[j]->shader; - break; - } - } - } - else if(surface->shaderIndex > 0) - shader = R_GetShaderByHandle( surface->shaderIndex ); - else - shader = tr.defaultShader; - - // we will add shadows even if the main object isn't visible in the view - - // stencil shadows can't do personal models unless I polyhedron clip - if ( !personalModel - && r_shadows->integer == 2 - && fogNum == 0 - && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) - && shader->sort == SS_OPAQUE ) - { - R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse, qfalse, 0 ); - } - - // projection shadows work fine with personal models - if ( r_shadows->integer == 3 - && fogNum == 0 - && (ent->e.renderfx & RF_SHADOW_PLANE ) - && shader->sort == SS_OPAQUE ) - { - R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, qfalse, 0 ); - } - - if (!personalModel) - R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse, qfalse, cubemapIndex ); - - surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd ); - } -} - -/* -============== -RB_MDRSurfaceAnim -============== -*/ -void RB_MDRSurfaceAnim( mdrSurface_t *surface ) -{ - int i, j, k; - float frontlerp, backlerp; - int *triangles; - int indexes; - int baseIndex, baseVertex; - int numVerts; - mdrVertex_t *v; - mdrHeader_t *header; - mdrFrame_t *frame; - mdrFrame_t *oldFrame; - mdrBone_t bones[MDR_MAX_BONES], *bonePtr, *bone; - - int frameSize; - - // don't lerp if lerping off, or this is the only frame, or the last frame... - // - if (backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame) - { - backlerp = 0; // if backlerp is 0, lerping is off and frontlerp is never used - frontlerp = 1; - } - else - { - backlerp = backEnd.currentEntity->e.backlerp; - frontlerp = 1.0f - backlerp; - } - - header = (mdrHeader_t *)((byte *)surface + surface->ofsHeader); - - frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); - - frame = (mdrFrame_t *)((byte *)header + header->ofsFrames + - backEnd.currentEntity->e.frame * frameSize ); - oldFrame = (mdrFrame_t *)((byte *)header + header->ofsFrames + - backEnd.currentEntity->e.oldframe * frameSize ); - - RB_CheckOverflow( surface->numVerts, surface->numTriangles ); - - triangles = (int *) ((byte *)surface + surface->ofsTriangles); - indexes = surface->numTriangles * 3; - baseIndex = tess.numIndexes; - baseVertex = tess.numVertexes; - - // Set up all triangles. - for (j = 0 ; j < indexes ; j++) - { - tess.indexes[baseIndex + j] = baseVertex + triangles[j]; - } - tess.numIndexes += indexes; - - // - // lerp all the needed bones - // - if ( !backlerp ) - { - // no lerping needed - bonePtr = frame->bones; - } - else - { - bonePtr = bones; - - for ( i = 0 ; i < header->numBones*12 ; i++ ) - { - ((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i] + backlerp * ((float *)oldFrame->bones)[i]; - } - } - - // - // deform the vertexes by the lerped bones - // - numVerts = surface->numVerts; - v = (mdrVertex_t *) ((byte *)surface + surface->ofsVerts); - for ( j = 0; j < numVerts; j++ ) - { - vec3_t tempVert, tempNormal; - mdrWeight_t *w; - - VectorClear( tempVert ); - VectorClear( tempNormal ); - w = v->weights; - for ( k = 0 ; k < v->numWeights ; k++, w++ ) - { - bone = bonePtr + w->boneIndex; - - tempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] ); - tempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] ); - tempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] ); - - tempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal ); - tempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal ); - tempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal ); - } - - tess.xyz[baseVertex + j][0] = tempVert[0]; - tess.xyz[baseVertex + j][1] = tempVert[1]; - tess.xyz[baseVertex + j][2] = tempVert[2]; - - tess.normal[baseVertex + j] = R_VboPackNormal(tempNormal); - - tess.texCoords[baseVertex + j][0][0] = v->texCoords[0]; - tess.texCoords[baseVertex + j][0][1] = v->texCoords[1]; - - v = (mdrVertex_t *)&v->weights[v->numWeights]; - } - - tess.numVertexes += surface->numVerts; -} - - -#define MC_MASK_X ((1<<(MC_BITS_X))-1) -#define MC_MASK_Y ((1<<(MC_BITS_Y))-1) -#define MC_MASK_Z ((1<<(MC_BITS_Z))-1) -#define MC_MASK_VECT ((1<<(MC_BITS_VECT))-1) - -#define MC_SCALE_VECT (1.0f/(float)((1<<(MC_BITS_VECT-1))-2)) - -#define MC_POS_X (0) -#define MC_SHIFT_X (0) - -#define MC_POS_Y ((((MC_BITS_X))/8)) -#define MC_SHIFT_Y ((((MC_BITS_X)%8))) - -#define MC_POS_Z ((((MC_BITS_X+MC_BITS_Y))/8)) -#define MC_SHIFT_Z ((((MC_BITS_X+MC_BITS_Y)%8))) - -#define MC_POS_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z))/8)) -#define MC_SHIFT_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z)%8))) - -#define MC_POS_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT))/8)) -#define MC_SHIFT_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT)%8))) - -#define MC_POS_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2))/8)) -#define MC_SHIFT_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2)%8))) - -#define MC_POS_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3))/8)) -#define MC_SHIFT_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3)%8))) - -#define MC_POS_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4))/8)) -#define MC_SHIFT_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4)%8))) - -#define MC_POS_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5))/8)) -#define MC_SHIFT_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5)%8))) - -#define MC_POS_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6))/8)) -#define MC_SHIFT_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6)%8))) - -#define MC_POS_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7))/8)) -#define MC_SHIFT_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7)%8))) - -#define MC_POS_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8))/8)) -#define MC_SHIFT_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8)%8))) - -void MC_UnCompress(float mat[3][4],const unsigned char * comp) -{ - int val; - - val=(int)((unsigned short *)(comp))[0]; - val-=1<<(MC_BITS_X-1); - mat[0][3]=((float)(val))*MC_SCALE_X; - - val=(int)((unsigned short *)(comp))[1]; - val-=1<<(MC_BITS_Y-1); - mat[1][3]=((float)(val))*MC_SCALE_Y; - - val=(int)((unsigned short *)(comp))[2]; - val-=1<<(MC_BITS_Z-1); - mat[2][3]=((float)(val))*MC_SCALE_Z; - - val=(int)((unsigned short *)(comp))[3]; - val-=1<<(MC_BITS_VECT-1); - mat[0][0]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[4]; - val-=1<<(MC_BITS_VECT-1); - mat[0][1]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[5]; - val-=1<<(MC_BITS_VECT-1); - mat[0][2]=((float)(val))*MC_SCALE_VECT; - - - val=(int)((unsigned short *)(comp))[6]; - val-=1<<(MC_BITS_VECT-1); - mat[1][0]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[7]; - val-=1<<(MC_BITS_VECT-1); - mat[1][1]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[8]; - val-=1<<(MC_BITS_VECT-1); - mat[1][2]=((float)(val))*MC_SCALE_VECT; - - - val=(int)((unsigned short *)(comp))[9]; - val-=1<<(MC_BITS_VECT-1); - mat[2][0]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[10]; - val-=1<<(MC_BITS_VECT-1); - mat[2][1]=((float)(val))*MC_SCALE_VECT; - - val=(int)((unsigned short *)(comp))[11]; - val-=1<<(MC_BITS_VECT-1); - mat[2][2]=((float)(val))*MC_SCALE_VECT; -} diff --git a/code/renderergl2/tr_backend.c b/code/renderergl2/tr_backend.c deleted file mode 100644 index e4431cf529..0000000000 --- a/code/renderergl2/tr_backend.c +++ /dev/null @@ -1,1783 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - -backEndData_t *backEndData; -backEndState_t backEnd; - - -static float s_flipMatrix[16] = { - // convert from our coordinate system (looking down X) - // to OpenGL's coordinate system (looking down -Z) - 0, 0, -1, 0, - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1 -}; - - -/* -** GL_Bind -*/ -void GL_Bind( image_t *image ) { - int texnum; - - if ( !image ) { - ri.Printf( PRINT_WARNING, "GL_Bind: NULL image\n" ); - texnum = tr.defaultImage->texnum; - } else { - texnum = image->texnum; - } - - if ( r_nobind->integer && tr.dlightImage ) { // performance evaluation option - texnum = tr.dlightImage->texnum; - } - - if ( glState.currenttextures[glState.currenttmu] != texnum ) { - if ( image ) { - image->frameUsed = tr.frameCount; - } - glState.currenttextures[glState.currenttmu] = texnum; - if (image && image->flags & IMGFLAG_CUBEMAP) - qglBindTexture( GL_TEXTURE_CUBE_MAP, texnum ); - else - qglBindTexture( GL_TEXTURE_2D, texnum ); - } -} - -/* -** GL_SelectTexture -*/ -void GL_SelectTexture( int unit ) -{ - if ( glState.currenttmu == unit ) - { - return; - } - - if (!(unit >= 0 && unit <= 31)) - ri.Error( ERR_DROP, "GL_SelectTexture: unit = %i", unit ); - - qglActiveTextureARB( GL_TEXTURE0_ARB + unit ); - - glState.currenttmu = unit; -} - -/* -** GL_BindToTMU -*/ -void GL_BindToTMU( image_t *image, int tmu ) -{ - int texnum; - int oldtmu = glState.currenttmu; - - if (!image) - texnum = 0; - else - texnum = image->texnum; - - if ( glState.currenttextures[tmu] != texnum ) { - GL_SelectTexture( tmu ); - if (image) - image->frameUsed = tr.frameCount; - glState.currenttextures[tmu] = texnum; - - if (image && (image->flags & IMGFLAG_CUBEMAP)) - qglBindTexture( GL_TEXTURE_CUBE_MAP, texnum ); - else - qglBindTexture( GL_TEXTURE_2D, texnum ); - GL_SelectTexture( oldtmu ); - } -} - - -/* -** GL_Cull -*/ -void GL_Cull( int cullType ) { - if ( glState.faceCulling == cullType ) { - return; - } - - glState.faceCulling = cullType; - - if ( cullType == CT_TWO_SIDED ) - { - qglDisable( GL_CULL_FACE ); - } - else - { - qboolean cullFront; - qglEnable( GL_CULL_FACE ); - - cullFront = (cullType == CT_FRONT_SIDED); - if ( backEnd.viewParms.isMirror ) - { - cullFront = !cullFront; - } - - if ( backEnd.currentEntity && backEnd.currentEntity->mirrored ) - { - cullFront = !cullFront; - } - - qglCullFace( cullFront ? GL_FRONT : GL_BACK ); - } -} - -/* -** GL_TexEnv -*/ -void GL_TexEnv( int env ) -{ - if ( env == glState.texEnv[glState.currenttmu] ) - { - return; - } - - glState.texEnv[glState.currenttmu] = env; - - - switch ( env ) - { - case GL_MODULATE: - qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); - break; - case GL_REPLACE: - qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); - break; - case GL_DECAL: - qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL ); - break; - case GL_ADD: - qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD ); - break; - default: - ri.Error( ERR_DROP, "GL_TexEnv: invalid env '%d' passed", env ); - break; - } -} - -/* -** GL_State -** -** This routine is responsible for setting the most commonly changed state -** in Q3. -*/ -void GL_State( unsigned long stateBits ) -{ - unsigned long diff = stateBits ^ glState.glStateBits; - - if ( !diff ) - { - return; - } - - // - // check depthFunc bits - // - if ( diff & GLS_DEPTHFUNC_BITS ) - { - if ( stateBits & GLS_DEPTHFUNC_EQUAL ) - { - qglDepthFunc( GL_EQUAL ); - } - else if ( stateBits & GLS_DEPTHFUNC_GREATER) - { - qglDepthFunc( GL_GREATER ); - } - else - { - qglDepthFunc( GL_LEQUAL ); - } - } - - // - // check blend bits - // - if ( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) - { - GLenum srcFactor = GL_ONE, dstFactor = GL_ONE; - - if ( stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) - { - switch ( stateBits & GLS_SRCBLEND_BITS ) - { - case GLS_SRCBLEND_ZERO: - srcFactor = GL_ZERO; - break; - case GLS_SRCBLEND_ONE: - srcFactor = GL_ONE; - break; - case GLS_SRCBLEND_DST_COLOR: - srcFactor = GL_DST_COLOR; - break; - case GLS_SRCBLEND_ONE_MINUS_DST_COLOR: - srcFactor = GL_ONE_MINUS_DST_COLOR; - break; - case GLS_SRCBLEND_SRC_ALPHA: - srcFactor = GL_SRC_ALPHA; - break; - case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA: - srcFactor = GL_ONE_MINUS_SRC_ALPHA; - break; - case GLS_SRCBLEND_DST_ALPHA: - srcFactor = GL_DST_ALPHA; - break; - case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA: - srcFactor = GL_ONE_MINUS_DST_ALPHA; - break; - case GLS_SRCBLEND_ALPHA_SATURATE: - srcFactor = GL_SRC_ALPHA_SATURATE; - break; - default: - ri.Error( ERR_DROP, "GL_State: invalid src blend state bits" ); - break; - } - - switch ( stateBits & GLS_DSTBLEND_BITS ) - { - case GLS_DSTBLEND_ZERO: - dstFactor = GL_ZERO; - break; - case GLS_DSTBLEND_ONE: - dstFactor = GL_ONE; - break; - case GLS_DSTBLEND_SRC_COLOR: - dstFactor = GL_SRC_COLOR; - break; - case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR: - dstFactor = GL_ONE_MINUS_SRC_COLOR; - break; - case GLS_DSTBLEND_SRC_ALPHA: - dstFactor = GL_SRC_ALPHA; - break; - case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA: - dstFactor = GL_ONE_MINUS_SRC_ALPHA; - break; - case GLS_DSTBLEND_DST_ALPHA: - dstFactor = GL_DST_ALPHA; - break; - case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA: - dstFactor = GL_ONE_MINUS_DST_ALPHA; - break; - default: - ri.Error( ERR_DROP, "GL_State: invalid dst blend state bits" ); - break; - } - - qglEnable( GL_BLEND ); - qglBlendFunc( srcFactor, dstFactor ); - } - else - { - qglDisable( GL_BLEND ); - } - } - - // - // check depthmask - // - if ( diff & GLS_DEPTHMASK_TRUE ) - { - if ( stateBits & GLS_DEPTHMASK_TRUE ) - { - qglDepthMask( GL_TRUE ); - } - else - { - qglDepthMask( GL_FALSE ); - } - } - - // - // fill/line mode - // - if ( diff & GLS_POLYMODE_LINE ) - { - if ( stateBits & GLS_POLYMODE_LINE ) - { - qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); - } - else - { - qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); - } - } - - // - // depthtest - // - if ( diff & GLS_DEPTHTEST_DISABLE ) - { - if ( stateBits & GLS_DEPTHTEST_DISABLE ) - { - qglDisable( GL_DEPTH_TEST ); - } - else - { - qglEnable( GL_DEPTH_TEST ); - } - } - - // - // alpha test - // - if ( diff & GLS_ATEST_BITS ) - { - switch ( stateBits & GLS_ATEST_BITS ) - { - case 0: - qglDisable( GL_ALPHA_TEST ); - break; - case GLS_ATEST_GT_0: - qglEnable( GL_ALPHA_TEST ); - qglAlphaFunc( GL_GREATER, 0.0f ); - break; - case GLS_ATEST_LT_80: - qglEnable( GL_ALPHA_TEST ); - qglAlphaFunc( GL_LESS, 0.5f ); - break; - case GLS_ATEST_GE_80: - qglEnable( GL_ALPHA_TEST ); - qglAlphaFunc( GL_GEQUAL, 0.5f ); - break; - default: - assert( 0 ); - break; - } - } - - glState.glStateBits = stateBits; -} - - -void GL_SetProjectionMatrix(mat4_t matrix) -{ - Mat4Copy(matrix, glState.projection); - Mat4Multiply(glState.projection, glState.modelview, glState.modelviewProjection); -} - - -void GL_SetModelviewMatrix(mat4_t matrix) -{ - Mat4Copy(matrix, glState.modelview); - Mat4Multiply(glState.projection, glState.modelview, glState.modelviewProjection); -} - - -/* -================ -RB_Hyperspace - -A player has predicted a teleport, but hasn't arrived yet -================ -*/ -static void RB_Hyperspace( void ) { - float c; - - if ( !backEnd.isHyperspace ) { - // do initialization shit - } - - c = ( backEnd.refdef.time & 255 ) / 255.0f; - qglClearColor( c, c, c, 1 ); - qglClear( GL_COLOR_BUFFER_BIT ); - - backEnd.isHyperspace = qtrue; -} - - -static void SetViewportAndScissor( void ) { - GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix ); - - // set the window clipping - qglViewport( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, - backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); - qglScissor( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, - backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); -} - -/* -================= -RB_BeginDrawingView - -Any mirrored or portaled views have already been drawn, so prepare -to actually render the visible surfaces for this view -================= -*/ -void RB_BeginDrawingView (void) { - int clearBits = 0; - - // sync with gl if needed - if ( r_finish->integer == 1 && !glState.finishCalled ) { - qglFinish (); - glState.finishCalled = qtrue; - } - if ( r_finish->integer == 0 ) { - glState.finishCalled = qtrue; - } - - // we will need to change the projection matrix before drawing - // 2D images again - backEnd.projection2D = qfalse; - - if (glRefConfig.framebufferObject) - { - // FIXME: HUGE HACK: render to the screen fbo if we've already postprocessed the frame and aren't drawing more world - // drawing more world check is in case of double renders, such as skyportals - if (backEnd.viewParms.targetFbo == NULL) - { - if (!tr.renderFbo || (backEnd.framePostProcessed && (backEnd.refdef.rdflags & RDF_NOWORLDMODEL))) - { - FBO_Bind(NULL); - } - else - { - FBO_Bind(tr.renderFbo); - } - } - else - { - FBO_Bind(backEnd.viewParms.targetFbo); - - // FIXME: hack for cubemap testing - if (tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo) - { - //qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, backEnd.viewParms.targetFbo->colorImage[0]->texnum, 0); - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex]->texnum, 0); - } - } - } - - // - // set the modelview matrix for the viewer - // - SetViewportAndScissor(); - - // ensures that depth writes are enabled for the depth clear - GL_State( GLS_DEFAULT ); - // clear relevant buffers - clearBits = GL_DEPTH_BUFFER_BIT; - - if ( r_measureOverdraw->integer || r_shadows->integer == 2 ) - { - clearBits |= GL_STENCIL_BUFFER_BIT; - } - if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) - { - clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used -#ifdef _DEBUG - qglClearColor( 0.8f, 0.7f, 0.4f, 1.0f ); // FIXME: get color of sky -#else - qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky -#endif - } - - // clear to white for shadow maps - if (backEnd.viewParms.flags & VPF_SHADOWMAP) - { - clearBits |= GL_COLOR_BUFFER_BIT; - qglClearColor( 1.0f, 1.0f, 1.0f, 1.0f ); - } - - // clear to black for cube maps - if (tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo) - { - clearBits |= GL_COLOR_BUFFER_BIT; - qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); - } - - qglClear( clearBits ); - - if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) ) - { - RB_Hyperspace(); - return; - } - else - { - backEnd.isHyperspace = qfalse; - } - - glState.faceCulling = -1; // force face culling to set next time - - // we will only draw a sun if there was sky rendered in this view - backEnd.skyRenderedThisView = qfalse; - - // clip to the plane of the portal - if ( backEnd.viewParms.isPortal ) { -#if 0 - float plane[4]; - double plane2[4]; - - plane[0] = backEnd.viewParms.portalPlane.normal[0]; - plane[1] = backEnd.viewParms.portalPlane.normal[1]; - plane[2] = backEnd.viewParms.portalPlane.normal[2]; - plane[3] = backEnd.viewParms.portalPlane.dist; - - plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane); - plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane); - plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane); - plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3]; -#endif - GL_SetModelviewMatrix( s_flipMatrix ); - } -} - - -#define MAC_EVENT_PUMP_MSEC 5 - -/* -================== -RB_RenderDrawSurfList -================== -*/ -void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { - shader_t *shader, *oldShader; - int fogNum, oldFogNum; - int entityNum, oldEntityNum; - int dlighted, oldDlighted; - int pshadowed, oldPshadowed; - int cubemapIndex, oldCubemapIndex; - qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair; - int i; - drawSurf_t *drawSurf; - int oldSort; - float originalTime; - FBO_t* fbo = NULL; - qboolean inQuery = qfalse; - - float depth[2]; - - - // save original time for entity shader offsets - originalTime = backEnd.refdef.floatTime; - - fbo = glState.currentFBO; - - // draw everything - oldEntityNum = -1; - backEnd.currentEntity = &tr.worldEntity; - oldShader = NULL; - oldFogNum = -1; - oldDepthRange = qfalse; - wasCrosshair = qfalse; - oldDlighted = qfalse; - oldPshadowed = qfalse; - oldCubemapIndex = -1; - oldSort = -1; - - depth[0] = 0.f; - depth[1] = 1.f; - - backEnd.pc.c_surfaces += numDrawSurfs; - - for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { - if ( drawSurf->sort == oldSort && drawSurf->cubemapIndex == oldCubemapIndex) { - if (backEnd.depthFill && shader && shader->sort != SS_OPAQUE) - continue; - - // fast path, same as previous sort - rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); - continue; - } - oldSort = drawSurf->sort; - R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed ); - cubemapIndex = drawSurf->cubemapIndex; - - // - // change the tess parameters if needed - // a "entityMergable" shader is a shader that can have surfaces from seperate - // entities merged into a single batch, like smoke and blood puff sprites - if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || pshadowed != oldPshadowed || cubemapIndex != oldCubemapIndex - || ( entityNum != oldEntityNum && !shader->entityMergable ) ) ) { - if (oldShader != NULL) { - RB_EndSurface(); - } - RB_BeginSurface( shader, fogNum, cubemapIndex ); - backEnd.pc.c_surfBatches++; - oldShader = shader; - oldFogNum = fogNum; - oldDlighted = dlighted; - oldPshadowed = pshadowed; - oldCubemapIndex = cubemapIndex; - } - - if (backEnd.depthFill && shader && shader->sort != SS_OPAQUE) - continue; - - // - // change the modelview matrix if needed - // - if ( entityNum != oldEntityNum ) { - qboolean sunflare = qfalse; - depthRange = isCrosshair = qfalse; - - if ( entityNum != REFENTITYNUM_WORLD ) { - backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; - backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; - // we have to reset the shaderTime as well otherwise image animations start - // from the wrong frame - tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; - - // set up the transformation matrix - R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or ); - - // set up the dynamic lighting if needed - if ( backEnd.currentEntity->needDlights ) { - R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); - } - - if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK) - { - // hack the depth range to prevent view model from poking into walls - depthRange = qtrue; - - if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR) - isCrosshair = qtrue; - } - } else { - backEnd.currentEntity = &tr.worldEntity; - backEnd.refdef.floatTime = originalTime; - backEnd.or = backEnd.viewParms.world; - // we have to reset the shaderTime as well otherwise image animations on - // the world (like water) continue with the wrong frame - tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; - R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); - } - - GL_SetModelviewMatrix( backEnd.or.modelMatrix ); - - // - // change depthrange. Also change projection matrix so first person weapon does not look like coming - // out of the screen. - // - if (oldDepthRange != depthRange || wasCrosshair != isCrosshair) - { - if (depthRange) - { - if(backEnd.viewParms.stereoFrame != STEREO_CENTER) - { - if(isCrosshair) - { - if(oldDepthRange) - { - // was not a crosshair but now is, change back proj matrix - GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix ); - } - } - else - { - viewParms_t temp = backEnd.viewParms; - - R_SetupProjection(&temp, r_znear->value, 0, qfalse); - - GL_SetProjectionMatrix( temp.projectionMatrix ); - } - } - - if(!oldDepthRange) - { - depth[0] = 0; - depth[1] = 0.3f; - qglDepthRange (depth[0], depth[1]); - } - } - else - { - if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER) - { - GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix ); - } - - if (!sunflare) - qglDepthRange (0, 1); - - depth[0] = 0; - depth[1] = 1; - } - - oldDepthRange = depthRange; - wasCrosshair = isCrosshair; - } - - oldEntityNum = entityNum; - } - - // add the triangles for this surface - rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); - } - - backEnd.refdef.floatTime = originalTime; - - // draw the contents of the last shader batch - if (oldShader != NULL) { - RB_EndSurface(); - } - - if (inQuery) { - qglEndQueryARB(GL_SAMPLES_PASSED_ARB); - } - - if (glRefConfig.framebufferObject) - FBO_Bind(fbo); - - // go back to the world modelview matrix - - GL_SetModelviewMatrix( backEnd.viewParms.world.modelMatrix ); - - qglDepthRange (0, 1); -} - - -/* -============================================================================ - -RENDER BACK END FUNCTIONS - -============================================================================ -*/ - -/* -================ -RB_SetGL2D - -================ -*/ -void RB_SetGL2D (void) { - mat4_t matrix; - int width, height; - - if (backEnd.projection2D && backEnd.last2DFBO == glState.currentFBO) - return; - - backEnd.projection2D = qtrue; - backEnd.last2DFBO = glState.currentFBO; - - if (glState.currentFBO) - { - width = glState.currentFBO->width; - height = glState.currentFBO->height; - } - else - { - width = glConfig.vidWidth; - height = glConfig.vidHeight; - } - - // set 2D virtual screen size - qglViewport( 0, 0, width, height ); - qglScissor( 0, 0, width, height ); - - Mat4Ortho(0, width, height, 0, 0, 1, matrix); - GL_SetProjectionMatrix(matrix); - Mat4Identity(matrix); - GL_SetModelviewMatrix(matrix); - - GL_State( GLS_DEPTHTEST_DISABLE | - GLS_SRCBLEND_SRC_ALPHA | - GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); - - qglDisable( GL_CULL_FACE ); - qglDisable( GL_CLIP_PLANE0 ); - - // set time for 2D shaders - backEnd.refdef.time = ri.Milliseconds(); - backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f; - - // reset color scaling - backEnd.refdef.colorScale = 1.0f; -} - - -/* -============= -RE_StretchRaw - -FIXME: not exactly backend -Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle. -Used for cinematics. -============= -*/ -void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { - int i, j; - int start, end; - vec4_t quadVerts[4]; - vec2_t texCoords[4]; - - if ( !tr.registered ) { - return; - } - R_IssuePendingRenderCommands(); - - if ( tess.numIndexes ) { - RB_EndSurface(); - } - - // we definately want to sync every frame for the cinematics - qglFinish(); - - start = 0; - if ( r_speeds->integer ) { - start = ri.Milliseconds(); - } - - // make sure rows and cols are powers of 2 - for ( i = 0 ; ( 1 << i ) < cols ; i++ ) { - } - for ( j = 0 ; ( 1 << j ) < rows ; j++ ) { - } - if ( ( 1 << i ) != cols || ( 1 << j ) != rows) { - ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows); - } - - RE_UploadCinematic (w, h, cols, rows, data, client, dirty); - - if ( r_speeds->integer ) { - end = ri.Milliseconds(); - ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start ); - } - - // FIXME: HUGE hack - if (glRefConfig.framebufferObject) - { - if (!tr.renderFbo || backEnd.framePostProcessed) - { - FBO_Bind(NULL); - } - else - { - FBO_Bind(tr.renderFbo); - } - } - - RB_SetGL2D(); - - VectorSet4(quadVerts[0], x, y, 0.0f, 1.0f); - VectorSet4(quadVerts[1], x + w, y, 0.0f, 1.0f); - VectorSet4(quadVerts[2], x + w, y + h, 0.0f, 1.0f); - VectorSet4(quadVerts[3], x, y + h, 0.0f, 1.0f); - - VectorSet2(texCoords[0], 0.5f / cols, 0.5f / rows); - VectorSet2(texCoords[1], (cols - 0.5f) / cols, 0.5f / rows); - VectorSet2(texCoords[2], (cols - 0.5f) / cols, (rows - 0.5f) / rows); - VectorSet2(texCoords[3], 0.5f / cols, (rows - 0.5f) / rows); - - GLSL_BindProgram(&tr.textureColorShader); - - GLSL_SetUniformMat4(&tr.textureColorShader, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - GLSL_SetUniformVec4(&tr.textureColorShader, UNIFORM_COLOR, colorWhite); - - RB_InstantQuad2(quadVerts, texCoords); -} - -void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { - - GL_Bind( tr.scratchImage[client] ); - - // if the scratchImage isn't in the format we want, specify it as a new texture - if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { - tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; - tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; - qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - } else { - if (dirty) { - // otherwise, just subimage upload it so that drivers can tell we are going to be changing - // it and don't try and do a texture compression - qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); - } - } -} - - -/* -============= -RB_SetColor - -============= -*/ -const void *RB_SetColor( const void *data ) { - const setColorCommand_t *cmd; - - cmd = (const setColorCommand_t *)data; - - backEnd.color2D[0] = cmd->color[0] * 255; - backEnd.color2D[1] = cmd->color[1] * 255; - backEnd.color2D[2] = cmd->color[2] * 255; - backEnd.color2D[3] = cmd->color[3] * 255; - - return (const void *)(cmd + 1); -} - -/* -============= -RB_StretchPic -============= -*/ -const void *RB_StretchPic ( const void *data ) { - const stretchPicCommand_t *cmd; - shader_t *shader; - int numVerts, numIndexes; - - cmd = (const stretchPicCommand_t *)data; - - // FIXME: HUGE hack - if (glRefConfig.framebufferObject) - { - if (!tr.renderFbo || backEnd.framePostProcessed) - { - FBO_Bind(NULL); - } - else - { - FBO_Bind(tr.renderFbo); - } - } - - RB_SetGL2D(); - - shader = cmd->shader; - if ( shader != tess.shader ) { - if ( tess.numIndexes ) { - RB_EndSurface(); - } - backEnd.currentEntity = &backEnd.entity2D; - RB_BeginSurface( shader, 0, 0 ); - } - - RB_CHECKOVERFLOW( 4, 6 ); - numVerts = tess.numVertexes; - numIndexes = tess.numIndexes; - - tess.numVertexes += 4; - tess.numIndexes += 6; - - tess.indexes[ numIndexes ] = numVerts + 3; - tess.indexes[ numIndexes + 1 ] = numVerts + 0; - tess.indexes[ numIndexes + 2 ] = numVerts + 2; - tess.indexes[ numIndexes + 3 ] = numVerts + 2; - tess.indexes[ numIndexes + 4 ] = numVerts + 0; - tess.indexes[ numIndexes + 5 ] = numVerts + 1; - - { - vec4_t color; - - VectorScale4(backEnd.color2D, 1.0f / 255.0f, color); - - VectorCopy4(color, tess.vertexColors[ numVerts ]); - VectorCopy4(color, tess.vertexColors[ numVerts + 1]); - VectorCopy4(color, tess.vertexColors[ numVerts + 2]); - VectorCopy4(color, tess.vertexColors[ numVerts + 3 ]); - } - - tess.xyz[ numVerts ][0] = cmd->x; - tess.xyz[ numVerts ][1] = cmd->y; - tess.xyz[ numVerts ][2] = 0; - - tess.texCoords[ numVerts ][0][0] = cmd->s1; - tess.texCoords[ numVerts ][0][1] = cmd->t1; - - tess.xyz[ numVerts + 1 ][0] = cmd->x + cmd->w; - tess.xyz[ numVerts + 1 ][1] = cmd->y; - tess.xyz[ numVerts + 1 ][2] = 0; - - tess.texCoords[ numVerts + 1 ][0][0] = cmd->s2; - tess.texCoords[ numVerts + 1 ][0][1] = cmd->t1; - - tess.xyz[ numVerts + 2 ][0] = cmd->x + cmd->w; - tess.xyz[ numVerts + 2 ][1] = cmd->y + cmd->h; - tess.xyz[ numVerts + 2 ][2] = 0; - - tess.texCoords[ numVerts + 2 ][0][0] = cmd->s2; - tess.texCoords[ numVerts + 2 ][0][1] = cmd->t2; - - tess.xyz[ numVerts + 3 ][0] = cmd->x; - tess.xyz[ numVerts + 3 ][1] = cmd->y + cmd->h; - tess.xyz[ numVerts + 3 ][2] = 0; - - tess.texCoords[ numVerts + 3 ][0][0] = cmd->s1; - tess.texCoords[ numVerts + 3 ][0][1] = cmd->t2; - - return (const void *)(cmd + 1); -} - - -/* -============= -RB_DrawSurfs - -============= -*/ -const void *RB_DrawSurfs( const void *data ) { - const drawSurfsCommand_t *cmd; - - // finish any 2D drawing if needed - if ( tess.numIndexes ) { - RB_EndSurface(); - } - - cmd = (const drawSurfsCommand_t *)data; - - backEnd.refdef = cmd->refdef; - backEnd.viewParms = cmd->viewParms; - - // clear the z buffer, set the modelview, etc - RB_BeginDrawingView (); - - if (glRefConfig.framebufferObject && (backEnd.viewParms.flags & VPF_DEPTHCLAMP) && glRefConfig.depthClamp) - { - qglEnable(GL_DEPTH_CLAMP); - } - - if (glRefConfig.framebufferObject && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) && (r_depthPrepass->integer || (backEnd.viewParms.flags & VPF_DEPTHSHADOW))) - { - FBO_t *oldFbo = glState.currentFBO; - - backEnd.depthFill = qtrue; - qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); - qglColorMask(!backEnd.colorMask[0], !backEnd.colorMask[1], !backEnd.colorMask[2], !backEnd.colorMask[3]); - backEnd.depthFill = qfalse; - - if (tr.msaaResolveFbo) - { - // If we're using multisampling, resolve the depth first - FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_DEPTH_BUFFER_BIT, GL_NEAREST); - } - else if (tr.renderFbo == NULL) - { - // If we're rendering directly to the screen, copy the depth to a texture - GL_BindToTMU(tr.renderDepthImage, 0); - qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 0, 0, glConfig.vidWidth, glConfig.vidHeight, 0); - } - - if (r_ssao->integer) - { - // need the depth in a texture we can do GL_LINEAR sampling on, so copy it to an HDR image - FBO_BlitFromTexture(tr.renderDepthImage, NULL, NULL, tr.hdrDepthFbo, NULL, NULL, NULL, 0); - } - - if (r_sunlightMode->integer && backEnd.viewParms.flags & VPF_USESUNLIGHT) - { - vec4_t quadVerts[4]; - vec2_t texCoords[4]; - vec4_t box; - - FBO_Bind(tr.screenShadowFbo); - - box[0] = backEnd.viewParms.viewportX * tr.screenShadowFbo->width / (float)glConfig.vidWidth; - box[1] = backEnd.viewParms.viewportY * tr.screenShadowFbo->height / (float)glConfig.vidHeight; - box[2] = backEnd.viewParms.viewportWidth * tr.screenShadowFbo->width / (float)glConfig.vidWidth; - box[3] = backEnd.viewParms.viewportHeight * tr.screenShadowFbo->height / (float)glConfig.vidHeight; - - qglViewport(box[0], box[1], box[2], box[3]); - qglScissor(box[0], box[1], box[2], box[3]); - - box[0] = backEnd.viewParms.viewportX / (float)glConfig.vidWidth; - box[1] = backEnd.viewParms.viewportY / (float)glConfig.vidHeight; - box[2] = box[0] + backEnd.viewParms.viewportWidth / (float)glConfig.vidWidth; - box[3] = box[1] + backEnd.viewParms.viewportHeight / (float)glConfig.vidHeight; - - texCoords[0][0] = box[0]; texCoords[0][1] = box[3]; - texCoords[1][0] = box[2]; texCoords[1][1] = box[3]; - texCoords[2][0] = box[2]; texCoords[2][1] = box[1]; - texCoords[3][0] = box[0]; texCoords[3][1] = box[1]; - - box[0] = -1.0f; - box[1] = -1.0f; - box[2] = 1.0f; - box[3] = 1.0f; - - VectorSet4(quadVerts[0], box[0], box[3], 0, 1); - VectorSet4(quadVerts[1], box[2], box[3], 0, 1); - VectorSet4(quadVerts[2], box[2], box[1], 0, 1); - VectorSet4(quadVerts[3], box[0], box[1], 0, 1); - - GL_State( GLS_DEPTHTEST_DISABLE ); - - GLSL_BindProgram(&tr.shadowmaskShader); - - GL_BindToTMU(tr.renderDepthImage, TB_COLORMAP); - GL_BindToTMU(tr.sunShadowDepthImage[0], TB_SHADOWMAP); - GL_BindToTMU(tr.sunShadowDepthImage[1], TB_SHADOWMAP2); - GL_BindToTMU(tr.sunShadowDepthImage[2], TB_SHADOWMAP3); - - GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[0]); - GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP2, backEnd.refdef.sunShadowMvp[1]); - GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP3, backEnd.refdef.sunShadowMvp[2]); - - GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWORIGIN, backEnd.refdef.vieworg); - { - vec4_t viewInfo; - vec3_t viewVector; - - float zmax = backEnd.viewParms.zFar; - float ymax = zmax * tan(backEnd.viewParms.fovY * M_PI / 360.0f); - float xmax = zmax * tan(backEnd.viewParms.fovX * M_PI / 360.0f); - - float zmin = r_znear->value; - - VectorScale(backEnd.refdef.viewaxis[0], zmax, viewVector); - GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWFORWARD, viewVector); - VectorScale(backEnd.refdef.viewaxis[1], xmax, viewVector); - GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWLEFT, viewVector); - VectorScale(backEnd.refdef.viewaxis[2], ymax, viewVector); - GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWUP, viewVector); - - VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); - - GLSL_SetUniformVec4(&tr.shadowmaskShader, UNIFORM_VIEWINFO, viewInfo); - } - - - RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); - } - - if (r_ssao->integer) - { - vec4_t quadVerts[4]; - vec2_t texCoords[4]; - - FBO_Bind(tr.quarterFbo[0]); - - qglViewport(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height); - qglScissor(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height); - - VectorSet4(quadVerts[0], -1, 1, 0, 1); - VectorSet4(quadVerts[1], 1, 1, 0, 1); - VectorSet4(quadVerts[2], 1, -1, 0, 1); - VectorSet4(quadVerts[3], -1, -1, 0, 1); - - texCoords[0][0] = 0; texCoords[0][1] = 1; - texCoords[1][0] = 1; texCoords[1][1] = 1; - texCoords[2][0] = 1; texCoords[2][1] = 0; - texCoords[3][0] = 0; texCoords[3][1] = 0; - - GL_State( GLS_DEPTHTEST_DISABLE ); - - GLSL_BindProgram(&tr.ssaoShader); - - GL_BindToTMU(tr.hdrDepthImage, TB_COLORMAP); - - { - vec4_t viewInfo; - - float zmax = backEnd.viewParms.zFar; - float zmin = r_znear->value; - - VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); - - GLSL_SetUniformVec4(&tr.ssaoShader, UNIFORM_VIEWINFO, viewInfo); - } - - RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); - - - FBO_Bind(tr.quarterFbo[1]); - - qglViewport(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height); - qglScissor(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height); - - GLSL_BindProgram(&tr.depthBlurShader[0]); - - GL_BindToTMU(tr.quarterImage[0], TB_COLORMAP); - GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP); - - { - vec4_t viewInfo; - - float zmax = backEnd.viewParms.zFar; - float zmin = r_znear->value; - - VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); - - GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo); - } - - RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); - - - FBO_Bind(tr.screenSsaoFbo); - - qglViewport(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height); - qglScissor(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height); - - GLSL_BindProgram(&tr.depthBlurShader[1]); - - GL_BindToTMU(tr.quarterImage[1], TB_COLORMAP); - GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP); - - { - vec4_t viewInfo; - - float zmax = backEnd.viewParms.zFar; - float zmin = r_znear->value; - - VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); - - GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo); - } - - - RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); - } - - // reset viewport and scissor - FBO_Bind(oldFbo); - SetViewportAndScissor(); - } - - if (glRefConfig.framebufferObject && (backEnd.viewParms.flags & VPF_DEPTHCLAMP) && glRefConfig.depthClamp) - { - qglDisable(GL_DEPTH_CLAMP); - } - - if (!(backEnd.viewParms.flags & VPF_DEPTHSHADOW)) - { - RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); - - if (r_drawSun->integer) - { - RB_DrawSun(0.1, tr.sunShader); - } - - if (r_drawSunRays->integer) - { - FBO_t *oldFbo = glState.currentFBO; - FBO_Bind(tr.sunRaysFbo); - - qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); - qglClear( GL_COLOR_BUFFER_BIT ); - - if (glRefConfig.occlusionQuery) - { - tr.sunFlareQueryActive[tr.sunFlareQueryIndex] = qtrue; - qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, tr.sunFlareQuery[tr.sunFlareQueryIndex]); - } - - RB_DrawSun(0.3, tr.sunFlareShader); - - if (glRefConfig.occlusionQuery) - { - qglEndQueryARB(GL_SAMPLES_PASSED_ARB); - } - - FBO_Bind(oldFbo); - } - - // darken down any stencil shadows - RB_ShadowFinish(); - - // add light flares on lights that aren't obscured - RB_RenderFlares(); - } - - if (glRefConfig.framebufferObject && tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo) - { - FBO_Bind(NULL); - GL_SelectTexture(TB_CUBEMAP); - GL_BindToTMU(tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex], TB_CUBEMAP); - qglGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP); - GL_SelectTexture(0); - } - - return (const void *)(cmd + 1); -} - - -/* -============= -RB_DrawBuffer - -============= -*/ -const void *RB_DrawBuffer( const void *data ) { - const drawBufferCommand_t *cmd; - - cmd = (const drawBufferCommand_t *)data; - - // finish any 2D drawing if needed - if(tess.numIndexes) - RB_EndSurface(); - - if (glRefConfig.framebufferObject) - FBO_Bind(NULL); - - qglDrawBuffer( cmd->buffer ); - - // clear screen for debugging - if ( r_clear->integer ) { - qglClearColor( 1, 0, 0.5, 1 ); - qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - } - - return (const void *)(cmd + 1); -} - -/* -=============== -RB_ShowImages - -Draw all the images to the screen, on top of whatever -was there. This is used to test for texture thrashing. - -Also called by RE_EndRegistration -=============== -*/ -void RB_ShowImages( void ) { - int i; - image_t *image; - float x, y, w, h; - int start, end; - - RB_SetGL2D(); - - qglClear( GL_COLOR_BUFFER_BIT ); - - qglFinish(); - - start = ri.Milliseconds(); - - for ( i=0 ; iinteger == 2 ) { - w *= image->uploadWidth / 512.0f; - h *= image->uploadHeight / 512.0f; - } - - { - vec4_t quadVerts[4]; - - GL_Bind(image); - - VectorSet4(quadVerts[0], x, y, 0, 1); - VectorSet4(quadVerts[1], x + w, y, 0, 1); - VectorSet4(quadVerts[2], x + w, y + h, 0, 1); - VectorSet4(quadVerts[3], x, y + h, 0, 1); - - RB_InstantQuad(quadVerts); - } - } - - qglFinish(); - - end = ri.Milliseconds(); - ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start ); - -} - -/* -============= -RB_ColorMask - -============= -*/ -const void *RB_ColorMask(const void *data) -{ - const colorMaskCommand_t *cmd = data; - - // finish any 2D drawing if needed - if(tess.numIndexes) - RB_EndSurface(); - - if (glRefConfig.framebufferObject) - { - // reverse color mask, so 0 0 0 0 is the default - backEnd.colorMask[0] = !cmd->rgba[0]; - backEnd.colorMask[1] = !cmd->rgba[1]; - backEnd.colorMask[2] = !cmd->rgba[2]; - backEnd.colorMask[3] = !cmd->rgba[3]; - } - - qglColorMask(cmd->rgba[0], cmd->rgba[1], cmd->rgba[2], cmd->rgba[3]); - - return (const void *)(cmd + 1); -} - -/* -============= -RB_ClearDepth - -============= -*/ -const void *RB_ClearDepth(const void *data) -{ - const clearDepthCommand_t *cmd = data; - - // finish any 2D drawing if needed - if(tess.numIndexes) - RB_EndSurface(); - - // texture swapping test - if (r_showImages->integer) - RB_ShowImages(); - - if (glRefConfig.framebufferObject) - { - if (!tr.renderFbo || backEnd.framePostProcessed) - { - FBO_Bind(NULL); - } - else - { - FBO_Bind(tr.renderFbo); - } - } - - qglClear(GL_DEPTH_BUFFER_BIT); - - // if we're doing MSAA, clear the depth texture for the resolve buffer - if (tr.msaaResolveFbo) - { - FBO_Bind(tr.msaaResolveFbo); - qglClear(GL_DEPTH_BUFFER_BIT); - } - - - return (const void *)(cmd + 1); -} - - -/* -============= -RB_SwapBuffers - -============= -*/ -const void *RB_SwapBuffers( const void *data ) { - const swapBuffersCommand_t *cmd; - - // finish any 2D drawing if needed - if ( tess.numIndexes ) { - RB_EndSurface(); - } - - // texture swapping test - if ( r_showImages->integer ) { - RB_ShowImages(); - } - - cmd = (const swapBuffersCommand_t *)data; - - // we measure overdraw by reading back the stencil buffer and - // counting up the number of increments that have happened - if ( r_measureOverdraw->integer ) { - int i; - long sum = 0; - unsigned char *stencilReadback; - - stencilReadback = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight ); - qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback ); - - for ( i = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++ ) { - sum += stencilReadback[i]; - } - - backEnd.pc.c_overDraw += sum; - ri.Hunk_FreeTempMemory( stencilReadback ); - } - - if (glRefConfig.framebufferObject) - { - if (!backEnd.framePostProcessed) - { - if (tr.msaaResolveFbo && r_hdr->integer) - { - // Resolving an RGB16F MSAA FBO to the screen messes with the brightness, so resolve to an RGB16F FBO first - FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST); - FBO_FastBlit(tr.msaaResolveFbo, NULL, NULL, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST); - } - else if (tr.renderFbo) - { - FBO_FastBlit(tr.renderFbo, NULL, NULL, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST); - } - } - } - - if ( !glState.finishCalled ) { - qglFinish(); - } - - GLimp_LogComment( "***************** RB_SwapBuffers *****************\n\n\n" ); - - GLimp_EndFrame(); - - backEnd.framePostProcessed = qfalse; - backEnd.projection2D = qfalse; - - return (const void *)(cmd + 1); -} - -/* -============= -RB_CapShadowMap - -============= -*/ -const void *RB_CapShadowMap(const void *data) -{ - const capShadowmapCommand_t *cmd = data; - - // finish any 2D drawing if needed - if(tess.numIndexes) - RB_EndSurface(); - - if (cmd->map != -1) - { - GL_SelectTexture(0); - if (cmd->cubeSide != -1) - { - if (tr.shadowCubemaps[cmd->map]) - { - GL_Bind(tr.shadowCubemaps[cmd->map]); - qglCopyTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cmd->cubeSide, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0); - } - } - else - { - if (tr.pshadowMaps[cmd->map]) - { - GL_Bind(tr.pshadowMaps[cmd->map]); - qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0); - } - } - } - - return (const void *)(cmd + 1); -} - - -/* -============= -RB_PostProcess - -============= -*/ -const void *RB_PostProcess(const void *data) -{ - const postProcessCommand_t *cmd = data; - FBO_t *srcFbo; - ivec4_t srcBox, dstBox; - qboolean autoExposure; - - // finish any 2D drawing if needed - if(tess.numIndexes) - RB_EndSurface(); - - if (!glRefConfig.framebufferObject || !r_postProcess->integer) - { - // do nothing - return (const void *)(cmd + 1); - } - - if (cmd) - { - backEnd.refdef = cmd->refdef; - backEnd.viewParms = cmd->viewParms; - } - - srcFbo = tr.renderFbo; - if (tr.msaaResolveFbo) - { - // Resolve the MSAA before anything else - // Can't resolve just part of the MSAA FBO, so multiple views will suffer a performance hit here - FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); - srcFbo = tr.msaaResolveFbo; - } - - dstBox[0] = backEnd.viewParms.viewportX; - dstBox[1] = backEnd.viewParms.viewportY; - dstBox[2] = backEnd.viewParms.viewportWidth; - dstBox[3] = backEnd.viewParms.viewportHeight; - - if (r_ssao->integer) - { - srcBox[0] = backEnd.viewParms.viewportX * tr.screenSsaoImage->width / (float)glConfig.vidWidth; - srcBox[1] = backEnd.viewParms.viewportY * tr.screenSsaoImage->height / (float)glConfig.vidHeight; - srcBox[2] = backEnd.viewParms.viewportWidth * tr.screenSsaoImage->width / (float)glConfig.vidWidth; - srcBox[3] = backEnd.viewParms.viewportHeight * tr.screenSsaoImage->height / (float)glConfig.vidHeight; - - //FBO_BlitFromTexture(tr.screenSsaoImage, srcBox, NULL, srcFbo, dstBox, NULL, NULL, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO); - srcBox[1] = tr.screenSsaoImage->height - srcBox[1]; - srcBox[3] = -srcBox[3]; - - FBO_Blit(tr.screenSsaoFbo, srcBox, NULL, srcFbo, dstBox, NULL, NULL, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO); - } - - srcBox[0] = backEnd.viewParms.viewportX; - srcBox[1] = backEnd.viewParms.viewportY; - srcBox[2] = backEnd.viewParms.viewportWidth; - srcBox[3] = backEnd.viewParms.viewportHeight; - - if (srcFbo) - { - if (r_hdr->integer && (r_toneMap->integer || r_forceToneMap->integer)) - { - autoExposure = r_autoExposure->integer || r_forceAutoExposure->integer; - RB_ToneMap(srcFbo, srcBox, NULL, dstBox, autoExposure); - } - else if (r_cameraExposure->value == 0.0f) - { - FBO_FastBlit(srcFbo, srcBox, NULL, dstBox, GL_COLOR_BUFFER_BIT, GL_NEAREST); - } - else - { - vec4_t color; - - color[0] = - color[1] = - color[2] = pow(2, r_cameraExposure->value); //exp2(r_cameraExposure->value); - color[3] = 1.0f; - - FBO_Blit(srcFbo, srcBox, NULL, NULL, dstBox, NULL, color, 0); - } - } - - if (r_drawSunRays->integer) - RB_SunRays(NULL, srcBox, NULL, dstBox); - - if (1) - RB_BokehBlur(NULL, srcBox, NULL, dstBox, backEnd.refdef.blurFactor); - else - RB_GaussianBlur(backEnd.refdef.blurFactor); - - if (0 && r_sunlightMode->integer) - { - ivec4_t dstBox; - VectorSet4(dstBox, 0, 0, 128, 128); - FBO_BlitFromTexture(tr.sunShadowDepthImage[0], NULL, NULL, NULL, dstBox, NULL, NULL, 0); - VectorSet4(dstBox, 128, 0, 128, 128); - FBO_BlitFromTexture(tr.sunShadowDepthImage[1], NULL, NULL, NULL, dstBox, NULL, NULL, 0); - VectorSet4(dstBox, 256, 0, 128, 128); - FBO_BlitFromTexture(tr.sunShadowDepthImage[2], NULL, NULL, NULL, dstBox, NULL, NULL, 0); - } - - if (0) - { - ivec4_t dstBox; - VectorSet4(dstBox, 256, glConfig.vidHeight - 256, 256, 256); - FBO_BlitFromTexture(tr.renderDepthImage, NULL, NULL, NULL, dstBox, NULL, NULL, 0); - VectorSet4(dstBox, 512, glConfig.vidHeight - 256, 256, 256); - FBO_BlitFromTexture(tr.screenShadowImage, NULL, NULL, NULL, dstBox, NULL, NULL, 0); - } - - if (0) - { - ivec4_t dstBox; - VectorSet4(dstBox, 256, glConfig.vidHeight - 256, 256, 256); - FBO_BlitFromTexture(tr.sunRaysImage, NULL, NULL, NULL, dstBox, NULL, NULL, 0); - } - -#if 0 - if (r_cubeMapping->integer && tr.numCubemaps) - { - ivec4_t dstBox; - int cubemapIndex = R_CubemapForPoint( backEnd.viewParms.or.origin ); - - if (cubemapIndex) - { - VectorSet4(dstBox, 0, glConfig.vidHeight - 256, 256, 256); - //FBO_BlitFromTexture(tr.renderCubeImage, NULL, NULL, NULL, dstBox, &tr.testcubeShader, NULL, 0); - FBO_BlitFromTexture(tr.cubemaps[cubemapIndex - 1], NULL, NULL, NULL, dstBox, &tr.testcubeShader, NULL, 0); - } - } -#endif - - backEnd.framePostProcessed = qtrue; - - return (const void *)(cmd + 1); -} - - -/* -==================== -RB_ExecuteRenderCommands -==================== -*/ -void RB_ExecuteRenderCommands( const void *data ) { - int t1, t2; - - t1 = ri.Milliseconds (); - - while ( 1 ) { - data = PADP(data, sizeof(void *)); - - switch ( *(const int *)data ) { - case RC_SET_COLOR: - data = RB_SetColor( data ); - break; - case RC_STRETCH_PIC: - data = RB_StretchPic( data ); - break; - case RC_DRAW_SURFS: - data = RB_DrawSurfs( data ); - break; - case RC_DRAW_BUFFER: - data = RB_DrawBuffer( data ); - break; - case RC_SWAP_BUFFERS: - data = RB_SwapBuffers( data ); - break; - case RC_SCREENSHOT: - data = RB_TakeScreenshotCmd( data ); - break; - case RC_VIDEOFRAME: - data = RB_TakeVideoFrameCmd( data ); - break; - case RC_COLORMASK: - data = RB_ColorMask(data); - break; - case RC_CLEARDEPTH: - data = RB_ClearDepth(data); - break; - case RC_CAPSHADOWMAP: - data = RB_CapShadowMap(data); - break; - case RC_POSTPROCESS: - data = RB_PostProcess(data); - break; - case RC_END_OF_LIST: - default: - // finish any 2D drawing if needed - if(tess.numIndexes) - RB_EndSurface(); - - // stop rendering - t2 = ri.Milliseconds (); - backEnd.pc.msec = t2 - t1; - return; - } - } - -} diff --git a/code/renderergl2/tr_bsp.c b/code/renderergl2/tr_bsp.c deleted file mode 100644 index ba1d21e8fd..0000000000 --- a/code/renderergl2/tr_bsp.c +++ /dev/null @@ -1,3591 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_map.c - -#include "tr_local.h" - -/* - -Loads and prepares a map file for scene rendering. - -A single entry point: - -void RE_LoadWorldMap( const char *name ); - -*/ - -static world_t s_worldData; -static byte *fileBase; - -int c_subdivisions; -int c_gridVerts; - -//=============================================================================== - -static void HSVtoRGB( float h, float s, float v, float rgb[3] ) -{ - int i; - float f; - float p, q, t; - - h *= 5; - - i = floor( h ); - f = h - i; - - p = v * ( 1 - s ); - q = v * ( 1 - s * f ); - t = v * ( 1 - s * ( 1 - f ) ); - - switch ( i ) - { - case 0: - rgb[0] = v; - rgb[1] = t; - rgb[2] = p; - break; - case 1: - rgb[0] = q; - rgb[1] = v; - rgb[2] = p; - break; - case 2: - rgb[0] = p; - rgb[1] = v; - rgb[2] = t; - break; - case 3: - rgb[0] = p; - rgb[1] = q; - rgb[2] = v; - break; - case 4: - rgb[0] = t; - rgb[1] = p; - rgb[2] = v; - break; - case 5: - rgb[0] = v; - rgb[1] = p; - rgb[2] = q; - break; - } -} - -/* -=============== -R_ColorShiftLightingBytes - -=============== -*/ -static void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) { - int shift, r, g, b; - - // shift the color data based on overbright range - shift = r_mapOverBrightBits->integer - tr.overbrightBits; - - // shift the data based on overbright range - r = in[0] << shift; - g = in[1] << shift; - b = in[2] << shift; - - // normalize by color instead of saturating to white - if ( ( r | g | b ) > 255 ) { - int max; - - max = r > g ? r : g; - max = max > b ? max : b; - r = r * 255 / max; - g = g * 255 / max; - b = b * 255 / max; - } - - out[0] = r; - out[1] = g; - out[2] = b; - out[3] = in[3]; -} - - -/* -=============== -R_ColorShiftLightingFloats - -=============== -*/ -static void R_ColorShiftLightingFloats(float in[4], float out[4], float scale ) -{ - float r, g, b; - - scale *= pow(2.0f, r_mapOverBrightBits->integer - tr.overbrightBits); - - r = in[0] * scale; - g = in[1] * scale; - b = in[2] * scale; - - // normalize by color instead of saturating to white - if ( !r_hdr->integer && ( r > 1 || g > 1 || b > 1 ) ) { - float max; - - max = r > g ? r : g; - max = max > b ? max : b; - r = r / max; - g = g / max; - b = b / max; - } - - out[0] = r; - out[1] = g; - out[2] = b; - out[3] = in[3]; -} - -// Modified from http://graphicrants.blogspot.jp/2009/04/rgbm-color-encoding.html -void ColorToRGBM(const vec3_t color, unsigned char rgbm[4]) -{ - vec3_t sample; - float maxComponent; - - maxComponent = MAX(sample[0], sample[1]); - maxComponent = MAX(maxComponent, sample[2]); - maxComponent = CLAMP(maxComponent, 1.0f/255.0f, 1.0f); - - rgbm[3] = (unsigned char) ceil(maxComponent * 255.0f); - maxComponent = 255.0f / rgbm[3]; - - VectorScale(sample, maxComponent, sample); - - rgbm[0] = (unsigned char) (sample[0] * 255); - rgbm[1] = (unsigned char) (sample[1] * 255); - rgbm[2] = (unsigned char) (sample[2] * 255); -} - -void ColorToRGBA16F(const vec3_t color, unsigned short rgba16f[4]) -{ - rgba16f[0] = FloatToHalf(color[0]); - rgba16f[1] = FloatToHalf(color[1]); - rgba16f[2] = FloatToHalf(color[2]); - rgba16f[3] = FloatToHalf(1.0f); -} - - -/* -=============== -R_LoadLightmaps - -=============== -*/ -#define DEFAULT_LIGHTMAP_SIZE 128 -#define MAX_LIGHTMAP_PAGES 2 -static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) { - byte *buf, *buf_p; - dsurface_t *surf; - int len; - byte *image; - int i, j, numLightmaps, textureInternalFormat = 0; - float maxIntensity = 0; - double sumIntensity = 0; - - len = l->filelen; - if ( !len ) { - return; - } - buf = fileBase + l->fileofs; - - // we are about to upload textures - R_IssuePendingRenderCommands(); - - tr.lightmapSize = DEFAULT_LIGHTMAP_SIZE; - numLightmaps = len / (tr.lightmapSize * tr.lightmapSize * 3); - - // check for deluxe mapping - if (numLightmaps <= 1) - { - tr.worldDeluxeMapping = qfalse; - } - else - { - tr.worldDeluxeMapping = qtrue; - for( i = 0, surf = (dsurface_t *)(fileBase + surfs->fileofs); - i < surfs->filelen / sizeof(dsurface_t); i++, surf++ ) { - int lightmapNum = LittleLong( surf->lightmapNum ); - - if ( lightmapNum >= 0 && (lightmapNum & 1) != 0 ) { - tr.worldDeluxeMapping = qfalse; - break; - } - } - } - - image = ri.Malloc(tr.lightmapSize * tr.lightmapSize * 4 * 2); - - if (tr.worldDeluxeMapping) - numLightmaps >>= 1; - - if(numLightmaps == 1) - { - //FIXME: HACK: maps with only one lightmap turn up fullbright for some reason. - //this avoids this, but isn't the correct solution. - numLightmaps++; - } - else if (r_mergeLightmaps->integer && numLightmaps >= 1024 ) - { - // FIXME: fat light maps don't support more than 1024 light maps - ri.Printf(PRINT_WARNING, "WARNING: number of lightmaps > 1024\n"); - numLightmaps = 1024; - } - - // use fat lightmaps of an appropriate size - if (r_mergeLightmaps->integer) - { - tr.fatLightmapSize = 512; - tr.fatLightmapStep = tr.fatLightmapSize / tr.lightmapSize; - - // at most MAX_LIGHTMAP_PAGES - while (tr.fatLightmapStep * tr.fatLightmapStep * MAX_LIGHTMAP_PAGES < numLightmaps && tr.fatLightmapSize != glConfig.maxTextureSize ) - { - tr.fatLightmapSize <<= 1; - tr.fatLightmapStep = tr.fatLightmapSize / tr.lightmapSize; - } - - tr.numLightmaps = numLightmaps / (tr.fatLightmapStep * tr.fatLightmapStep); - - if (numLightmaps % (tr.fatLightmapStep * tr.fatLightmapStep) != 0) - tr.numLightmaps++; - } - else - { - tr.numLightmaps = numLightmaps; - } - - tr.lightmaps = ri.Hunk_Alloc( tr.numLightmaps * sizeof(image_t *), h_low ); - - if (tr.worldDeluxeMapping) - { - tr.deluxemaps = ri.Hunk_Alloc( tr.numLightmaps * sizeof(image_t *), h_low ); - } - - if (r_hdr->integer) - { - if (glRefConfig.textureFloat && glRefConfig.halfFloatPixel && r_floatLightmap->integer) - textureInternalFormat = GL_RGBA16F_ARB; - else - textureInternalFormat = GL_RGBA8; - } - - if (r_mergeLightmaps->integer) - { - for (i = 0; i < tr.numLightmaps; i++) - { - tr.lightmaps[i] = R_CreateImage(va("_fatlightmap%d", i), NULL, tr.fatLightmapSize, tr.fatLightmapSize, IMGTYPE_COLORALPHA, IMGFLAG_NOLIGHTSCALE | IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, textureInternalFormat ); - - if (tr.worldDeluxeMapping) - { - tr.deluxemaps[i] = R_CreateImage(va("_fatdeluxemap%d", i), NULL, tr.fatLightmapSize, tr.fatLightmapSize, IMGTYPE_DELUXE, IMGFLAG_NOLIGHTSCALE | IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, 0 ); - } - } - } - - for(i = 0; i < numLightmaps; i++) - { - int xoff = 0, yoff = 0; - int lightmapnum = i; - // expand the 24 bit on-disk to 32 bit - - if (r_mergeLightmaps->integer) - { - int lightmaponpage = i % (tr.fatLightmapStep * tr.fatLightmapStep); - xoff = (lightmaponpage % tr.fatLightmapStep) * tr.lightmapSize; - yoff = (lightmaponpage / tr.fatLightmapStep) * tr.lightmapSize; - - lightmapnum /= (tr.fatLightmapStep * tr.fatLightmapStep); - } - - // if (tr.worldLightmapping) - { - char filename[MAX_QPATH]; - byte *hdrLightmap = NULL; - int size = 0; - - // look for hdr lightmaps - if (r_hdr->integer) - { - Com_sprintf( filename, sizeof( filename ), "maps/%s/lm_%04d.hdr", s_worldData.baseName, i * (tr.worldDeluxeMapping ? 2 : 1) ); - //ri.Printf(PRINT_ALL, "looking for %s\n", filename); - - size = ri.FS_ReadFile(filename, (void **)&hdrLightmap); - } - - if (hdrLightmap) - { - byte *p = hdrLightmap; - //ri.Printf(PRINT_ALL, "found!\n"); - - /* FIXME: don't just skip over this header and actually parse it */ - while (size && !(*p == '\n' && *(p+1) == '\n')) - { - size--; - p++; - } - - if (!size) - ri.Error(ERR_DROP, "Bad header for %s!", filename); - - size -= 2; - p += 2; - - while (size && !(*p == '\n')) - { - size--; - p++; - } - - size--; - p++; - - buf_p = (byte *)p; - -#if 0 // HDRFILE_RGBE - if (size != tr.lightmapSize * tr.lightmapSize * 4) - ri.Error(ERR_DROP, "Bad size for %s (%i)!", filename, size); -#else // HDRFILE_FLOAT - if (size != tr.lightmapSize * tr.lightmapSize * 12) - ri.Error(ERR_DROP, "Bad size for %s (%i)!", filename, size); -#endif - } - else - { - if (tr.worldDeluxeMapping) - buf_p = buf + (i * 2) * tr.lightmapSize * tr.lightmapSize * 3; - else - buf_p = buf + i * tr.lightmapSize * tr.lightmapSize * 3; - } - - for ( j = 0 ; j < tr.lightmapSize * tr.lightmapSize; j++ ) - { - if (hdrLightmap) - { - float color[3]; - -#if 0 // HDRFILE_RGBE - float exponent = exp2(buf_p[j*4+3] - 128); - - color[0] = buf_p[j*4+0] * exponent; - color[1] = buf_p[j*4+1] * exponent; - color[2] = buf_p[j*4+2] * exponent; -#else // HDRFILE_FLOAT - memcpy(color, &buf_p[j*12], 12); - - color[0] = LittleFloat(color[0]); - color[1] = LittleFloat(color[1]); - color[2] = LittleFloat(color[2]); -#endif - R_ColorShiftLightingFloats(color, color, 1.0f/255.0f); - - if (glRefConfig.textureFloat && glRefConfig.halfFloatPixel && r_floatLightmap->integer) - ColorToRGBA16F(color, (unsigned short *)(&image[j*8])); - else - ColorToRGBM(color, &image[j*4]); - } - else if (glRefConfig.textureFloat && glRefConfig.halfFloatPixel && r_floatLightmap->integer) - { - float color[3]; - - //hack: convert LDR lightmap to HDR one - color[0] = MAX(buf_p[j*3+0], 0.499f); - color[1] = MAX(buf_p[j*3+1], 0.499f); - color[2] = MAX(buf_p[j*3+2], 0.499f); - - // if under an arbitrary value (say 12) grey it out - // this prevents weird splotches in dimly lit areas - if (color[0] + color[1] + color[2] < 12.0f) - { - float avg = (color[0] + color[1] + color[2]) * 0.3333f; - color[0] = avg; - color[1] = avg; - color[2] = avg; - } - - R_ColorShiftLightingFloats(color, color, 1.0f/255.0f); - - ColorToRGBA16F(color, (unsigned short *)(&image[j*8])); - } - else - { - if ( r_lightmap->integer == 2 ) - { // color code by intensity as development tool (FIXME: check range) - float r = buf_p[j*3+0]; - float g = buf_p[j*3+1]; - float b = buf_p[j*3+2]; - float intensity; - float out[3] = {0.0, 0.0, 0.0}; - - intensity = 0.33f * r + 0.685f * g + 0.063f * b; - - if ( intensity > 255 ) - intensity = 1.0f; - else - intensity /= 255.0f; - - if ( intensity > maxIntensity ) - maxIntensity = intensity; - - HSVtoRGB( intensity, 1.00, 0.50, out ); - - image[j*4+0] = out[0] * 255; - image[j*4+1] = out[1] * 255; - image[j*4+2] = out[2] * 255; - image[j*4+3] = 255; - - sumIntensity += intensity; - } - else - { - R_ColorShiftLightingBytes( &buf_p[j*3], &image[j*4] ); - image[j*4+3] = 255; - } - } - } - - if (r_mergeLightmaps->integer) - R_UpdateSubImage(tr.lightmaps[lightmapnum], image, xoff, yoff, tr.lightmapSize, tr.lightmapSize); - else - tr.lightmaps[i] = R_CreateImage(va("*lightmap%d", i), image, tr.lightmapSize, tr.lightmapSize, IMGTYPE_COLORALPHA, IMGFLAG_NOLIGHTSCALE | IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, textureInternalFormat ); - - if (hdrLightmap) - ri.FS_FreeFile(hdrLightmap); - } - - if (tr.worldDeluxeMapping) - { - buf_p = buf + (i * 2 + 1) * tr.lightmapSize * tr.lightmapSize * 3; - - for ( j = 0 ; j < tr.lightmapSize * tr.lightmapSize; j++ ) { - image[j*4+0] = buf_p[j*3+0]; - image[j*4+1] = buf_p[j*3+1]; - image[j*4+2] = buf_p[j*3+2]; - - // make 0,0,0 into 127,127,127 - if ((image[j*4+0] == 0) && (image[j*4+1] == 0) && (image[j*4+2] == 0)) - { - image[j*4+0] = - image[j*4+1] = - image[j*4+2] = 127; - } - - image[j*4+3] = 255; - } - - if (r_mergeLightmaps->integer) - { - R_UpdateSubImage(tr.deluxemaps[lightmapnum], image, xoff, yoff, tr.lightmapSize, tr.lightmapSize ); - } - else - { - tr.deluxemaps[i] = R_CreateImage(va("*deluxemap%d", i), image, tr.lightmapSize, tr.lightmapSize, IMGTYPE_DELUXE, IMGFLAG_NOLIGHTSCALE | IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, 0 ); - } - } - } - - if ( r_lightmap->integer == 2 ) { - ri.Printf( PRINT_ALL, "Brightest lightmap value: %d\n", ( int ) ( maxIntensity * 255 ) ); - } - - ri.Free(image); -} - - -static float FatPackU(float input, int lightmapnum) -{ - if (lightmapnum < 0) - return input; - - if (tr.worldDeluxeMapping) - lightmapnum >>= 1; - - if(tr.fatLightmapSize > 0) - { - int x; - - lightmapnum %= (tr.fatLightmapStep * tr.fatLightmapStep); - - x = lightmapnum % tr.fatLightmapStep; - - return (input / ((float)tr.fatLightmapStep)) + ((1.0 / ((float)tr.fatLightmapStep)) * (float)x); - } - - return input; -} - -static float FatPackV(float input, int lightmapnum) -{ - if (lightmapnum < 0) - return input; - - if (tr.worldDeluxeMapping) - lightmapnum >>= 1; - - if(tr.fatLightmapSize > 0) - { - int y; - - lightmapnum %= (tr.fatLightmapStep * tr.fatLightmapStep); - - y = lightmapnum / tr.fatLightmapStep; - - return (input / ((float)tr.fatLightmapStep)) + ((1.0 / ((float)tr.fatLightmapStep)) * (float)y); - } - - return input; -} - - -static int FatLightmap(int lightmapnum) -{ - if (lightmapnum < 0) - return lightmapnum; - - if (tr.worldDeluxeMapping) - lightmapnum >>= 1; - - if (tr.fatLightmapSize > 0) - { - return lightmapnum / (tr.fatLightmapStep * tr.fatLightmapStep); - } - - return lightmapnum; -} - -/* -================= -RE_SetWorldVisData - -This is called by the clipmodel subsystem so we can share the 1.8 megs of -space in big maps... -================= -*/ -void RE_SetWorldVisData( const byte *vis ) { - tr.externalVisData = vis; -} - - -/* -================= -R_LoadVisibility -================= -*/ -static void R_LoadVisibility( lump_t *l ) { - int len; - byte *buf; - - len = ( s_worldData.numClusters + 63 ) & ~63; - s_worldData.novis = ri.Hunk_Alloc( len, h_low ); - Com_Memset( s_worldData.novis, 0xff, len ); - - len = l->filelen; - if ( !len ) { - return; - } - buf = fileBase + l->fileofs; - - s_worldData.numClusters = LittleLong( ((int *)buf)[0] ); - s_worldData.clusterBytes = LittleLong( ((int *)buf)[1] ); - - // CM_Load should have given us the vis data to share, so - // we don't need to allocate another copy - if ( tr.externalVisData ) { - s_worldData.vis = tr.externalVisData; - } else { - byte *dest; - - dest = ri.Hunk_Alloc( len - 8, h_low ); - Com_Memcpy( dest, buf + 8, len - 8 ); - s_worldData.vis = dest; - } -} - -//=============================================================================== - - -/* -=============== -ShaderForShaderNum -=============== -*/ -static shader_t *ShaderForShaderNum( int shaderNum, int lightmapNum ) { - shader_t *shader; - dshader_t *dsh; - - int _shaderNum = LittleLong( shaderNum ); - if ( _shaderNum < 0 || _shaderNum >= s_worldData.numShaders ) { - ri.Error( ERR_DROP, "ShaderForShaderNum: bad num %i", _shaderNum ); - } - dsh = &s_worldData.shaders[ _shaderNum ]; - - if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) { - lightmapNum = LIGHTMAP_BY_VERTEX; - } - - if ( r_fullbright->integer ) { - lightmapNum = LIGHTMAP_WHITEIMAGE; - } - - shader = R_FindShader( dsh->shader, lightmapNum, qtrue ); - - // if the shader had errors, just use default shader - if ( shader->defaultShader ) { - return tr.defaultShader; - } - - return shader; -} - -/* -=============== -ParseFace -=============== -*/ -static void ParseFace( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, msurface_t *surf, int *indexes ) { - int i, j; - srfBspSurface_t *cv; - glIndex_t *tri; - int numVerts, numIndexes, badTriangles; - int realLightmapNum; - - realLightmapNum = LittleLong( ds->lightmapNum ); - - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; - - // get shader value - surf->shader = ShaderForShaderNum( ds->shaderNum, FatLightmap(realLightmapNum) ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } - - numVerts = LittleLong(ds->numVerts); - if (numVerts > MAX_FACE_POINTS) { - ri.Printf( PRINT_WARNING, "WARNING: MAX_FACE_POINTS exceeded: %i\n", numVerts); - numVerts = MAX_FACE_POINTS; - surf->shader = tr.defaultShader; - } - - numIndexes = LittleLong(ds->numIndexes); - - //cv = ri.Hunk_Alloc(sizeof(*cv), h_low); - cv = (void *)surf->data; - cv->surfaceType = SF_FACE; - - cv->numIndexes = numIndexes; - cv->indexes = ri.Hunk_Alloc(numIndexes * sizeof(cv->indexes[0]), h_low); - - cv->numVerts = numVerts; - cv->verts = ri.Hunk_Alloc(numVerts * sizeof(cv->verts[0]), h_low); - - // copy vertexes - surf->cullinfo.type = CULLINFO_PLANE | CULLINFO_BOX; - ClearBounds(surf->cullinfo.bounds[0], surf->cullinfo.bounds[1]); - verts += LittleLong(ds->firstVert); - for(i = 0; i < numVerts; i++) - { - vec4_t color; - - for(j = 0; j < 3; j++) - { - cv->verts[i].xyz[j] = LittleFloat(verts[i].xyz[j]); - cv->verts[i].normal[j] = LittleFloat(verts[i].normal[j]); - } - AddPointToBounds(cv->verts[i].xyz, surf->cullinfo.bounds[0], surf->cullinfo.bounds[1]); - for(j = 0; j < 2; j++) - { - cv->verts[i].st[j] = LittleFloat(verts[i].st[j]); - //cv->verts[i].lightmap[j] = LittleFloat(verts[i].lightmap[j]); - } - cv->verts[i].lightmap[0] = FatPackU(LittleFloat(verts[i].lightmap[0]), realLightmapNum); - cv->verts[i].lightmap[1] = FatPackV(LittleFloat(verts[i].lightmap[1]), realLightmapNum); - - if (hdrVertColors) - { - color[0] = hdrVertColors[(ds->firstVert + i) * 3 ]; - color[1] = hdrVertColors[(ds->firstVert + i) * 3 + 1]; - color[2] = hdrVertColors[(ds->firstVert + i) * 3 + 2]; - } - else - { - //hack: convert LDR vertex colors to HDR - if (r_hdr->integer) - { - color[0] = MAX(verts[i].color[0], 0.499f); - color[1] = MAX(verts[i].color[1], 0.499f); - color[2] = MAX(verts[i].color[2], 0.499f); - } - else - { - color[0] = verts[i].color[0]; - color[1] = verts[i].color[1]; - color[2] = verts[i].color[2]; - } - - } - color[3] = verts[i].color[3] / 255.0f; - - R_ColorShiftLightingFloats( color, cv->verts[i].vertexColors, 1.0f / 255.0f ); - } - - // copy triangles - badTriangles = 0; - indexes += LittleLong(ds->firstIndex); - for(i = 0, tri = cv->indexes; i < numIndexes; i += 3, tri += 3) - { - for(j = 0; j < 3; j++) - { - tri[j] = LittleLong(indexes[i + j]); - - if(tri[j] >= numVerts) - { - ri.Error(ERR_DROP, "Bad index in face surface"); - } - } - - if ((tri[0] == tri[1]) || (tri[1] == tri[2]) || (tri[0] == tri[2])) - { - tri -= 3; - badTriangles++; - } - } - - if (badTriangles) - { - ri.Printf(PRINT_WARNING, "Face has bad triangles, originally shader %s %d tris %d verts, now %d tris\n", surf->shader->name, numIndexes / 3, numVerts, numIndexes / 3 - badTriangles); - cv->numIndexes -= badTriangles * 3; - } - - // take the plane information from the lightmap vector - for ( i = 0 ; i < 3 ; i++ ) { - cv->cullPlane.normal[i] = LittleFloat( ds->lightmapVecs[2][i] ); - } - cv->cullPlane.dist = DotProduct( cv->verts[0].xyz, cv->cullPlane.normal ); - SetPlaneSignbits( &cv->cullPlane ); - cv->cullPlane.type = PlaneTypeForNormal( cv->cullPlane.normal ); - surf->cullinfo.plane = cv->cullPlane; - - surf->data = (surfaceType_t *)cv; - -#ifdef USE_VERT_TANGENT_SPACE - // Calculate tangent spaces - { - srfVert_t *dv[3]; - - for(i = 0, tri = cv->indexes; i < numIndexes; i += 3, tri += 3) - { - dv[0] = &cv->verts[tri[0]]; - dv[1] = &cv->verts[tri[1]]; - dv[2] = &cv->verts[tri[2]]; - - R_CalcTangentVectors(dv); - } - } -#endif -} - - -/* -=============== -ParseMesh -=============== -*/ -static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, msurface_t *surf ) { - srfBspSurface_t *grid; - int i, j; - int width, height, numPoints; - srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE]; - vec3_t bounds[2]; - vec3_t tmpVec; - static surfaceType_t skipData = SF_SKIP; - int realLightmapNum; - - realLightmapNum = LittleLong( ds->lightmapNum ); - - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; - - // get shader value - surf->shader = ShaderForShaderNum( ds->shaderNum, FatLightmap(realLightmapNum) ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } - - // we may have a nodraw surface, because they might still need to - // be around for movement clipping - if ( s_worldData.shaders[ LittleLong( ds->shaderNum ) ].surfaceFlags & SURF_NODRAW ) { - surf->data = &skipData; - return; - } - - width = LittleLong( ds->patchWidth ); - height = LittleLong( ds->patchHeight ); - - if(width < 0 || width > MAX_PATCH_SIZE || height < 0 || height > MAX_PATCH_SIZE) - ri.Error(ERR_DROP, "ParseMesh: bad size"); - - verts += LittleLong( ds->firstVert ); - numPoints = width * height; - for(i = 0; i < numPoints; i++) - { - vec4_t color; - - for(j = 0; j < 3; j++) - { - points[i].xyz[j] = LittleFloat(verts[i].xyz[j]); - points[i].normal[j] = LittleFloat(verts[i].normal[j]); - } - - for(j = 0; j < 2; j++) - { - points[i].st[j] = LittleFloat(verts[i].st[j]); - //points[i].lightmap[j] = LittleFloat(verts[i].lightmap[j]); - } - points[i].lightmap[0] = FatPackU(LittleFloat(verts[i].lightmap[0]), realLightmapNum); - points[i].lightmap[1] = FatPackV(LittleFloat(verts[i].lightmap[1]), realLightmapNum); - - if (hdrVertColors) - { - color[0] = hdrVertColors[(ds->firstVert + i) * 3 ]; - color[1] = hdrVertColors[(ds->firstVert + i) * 3 + 1]; - color[2] = hdrVertColors[(ds->firstVert + i) * 3 + 2]; - } - else - { - //hack: convert LDR vertex colors to HDR - if (r_hdr->integer) - { - color[0] = MAX(verts[i].color[0], 0.499f); - color[1] = MAX(verts[i].color[1], 0.499f); - color[2] = MAX(verts[i].color[2], 0.499f); - } - else - { - color[0] = verts[i].color[0]; - color[1] = verts[i].color[1]; - color[2] = verts[i].color[2]; - } - } - color[3] = verts[i].color[3] / 255.0f; - - R_ColorShiftLightingFloats( color, points[i].vertexColors, 1.0f / 255.0f ); - } - - // pre-tesseleate - grid = R_SubdividePatchToGrid( width, height, points ); - surf->data = (surfaceType_t *)grid; - - // copy the level of detail origin, which is the center - // of the group of all curves that must subdivide the same - // to avoid cracking - for ( i = 0 ; i < 3 ; i++ ) { - bounds[0][i] = LittleFloat( ds->lightmapVecs[0][i] ); - bounds[1][i] = LittleFloat( ds->lightmapVecs[1][i] ); - } - VectorAdd( bounds[0], bounds[1], bounds[1] ); - VectorScale( bounds[1], 0.5f, grid->lodOrigin ); - VectorSubtract( bounds[0], grid->lodOrigin, tmpVec ); - grid->lodRadius = VectorLength( tmpVec ); -} - -/* -=============== -ParseTriSurf -=============== -*/ -static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, msurface_t *surf, int *indexes ) { - srfBspSurface_t *cv; - glIndex_t *tri; - int i, j; - int numVerts, numIndexes, badTriangles; - - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; - - // get shader - surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } - - numVerts = LittleLong(ds->numVerts); - numIndexes = LittleLong(ds->numIndexes); - - //cv = ri.Hunk_Alloc(sizeof(*cv), h_low); - cv = (void *)surf->data; - cv->surfaceType = SF_TRIANGLES; - - cv->numIndexes = numIndexes; - cv->indexes = ri.Hunk_Alloc(numIndexes * sizeof(cv->indexes[0]), h_low); - - cv->numVerts = numVerts; - cv->verts = ri.Hunk_Alloc(numVerts * sizeof(cv->verts[0]), h_low); - - surf->data = (surfaceType_t *) cv; - - // copy vertexes - surf->cullinfo.type = CULLINFO_BOX; - ClearBounds(surf->cullinfo.bounds[0], surf->cullinfo.bounds[1]); - verts += LittleLong(ds->firstVert); - for(i = 0; i < numVerts; i++) - { - vec4_t color; - - for(j = 0; j < 3; j++) - { - cv->verts[i].xyz[j] = LittleFloat(verts[i].xyz[j]); - cv->verts[i].normal[j] = LittleFloat(verts[i].normal[j]); - } - - AddPointToBounds( cv->verts[i].xyz, surf->cullinfo.bounds[0], surf->cullinfo.bounds[1] ); - - for(j = 0; j < 2; j++) - { - cv->verts[i].st[j] = LittleFloat(verts[i].st[j]); - cv->verts[i].lightmap[j] = LittleFloat(verts[i].lightmap[j]); - } - - if (hdrVertColors) - { - color[0] = hdrVertColors[(ds->firstVert + i) * 3 ]; - color[1] = hdrVertColors[(ds->firstVert + i) * 3 + 1]; - color[2] = hdrVertColors[(ds->firstVert + i) * 3 + 2]; - } - else - { - //hack: convert LDR vertex colors to HDR - if (r_hdr->integer) - { - color[0] = MAX(verts[i].color[0], 0.499f); - color[1] = MAX(verts[i].color[1], 0.499f); - color[2] = MAX(verts[i].color[2], 0.499f); - } - else - { - color[0] = verts[i].color[0]; - color[1] = verts[i].color[1]; - color[2] = verts[i].color[2]; - } - } - color[3] = verts[i].color[3] / 255.0f; - - R_ColorShiftLightingFloats( color, cv->verts[i].vertexColors, 1.0f / 255.0f ); - } - - // copy triangles - badTriangles = 0; - indexes += LittleLong(ds->firstIndex); - for(i = 0, tri = cv->indexes; i < numIndexes; i += 3, tri += 3) - { - for(j = 0; j < 3; j++) - { - tri[j] = LittleLong(indexes[i + j]); - - if(tri[j] >= numVerts) - { - ri.Error(ERR_DROP, "Bad index in face surface"); - } - } - - if ((tri[0] == tri[1]) || (tri[1] == tri[2]) || (tri[0] == tri[2])) - { - tri -= 3; - badTriangles++; - } - } - - if (badTriangles) - { - ri.Printf(PRINT_WARNING, "Trisurf has bad triangles, originally shader %s %d tris %d verts, now %d tris\n", surf->shader->name, numIndexes / 3, numVerts, numIndexes / 3 - badTriangles); - cv->numIndexes -= badTriangles * 3; - } - -#ifdef USE_VERT_TANGENT_SPACE - // Calculate tangent spaces - { - srfVert_t *dv[3]; - - for(i = 0, tri = cv->indexes; i < numIndexes; i += 3, tri += 3) - { - dv[0] = &cv->verts[tri[0]]; - dv[1] = &cv->verts[tri[1]]; - dv[2] = &cv->verts[tri[2]]; - - R_CalcTangentVectors(dv); - } - } -#endif -} - -/* -=============== -ParseFlare -=============== -*/ -static void ParseFlare( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) { - srfFlare_t *flare; - int i; - - // get fog volume - surf->fogIndex = LittleLong( ds->fogNum ) + 1; - - // get shader - surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX ); - if ( r_singleShader->integer && !surf->shader->isSky ) { - surf->shader = tr.defaultShader; - } - - //flare = ri.Hunk_Alloc( sizeof( *flare ), h_low ); - flare = (void *)surf->data; - flare->surfaceType = SF_FLARE; - - surf->data = (surfaceType_t *)flare; - - for ( i = 0 ; i < 3 ; i++ ) { - flare->origin[i] = LittleFloat( ds->lightmapOrigin[i] ); - flare->color[i] = LittleFloat( ds->lightmapVecs[0][i] ); - flare->normal[i] = LittleFloat( ds->lightmapVecs[2][i] ); - } -} - - -/* -================= -R_MergedWidthPoints - -returns true if there are grid points merged on a width edge -================= -*/ -int R_MergedWidthPoints(srfBspSurface_t *grid, int offset) { - int i, j; - - for (i = 1; i < grid->width-1; i++) { - for (j = i + 1; j < grid->width-1; j++) { - if ( fabs(grid->verts[i + offset].xyz[0] - grid->verts[j + offset].xyz[0]) > .1) continue; - if ( fabs(grid->verts[i + offset].xyz[1] - grid->verts[j + offset].xyz[1]) > .1) continue; - if ( fabs(grid->verts[i + offset].xyz[2] - grid->verts[j + offset].xyz[2]) > .1) continue; - return qtrue; - } - } - return qfalse; -} - -/* -================= -R_MergedHeightPoints - -returns true if there are grid points merged on a height edge -================= -*/ -int R_MergedHeightPoints(srfBspSurface_t *grid, int offset) { - int i, j; - - for (i = 1; i < grid->height-1; i++) { - for (j = i + 1; j < grid->height-1; j++) { - if ( fabs(grid->verts[grid->width * i + offset].xyz[0] - grid->verts[grid->width * j + offset].xyz[0]) > .1) continue; - if ( fabs(grid->verts[grid->width * i + offset].xyz[1] - grid->verts[grid->width * j + offset].xyz[1]) > .1) continue; - if ( fabs(grid->verts[grid->width * i + offset].xyz[2] - grid->verts[grid->width * j + offset].xyz[2]) > .1) continue; - return qtrue; - } - } - return qfalse; -} - -/* -================= -R_FixSharedVertexLodError_r - -NOTE: never sync LoD through grid edges with merged points! - -FIXME: write generalized version that also avoids cracks between a patch and one that meets half way? -================= -*/ -void R_FixSharedVertexLodError_r( int start, srfBspSurface_t *grid1 ) { - int j, k, l, m, n, offset1, offset2, touch; - srfBspSurface_t *grid2; - - for ( j = start; j < s_worldData.numsurfaces; j++ ) { - // - grid2 = (srfBspSurface_t *) s_worldData.surfaces[j].data; - // if this surface is not a grid - if ( grid2->surfaceType != SF_GRID ) continue; - // if the LOD errors are already fixed for this patch - if ( grid2->lodFixed == 2 ) continue; - // grids in the same LOD group should have the exact same lod radius - if ( grid1->lodRadius != grid2->lodRadius ) continue; - // grids in the same LOD group should have the exact same lod origin - if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue; - if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue; - if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue; - // - touch = qfalse; - for (n = 0; n < 2; n++) { - // - if (n) offset1 = (grid1->height-1) * grid1->width; - else offset1 = 0; - if (R_MergedWidthPoints(grid1, offset1)) continue; - for (k = 1; k < grid1->width-1; k++) { - for (m = 0; m < 2; m++) { - - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - if (R_MergedWidthPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->width-1; l++) { - // - if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->widthLodError[l] = grid1->widthLodError[k]; - touch = qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (m) offset2 = grid2->width-1; - else offset2 = 0; - if (R_MergedHeightPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->height-1; l++) { - // - if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->heightLodError[l] = grid1->widthLodError[k]; - touch = qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = grid1->width-1; - else offset1 = 0; - if (R_MergedHeightPoints(grid1, offset1)) continue; - for (k = 1; k < grid1->height-1; k++) { - for (m = 0; m < 2; m++) { - - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - if (R_MergedWidthPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->width-1; l++) { - // - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->widthLodError[l] = grid1->heightLodError[k]; - touch = qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (m) offset2 = grid2->width-1; - else offset2 = 0; - if (R_MergedHeightPoints(grid2, offset2)) continue; - for ( l = 1; l < grid2->height-1; l++) { - // - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue; - if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue; - // ok the points are equal and should have the same lod error - grid2->heightLodError[l] = grid1->heightLodError[k]; - touch = qtrue; - } - } - } - } - if (touch) { - grid2->lodFixed = 2; - R_FixSharedVertexLodError_r ( start, grid2 ); - //NOTE: this would be correct but makes things really slow - //grid2->lodFixed = 1; - } - } -} - -/* -================= -R_FixSharedVertexLodError - -This function assumes that all patches in one group are nicely stitched together for the highest LoD. -If this is not the case this function will still do its job but won't fix the highest LoD cracks. -================= -*/ -void R_FixSharedVertexLodError( void ) { - int i; - srfBspSurface_t *grid1; - - for ( i = 0; i < s_worldData.numsurfaces; i++ ) { - // - grid1 = (srfBspSurface_t *) s_worldData.surfaces[i].data; - // if this surface is not a grid - if ( grid1->surfaceType != SF_GRID ) - continue; - // - if ( grid1->lodFixed ) - continue; - // - grid1->lodFixed = 2; - // recursively fix other patches in the same LOD group - R_FixSharedVertexLodError_r( i + 1, grid1); - } -} - - -/* -=============== -R_StitchPatches -=============== -*/ -int R_StitchPatches( int grid1num, int grid2num ) { - float *v1, *v2; - srfBspSurface_t *grid1, *grid2; - int k, l, m, n, offset1, offset2, row, column; - - grid1 = (srfBspSurface_t *) s_worldData.surfaces[grid1num].data; - grid2 = (srfBspSurface_t *) s_worldData.surfaces[grid2num].data; - for (n = 0; n < 2; n++) { - // - if (n) offset1 = (grid1->height-1) * grid1->width; - else offset1 = 0; - if (R_MergedWidthPoints(grid1, offset1)) - continue; - for (k = 0; k < grid1->width-2; k += 2) { - - for (m = 0; m < 2; m++) { - - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[k + 2 + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[k + 2 + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = grid1->width-1; - else offset1 = 0; - if (R_MergedHeightPoints(grid1, offset1)) - continue; - for (k = 0; k < grid1->height-2; k += 2) { - for (m = 0; m < 2; m++) { - - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[(l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = (grid1->height-1) * grid1->width; - else offset1 = 0; - if (R_MergedWidthPoints(grid1, offset1)) - continue; - for (k = grid1->width-1; k > 1; k -= 2) { - - for (m = 0; m < 2; m++) { - - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[k - 2 + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[(l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[k - 2 + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]); - if (!grid2) - break; - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - for (n = 0; n < 2; n++) { - // - if (n) offset1 = grid1->width-1; - else offset1 = 0; - if (R_MergedHeightPoints(grid1, offset1)) - continue; - for (k = grid1->height-1; k > 1; k -= 2) { - for (m = 0; m < 2; m++) { - - if ( grid2->width >= MAX_GRID_SIZE ) - break; - if (m) offset2 = (grid2->height-1) * grid2->width; - else offset2 = 0; - for ( l = 0; l < grid2->width-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz; - v2 = grid2->verts[l + 1 + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[l + offset2].xyz; - v2 = grid2->verts[(l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert column into grid2 right after after column l - if (m) row = grid2->height-1; - else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, - grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - for (m = 0; m < 2; m++) { - - if (grid2->height >= MAX_GRID_SIZE) - break; - if (m) offset2 = grid2->width-1; - else offset2 = 0; - for ( l = 0; l < grid2->height-1; l++) { - // - v1 = grid1->verts[grid1->width * k + offset1].xyz; - v2 = grid2->verts[grid2->width * l + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - - v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) > .1) - continue; - if ( fabs(v1[1] - v2[1]) > .1) - continue; - if ( fabs(v1[2] - v2[2]) > .1) - continue; - // - v1 = grid2->verts[grid2->width * l + offset2].xyz; - v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz; - if ( fabs(v1[0] - v2[0]) < .01 && - fabs(v1[1] - v2[1]) < .01 && - fabs(v1[2] - v2[2]) < .01) - continue; - // - //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" ); - // insert row into grid2 right after after row l - if (m) column = grid2->width-1; - else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, - grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]); - grid2->lodStitched = qfalse; - s_worldData.surfaces[grid2num].data = (void *) grid2; - return qtrue; - } - } - } - } - return qfalse; -} - -/* -=============== -R_TryStitchPatch - -This function will try to stitch patches in the same LoD group together for the highest LoD. - -Only single missing vertice cracks will be fixed. - -Vertices will be joined at the patch side a crack is first found, at the other side -of the patch (on the same row or column) the vertices will not be joined and cracks -might still appear at that side. -=============== -*/ -int R_TryStitchingPatch( int grid1num ) { - int j, numstitches; - srfBspSurface_t *grid1, *grid2; - - numstitches = 0; - grid1 = (srfBspSurface_t *) s_worldData.surfaces[grid1num].data; - for ( j = 0; j < s_worldData.numsurfaces; j++ ) { - // - grid2 = (srfBspSurface_t *) s_worldData.surfaces[j].data; - // if this surface is not a grid - if ( grid2->surfaceType != SF_GRID ) continue; - // grids in the same LOD group should have the exact same lod radius - if ( grid1->lodRadius != grid2->lodRadius ) continue; - // grids in the same LOD group should have the exact same lod origin - if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue; - if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue; - if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue; - // - while (R_StitchPatches(grid1num, j)) - { - numstitches++; - } - } - return numstitches; -} - -/* -=============== -R_StitchAllPatches -=============== -*/ -void R_StitchAllPatches( void ) { - int i, stitched, numstitches; - srfBspSurface_t *grid1; - - numstitches = 0; - do - { - stitched = qfalse; - for ( i = 0; i < s_worldData.numsurfaces; i++ ) { - // - grid1 = (srfBspSurface_t *) s_worldData.surfaces[i].data; - // if this surface is not a grid - if ( grid1->surfaceType != SF_GRID ) - continue; - // - if ( grid1->lodStitched ) - continue; - // - grid1->lodStitched = qtrue; - stitched = qtrue; - // - numstitches += R_TryStitchingPatch( i ); - } - } - while (stitched); - ri.Printf( PRINT_ALL, "stitched %d LoD cracks\n", numstitches ); -} - -/* -=============== -R_MovePatchSurfacesToHunk -=============== -*/ -void R_MovePatchSurfacesToHunk(void) { - int i, size; - srfBspSurface_t *grid, *hunkgrid; - - for ( i = 0; i < s_worldData.numsurfaces; i++ ) { - // - grid = (srfBspSurface_t *) s_worldData.surfaces[i].data; - // if this surface is not a grid - if ( grid->surfaceType != SF_GRID ) - continue; - // - size = sizeof(*grid); - hunkgrid = ri.Hunk_Alloc(size, h_low); - Com_Memcpy(hunkgrid, grid, size); - - hunkgrid->widthLodError = ri.Hunk_Alloc( grid->width * 4, h_low ); - Com_Memcpy( hunkgrid->widthLodError, grid->widthLodError, grid->width * 4 ); - - hunkgrid->heightLodError = ri.Hunk_Alloc( grid->height * 4, h_low ); - Com_Memcpy( hunkgrid->heightLodError, grid->heightLodError, grid->height * 4 ); - - hunkgrid->numIndexes = grid->numIndexes; - hunkgrid->indexes = ri.Hunk_Alloc(grid->numIndexes * sizeof(glIndex_t), h_low); - Com_Memcpy(hunkgrid->indexes, grid->indexes, grid->numIndexes * sizeof(glIndex_t)); - - hunkgrid->numVerts = grid->numVerts; - hunkgrid->verts = ri.Hunk_Alloc(grid->numVerts * sizeof(srfVert_t), h_low); - Com_Memcpy(hunkgrid->verts, grid->verts, grid->numVerts * sizeof(srfVert_t)); - - R_FreeSurfaceGridMesh( grid ); - - s_worldData.surfaces[i].data = (void *) hunkgrid; - } -} - - -/* -================= -BSPSurfaceCompare -compare function for qsort() -================= -*/ -static int BSPSurfaceCompare(const void *a, const void *b) -{ - msurface_t *aa, *bb; - - aa = *(msurface_t **) a; - bb = *(msurface_t **) b; - - // shader first - if(aa->shader->sortedIndex < bb->shader->sortedIndex) - return -1; - - else if(aa->shader->sortedIndex > bb->shader->sortedIndex) - return 1; - - // by fogIndex - if(aa->fogIndex < bb->fogIndex) - return -1; - - else if(aa->fogIndex > bb->fogIndex) - return 1; - - // by cubemapIndex - if(aa->cubemapIndex < bb->cubemapIndex) - return -1; - - else if(aa->cubemapIndex > bb->cubemapIndex) - return 1; - - - return 0; -} - - -static void CopyVert(const srfVert_t * in, srfVert_t * out) -{ - int j; - - for(j = 0; j < 3; j++) - { - out->xyz[j] = in->xyz[j]; -#ifdef USE_VERT_TANGENT_SPACE - out->tangent[j] = in->tangent[j]; - //out->bitangent[j] = in->bitangent[j]; -#endif - out->normal[j] = in->normal[j]; - out->lightdir[j] = in->lightdir[j]; - } - - out->tangent[3] = in->tangent[3]; - - for(j = 0; j < 2; j++) - { - out->st[j] = in->st[j]; - out->lightmap[j] = in->lightmap[j]; - } - - for(j = 0; j < 4; j++) - { - out->vertexColors[j] = in->vertexColors[j]; - } -} - - -/* -=============== -R_CreateWorldVBOs -=============== -*/ -static void R_CreateWorldVBOs(void) -{ - int i, j, k; - - int numVerts; - srfVert_t *verts; - - int numIndexes; - glIndex_t *indexes; - - int numSortedSurfaces, numSurfaces; - msurface_t *surface, **firstSurf, **lastSurf, **currSurf; - msurface_t **surfacesSorted; - - VBO_t *vbo; - IBO_t *ibo; - - int maxVboSize = 4 * 1024 * 1024; - int maxIboSize = 4 * 1024 * 1024; - - int startTime, endTime; - - startTime = ri.Milliseconds(); - - // count surfaces - numSortedSurfaces = 0; - for(surface = &s_worldData.surfaces[0]; surface < &s_worldData.surfaces[s_worldData.numsurfaces]; surface++) - { - srfBspSurface_t *bspSurf; - shader_t *shader = surface->shader; - - if (shader->isPortal) - continue; - - if (shader->isSky) - continue; - - if (ShaderRequiresCPUDeforms(shader)) - continue; - - // check for this now so we can use srfBspSurface_t* universally in the rest of the function - if (!(*surface->data == SF_FACE || *surface->data == SF_GRID || *surface->data == SF_TRIANGLES)) - continue; - - bspSurf = (srfBspSurface_t *) surface->data; - - if (!bspSurf->numIndexes || !bspSurf->numVerts) - continue; - - numSortedSurfaces++; - } - - // presort surfaces - surfacesSorted = ri.Malloc(numSortedSurfaces * sizeof(*surfacesSorted)); - - j = 0; - for(surface = &s_worldData.surfaces[0]; surface < &s_worldData.surfaces[s_worldData.numsurfaces]; surface++) - { - srfBspSurface_t *bspSurf; - shader_t *shader = surface->shader; - - if (shader->isPortal) - continue; - - if (shader->isSky) - continue; - - if (ShaderRequiresCPUDeforms(shader)) - continue; - - // check for this now so we can use srfBspSurface_t* universally in the rest of the function - if (!(*surface->data == SF_FACE || *surface->data == SF_GRID || *surface->data == SF_TRIANGLES)) - continue; - - bspSurf = (srfBspSurface_t *) surface->data; - - if (!bspSurf->numIndexes || !bspSurf->numVerts) - continue; - - surfacesSorted[j++] = surface; - } - - qsort(surfacesSorted, numSortedSurfaces, sizeof(*surfacesSorted), BSPSurfaceCompare); - - k = 0; - for(firstSurf = lastSurf = surfacesSorted; firstSurf < &surfacesSorted[numSortedSurfaces]; firstSurf = lastSurf) - { - int currVboSize, currIboSize; - - // Find range of surfaces to merge by: - // - Collecting a number of surfaces which fit under maxVboSize/maxIboSize, or - // - All the surfaces with a single shader which go over maxVboSize/maxIboSize - currVboSize = currIboSize = 0; - while (currVboSize < maxVboSize && currIboSize < maxIboSize && lastSurf < &surfacesSorted[numSortedSurfaces]) - { - int addVboSize, addIboSize, currShaderIndex; - - addVboSize = addIboSize = 0; - currShaderIndex = (*lastSurf)->shader->sortedIndex; - - for(currSurf = lastSurf; currSurf < &surfacesSorted[numSortedSurfaces] && (*currSurf)->shader->sortedIndex == currShaderIndex; currSurf++) - { - srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data; - - addVboSize += bspSurf->numVerts * sizeof(srfVert_t); - addIboSize += bspSurf->numIndexes * sizeof(glIndex_t); - } - - if ((currVboSize != 0 && addVboSize + currVboSize > maxVboSize) - || (currIboSize != 0 && addIboSize + currIboSize > maxIboSize)) - break; - - lastSurf = currSurf; - - currVboSize += addVboSize; - currIboSize += addIboSize; - } - - // count verts/indexes/surfaces - numVerts = 0; - numIndexes = 0; - numSurfaces = 0; - for (currSurf = firstSurf; currSurf < lastSurf; currSurf++) - { - srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data; - - numVerts += bspSurf->numVerts; - numIndexes += bspSurf->numIndexes; - numSurfaces++; - } - - ri.Printf(PRINT_ALL, "...calculating world VBO %d ( %i verts %i tris )\n", k, numVerts, numIndexes / 3); - - // create arrays - verts = ri.Hunk_AllocateTempMemory(numVerts * sizeof(srfVert_t)); - indexes = ri.Hunk_AllocateTempMemory(numIndexes * sizeof(glIndex_t)); - - // set up indices and copy vertices - numVerts = 0; - numIndexes = 0; - for (currSurf = firstSurf; currSurf < lastSurf; currSurf++) - { - srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data; - glIndex_t *surfIndex; - - bspSurf->firstIndex = numIndexes; - bspSurf->minIndex = numVerts + bspSurf->indexes[0]; - bspSurf->maxIndex = numVerts + bspSurf->indexes[0]; - - for(i = 0, surfIndex = bspSurf->indexes; i < bspSurf->numIndexes; i++, surfIndex++) - { - indexes[numIndexes++] = numVerts + *surfIndex; - bspSurf->minIndex = MIN(bspSurf->minIndex, numVerts + *surfIndex); - bspSurf->maxIndex = MAX(bspSurf->maxIndex, numVerts + *surfIndex); - } - - bspSurf->firstVert = numVerts; - - for(i = 0; i < bspSurf->numVerts; i++) - { - CopyVert(&bspSurf->verts[i], &verts[numVerts++]); - } - } - -#ifdef USE_VERT_TANGENT_SPACE - vbo = R_CreateVBO2(va("staticBspModel0_VBO %i", k), numVerts, verts, - ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_TANGENT | - ATTR_NORMAL | ATTR_COLOR | ATTR_LIGHTDIRECTION, VBO_USAGE_STATIC); -#else - vbo = R_CreateVBO2(va("staticBspModel0_VBO %i", k), numVerts, verts, - ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | - ATTR_NORMAL | ATTR_COLOR | ATTR_LIGHTDIRECTION, VBO_USAGE_STATIC); -#endif - - ibo = R_CreateIBO2(va("staticBspModel0_IBO %i", k), numIndexes, indexes, VBO_USAGE_STATIC); - - // point bsp surfaces to VBO - for (currSurf = firstSurf; currSurf < lastSurf; currSurf++) - { - srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data; - - bspSurf->vbo = vbo; - bspSurf->ibo = ibo; - } - - ri.Hunk_FreeTempMemory(indexes); - ri.Hunk_FreeTempMemory(verts); - - k++; - } - - ri.Free(surfacesSorted); - - endTime = ri.Milliseconds(); - ri.Printf(PRINT_ALL, "world VBOs calculation time = %5.2f seconds\n", (endTime - startTime) / 1000.0); -} - -/* -=============== -R_LoadSurfaces -=============== -*/ -static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) { - dsurface_t *in; - msurface_t *out; - drawVert_t *dv; - int *indexes; - int count; - int numFaces, numMeshes, numTriSurfs, numFlares; - int i; - float *hdrVertColors = NULL; - - numFaces = 0; - numMeshes = 0; - numTriSurfs = 0; - numFlares = 0; - - if (surfs->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = surfs->filelen / sizeof(*in); - - dv = (void *)(fileBase + verts->fileofs); - if (verts->filelen % sizeof(*dv)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - - indexes = (void *)(fileBase + indexLump->fileofs); - if ( indexLump->filelen % sizeof(*indexes)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - - out = ri.Hunk_Alloc ( count * sizeof(*out), h_low ); - - s_worldData.surfaces = out; - s_worldData.numsurfaces = count; - s_worldData.surfacesViewCount = ri.Hunk_Alloc ( count * sizeof(*s_worldData.surfacesViewCount), h_low ); - s_worldData.surfacesDlightBits = ri.Hunk_Alloc ( count * sizeof(*s_worldData.surfacesDlightBits), h_low ); - s_worldData.surfacesPshadowBits = ri.Hunk_Alloc ( count * sizeof(*s_worldData.surfacesPshadowBits), h_low ); - - // load hdr vertex colors - if (r_hdr->integer) - { - char filename[MAX_QPATH]; - int size; - - Com_sprintf( filename, sizeof( filename ), "maps/%s/vertlight.raw", s_worldData.baseName); - //ri.Printf(PRINT_ALL, "looking for %s\n", filename); - - size = ri.FS_ReadFile(filename, (void **)&hdrVertColors); - - if (hdrVertColors) - { - //ri.Printf(PRINT_ALL, "Found!\n"); - if (size != sizeof(float) * 3 * (verts->filelen / sizeof(*dv))) - ri.Error(ERR_DROP, "Bad size for %s (%i, expected %i)!", filename, size, (int)((sizeof(float)) * 3 * (verts->filelen / sizeof(*dv)))); - } - } - - - // Two passes, allocate surfaces first, then load them full of data - // This ensures surfaces are close together to reduce L2 cache misses when using VBOs, - // which don't actually use the verts and indexes - in = (void *)(fileBase + surfs->fileofs); - out = s_worldData.surfaces; - for ( i = 0 ; i < count ; i++, in++, out++ ) { - switch ( LittleLong( in->surfaceType ) ) { - case MST_PATCH: - // FIXME: do this - break; - case MST_TRIANGLE_SOUP: - out->data = ri.Hunk_Alloc( sizeof(srfBspSurface_t), h_low); - break; - case MST_PLANAR: - out->data = ri.Hunk_Alloc( sizeof(srfBspSurface_t), h_low); - break; - case MST_FLARE: - out->data = ri.Hunk_Alloc( sizeof(srfFlare_t), h_low); - break; - default: - break; - } - } - - in = (void *)(fileBase + surfs->fileofs); - out = s_worldData.surfaces; - for ( i = 0 ; i < count ; i++, in++, out++ ) { - switch ( LittleLong( in->surfaceType ) ) { - case MST_PATCH: - ParseMesh ( in, dv, hdrVertColors, out ); - { - srfBspSurface_t *surface = (srfBspSurface_t *)out->data; - - out->cullinfo.type = CULLINFO_BOX | CULLINFO_SPHERE; - VectorCopy(surface->cullBounds[0], out->cullinfo.bounds[0]); - VectorCopy(surface->cullBounds[1], out->cullinfo.bounds[1]); - VectorCopy(surface->cullOrigin, out->cullinfo.localOrigin); - out->cullinfo.radius = surface->cullRadius; - } - numMeshes++; - break; - case MST_TRIANGLE_SOUP: - ParseTriSurf( in, dv, hdrVertColors, out, indexes ); - numTriSurfs++; - break; - case MST_PLANAR: - ParseFace( in, dv, hdrVertColors, out, indexes ); - numFaces++; - break; - case MST_FLARE: - ParseFlare( in, dv, out, indexes ); - { - out->cullinfo.type = CULLINFO_NONE; - } - numFlares++; - break; - default: - ri.Error( ERR_DROP, "Bad surfaceType" ); - } - } - - if (hdrVertColors) - { - ri.FS_FreeFile(hdrVertColors); - } - -#ifdef PATCH_STITCHING - R_StitchAllPatches(); -#endif - - R_FixSharedVertexLodError(); - -#ifdef PATCH_STITCHING - R_MovePatchSurfacesToHunk(); -#endif - - ri.Printf( PRINT_ALL, "...loaded %d faces, %i meshes, %i trisurfs, %i flares\n", - numFaces, numMeshes, numTriSurfs, numFlares ); -} - - - -/* -================= -R_LoadSubmodels -================= -*/ -static void R_LoadSubmodels( lump_t *l ) { - dmodel_t *in; - bmodel_t *out; - int i, j, count; - - in = (void *)(fileBase + l->fileofs); - if (l->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = l->filelen / sizeof(*in); - - s_worldData.numBModels = count; - s_worldData.bmodels = out = ri.Hunk_Alloc( count * sizeof(*out), h_low ); - - for ( i=0 ; itype = MOD_BRUSH; - model->bmodel = out; - Com_sprintf( model->name, sizeof( model->name ), "*%d", i ); - - for (j=0 ; j<3 ; j++) { - out->bounds[0][j] = LittleFloat (in->mins[j]); - out->bounds[1][j] = LittleFloat (in->maxs[j]); - } - - out->firstSurface = LittleLong( in->firstSurface ); - out->numSurfaces = LittleLong( in->numSurfaces ); - - if(i == 0) - { - // Add this for limiting VBO surface creation - s_worldData.numWorldSurfaces = out->numSurfaces; - } - } -} - - - -//================================================================== - -/* -================= -R_SetParent -================= -*/ -static void R_SetParent (mnode_t *node, mnode_t *parent) -{ - node->parent = parent; - if (node->contents != -1) - return; - R_SetParent (node->children[0], node); - R_SetParent (node->children[1], node); -} - -/* -================= -R_LoadNodesAndLeafs -================= -*/ -static void R_LoadNodesAndLeafs (lump_t *nodeLump, lump_t *leafLump) { - int i, j, p; - dnode_t *in; - dleaf_t *inLeaf; - mnode_t *out; - int numNodes, numLeafs; - - in = (void *)(fileBase + nodeLump->fileofs); - if (nodeLump->filelen % sizeof(dnode_t) || - leafLump->filelen % sizeof(dleaf_t) ) { - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - } - numNodes = nodeLump->filelen / sizeof(dnode_t); - numLeafs = leafLump->filelen / sizeof(dleaf_t); - - out = ri.Hunk_Alloc ( (numNodes + numLeafs) * sizeof(*out), h_low); - - s_worldData.nodes = out; - s_worldData.numnodes = numNodes + numLeafs; - s_worldData.numDecisionNodes = numNodes; - - // load nodes - for ( i=0 ; imins[j] = LittleLong (in->mins[j]); - out->maxs[j] = LittleLong (in->maxs[j]); - } - - p = LittleLong(in->planeNum); - out->plane = s_worldData.planes + p; - - out->contents = CONTENTS_NODE; // differentiate from leafs - - for (j=0 ; j<2 ; j++) - { - p = LittleLong (in->children[j]); - if (p >= 0) - out->children[j] = s_worldData.nodes + p; - else - out->children[j] = s_worldData.nodes + numNodes + (-1 - p); - } - } - - // load leafs - inLeaf = (void *)(fileBase + leafLump->fileofs); - for ( i=0 ; imins[j] = LittleLong (inLeaf->mins[j]); - out->maxs[j] = LittleLong (inLeaf->maxs[j]); - } - - out->cluster = LittleLong(inLeaf->cluster); - out->area = LittleLong(inLeaf->area); - - if ( out->cluster >= s_worldData.numClusters ) { - s_worldData.numClusters = out->cluster + 1; - } - - out->firstmarksurface = LittleLong(inLeaf->firstLeafSurface); - out->nummarksurfaces = LittleLong(inLeaf->numLeafSurfaces); - } - - // chain decendants - R_SetParent (s_worldData.nodes, NULL); -} - -//============================================================================= - -/* -================= -R_LoadShaders -================= -*/ -static void R_LoadShaders( lump_t *l ) { - int i, count; - dshader_t *in, *out; - - in = (void *)(fileBase + l->fileofs); - if (l->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = l->filelen / sizeof(*in); - out = ri.Hunk_Alloc ( count*sizeof(*out), h_low ); - - s_worldData.shaders = out; - s_worldData.numShaders = count; - - Com_Memcpy( out, in, count*sizeof(*out) ); - - for ( i=0 ; ifileofs); - if (l->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = l->filelen / sizeof(*in); - out = ri.Hunk_Alloc ( count*sizeof(*out), h_low); - - s_worldData.marksurfaces = out; - s_worldData.nummarksurfaces = count; - - for ( i=0 ; ifileofs); - if (l->filelen % sizeof(*in)) - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - count = l->filelen / sizeof(*in); - out = ri.Hunk_Alloc ( count*2*sizeof(*out), h_low); - - s_worldData.planes = out; - s_worldData.numplanes = count; - - for ( i=0 ; inormal[j] = LittleFloat (in->normal[j]); - if (out->normal[j] < 0) { - bits |= 1<dist = LittleFloat (in->dist); - out->type = PlaneTypeForNormal( out->normal ); - out->signbits = bits; - } -} - -/* -================= -R_LoadFogs - -================= -*/ -static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) { - int i; - fog_t *out; - dfog_t *fogs; - dbrush_t *brushes, *brush; - dbrushside_t *sides; - int count, brushesCount, sidesCount; - int sideNum; - int planeNum; - shader_t *shader; - float d; - int firstSide; - - fogs = (void *)(fileBase + l->fileofs); - if (l->filelen % sizeof(*fogs)) { - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - } - count = l->filelen / sizeof(*fogs); - - // create fog strucutres for them - s_worldData.numfogs = count + 1; - s_worldData.fogs = ri.Hunk_Alloc ( s_worldData.numfogs*sizeof(*out), h_low); - out = s_worldData.fogs + 1; - - if ( !count ) { - return; - } - - brushes = (void *)(fileBase + brushesLump->fileofs); - if (brushesLump->filelen % sizeof(*brushes)) { - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - } - brushesCount = brushesLump->filelen / sizeof(*brushes); - - sides = (void *)(fileBase + sidesLump->fileofs); - if (sidesLump->filelen % sizeof(*sides)) { - ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); - } - sidesCount = sidesLump->filelen / sizeof(*sides); - - for ( i=0 ; ioriginalBrushNumber = LittleLong( fogs->brushNum ); - - if ( (unsigned)out->originalBrushNumber >= brushesCount ) { - ri.Error( ERR_DROP, "fog brushNumber out of range" ); - } - brush = brushes + out->originalBrushNumber; - - firstSide = LittleLong( brush->firstSide ); - - if ( (unsigned)firstSide > sidesCount - 6 ) { - ri.Error( ERR_DROP, "fog brush sideNumber out of range" ); - } - - // brushes are always sorted with the axial sides first - sideNum = firstSide + 0; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[0][0] = -s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 1; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[1][0] = s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 2; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[0][1] = -s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 3; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[1][1] = s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 4; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[0][2] = -s_worldData.planes[ planeNum ].dist; - - sideNum = firstSide + 5; - planeNum = LittleLong( sides[ sideNum ].planeNum ); - out->bounds[1][2] = s_worldData.planes[ planeNum ].dist; - - // get information from the shader for fog parameters - shader = R_FindShader( fogs->shader, LIGHTMAP_NONE, qtrue ); - - out->parms = shader->fogParms; - - out->colorInt = ColorBytes4 ( shader->fogParms.color[0] * tr.identityLight, - shader->fogParms.color[1] * tr.identityLight, - shader->fogParms.color[2] * tr.identityLight, 1.0 ); - - d = shader->fogParms.depthForOpaque < 1 ? 1 : shader->fogParms.depthForOpaque; - out->tcScale = 1.0f / ( d * 8 ); - - // set the gradient vector - sideNum = LittleLong( fogs->visibleSide ); - - if ( sideNum == -1 ) { - out->hasSurface = qfalse; - } else { - out->hasSurface = qtrue; - planeNum = LittleLong( sides[ firstSide + sideNum ].planeNum ); - VectorSubtract( vec3_origin, s_worldData.planes[ planeNum ].normal, out->surface ); - out->surface[3] = -s_worldData.planes[ planeNum ].dist; - } - - out++; - } - -} - - -/* -================ -R_LoadLightGrid - -================ -*/ -void R_LoadLightGrid( lump_t *l ) { - int i; - vec3_t maxs; - int numGridPoints; - world_t *w; - float *wMins, *wMaxs; - - w = &s_worldData; - - w->lightGridInverseSize[0] = 1.0f / w->lightGridSize[0]; - w->lightGridInverseSize[1] = 1.0f / w->lightGridSize[1]; - w->lightGridInverseSize[2] = 1.0f / w->lightGridSize[2]; - - wMins = w->bmodels[0].bounds[0]; - wMaxs = w->bmodels[0].bounds[1]; - - for ( i = 0 ; i < 3 ; i++ ) { - w->lightGridOrigin[i] = w->lightGridSize[i] * ceil( wMins[i] / w->lightGridSize[i] ); - maxs[i] = w->lightGridSize[i] * floor( wMaxs[i] / w->lightGridSize[i] ); - w->lightGridBounds[i] = (maxs[i] - w->lightGridOrigin[i])/w->lightGridSize[i] + 1; - } - - numGridPoints = w->lightGridBounds[0] * w->lightGridBounds[1] * w->lightGridBounds[2]; - - if ( l->filelen != numGridPoints * 8 ) { - ri.Printf( PRINT_WARNING, "WARNING: light grid mismatch\n" ); - w->lightGridData = NULL; - return; - } - - w->lightGridData = ri.Hunk_Alloc( l->filelen, h_low ); - Com_Memcpy( w->lightGridData, (void *)(fileBase + l->fileofs), l->filelen ); - - // deal with overbright bits - for ( i = 0 ; i < numGridPoints ; i++ ) { - R_ColorShiftLightingBytes( &w->lightGridData[i*8], &w->lightGridData[i*8] ); - R_ColorShiftLightingBytes( &w->lightGridData[i*8+3], &w->lightGridData[i*8+3] ); - } - - // load hdr lightgrid - if (r_hdr->integer) - { - char filename[MAX_QPATH]; - float *hdrLightGrid; - int size; - - Com_sprintf( filename, sizeof( filename ), "maps/%s/lightgrid.raw", s_worldData.baseName); - //ri.Printf(PRINT_ALL, "looking for %s\n", filename); - - size = ri.FS_ReadFile(filename, (void **)&hdrLightGrid); - - if (hdrLightGrid) - { - float lightScale = pow(2, r_mapOverBrightBits->integer - tr.overbrightBits); - - //ri.Printf(PRINT_ALL, "found!\n"); - - if (size != sizeof(float) * 6 * numGridPoints) - { - ri.Error(ERR_DROP, "Bad size for %s (%i, expected %i)!", filename, size, (int)(sizeof(float)) * 6 * numGridPoints); - } - - w->hdrLightGrid = ri.Hunk_Alloc(size, h_low); - - for (i = 0; i < numGridPoints ; i++) - { - w->hdrLightGrid[i * 6 ] = hdrLightGrid[i * 6 ] * lightScale; - w->hdrLightGrid[i * 6 + 1] = hdrLightGrid[i * 6 + 1] * lightScale; - w->hdrLightGrid[i * 6 + 2] = hdrLightGrid[i * 6 + 2] * lightScale; - w->hdrLightGrid[i * 6 + 3] = hdrLightGrid[i * 6 + 3] * lightScale; - w->hdrLightGrid[i * 6 + 4] = hdrLightGrid[i * 6 + 4] * lightScale; - w->hdrLightGrid[i * 6 + 5] = hdrLightGrid[i * 6 + 5] * lightScale; - } - } - - if (hdrLightGrid) - ri.FS_FreeFile(hdrLightGrid); - } -} - -/* -================ -R_LoadEntities -================ -*/ -void R_LoadEntities( lump_t *l ) { - char *p, *token, *s; - char keyname[MAX_TOKEN_CHARS]; - char value[MAX_TOKEN_CHARS]; - world_t *w; - - w = &s_worldData; - w->lightGridSize[0] = 64; - w->lightGridSize[1] = 64; - w->lightGridSize[2] = 128; - - p = (char *)(fileBase + l->fileofs); - - // store for reference by the cgame - w->entityString = ri.Hunk_Alloc( l->filelen + 1, h_low ); - strcpy( w->entityString, p ); - w->entityParsePoint = w->entityString; - - token = COM_ParseExt( &p, qtrue ); - if (!*token || *token != '{') { - return; - } - - // only parse the world spawn - while ( 1 ) { - // parse key - token = COM_ParseExt( &p, qtrue ); - - if ( !*token || *token == '}' ) { - break; - } - Q_strncpyz(keyname, token, sizeof(keyname)); - - // parse value - token = COM_ParseExt( &p, qtrue ); - - if ( !*token || *token == '}' ) { - break; - } - Q_strncpyz(value, token, sizeof(value)); - - // check for remapping of shaders for vertex lighting - s = "vertexremapshader"; - if (!Q_strncmp(keyname, s, strlen(s)) ) { - s = strchr(value, ';'); - if (!s) { - ri.Printf( PRINT_WARNING, "WARNING: no semi colon in vertexshaderremap '%s'\n", value ); - break; - } - *s++ = 0; - if (r_vertexLight->integer) { - R_RemapShader(value, s, "0"); - } - continue; - } - // check for remapping of shaders - s = "remapshader"; - if (!Q_strncmp(keyname, s, strlen(s)) ) { - s = strchr(value, ';'); - if (!s) { - ri.Printf( PRINT_WARNING, "WARNING: no semi colon in shaderremap '%s'\n", value ); - break; - } - *s++ = 0; - R_RemapShader(value, s, "0"); - continue; - } - // check for a different grid size - if (!Q_stricmp(keyname, "gridsize")) { - sscanf(value, "%f %f %f", &w->lightGridSize[0], &w->lightGridSize[1], &w->lightGridSize[2] ); - continue; - } - - // check for auto exposure - if (!Q_stricmp(keyname, "autoExposureMinMax")) { - sscanf(value, "%f %f", &tr.autoExposureMinMax[0], &tr.autoExposureMinMax[1]); - continue; - } - } -} - -/* -================= -R_GetEntityToken -================= -*/ -qboolean R_GetEntityToken( char *buffer, int size ) { - const char *s; - - s = COM_Parse( &s_worldData.entityParsePoint ); - Q_strncpyz( buffer, s, size ); - if ( !s_worldData.entityParsePoint || !s[0] ) { - s_worldData.entityParsePoint = s_worldData.entityString; - return qfalse; - } else { - return qtrue; - } -} - -#ifndef MAX_SPAWN_VARS -#define MAX_SPAWN_VARS 64 -#endif - -// derived from G_ParseSpawnVars() in g_spawn.c -qboolean R_ParseSpawnVars( char *spawnVarChars, int maxSpawnVarChars, int *numSpawnVars, char *spawnVars[MAX_SPAWN_VARS][2] ) -{ - char keyname[MAX_TOKEN_CHARS]; - char com_token[MAX_TOKEN_CHARS]; - int numSpawnVarChars = 0; - - *numSpawnVars = 0; - - // parse the opening brace - if ( !R_GetEntityToken( com_token, sizeof( com_token ) ) ) { - // end of spawn string - return qfalse; - } - if ( com_token[0] != '{' ) { - ri.Printf( PRINT_ALL, "R_ParseSpawnVars: found %s when expecting {",com_token ); - } - - // go through all the key / value pairs - while ( 1 ) { - int keyLength, tokenLength; - - // parse key - if ( !R_GetEntityToken( keyname, sizeof( keyname ) ) ) { - ri.Printf( PRINT_ALL, "R_ParseSpawnVars: EOF without closing brace" ); - } - - if ( keyname[0] == '}' ) { - break; - } - - // parse value - if ( !R_GetEntityToken( com_token, sizeof( com_token ) ) ) { - ri.Printf( PRINT_ALL, "R_ParseSpawnVars: EOF without closing brace" ); - break; - } - - if ( com_token[0] == '}' ) { - ri.Printf( PRINT_ALL, "R_ParseSpawnVars: closing brace without data" ); - break; - } - - if ( *numSpawnVars == MAX_SPAWN_VARS ) { - ri.Printf( PRINT_ALL, "R_ParseSpawnVars: MAX_SPAWN_VARS" ); - break; - } - - keyLength = strlen(keyname) + 1; - tokenLength = strlen(com_token) + 1; - - if (numSpawnVarChars + keyLength + tokenLength > maxSpawnVarChars) - { - ri.Printf( PRINT_ALL, "R_ParseSpawnVars: MAX_SPAWN_VAR_CHARS" ); - break; - } - - strcpy(spawnVarChars + numSpawnVarChars, keyname); - spawnVars[ *numSpawnVars ][0] = spawnVarChars + numSpawnVarChars; - numSpawnVarChars += keyLength; - - strcpy(spawnVarChars + numSpawnVarChars, com_token); - spawnVars[ *numSpawnVars ][1] = spawnVarChars + numSpawnVarChars; - numSpawnVarChars += tokenLength; - - (*numSpawnVars)++; - } - - return qtrue; -} - -void R_LoadCubemapEntities(char *cubemapEntityName) -{ - char spawnVarChars[2048]; - int numSpawnVars; - char *spawnVars[MAX_SPAWN_VARS][2]; - int numCubemaps = 0; - - // count cubemaps - numCubemaps = 0; - while(R_ParseSpawnVars(spawnVarChars, sizeof(spawnVarChars), &numSpawnVars, spawnVars)) - { - int i; - - for (i = 0; i < numSpawnVars; i++) - { - if (!Q_stricmp(spawnVars[i][0], "classname") && !Q_stricmp(spawnVars[i][1], cubemapEntityName)) - numCubemaps++; - } - } - - if (!numCubemaps) - return; - - tr.numCubemaps = numCubemaps; - tr.cubemapOrigins = ri.Hunk_Alloc( tr.numCubemaps * sizeof(*tr.cubemapOrigins), h_low); - tr.cubemaps = ri.Hunk_Alloc( tr.numCubemaps * sizeof(*tr.cubemaps), h_low); - - numCubemaps = 0; - while(R_ParseSpawnVars(spawnVarChars, sizeof(spawnVarChars), &numSpawnVars, spawnVars)) - { - int i; - qboolean isCubemap = qfalse; - qboolean positionSet = qfalse; - vec3_t origin; - - for (i = 0; i < numSpawnVars; i++) - { - if (!Q_stricmp(spawnVars[i][0], "classname") && !Q_stricmp(spawnVars[i][1], cubemapEntityName)) - isCubemap = qtrue; - - if (!Q_stricmp(spawnVars[i][0], "origin")) - { - sscanf(spawnVars[i][1], "%f %f %f", &origin[0], &origin[1], &origin[2]); - positionSet = qtrue; - } - } - - if (isCubemap && positionSet) - { - //ri.Printf(PRINT_ALL, "cubemap at %f %f %f\n", origin[0], origin[1], origin[2]); - VectorCopy(origin, tr.cubemapOrigins[numCubemaps]); - numCubemaps++; - } - } -} - -void R_AssignCubemapsToWorldSurfaces(void) -{ - world_t *w; - int i; - - w = &s_worldData; - - for (i = 0; i < w->numsurfaces; i++) - { - msurface_t *surf = &w->surfaces[i]; - vec3_t surfOrigin; - - if (surf->cullinfo.type & CULLINFO_SPHERE) - { - VectorCopy(surf->cullinfo.localOrigin, surfOrigin); - } - else if (surf->cullinfo.type & CULLINFO_BOX) - { - surfOrigin[0] = (surf->cullinfo.bounds[0][0] + surf->cullinfo.bounds[1][0]) * 0.5f; - surfOrigin[1] = (surf->cullinfo.bounds[0][1] + surf->cullinfo.bounds[1][1]) * 0.5f; - surfOrigin[2] = (surf->cullinfo.bounds[0][2] + surf->cullinfo.bounds[1][2]) * 0.5f; - } - else - { - //ri.Printf(PRINT_ALL, "surface %d has no cubemap\n", i); - continue; - } - - surf->cubemapIndex = R_CubemapForPoint(surfOrigin); - //ri.Printf(PRINT_ALL, "surface %d has cubemap %d\n", i, surf->cubemapIndex); - } -} - - -void R_RenderAllCubemaps(void) -{ - int i, j; - - for (i = 0; i < tr.numCubemaps; i++) - { - tr.cubemaps[i] = R_CreateImage(va("*cubeMap%d", i), NULL, CUBE_MAP_SIZE, CUBE_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_CUBEMAP, GL_RGBA8); - } - - for (i = 0; i < tr.numCubemaps; i++) - { - for (j = 0; j < 6; j++) - { - RE_ClearScene(); - R_RenderCubemapSide(i, j, qfalse); - R_IssuePendingRenderCommands(); - R_InitNextFrame(); - } - } -} - - -/* -================= -R_MergeLeafSurfaces - -Merges surfaces that share a common leaf -================= -*/ -void R_MergeLeafSurfaces(void) -{ - int i, j, k; - int numWorldSurfaces; - int mergedSurfIndex; - int numMergedSurfaces; - int numUnmergedSurfaces; - VBO_t *vbo; - IBO_t *ibo; - - msurface_t *mergedSurf; - - glIndex_t *iboIndexes, *outIboIndexes; - int numIboIndexes; - - int startTime, endTime; - - startTime = ri.Milliseconds(); - - numWorldSurfaces = s_worldData.numWorldSurfaces; - - // use viewcount to keep track of mergers - for (i = 0; i < numWorldSurfaces; i++) - { - s_worldData.surfacesViewCount[i] = -1; - } - - // mark matching surfaces - for (i = 0; i < s_worldData.numnodes - s_worldData.numDecisionNodes; i++) - { - mnode_t *leaf = s_worldData.nodes + s_worldData.numDecisionNodes + i; - - for (j = 0; j < leaf->nummarksurfaces; j++) - { - msurface_t *surf1; - shader_t *shader1; - int fogIndex1; - int cubemapIndex1; - int surfNum1; - - surfNum1 = *(s_worldData.marksurfaces + leaf->firstmarksurface + j); - - if (s_worldData.surfacesViewCount[surfNum1] != -1) - continue; - - surf1 = s_worldData.surfaces + surfNum1; - - if ((*surf1->data != SF_GRID) && (*surf1->data != SF_TRIANGLES) && (*surf1->data != SF_FACE)) - continue; - - shader1 = surf1->shader; - - if(shader1->isSky) - continue; - - if(shader1->isPortal) - continue; - - if(ShaderRequiresCPUDeforms(shader1)) - continue; - - fogIndex1 = surf1->fogIndex; - cubemapIndex1 = surf1->cubemapIndex; - - s_worldData.surfacesViewCount[surfNum1] = surfNum1; - - for (k = j + 1; k < leaf->nummarksurfaces; k++) - { - msurface_t *surf2; - shader_t *shader2; - int fogIndex2; - int cubemapIndex2; - int surfNum2; - - surfNum2 = *(s_worldData.marksurfaces + leaf->firstmarksurface + k); - - if (s_worldData.surfacesViewCount[surfNum2] != -1) - continue; - - surf2 = s_worldData.surfaces + surfNum2; - - if ((*surf2->data != SF_GRID) && (*surf2->data != SF_TRIANGLES) && (*surf2->data != SF_FACE)) - continue; - - shader2 = surf2->shader; - - if (shader1 != shader2) - continue; - - fogIndex2 = surf2->fogIndex; - - if (fogIndex1 != fogIndex2) - continue; - - cubemapIndex2 = surf2->cubemapIndex; - - if (cubemapIndex1 != cubemapIndex2) - continue; - - s_worldData.surfacesViewCount[surfNum2] = surfNum1; - } - } - } - - // don't add surfaces that don't merge to any others to the merged list - for (i = 0; i < numWorldSurfaces; i++) - { - qboolean merges = qfalse; - - if (s_worldData.surfacesViewCount[i] != i) - continue; - - for (j = 0; j < numWorldSurfaces; j++) - { - if (j == i) - continue; - - if (s_worldData.surfacesViewCount[j] == i) - { - merges = qtrue; - break; - } - } - - if (!merges) - s_worldData.surfacesViewCount[i] = -1; - } - - // count merged/unmerged surfaces - numMergedSurfaces = 0; - numUnmergedSurfaces = 0; - for (i = 0; i < numWorldSurfaces; i++) - { - if (s_worldData.surfacesViewCount[i] == i) - { - numMergedSurfaces++; - } - else if (s_worldData.surfacesViewCount[i] == -1) - { - numUnmergedSurfaces++; - } - } - - // Allocate merged surfaces - s_worldData.mergedSurfaces = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfaces) * numMergedSurfaces, h_low); - s_worldData.mergedSurfacesViewCount = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesViewCount) * numMergedSurfaces, h_low); - s_worldData.mergedSurfacesDlightBits = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesDlightBits) * numMergedSurfaces, h_low); - s_worldData.mergedSurfacesPshadowBits = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesPshadowBits) * numMergedSurfaces, h_low); - s_worldData.numMergedSurfaces = numMergedSurfaces; - - // view surfaces are like mark surfaces, except negative ones represent merged surfaces - // -1 represents 0, -2 represents 1, and so on - s_worldData.viewSurfaces = ri.Hunk_Alloc(sizeof(*s_worldData.viewSurfaces) * s_worldData.nummarksurfaces, h_low); - - // copy view surfaces into mark surfaces - for (i = 0; i < s_worldData.nummarksurfaces; i++) - { - s_worldData.viewSurfaces[i] = s_worldData.marksurfaces[i]; - } - - // need to be synched here - R_IssuePendingRenderCommands(); - - // actually merge surfaces - numIboIndexes = 0; - mergedSurfIndex = 0; - mergedSurf = s_worldData.mergedSurfaces; - for (i = 0; i < numWorldSurfaces; i++) - { - msurface_t *surf1; - - vec3_t bounds[2]; - - int numSurfsToMerge; - int numIndexes; - int numVerts; - int firstIndex; - - srfBspSurface_t *vboSurf; - - if (s_worldData.surfacesViewCount[i] != i) - continue; - - surf1 = s_worldData.surfaces + i; - - // retrieve vbo - vbo = ((srfBspSurface_t *)(surf1->data))->vbo; - - // count verts, indexes, and surfaces - numSurfsToMerge = 0; - numIndexes = 0; - numVerts = 0; - for (j = i; j < numWorldSurfaces; j++) - { - msurface_t *surf2; - srfBspSurface_t *bspSurf; - - if (s_worldData.surfacesViewCount[j] != i) - continue; - - surf2 = s_worldData.surfaces + j; - - bspSurf = (srfBspSurface_t *) surf2->data; - numIndexes += bspSurf->numIndexes; - numVerts += bspSurf->numVerts; - numSurfsToMerge++; - } - - if (numVerts == 0 || numIndexes == 0 || numSurfsToMerge < 2) - { - continue; - } - - // create ibo - ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low); - memset(ibo, 0, sizeof(*ibo)); - Q_strncpyz(ibo->name, va("staticWorldMesh_IBO_mergedSurfs%i", tr.numIBOs++), sizeof(ibo->name)); - numIboIndexes = 0; - - // allocate indexes - iboIndexes = outIboIndexes = ri.Malloc(numIndexes * sizeof(*outIboIndexes)); - - // Merge surfaces (indexes) and calculate bounds - ClearBounds(bounds[0], bounds[1]); - firstIndex = numIboIndexes; - for (j = i; j < numWorldSurfaces; j++) - { - msurface_t *surf2; - srfBspSurface_t *bspSurf; - - if (s_worldData.surfacesViewCount[j] != i) - continue; - - surf2 = s_worldData.surfaces + j; - - AddPointToBounds(surf2->cullinfo.bounds[0], bounds[0], bounds[1]); - AddPointToBounds(surf2->cullinfo.bounds[1], bounds[0], bounds[1]); - - bspSurf = (srfBspSurface_t *) surf2->data; - for (k = 0; k < bspSurf->numIndexes; k++) - { - *outIboIndexes++ = bspSurf->indexes[k] + bspSurf->firstVert; - numIboIndexes++; - } - break; - } - - vboSurf = ri.Hunk_Alloc(sizeof(*vboSurf), h_low); - memset(vboSurf, 0, sizeof(*vboSurf)); - vboSurf->surfaceType = SF_VBO_MESH; - - vboSurf->vbo = vbo; - vboSurf->ibo = ibo; - - vboSurf->numIndexes = numIndexes; - vboSurf->numVerts = numVerts; - vboSurf->firstIndex = firstIndex; - - vboSurf->minIndex = *(iboIndexes + firstIndex); - vboSurf->maxIndex = *(iboIndexes + firstIndex); - - for (j = 0; j < numIndexes; j++) - { - vboSurf->minIndex = MIN(vboSurf->minIndex, *(iboIndexes + firstIndex + j)); - vboSurf->maxIndex = MAX(vboSurf->maxIndex, *(iboIndexes + firstIndex + j)); - } - - VectorCopy(bounds[0], vboSurf->cullBounds[0]); - VectorCopy(bounds[1], vboSurf->cullBounds[1]); - - VectorCopy(bounds[0], mergedSurf->cullinfo.bounds[0]); - VectorCopy(bounds[1], mergedSurf->cullinfo.bounds[1]); - - mergedSurf->cullinfo.type = CULLINFO_BOX; - mergedSurf->data = (surfaceType_t *)vboSurf; - mergedSurf->fogIndex = surf1->fogIndex; - mergedSurf->cubemapIndex = surf1->cubemapIndex; - mergedSurf->shader = surf1->shader; - - // finish up the ibo - qglGenBuffersARB(1, &ibo->indexesVBO); - - R_BindIBO(ibo); - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, numIboIndexes * sizeof(*iboIndexes), iboIndexes, GL_STATIC_DRAW_ARB); - R_BindNullIBO(); - - GL_CheckErrors(); - - ri.Free(iboIndexes); - - // redirect view surfaces to this surf - for (j = 0; j < numWorldSurfaces; j++) - { - if (s_worldData.surfacesViewCount[j] != i) - continue; - - for (k = 0; k < s_worldData.nummarksurfaces; k++) - { - int *mark = s_worldData.marksurfaces + k; - int *view = s_worldData.viewSurfaces + k; - - if (*mark == j) - *view = -(mergedSurfIndex + 1); - } - } - - mergedSurfIndex++; - mergedSurf++; - } - - endTime = ri.Milliseconds(); - - ri.Printf(PRINT_ALL, "Processed %d surfaces into %d merged, %d unmerged in %5.2f seconds\n", - numWorldSurfaces, numMergedSurfaces, numUnmergedSurfaces, (endTime - startTime) / 1000.0f); - - // reset viewcounts - for (i = 0; i < numWorldSurfaces; i++) - { - s_worldData.surfacesViewCount[i] = -1; - } -} - - -void R_CalcVertexLightDirs( void ) -{ - int i, k; - msurface_t *surface; - - for(k = 0, surface = &s_worldData.surfaces[0]; k < s_worldData.numsurfaces /* s_worldData.numWorldSurfaces */; k++, surface++) - { - srfBspSurface_t *bspSurf = (srfBspSurface_t *) surface->data; - - switch(bspSurf->surfaceType) - { - case SF_FACE: - case SF_GRID: - case SF_TRIANGLES: - for(i = 0; i < bspSurf->numVerts; i++) - R_LightDirForPoint( bspSurf->verts[i].xyz, bspSurf->verts[i].lightdir, bspSurf->verts[i].normal, &s_worldData ); - - break; - - default: - break; - } - } -} - - -/* -================= -RE_LoadWorldMap - -Called directly from cgame -================= -*/ -void RE_LoadWorldMap( const char *name ) { - int i; - dheader_t *header; - union { - byte *b; - void *v; - } buffer; - byte *startMarker; - - if ( tr.worldMapLoaded ) { - ri.Error( ERR_DROP, "ERROR: attempted to redundantly load world map" ); - } - - // set default map light scale - tr.mapLightScale = 1.0f; - tr.sunShadowScale = 0.5f; - - // set default sun direction to be used if it isn't - // overridden by a shader - tr.sunDirection[0] = 0.45f; - tr.sunDirection[1] = 0.3f; - tr.sunDirection[2] = 0.9f; - - VectorNormalize( tr.sunDirection ); - - // set default autoexposure settings - tr.autoExposureMinMax[0] = -2.0f; - tr.autoExposureMinMax[1] = 2.0f; - - // set default tone mapping settings - tr.toneMinAvgMaxLevel[0] = -8.0f; - tr.toneMinAvgMaxLevel[1] = -2.0f; - tr.toneMinAvgMaxLevel[2] = 0.0f; - - tr.worldMapLoaded = qtrue; - - // load it - ri.FS_ReadFile( name, &buffer.v ); - if ( !buffer.b ) { - ri.Error (ERR_DROP, "RE_LoadWorldMap: %s not found", name); - } - - // clear tr.world so if the level fails to load, the next - // try will not look at the partially loaded version - tr.world = NULL; - - Com_Memset( &s_worldData, 0, sizeof( s_worldData ) ); - Q_strncpyz( s_worldData.name, name, sizeof( s_worldData.name ) ); - - Q_strncpyz( s_worldData.baseName, COM_SkipPath( s_worldData.name ), sizeof( s_worldData.name ) ); - COM_StripExtension(s_worldData.baseName, s_worldData.baseName, sizeof(s_worldData.baseName)); - - startMarker = ri.Hunk_Alloc(0, h_low); - c_gridVerts = 0; - - header = (dheader_t *)buffer.b; - fileBase = (byte *)header; - - i = LittleLong (header->version); - if ( i != BSP_VERSION ) { - ri.Error (ERR_DROP, "RE_LoadWorldMap: %s has wrong version number (%i should be %i)", - name, i, BSP_VERSION); - } - - // swap all the lumps - for (i=0 ; ilumps[LUMP_ENTITIES] ); - R_LoadShaders( &header->lumps[LUMP_SHADERS] ); - R_LoadLightmaps( &header->lumps[LUMP_LIGHTMAPS], &header->lumps[LUMP_SURFACES] ); - R_LoadPlanes (&header->lumps[LUMP_PLANES]); - R_LoadFogs( &header->lumps[LUMP_FOGS], &header->lumps[LUMP_BRUSHES], &header->lumps[LUMP_BRUSHSIDES] ); - R_LoadSurfaces( &header->lumps[LUMP_SURFACES], &header->lumps[LUMP_DRAWVERTS], &header->lumps[LUMP_DRAWINDEXES] ); - R_LoadMarksurfaces (&header->lumps[LUMP_LEAFSURFACES]); - R_LoadNodesAndLeafs (&header->lumps[LUMP_NODES], &header->lumps[LUMP_LEAFS]); - R_LoadSubmodels (&header->lumps[LUMP_MODELS]); - R_LoadVisibility( &header->lumps[LUMP_VISIBILITY] ); - R_LoadLightGrid( &header->lumps[LUMP_LIGHTGRID] ); - - // determine vertex light directions - R_CalcVertexLightDirs(); - - // determine which parts of the map are in sunlight - if (0) - { - world_t *w; - uint8_t *primaryLightGrid, *data; - int lightGridSize; - int i; - - w = &s_worldData; - - lightGridSize = w->lightGridBounds[0] * w->lightGridBounds[1] * w->lightGridBounds[2]; - primaryLightGrid = ri.Malloc(lightGridSize * sizeof(*primaryLightGrid)); - - memset(primaryLightGrid, 0, lightGridSize * sizeof(*primaryLightGrid)); - - data = w->lightGridData; - for (i = 0; i < lightGridSize; i++, data += 8) - { - int lat, lng; - vec3_t gridLightDir, gridLightCol; - - // skip samples in wall - if (!(data[0]+data[1]+data[2]+data[3]+data[4]+data[5]) ) - continue; - - gridLightCol[0] = ByteToFloat(data[3]); - gridLightCol[1] = ByteToFloat(data[4]); - gridLightCol[2] = ByteToFloat(data[5]); - (void)gridLightCol; // Suppress unused-but-set-variable warning - - lat = data[7]; - lng = data[6]; - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - gridLightDir[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - gridLightDir[1] = tr.sinTable[lat] * tr.sinTable[lng]; - gridLightDir[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - // FIXME: magic number for determining if light direction is close enough to sunlight - if (DotProduct(gridLightDir, tr.sunDirection) > 0.75f) - { - primaryLightGrid[i] = 1; - } - else - { - primaryLightGrid[i] = 255; - } - } - - if (0) - { - int i; - byte *buffer = ri.Malloc(w->lightGridBounds[0] * w->lightGridBounds[1] * 3 + 18); - byte *out; - uint8_t *in; - char fileName[MAX_QPATH]; - - Com_Memset (buffer, 0, 18); - buffer[2] = 2; // uncompressed type - buffer[12] = w->lightGridBounds[0] & 255; - buffer[13] = w->lightGridBounds[0] >> 8; - buffer[14] = w->lightGridBounds[1] & 255; - buffer[15] = w->lightGridBounds[1] >> 8; - buffer[16] = 24; // pixel size - - in = primaryLightGrid; - for (i = 0; i < w->lightGridBounds[2]; i++) - { - int j; - - sprintf(fileName, "primarylg%d.tga", i); - - out = buffer + 18; - for (j = 0; j < w->lightGridBounds[0] * w->lightGridBounds[1]; j++) - { - if (*in == 1) - { - *out++ = 255; - *out++ = 255; - *out++ = 255; - } - else if (*in == 255) - { - *out++ = 64; - *out++ = 64; - *out++ = 64; - } - else - { - *out++ = 0; - *out++ = 0; - *out++ = 0; - } - in++; - } - - ri.FS_WriteFile(fileName, buffer, w->lightGridBounds[0] * w->lightGridBounds[1] * 3 + 18); - } - - ri.Free(buffer); - } - - for (i = 0; i < w->numWorldSurfaces; i++) - { - msurface_t *surf = w->surfaces + i; - cullinfo_t *ci = &surf->cullinfo; - - if(ci->type & CULLINFO_PLANE) - { - if (DotProduct(ci->plane.normal, tr.sunDirection) <= 0.0f) - { - //ri.Printf(PRINT_ALL, "surface %d is not oriented towards sunlight\n", i); - continue; - } - } - - if(ci->type & CULLINFO_BOX) - { - int ibounds[2][3], x, y, z, goodSamples, numSamples; - vec3_t lightOrigin; - - VectorSubtract( ci->bounds[0], w->lightGridOrigin, lightOrigin ); - - ibounds[0][0] = floor(lightOrigin[0] * w->lightGridInverseSize[0]); - ibounds[0][1] = floor(lightOrigin[1] * w->lightGridInverseSize[1]); - ibounds[0][2] = floor(lightOrigin[2] * w->lightGridInverseSize[2]); - - VectorSubtract( ci->bounds[1], w->lightGridOrigin, lightOrigin ); - - ibounds[1][0] = ceil(lightOrigin[0] * w->lightGridInverseSize[0]); - ibounds[1][1] = ceil(lightOrigin[1] * w->lightGridInverseSize[1]); - ibounds[1][2] = ceil(lightOrigin[2] * w->lightGridInverseSize[2]); - - ibounds[0][0] = CLAMP(ibounds[0][0], 0, w->lightGridSize[0]); - ibounds[0][1] = CLAMP(ibounds[0][1], 0, w->lightGridSize[1]); - ibounds[0][2] = CLAMP(ibounds[0][2], 0, w->lightGridSize[2]); - - ibounds[1][0] = CLAMP(ibounds[1][0], 0, w->lightGridSize[0]); - ibounds[1][1] = CLAMP(ibounds[1][1], 0, w->lightGridSize[1]); - ibounds[1][2] = CLAMP(ibounds[1][2], 0, w->lightGridSize[2]); - - /* - ri.Printf(PRINT_ALL, "surf %d bounds (%f %f %f)-(%f %f %f) ibounds (%d %d %d)-(%d %d %d)\n", i, - ci->bounds[0][0], ci->bounds[0][1], ci->bounds[0][2], - ci->bounds[1][0], ci->bounds[1][1], ci->bounds[1][2], - ibounds[0][0], ibounds[0][1], ibounds[0][2], - ibounds[1][0], ibounds[1][1], ibounds[1][2]); - */ - - goodSamples = 0; - numSamples = 0; - for (x = ibounds[0][0]; x <= ibounds[1][0]; x++) - { - for (y = ibounds[0][1]; y <= ibounds[1][1]; y++) - { - for (z = ibounds[0][2]; z <= ibounds[1][2]; z++) - { - uint8_t primaryLight = primaryLightGrid[x * 8 + y * 8 * w->lightGridBounds[0] + z * 8 * w->lightGridBounds[0] * w->lightGridBounds[2]]; - - if (primaryLight == 0) - continue; - - numSamples++; - - if (primaryLight == 1) - goodSamples++; - } - } - } - - // FIXME: magic number for determining whether object is mostly in sunlight - if (goodSamples > numSamples * 0.75f) - { - //ri.Printf(PRINT_ALL, "surface %d is in sunlight\n", i); - //surf->primaryLight = 1; - } - } - } - - ri.Free(primaryLightGrid); - } - - // load cubemaps - if (r_cubeMapping->integer) - { - R_LoadCubemapEntities("misc_cubemap"); - if (!tr.numCubemaps) - { - // use deathmatch spawn points as cubemaps - R_LoadCubemapEntities("info_player_deathmatch"); - } - - if (tr.numCubemaps) - { - R_AssignCubemapsToWorldSurfaces(); - } - } - - // create static VBOS from the world - R_CreateWorldVBOs(); - if (r_mergeLeafSurfaces->integer) - { - R_MergeLeafSurfaces(); - } - - s_worldData.dataSize = (byte *)ri.Hunk_Alloc(0, h_low) - startMarker; - - // only set tr.world now that we know the entire level has loaded properly - tr.world = &s_worldData; - - // make sure the VBO glState entries are safe - R_BindNullVBO(); - R_BindNullIBO(); - - // Render all cubemaps - if (r_cubeMapping->integer && tr.numCubemaps) - { - R_RenderAllCubemaps(); - } - - ri.FS_FreeFile( buffer.v ); -} diff --git a/code/renderergl2/tr_cmds.c b/code/renderergl2/tr_cmds.c deleted file mode 100644 index 139a34302d..0000000000 --- a/code/renderergl2/tr_cmds.c +++ /dev/null @@ -1,575 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - -/* -===================== -R_PerformanceCounters -===================== -*/ -void R_PerformanceCounters( void ) { - if ( !r_speeds->integer ) { - // clear the counters even if we aren't printing - Com_Memset( &tr.pc, 0, sizeof( tr.pc ) ); - Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) ); - return; - } - - if (r_speeds->integer == 1) { - ri.Printf (PRINT_ALL, "%i/%i/%i shaders/batches/surfs %i leafs %i verts %i/%i tris %.2f mtex %.2f dc\n", - backEnd.pc.c_shaders, backEnd.pc.c_surfBatches, backEnd.pc.c_surfaces, tr.pc.c_leafs, backEnd.pc.c_vertexes, - backEnd.pc.c_indexes/3, backEnd.pc.c_totalIndexes/3, - R_SumOfUsedImages()/(1000000.0f), backEnd.pc.c_overDraw / (float)(glConfig.vidWidth * glConfig.vidHeight) ); - } else if (r_speeds->integer == 2) { - ri.Printf (PRINT_ALL, "(patch) %i sin %i sclip %i sout %i bin %i bclip %i bout\n", - tr.pc.c_sphere_cull_patch_in, tr.pc.c_sphere_cull_patch_clip, tr.pc.c_sphere_cull_patch_out, - tr.pc.c_box_cull_patch_in, tr.pc.c_box_cull_patch_clip, tr.pc.c_box_cull_patch_out ); - ri.Printf (PRINT_ALL, "(md3) %i sin %i sclip %i sout %i bin %i bclip %i bout\n", - tr.pc.c_sphere_cull_md3_in, tr.pc.c_sphere_cull_md3_clip, tr.pc.c_sphere_cull_md3_out, - tr.pc.c_box_cull_md3_in, tr.pc.c_box_cull_md3_clip, tr.pc.c_box_cull_md3_out ); - } else if (r_speeds->integer == 3) { - ri.Printf (PRINT_ALL, "viewcluster: %i\n", tr.viewCluster ); - } else if (r_speeds->integer == 4) { - if ( backEnd.pc.c_dlightVertexes ) { - ri.Printf (PRINT_ALL, "dlight srf:%i culled:%i verts:%i tris:%i\n", - tr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled, - backEnd.pc.c_dlightVertexes, backEnd.pc.c_dlightIndexes / 3 ); - } - } - else if (r_speeds->integer == 5 ) - { - ri.Printf( PRINT_ALL, "zFar: %.0f\n", tr.viewParms.zFar ); - } - else if (r_speeds->integer == 6 ) - { - ri.Printf( PRINT_ALL, "flare adds:%i tests:%i renders:%i\n", - backEnd.pc.c_flareAdds, backEnd.pc.c_flareTests, backEnd.pc.c_flareRenders ); - } - else if (r_speeds->integer == 7 ) - { - ri.Printf( PRINT_ALL, "VBO draws: static %i dynamic %i\nMultidraws: %i merged %i\n", - backEnd.pc.c_staticVboDraws, backEnd.pc.c_dynamicVboDraws, backEnd.pc.c_multidraws, backEnd.pc.c_multidrawsMerged ); - ri.Printf( PRINT_ALL, "GLSL binds: %i draws: gen %i light %i fog %i dlight %i\n", - backEnd.pc.c_glslShaderBinds, backEnd.pc.c_genericDraws, backEnd.pc.c_lightallDraws, backEnd.pc.c_fogDraws, backEnd.pc.c_dlightDraws); - } - - Com_Memset( &tr.pc, 0, sizeof( tr.pc ) ); - Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) ); -} - - -/* -==================== -R_IssueRenderCommands -==================== -*/ -void R_IssueRenderCommands( qboolean runPerformanceCounters ) { - renderCommandList_t *cmdList; - - cmdList = &backEndData->commands; - assert(cmdList); - // add an end-of-list command - *(int *)(cmdList->cmds + cmdList->used) = RC_END_OF_LIST; - - // clear it out, in case this is a sync and not a buffer flip - cmdList->used = 0; - - if ( runPerformanceCounters ) { - R_PerformanceCounters(); - } - - // actually start the commands going - if ( !r_skipBackEnd->integer ) { - // let it start on the new batch - RB_ExecuteRenderCommands( cmdList->cmds ); - } -} - - -/* -==================== -R_IssuePendingRenderCommands - -Issue any pending commands and wait for them to complete. -==================== -*/ -void R_IssuePendingRenderCommands( void ) { - if ( !tr.registered ) { - return; - } - R_IssueRenderCommands( qfalse ); -} - -/* -============ -R_GetCommandBuffer - -make sure there is enough command space -============ -*/ -void *R_GetCommandBuffer( int bytes ) { - renderCommandList_t *cmdList; - - cmdList = &backEndData->commands; - bytes = PAD(bytes, sizeof(void *)); - - // always leave room for the end of list command - if ( cmdList->used + bytes + 4 > MAX_RENDER_COMMANDS ) { - if ( bytes > MAX_RENDER_COMMANDS - 4 ) { - ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes ); - } - // if we run out of room, just start dropping commands - return NULL; - } - - cmdList->used += bytes; - - return cmdList->cmds + cmdList->used - bytes; -} - - -/* -============= -R_AddDrawSurfCmd - -============= -*/ -void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ) { - drawSurfsCommand_t *cmd; - - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_DRAW_SURFS; - - cmd->drawSurfs = drawSurfs; - cmd->numDrawSurfs = numDrawSurfs; - - cmd->refdef = tr.refdef; - cmd->viewParms = tr.viewParms; -} - - -/* -============= -R_AddCapShadowmapCmd - -============= -*/ -void R_AddCapShadowmapCmd( int map, int cubeSide ) { - capShadowmapCommand_t *cmd; - - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_CAPSHADOWMAP; - - cmd->map = map; - cmd->cubeSide = cubeSide; -} - - -/* -============= -R_PostProcessingCmd - -============= -*/ -void R_AddPostProcessCmd( ) { - postProcessCommand_t *cmd; - - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_POSTPROCESS; - - cmd->refdef = tr.refdef; - cmd->viewParms = tr.viewParms; -} - -/* -============= -RE_SetColor - -Passing NULL will set the color to white -============= -*/ -void RE_SetColor( const float *rgba ) { - setColorCommand_t *cmd; - - if ( !tr.registered ) { - return; - } - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_SET_COLOR; - if ( !rgba ) { - static float colorWhite[4] = { 1, 1, 1, 1 }; - - rgba = colorWhite; - } - - cmd->color[0] = rgba[0]; - cmd->color[1] = rgba[1]; - cmd->color[2] = rgba[2]; - cmd->color[3] = rgba[3]; -} - - -/* -============= -RE_StretchPic -============= -*/ -void RE_StretchPic ( float x, float y, float w, float h, - float s1, float t1, float s2, float t2, qhandle_t hShader ) { - stretchPicCommand_t *cmd; - - if (!tr.registered) { - return; - } - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_STRETCH_PIC; - cmd->shader = R_GetShaderByHandle( hShader ); - cmd->x = x; - cmd->y = y; - cmd->w = w; - cmd->h = h; - cmd->s1 = s1; - cmd->t1 = t1; - cmd->s2 = s2; - cmd->t2 = t2; -} - -#define MODE_RED_CYAN 1 -#define MODE_RED_BLUE 2 -#define MODE_RED_GREEN 3 -#define MODE_GREEN_MAGENTA 4 -#define MODE_MAX MODE_GREEN_MAGENTA - -void R_SetColorMode(GLboolean *rgba, stereoFrame_t stereoFrame, int colormode) -{ - rgba[0] = rgba[1] = rgba[2] = rgba[3] = GL_TRUE; - - if(colormode > MODE_MAX) - { - if(stereoFrame == STEREO_LEFT) - stereoFrame = STEREO_RIGHT; - else if(stereoFrame == STEREO_RIGHT) - stereoFrame = STEREO_LEFT; - - colormode -= MODE_MAX; - } - - if(colormode == MODE_GREEN_MAGENTA) - { - if(stereoFrame == STEREO_LEFT) - rgba[0] = rgba[2] = GL_FALSE; - else if(stereoFrame == STEREO_RIGHT) - rgba[1] = GL_FALSE; - } - else - { - if(stereoFrame == STEREO_LEFT) - rgba[1] = rgba[2] = GL_FALSE; - else if(stereoFrame == STEREO_RIGHT) - { - rgba[0] = GL_FALSE; - - if(colormode == MODE_RED_BLUE) - rgba[1] = GL_FALSE; - else if(colormode == MODE_RED_GREEN) - rgba[2] = GL_FALSE; - } - } -} - - -/* -==================== -RE_BeginFrame - -If running in stereo, RE_BeginFrame will be called twice -for each RE_EndFrame -==================== -*/ -void RE_BeginFrame( stereoFrame_t stereoFrame ) { - drawBufferCommand_t *cmd = NULL; - colorMaskCommand_t *colcmd = NULL; - - if ( !tr.registered ) { - return; - } - glState.finishCalled = qfalse; - - tr.frameCount++; - tr.frameSceneNum = 0; - - // - // do overdraw measurement - // - if ( r_measureOverdraw->integer ) - { - if ( glConfig.stencilBits < 4 ) - { - ri.Printf( PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits ); - ri.Cvar_Set( "r_measureOverdraw", "0" ); - r_measureOverdraw->modified = qfalse; - } - else if ( r_shadows->integer == 2 ) - { - ri.Printf( PRINT_ALL, "Warning: stencil shadows and overdraw measurement are mutually exclusive\n" ); - ri.Cvar_Set( "r_measureOverdraw", "0" ); - r_measureOverdraw->modified = qfalse; - } - else - { - R_IssuePendingRenderCommands(); - qglEnable( GL_STENCIL_TEST ); - qglStencilMask( ~0U ); - qglClearStencil( 0U ); - qglStencilFunc( GL_ALWAYS, 0U, ~0U ); - qglStencilOp( GL_KEEP, GL_INCR, GL_INCR ); - } - r_measureOverdraw->modified = qfalse; - } - else - { - // this is only reached if it was on and is now off - if ( r_measureOverdraw->modified ) { - R_IssuePendingRenderCommands(); - qglDisable( GL_STENCIL_TEST ); - } - r_measureOverdraw->modified = qfalse; - } - - // - // texturemode stuff - // - if ( r_textureMode->modified ) { - R_IssuePendingRenderCommands(); - GL_TextureMode( r_textureMode->string ); - r_textureMode->modified = qfalse; - } - - // - // gamma stuff - // - if ( r_gamma->modified ) { - r_gamma->modified = qfalse; - - R_IssuePendingRenderCommands(); - R_SetColorMappings(); - } - - // check for errors - if ( !r_ignoreGLErrors->integer ) - { - int err; - - R_IssuePendingRenderCommands(); - if ((err = qglGetError()) != GL_NO_ERROR) - ri.Error(ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!", err); - } - - if (glConfig.stereoEnabled) { - if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) ) - return; - - cmd->commandId = RC_DRAW_BUFFER; - - if ( stereoFrame == STEREO_LEFT ) { - cmd->buffer = (int)GL_BACK_LEFT; - } else if ( stereoFrame == STEREO_RIGHT ) { - cmd->buffer = (int)GL_BACK_RIGHT; - } else { - ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame ); - } - } - else - { - if(r_anaglyphMode->integer) - { - if(r_anaglyphMode->modified) - { - // clear both, front and backbuffer. - qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - backEnd.colorMask[0] = GL_FALSE; - backEnd.colorMask[1] = GL_FALSE; - backEnd.colorMask[2] = GL_FALSE; - backEnd.colorMask[3] = GL_FALSE; - qglClearColor(0.0f, 0.0f, 0.0f, 1.0f); - - if (glRefConfig.framebufferObject) - { - // clear all framebuffers - if (tr.msaaResolveFbo) - { - FBO_Bind(tr.msaaResolveFbo); - qglClear(GL_COLOR_BUFFER_BIT); - } - - if (tr.renderFbo) - { - FBO_Bind(tr.renderFbo); - qglClear(GL_COLOR_BUFFER_BIT); - } - - FBO_Bind(NULL); - } - - qglDrawBuffer(GL_FRONT); - qglClear(GL_COLOR_BUFFER_BIT); - qglDrawBuffer(GL_BACK); - qglClear(GL_COLOR_BUFFER_BIT); - - r_anaglyphMode->modified = qfalse; - } - - if(stereoFrame == STEREO_LEFT) - { - if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) ) - return; - - if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) ) - return; - } - else if(stereoFrame == STEREO_RIGHT) - { - clearDepthCommand_t *cldcmd; - - if( !(cldcmd = R_GetCommandBuffer(sizeof(*cldcmd))) ) - return; - - cldcmd->commandId = RC_CLEARDEPTH; - - if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) ) - return; - } - else - ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame ); - - R_SetColorMode(colcmd->rgba, stereoFrame, r_anaglyphMode->integer); - colcmd->commandId = RC_COLORMASK; - } - else - { - if(stereoFrame != STEREO_CENTER) - ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame ); - - if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) ) - return; - } - - if(cmd) - { - cmd->commandId = RC_DRAW_BUFFER; - - if(r_anaglyphMode->modified) - { - qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - backEnd.colorMask[0] = 0; - backEnd.colorMask[1] = 0; - backEnd.colorMask[2] = 0; - backEnd.colorMask[3] = 0; - r_anaglyphMode->modified = qfalse; - } - - if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT")) - cmd->buffer = (int)GL_FRONT; - else - cmd->buffer = (int)GL_BACK; - } - } - - tr.refdef.stereoFrame = stereoFrame; -} - - -/* -============= -RE_EndFrame - -Returns the number of msec spent in the back end -============= -*/ -void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) { - swapBuffersCommand_t *cmd; - - if ( !tr.registered ) { - return; - } - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_SWAP_BUFFERS; - - R_IssueRenderCommands( qtrue ); - - R_InitNextFrame(); - - if ( frontEndMsec ) { - *frontEndMsec = tr.frontEndMsec; - } - tr.frontEndMsec = 0; - if ( backEndMsec ) { - *backEndMsec = backEnd.pc.msec; - } - backEnd.pc.msec = 0; -} - -/* -============= -RE_TakeVideoFrame -============= -*/ -void RE_TakeVideoFrame( int width, int height, - byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg ) -{ - videoFrameCommand_t *cmd; - - if( !tr.registered ) { - return; - } - - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if( !cmd ) { - return; - } - - cmd->commandId = RC_VIDEOFRAME; - - cmd->width = width; - cmd->height = height; - cmd->captureBuffer = captureBuffer; - cmd->encodeBuffer = encodeBuffer; - cmd->motionJpeg = motionJpeg; -} diff --git a/code/renderergl2/tr_curve.c b/code/renderergl2/tr_curve.c deleted file mode 100644 index 91c80a4d19..0000000000 --- a/code/renderergl2/tr_curve.c +++ /dev/null @@ -1,761 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "tr_local.h" - -/* - -This file does all of the processing necessary to turn a raw grid of points -read from the map file into a srfBspSurface_t ready for rendering. - -The level of detail solution is direction independent, based only on subdivided -distance from the true curve. - -Only a single entry point: - -srfBspSurface_t *R_SubdividePatchToGrid( int width, int height, - srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) { - -*/ - - -/* -============ -LerpDrawVert -============ -*/ -static void LerpDrawVert( srfVert_t *a, srfVert_t *b, srfVert_t *out ) { - out->xyz[0] = 0.5f * (a->xyz[0] + b->xyz[0]); - out->xyz[1] = 0.5f * (a->xyz[1] + b->xyz[1]); - out->xyz[2] = 0.5f * (a->xyz[2] + b->xyz[2]); - - out->st[0] = 0.5f * (a->st[0] + b->st[0]); - out->st[1] = 0.5f * (a->st[1] + b->st[1]); - - out->lightmap[0] = 0.5f * (a->lightmap[0] + b->lightmap[0]); - out->lightmap[1] = 0.5f * (a->lightmap[1] + b->lightmap[1]); - - out->vertexColors[0] = 0.5f * (a->vertexColors[0] + b->vertexColors[0]); - out->vertexColors[1] = 0.5f * (a->vertexColors[1] + b->vertexColors[1]); - out->vertexColors[2] = 0.5f * (a->vertexColors[2] + b->vertexColors[2]); - out->vertexColors[3] = 0.5f * (a->vertexColors[3] + b->vertexColors[3]); -} - -/* -============ -Transpose -============ -*/ -static void Transpose( int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) { - int i, j; - srfVert_t temp; - - if ( width > height ) { - for ( i = 0 ; i < height ; i++ ) { - for ( j = i + 1 ; j < width ; j++ ) { - if ( j < height ) { - // swap the value - temp = ctrl[j][i]; - ctrl[j][i] = ctrl[i][j]; - ctrl[i][j] = temp; - } else { - // just copy - ctrl[j][i] = ctrl[i][j]; - } - } - } - } else { - for ( i = 0 ; i < width ; i++ ) { - for ( j = i + 1 ; j < height ; j++ ) { - if ( j < width ) { - // swap the value - temp = ctrl[i][j]; - ctrl[i][j] = ctrl[j][i]; - ctrl[j][i] = temp; - } else { - // just copy - ctrl[i][j] = ctrl[j][i]; - } - } - } - } - -} - - -/* -================= -MakeMeshNormals - -Handles all the complicated wrapping and degenerate cases -================= -*/ -static void MakeMeshNormals( int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) { - int i, j, k, dist; - vec3_t normal; - vec3_t sum; - int count = 0; - vec3_t base; - vec3_t delta; - int x, y; - srfVert_t *dv; - vec3_t around[8], temp; - qboolean good[8]; - qboolean wrapWidth, wrapHeight; - float len; -static int neighbors[8][2] = { - {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1} - }; - - wrapWidth = qfalse; - for ( i = 0 ; i < height ; i++ ) { - VectorSubtract( ctrl[i][0].xyz, ctrl[i][width-1].xyz, delta ); - len = VectorLengthSquared( delta ); - if ( len > 1.0 ) { - break; - } - } - if ( i == height ) { - wrapWidth = qtrue; - } - - wrapHeight = qfalse; - for ( i = 0 ; i < width ; i++ ) { - VectorSubtract( ctrl[0][i].xyz, ctrl[height-1][i].xyz, delta ); - len = VectorLengthSquared( delta ); - if ( len > 1.0 ) { - break; - } - } - if ( i == width) { - wrapHeight = qtrue; - } - - - for ( i = 0 ; i < width ; i++ ) { - for ( j = 0 ; j < height ; j++ ) { - count = 0; - dv = &ctrl[j][i]; - VectorCopy( dv->xyz, base ); - for ( k = 0 ; k < 8 ; k++ ) { - VectorClear( around[k] ); - good[k] = qfalse; - - for ( dist = 1 ; dist <= 3 ; dist++ ) { - x = i + neighbors[k][0] * dist; - y = j + neighbors[k][1] * dist; - if ( wrapWidth ) { - if ( x < 0 ) { - x = width - 1 + x; - } else if ( x >= width ) { - x = 1 + x - width; - } - } - if ( wrapHeight ) { - if ( y < 0 ) { - y = height - 1 + y; - } else if ( y >= height ) { - y = 1 + y - height; - } - } - - if ( x < 0 || x >= width || y < 0 || y >= height ) { - break; // edge of patch - } - VectorSubtract( ctrl[y][x].xyz, base, temp ); - if ( VectorNormalize2( temp, temp ) == 0 ) { - continue; // degenerate edge, get more dist - } else { - good[k] = qtrue; - VectorCopy( temp, around[k] ); - break; // good edge - } - } - } - - VectorClear( sum ); - for ( k = 0 ; k < 8 ; k++ ) { - if ( !good[k] || !good[(k+1)&7] ) { - continue; // didn't get two points - } - CrossProduct( around[(k+1)&7], around[k], normal ); - if ( VectorNormalize2( normal, normal ) == 0 ) { - continue; - } - VectorAdd( normal, sum, sum ); - count++; - } - //if ( count == 0 ) { - // printf("bad normal\n"); - //} - VectorNormalize2( sum, dv->normal ); - } - } -} - -#ifdef USE_VERT_TANGENT_SPACE -static void MakeMeshTangentVectors(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], int numIndexes, - glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]) -{ - int i, j; - srfVert_t *dv[3]; - static srfVert_t ctrl2[MAX_GRID_SIZE * MAX_GRID_SIZE]; - glIndex_t *tri; - - // FIXME: use more elegant way - for(i = 0; i < width; i++) - { - for(j = 0; j < height; j++) - { - dv[0] = &ctrl2[j * width + i]; - *dv[0] = ctrl[j][i]; - } - } - - for(i = 0, tri = indexes; i < numIndexes; i += 3, tri += 3) - { - dv[0] = &ctrl2[tri[0]]; - dv[1] = &ctrl2[tri[1]]; - dv[2] = &ctrl2[tri[2]]; - - R_CalcTangentVectors(dv); - } - - for(i = 0; i < width; i++) - { - for(j = 0; j < height; j++) - { - dv[0] = &ctrl2[j * width + i]; - dv[1] = &ctrl[j][i]; - - VectorCopy4(dv[0]->tangent, dv[1]->tangent); - } - } -} -#endif - - -static int MakeMeshIndexes(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], - glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]) -{ - int i, j; - int numIndexes; - int w, h; - srfVert_t *dv; - static srfVert_t ctrl2[MAX_GRID_SIZE * MAX_GRID_SIZE]; - - h = height - 1; - w = width - 1; - numIndexes = 0; - 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 = i * width + j + 1; - v2 = v1 - 1; - v3 = v2 + width; - v4 = v3 + 1; - - indexes[numIndexes++] = v2; - indexes[numIndexes++] = v3; - indexes[numIndexes++] = v1; - - indexes[numIndexes++] = v1; - indexes[numIndexes++] = v3; - indexes[numIndexes++] = v4; - } - } - - // FIXME: use more elegant way - for(i = 0; i < width; i++) - { - for(j = 0; j < height; j++) - { - dv = &ctrl2[j * width + i]; - *dv = ctrl[j][i]; - } - } - - return numIndexes; -} - - -/* -============ -InvertCtrl -============ -*/ -static void InvertCtrl( int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) { - int i, j; - srfVert_t temp; - - for ( i = 0 ; i < height ; i++ ) { - for ( j = 0 ; j < width/2 ; j++ ) { - temp = ctrl[i][j]; - ctrl[i][j] = ctrl[i][width-1-j]; - ctrl[i][width-1-j] = temp; - } - } -} - - -/* -================= -InvertErrorTable -================= -*/ -static void InvertErrorTable( float errorTable[2][MAX_GRID_SIZE], int width, int height ) { - int i; - float copy[2][MAX_GRID_SIZE]; - - Com_Memcpy( copy, errorTable, sizeof( copy ) ); - - for ( i = 0 ; i < width ; i++ ) { - errorTable[1][i] = copy[0][i]; //[width-1-i]; - } - - for ( i = 0 ; i < height ; i++ ) { - errorTable[0][i] = copy[1][height-1-i]; - } - -} - -/* -================== -PutPointsOnCurve -================== -*/ -static void PutPointsOnCurve( srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], - int width, int height ) { - int i, j; - srfVert_t prev, next; - - for ( i = 0 ; i < width ; i++ ) { - for ( j = 1 ; j < height ; j += 2 ) { - LerpDrawVert( &ctrl[j][i], &ctrl[j+1][i], &prev ); - LerpDrawVert( &ctrl[j][i], &ctrl[j-1][i], &next ); - LerpDrawVert( &prev, &next, &ctrl[j][i] ); - } - } - - - for ( j = 0 ; j < height ; j++ ) { - for ( i = 1 ; i < width ; i += 2 ) { - LerpDrawVert( &ctrl[j][i], &ctrl[j][i+1], &prev ); - LerpDrawVert( &ctrl[j][i], &ctrl[j][i-1], &next ); - LerpDrawVert( &prev, &next, &ctrl[j][i] ); - } - } -} - -/* -================= -R_CreateSurfaceGridMesh -================= -*/ -srfBspSurface_t *R_CreateSurfaceGridMesh(int width, int height, - srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE], - int numIndexes, glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]) { - int i, j, size; - srfVert_t *vert; - vec3_t tmpVec; - srfBspSurface_t *grid; - - // copy the results out to a grid - size = (width * height - 1) * sizeof( srfVert_t ) + sizeof( *grid ); - -#ifdef PATCH_STITCHING - grid = /*ri.Hunk_Alloc*/ ri.Malloc( size ); - Com_Memset(grid, 0, size); - - grid->widthLodError = /*ri.Hunk_Alloc*/ ri.Malloc( width * 4 ); - Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 ); - - grid->heightLodError = /*ri.Hunk_Alloc*/ ri.Malloc( height * 4 ); - Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 ); - - grid->numIndexes = numIndexes; - grid->indexes = ri.Malloc(grid->numIndexes * sizeof(glIndex_t)); - Com_Memcpy(grid->indexes, indexes, numIndexes * sizeof(glIndex_t)); - - grid->numVerts = (width * height); - grid->verts = ri.Malloc(grid->numVerts * sizeof(srfVert_t)); -#else - grid = ri.Hunk_Alloc( size ); - Com_Memset(grid, 0, size); - - grid->widthLodError = ri.Hunk_Alloc( width * 4 ); - Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 ); - - grid->heightLodError = ri.Hunk_Alloc( height * 4 ); - Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 ); - - grid->numIndexes = numIndexes; - grid->indexes = ri.Hunk_Alloc(grid->numIndexes * sizeof(glIndex_t), h_low); - Com_Memcpy(grid->indexes, indexes, numIndexes * sizeof(glIndex_t)); - - grid->numVerts = (width * height); - grid->verts = ri.Hunk_Alloc(grid->numVerts * sizeof(srfVert_t), h_low); -#endif - - grid->width = width; - grid->height = height; - grid->surfaceType = SF_GRID; - ClearBounds( grid->cullBounds[0], grid->cullBounds[1] ); - for ( i = 0 ; i < width ; i++ ) { - for ( j = 0 ; j < height ; j++ ) { - vert = &grid->verts[j*width+i]; - *vert = ctrl[j][i]; - AddPointToBounds( vert->xyz, grid->cullBounds[0], grid->cullBounds[1] ); - } - } - - // compute local origin and bounds - VectorAdd( grid->cullBounds[0], grid->cullBounds[1], grid->cullOrigin ); - VectorScale( grid->cullOrigin, 0.5f, grid->cullOrigin ); - VectorSubtract( grid->cullBounds[0], grid->cullOrigin, tmpVec ); - grid->cullRadius = VectorLength( tmpVec ); - - VectorCopy( grid->cullOrigin, grid->lodOrigin ); - grid->lodRadius = grid->cullRadius; - // - return grid; -} - -/* -================= -R_FreeSurfaceGridMesh -================= -*/ -void R_FreeSurfaceGridMesh( srfBspSurface_t *grid ) { - ri.Free(grid->widthLodError); - ri.Free(grid->heightLodError); - ri.Free(grid->indexes); - ri.Free(grid->verts); - ri.Free(grid); -} - -/* -================= -R_SubdividePatchToGrid -================= -*/ -srfBspSurface_t *R_SubdividePatchToGrid( int width, int height, - srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) { - int i, j, k, l; - srfVert_t_cleared( prev ); - srfVert_t_cleared( next ); - srfVert_t_cleared( mid ); - float len, maxLen; - int dir; - int t; - srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; - float errorTable[2][MAX_GRID_SIZE]; - int numIndexes; - static glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]; - int consecutiveComplete; - - for ( i = 0 ; i < width ; i++ ) { - for ( j = 0 ; j < height ; j++ ) { - ctrl[j][i] = points[j*width+i]; - } - } - - for ( dir = 0 ; dir < 2 ; dir++ ) { - - for ( j = 0 ; j < MAX_GRID_SIZE ; j++ ) { - errorTable[dir][j] = 0; - } - - consecutiveComplete = 0; - - // horizontal subdivisions - for ( j = 0 ; ; j = (j + 2) % (width - 1) ) { - // check subdivided midpoints against control points - - // FIXME: also check midpoints of adjacent patches against the control points - // this would basically stitch all patches in the same LOD group together. - - maxLen = 0; - for ( i = 0 ; i < height ; i++ ) { - vec3_t midxyz; - vec3_t midxyz2; - vec3_t dir; - vec3_t projected; - float d; - - // calculate the point on the curve - for ( l = 0 ; l < 3 ; l++ ) { - midxyz[l] = (ctrl[i][j].xyz[l] + ctrl[i][j+1].xyz[l] * 2 - + ctrl[i][j+2].xyz[l] ) * 0.25f; - } - - // see how far off the line it is - // using dist-from-line will not account for internal - // texture warping, but it gives a lot less polygons than - // dist-from-midpoint - VectorSubtract( midxyz, ctrl[i][j].xyz, midxyz ); - VectorSubtract( ctrl[i][j+2].xyz, ctrl[i][j].xyz, dir ); - VectorNormalize( dir ); - - d = DotProduct( midxyz, dir ); - VectorScale( dir, d, projected ); - VectorSubtract( midxyz, projected, midxyz2); - len = VectorLengthSquared( midxyz2 ); // we will do the sqrt later - if ( len > maxLen ) { - maxLen = len; - } - } - - maxLen = sqrt(maxLen); - - // if all the points are on the lines, remove the entire columns - if ( maxLen < 0.1f ) { - errorTable[dir][j+1] = 999; - // if we go over the whole grid twice without adding any columns, stop - if (++consecutiveComplete >= width) - break; - continue; - } - - // see if we want to insert subdivided columns - if ( width + 2 > MAX_GRID_SIZE ) { - errorTable[dir][j+1] = 1.0f/maxLen; - break; // can't subdivide any more - } - - if ( maxLen <= r_subdivisions->value ) { - errorTable[dir][j+1] = 1.0f/maxLen; - // if we go over the whole grid twice without adding any columns, stop - if (++consecutiveComplete >= width) - break; - continue; // didn't need subdivision - } - - errorTable[dir][j+2] = 1.0f/maxLen; - - consecutiveComplete = 0; - - // insert two columns and replace the peak - width += 2; - for ( i = 0 ; i < height ; i++ ) { - LerpDrawVert( &ctrl[i][j], &ctrl[i][j+1], &prev ); - LerpDrawVert( &ctrl[i][j+1], &ctrl[i][j+2], &next ); - LerpDrawVert( &prev, &next, &mid ); - - for ( k = width - 1 ; k > j + 3 ; k-- ) { - ctrl[i][k] = ctrl[i][k-2]; - } - ctrl[i][j + 1] = prev; - ctrl[i][j + 2] = mid; - ctrl[i][j + 3] = next; - } - - // skip the new one, we'll get it on the next pass - j += 2; - } - - Transpose( width, height, ctrl ); - t = width; - width = height; - height = t; - } - - - // put all the aproximating points on the curve - PutPointsOnCurve( ctrl, width, height ); - - // cull out any rows or columns that are colinear - for ( i = 1 ; i < width-1 ; i++ ) { - if ( errorTable[0][i] != 999 ) { - continue; - } - for ( j = i+1 ; j < width ; j++ ) { - for ( k = 0 ; k < height ; k++ ) { - ctrl[k][j-1] = ctrl[k][j]; - } - errorTable[0][j-1] = errorTable[0][j]; - } - width--; - } - - for ( i = 1 ; i < height-1 ; i++ ) { - if ( errorTable[1][i] != 999 ) { - continue; - } - for ( j = i+1 ; j < height ; j++ ) { - for ( k = 0 ; k < width ; k++ ) { - ctrl[j-1][k] = ctrl[j][k]; - } - errorTable[1][j-1] = errorTable[1][j]; - } - height--; - } - -#if 1 - // flip for longest tristrips as an optimization - // the results should be visually identical with or - // without this step - if ( height > width ) { - Transpose( width, height, ctrl ); - InvertErrorTable( errorTable, width, height ); - t = width; - width = height; - height = t; - InvertCtrl( width, height, ctrl ); - } -#endif - - // calculate indexes - numIndexes = MakeMeshIndexes(width, height, ctrl, indexes); - - // calculate normals - MakeMeshNormals( width, height, ctrl ); -#ifdef USE_VERT_TANGENT_SPACE - MakeMeshTangentVectors(width, height, ctrl, numIndexes, indexes); -#endif - - return R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numIndexes, indexes); -} - -/* -=============== -R_GridInsertColumn -=============== -*/ -srfBspSurface_t *R_GridInsertColumn( srfBspSurface_t *grid, int column, int row, vec3_t point, float loderror ) { - int i, j; - int width, height, oldwidth; - srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; - float errorTable[2][MAX_GRID_SIZE]; - float lodRadius; - vec3_t lodOrigin; - int numIndexes; - static glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]; - - oldwidth = 0; - width = grid->width + 1; - if (width > MAX_GRID_SIZE) - return NULL; - height = grid->height; - for (i = 0; i < width; i++) { - if (i == column) { - //insert new column - for (j = 0; j < grid->height; j++) { - LerpDrawVert( &grid->verts[j * grid->width + i-1], &grid->verts[j * grid->width + i], &ctrl[j][i] ); - if (j == row) - VectorCopy(point, ctrl[j][i].xyz); - } - errorTable[0][i] = loderror; - continue; - } - errorTable[0][i] = grid->widthLodError[oldwidth]; - for (j = 0; j < grid->height; j++) { - ctrl[j][i] = grid->verts[j * grid->width + oldwidth]; - } - oldwidth++; - } - for (j = 0; j < grid->height; j++) { - errorTable[1][j] = grid->heightLodError[j]; - } - // put all the aproximating points on the curve - //PutPointsOnCurve( ctrl, width, height ); - - // calculate indexes - numIndexes = MakeMeshIndexes(width, height, ctrl, indexes); - - // calculate normals - MakeMeshNormals( width, height, ctrl ); - - VectorCopy(grid->lodOrigin, lodOrigin); - lodRadius = grid->lodRadius; - // free the old grid - R_FreeSurfaceGridMesh(grid); - // create a new grid - grid = R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numIndexes, indexes); - grid->lodRadius = lodRadius; - VectorCopy(lodOrigin, grid->lodOrigin); - return grid; -} - -/* -=============== -R_GridInsertRow -=============== -*/ -srfBspSurface_t *R_GridInsertRow( srfBspSurface_t *grid, int row, int column, vec3_t point, float loderror ) { - int i, j; - int width, height, oldheight; - srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; - float errorTable[2][MAX_GRID_SIZE]; - float lodRadius; - vec3_t lodOrigin; - int numIndexes; - static glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]; - - oldheight = 0; - width = grid->width; - height = grid->height + 1; - if (height > MAX_GRID_SIZE) - return NULL; - for (i = 0; i < height; i++) { - if (i == row) { - //insert new row - for (j = 0; j < grid->width; j++) { - LerpDrawVert( &grid->verts[(i-1) * grid->width + j], &grid->verts[i * grid->width + j], &ctrl[i][j] ); - if (j == column) - VectorCopy(point, ctrl[i][j].xyz); - } - errorTable[1][i] = loderror; - continue; - } - errorTable[1][i] = grid->heightLodError[oldheight]; - for (j = 0; j < grid->width; j++) { - ctrl[i][j] = grid->verts[oldheight * grid->width + j]; - } - oldheight++; - } - for (j = 0; j < grid->width; j++) { - errorTable[0][j] = grid->widthLodError[j]; - } - // put all the aproximating points on the curve - //PutPointsOnCurve( ctrl, width, height ); - - // calculate indexes - numIndexes = MakeMeshIndexes(width, height, ctrl, indexes); - - // calculate normals - MakeMeshNormals( width, height, ctrl ); - - VectorCopy(grid->lodOrigin, lodOrigin); - lodRadius = grid->lodRadius; - // free the old grid - R_FreeSurfaceGridMesh(grid); - // create a new grid - grid = R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numIndexes, indexes); - grid->lodRadius = lodRadius; - VectorCopy(lodOrigin, grid->lodOrigin); - return grid; -} diff --git a/code/renderergl2/tr_extensions.c b/code/renderergl2/tr_extensions.c deleted file mode 100644 index d7e5f1bae0..0000000000 --- a/code/renderergl2/tr_extensions.c +++ /dev/null @@ -1,728 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2011 James Canete (use.less01@gmail.com) - -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_extensions.c - extensions needed by the renderer not in sdl_glimp.c - -#ifdef USE_LOCAL_HEADERS -# include "SDL.h" -#else -# include -#endif - -#include "tr_local.h" - -// GL_EXT_draw_range_elements -void (APIENTRY * qglDrawRangeElementsEXT) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); - -// GL_EXT_multi_draw_arrays -void (APIENTRY * qglMultiDrawArraysEXT) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); -void (APIENTRY * qglMultiDrawElementsEXT) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid **indices, GLsizei primcount); - -// GL_ARB_vertex_shader -void (APIENTRY * qglBindAttribLocationARB) (GLhandleARB programObj, GLuint index, const GLcharARB * name); -void (APIENTRY * qglGetActiveAttribARB) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei * length, - GLint * size, GLenum * type, GLcharARB * name); -GLint(APIENTRY * qglGetAttribLocationARB) (GLhandleARB programObj, const GLcharARB * name); - -// GL_ARB_vertex_program -void (APIENTRY * qglVertexAttrib4fARB) (GLuint, GLfloat, GLfloat, GLfloat, GLfloat); -void (APIENTRY * qglVertexAttrib4fvARB) (GLuint, const GLfloat *); -void (APIENTRY * qglVertexAttribPointerARB) (GLuint index, GLint size, GLenum type, GLboolean normalized, - GLsizei stride, const GLvoid * pointer); -void (APIENTRY * qglEnableVertexAttribArrayARB) (GLuint index); -void (APIENTRY * qglDisableVertexAttribArrayARB) (GLuint index); - -// GL_ARB_vertex_buffer_object -void (APIENTRY * qglBindBufferARB) (GLenum target, GLuint buffer); -void (APIENTRY * qglDeleteBuffersARB) (GLsizei n, const GLuint * buffers); -void (APIENTRY * qglGenBuffersARB) (GLsizei n, GLuint * buffers); - -GLboolean(APIENTRY * qglIsBufferARB) (GLuint buffer); -void (APIENTRY * qglBufferDataARB) (GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage); -void (APIENTRY * qglBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid * data); -void (APIENTRY * qglGetBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid * data); - -void (APIENTRY * qglGetBufferParameterivARB) (GLenum target, GLenum pname, GLint * params); -void (APIENTRY * qglGetBufferPointervARB) (GLenum target, GLenum pname, GLvoid * *params); - -// GL_ARB_shader_objects -void (APIENTRY * qglDeleteObjectARB) (GLhandleARB obj); - -GLhandleARB(APIENTRY * qglGetHandleARB) (GLenum pname); -void (APIENTRY * qglDetachObjectARB) (GLhandleARB containerObj, GLhandleARB attachedObj); - -GLhandleARB(APIENTRY * qglCreateShaderObjectARB) (GLenum shaderType); -void (APIENTRY * qglShaderSourceARB) (GLhandleARB shaderObj, GLsizei count, const GLcharARB * *string, - const GLint * length); -void (APIENTRY * qglCompileShaderARB) (GLhandleARB shaderObj); - -GLhandleARB(APIENTRY * qglCreateProgramObjectARB) (void); -void (APIENTRY * qglAttachObjectARB) (GLhandleARB containerObj, GLhandleARB obj); -void (APIENTRY * qglLinkProgramARB) (GLhandleARB programObj); -void (APIENTRY * qglUseProgramObjectARB) (GLhandleARB programObj); -void (APIENTRY * qglValidateProgramARB) (GLhandleARB programObj); -void (APIENTRY * qglUniform1fARB) (GLint location, GLfloat v0); -void (APIENTRY * qglUniform2fARB) (GLint location, GLfloat v0, GLfloat v1); -void (APIENTRY * qglUniform3fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -void (APIENTRY * qglUniform4fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -void (APIENTRY * qglUniform1iARB) (GLint location, GLint v0); -void (APIENTRY * qglUniform2iARB) (GLint location, GLint v0, GLint v1); -void (APIENTRY * qglUniform3iARB) (GLint location, GLint v0, GLint v1, GLint v2); -void (APIENTRY * qglUniform4iARB) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -void (APIENTRY * qglUniform1fvARB) (GLint location, GLsizei count, const GLfloat * value); -void (APIENTRY * qglUniform2fvARB) (GLint location, GLsizei count, const GLfloat * value); -void (APIENTRY * qglUniform3fvARB) (GLint location, GLsizei count, const GLfloat * value); -void (APIENTRY * qglUniform4fvARB) (GLint location, GLsizei count, const GLfloat * value); -void (APIENTRY * qglUniform2ivARB) (GLint location, GLsizei count, const GLint * value); -void (APIENTRY * qglUniform3ivARB) (GLint location, GLsizei count, const GLint * value); -void (APIENTRY * qglUniform4ivARB) (GLint location, GLsizei count, const GLint * value); -void (APIENTRY * qglUniformMatrix2fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -void (APIENTRY * qglUniformMatrix3fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -void (APIENTRY * qglUniformMatrix4fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -void (APIENTRY * qglGetObjectParameterfvARB) (GLhandleARB obj, GLenum pname, GLfloat * params); -void (APIENTRY * qglGetObjectParameterivARB) (GLhandleARB obj, GLenum pname, GLint * params); -void (APIENTRY * qglGetInfoLogARB) (GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog); -void (APIENTRY * qglGetAttachedObjectsARB) (GLhandleARB containerObj, GLsizei maxCount, GLsizei * count, - GLhandleARB * obj); -GLint(APIENTRY * qglGetUniformLocationARB) (GLhandleARB programObj, const GLcharARB * name); -void (APIENTRY * qglGetActiveUniformARB) (GLhandleARB programObj, GLuint index, GLsizei maxIndex, GLsizei * length, - GLint * size, GLenum * type, GLcharARB * name); -void (APIENTRY * qglGetUniformfvARB) (GLhandleARB programObj, GLint location, GLfloat * params); -void (APIENTRY * qglGetUniformivARB) (GLhandleARB programObj, GLint location, GLint * params); -void (APIENTRY * qglGetShaderSourceARB) (GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * source); - -// GL_ARB_texture_compression -void (APIENTRY * qglCompressedTexImage3DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, - GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); -void (APIENTRY * qglCompressedTexImage2DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, - GLint border, GLsizei imageSize, const GLvoid *data); -void (APIENTRY * qglCompressedTexImage1DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, - GLsizei imageSize, const GLvoid *data); -void (APIENTRY * qglCompressedTexSubImage3DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); -void (APIENTRY * qglCompressedTexSubImage2DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, - GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); -void (APIENTRY * qglCompressedTexSubImage1DARB)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, - GLsizei imageSize, const GLvoid *data); -void (APIENTRY * qglGetCompressedTexImageARB)(GLenum target, GLint lod, - GLvoid *img); - -// GL_EXT_framebuffer_object -GLboolean (APIENTRY * qglIsRenderbufferEXT)(GLuint renderbuffer); -void (APIENTRY * qglBindRenderbufferEXT)(GLenum target, GLuint renderbuffer); -void (APIENTRY * qglDeleteRenderbuffersEXT)(GLsizei n, const GLuint *renderbuffers); -void (APIENTRY * qglGenRenderbuffersEXT)(GLsizei n, GLuint *renderbuffers); - -void (APIENTRY * qglRenderbufferStorageEXT)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); - -void (APIENTRY * qglGetRenderbufferParameterivEXT)(GLenum target, GLenum pname, GLint *params); - -GLboolean (APIENTRY * qglIsFramebufferEXT)(GLuint framebuffer); -void (APIENTRY * qglBindFramebufferEXT)(GLenum target, GLuint framebuffer); -void (APIENTRY * qglDeleteFramebuffersEXT)(GLsizei n, const GLuint *framebuffers); -void (APIENTRY * qglGenFramebuffersEXT)(GLsizei n, GLuint *framebuffers); - -GLenum (APIENTRY * qglCheckFramebufferStatusEXT)(GLenum target); - -void (APIENTRY * qglFramebufferTexture1DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, - GLint level); -void (APIENTRY * qglFramebufferTexture2DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, - GLint level); -void (APIENTRY * qglFramebufferTexture3DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, - GLint level, GLint zoffset); - -void (APIENTRY * qglFramebufferRenderbufferEXT)(GLenum target, GLenum attachment, GLenum renderbuffertarget, - GLuint renderbuffer); - -void (APIENTRY * qglGetFramebufferAttachmentParameterivEXT)(GLenum target, GLenum attachment, GLenum pname, GLint *params); - -void (APIENTRY * qglGenerateMipmapEXT)(GLenum target); - -// GL_ARB_occlusion_query -void (APIENTRY * qglGenQueriesARB)(GLsizei n, GLuint *ids); -void (APIENTRY * qglDeleteQueriesARB)(GLsizei n, const GLuint *ids); -GLboolean (APIENTRY * qglIsQueryARB)(GLuint id); -void (APIENTRY * qglBeginQueryARB)(GLenum target, GLuint id); -void (APIENTRY * qglEndQueryARB)(GLenum target); -void (APIENTRY * qglGetQueryivARB)(GLenum target, GLenum pname, GLint *params); -void (APIENTRY * qglGetQueryObjectivARB)(GLuint id, GLenum pname, GLint *params); -void (APIENTRY * qglGetQueryObjectuivARB)(GLuint id, GLenum pname, GLuint *params); - -// GL_EXT_framebuffer_blit -void (APIENTRY * qglBlitFramebufferEXT)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter); - -// GL_EXT_framebuffer_multisample -void (APIENTRY * qglRenderbufferStorageMultisampleEXT)(GLenum target, GLsizei samples, - GLenum internalformat, GLsizei width, GLsizei height); - -// GL_ARB_draw_buffers -void (APIENTRY * qglDrawBuffersARB)(GLsizei n, const GLenum *bufs); - -static qboolean GLimp_HaveExtension(const char *ext) -{ - const char *ptr = Q_stristr( glConfig.extensions_string, ext ); - if (ptr == NULL) - return qfalse; - ptr += strlen(ext); - return ((*ptr == ' ') || (*ptr == '\0')); // verify it's complete string. -} - -void GLimp_InitExtraExtensions() -{ - char *extension; - const char* result[3] = { "...ignoring %s\n", "...using %s\n", "...%s not found\n" }; - - // GL_EXT_draw_range_elements - extension = "GL_EXT_draw_range_elements"; - glRefConfig.drawRangeElements = qfalse; - qglMultiDrawArraysEXT = NULL; - qglMultiDrawElementsEXT = NULL; - if( GLimp_HaveExtension( extension ) ) - { - qglDrawRangeElementsEXT = (void *) SDL_GL_GetProcAddress("glDrawRangeElementsEXT"); - - if ( r_ext_draw_range_elements->integer) - glRefConfig.drawRangeElements = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.drawRangeElements], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_EXT_multi_draw_arrays - extension = "GL_EXT_multi_draw_arrays"; - glRefConfig.multiDrawArrays = qfalse; - qglMultiDrawArraysEXT = NULL; - qglMultiDrawElementsEXT = NULL; - if( GLimp_HaveExtension( extension ) ) - { - qglMultiDrawArraysEXT = (PFNGLMULTIDRAWARRAYSEXTPROC) SDL_GL_GetProcAddress("glMultiDrawArraysEXT"); - qglMultiDrawElementsEXT = (PFNGLMULTIDRAWELEMENTSEXTPROC) SDL_GL_GetProcAddress("glMultiDrawElementsEXT"); - - if ( r_ext_multi_draw_arrays->integer ) - glRefConfig.multiDrawArrays = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.multiDrawArrays], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_vertex_program - //glRefConfig.vertexProgram = qfalse; - extension = "GL_ARB_vertex_program"; - qglVertexAttrib4fARB = NULL; - qglVertexAttrib4fvARB = NULL; - qglVertexAttribPointerARB = NULL; - qglEnableVertexAttribArrayARB = NULL; - qglDisableVertexAttribArrayARB = NULL; - if( GLimp_HaveExtension( extension ) ) - { - qglVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC) SDL_GL_GetProcAddress("glVertexAttrib4fARB"); - qglVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC) SDL_GL_GetProcAddress("glVertexAttrib4fvARB"); - qglVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) SDL_GL_GetProcAddress("glVertexAttribPointerARB"); - qglEnableVertexAttribArrayARB = - (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) SDL_GL_GetProcAddress("glEnableVertexAttribArrayARB"); - qglDisableVertexAttribArrayARB = - (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) SDL_GL_GetProcAddress("glDisableVertexAttribArrayARB"); - - ri.Printf(PRINT_ALL, result[1], extension); - //glRefConfig.vertexProgram = qtrue; - } - else - { - ri.Error(ERR_FATAL, result[2], extension); - } - - // GL_ARB_vertex_buffer_object - //glRefConfig.vertexBufferObject = qfalse; - extension = "GL_ARB_vertex_buffer_object"; - qglBindBufferARB = NULL; - qglDeleteBuffersARB = NULL; - qglGenBuffersARB = NULL; - qglIsBufferARB = NULL; - qglBufferDataARB = NULL; - qglBufferSubDataARB = NULL; - qglGetBufferSubDataARB = NULL; - qglGetBufferParameterivARB = NULL; - qglGetBufferPointervARB = NULL; - if( GLimp_HaveExtension( extension ) ) - { - qglBindBufferARB = (PFNGLBINDBUFFERARBPROC) SDL_GL_GetProcAddress("glBindBufferARB"); - qglDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) SDL_GL_GetProcAddress("glDeleteBuffersARB"); - qglGenBuffersARB = (PFNGLGENBUFFERSARBPROC) SDL_GL_GetProcAddress("glGenBuffersARB"); - qglIsBufferARB = (PFNGLISBUFFERARBPROC) SDL_GL_GetProcAddress("glIsBufferARB"); - qglBufferDataARB = (PFNGLBUFFERDATAARBPROC) SDL_GL_GetProcAddress("glBufferDataARB"); - qglBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC) SDL_GL_GetProcAddress("glBufferSubDataARB"); - qglGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC) SDL_GL_GetProcAddress("glGetBufferSubDataARB"); - qglGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetBufferParameterivARB"); - qglGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC) SDL_GL_GetProcAddress("glGetBufferPointervARB"); - ri.Printf(PRINT_ALL, result[1], extension); - //glRefConfig.vertexBufferObject = qtrue; - } - else - { - ri.Error(ERR_FATAL, result[2], extension); - } - - // GL_ARB_shader_objects - extension = "GL_ARB_shader_objects"; - //glRefConfig.shaderObjects = qfalse; - qglDeleteObjectARB = NULL; - qglGetHandleARB = NULL; - qglDetachObjectARB = NULL; - qglCreateShaderObjectARB = NULL; - qglShaderSourceARB = NULL; - qglCompileShaderARB = NULL; - qglCreateProgramObjectARB = NULL; - qglAttachObjectARB = NULL; - qglLinkProgramARB = NULL; - qglUseProgramObjectARB = NULL; - qglValidateProgramARB = NULL; - qglUniform1fARB = NULL; - qglUniform2fARB = NULL; - qglUniform3fARB = NULL; - qglUniform4fARB = NULL; - qglUniform1iARB = NULL; - qglUniform2iARB = NULL; - qglUniform3iARB = NULL; - qglUniform4iARB = NULL; - qglUniform1fvARB = NULL; - qglUniform2fvARB = NULL; - qglUniform3fvARB = NULL; - qglUniform4fvARB = NULL; - qglUniform2ivARB = NULL; - qglUniform3ivARB = NULL; - qglUniform4ivARB = NULL; - qglUniformMatrix2fvARB = NULL; - qglUniformMatrix3fvARB = NULL; - qglUniformMatrix4fvARB = NULL; - qglGetObjectParameterfvARB = NULL; - qglGetObjectParameterivARB = NULL; - qglGetInfoLogARB = NULL; - qglGetAttachedObjectsARB = NULL; - qglGetUniformLocationARB = NULL; - qglGetActiveUniformARB = NULL; - qglGetUniformfvARB = NULL; - qglGetUniformivARB = NULL; - qglGetShaderSourceARB = NULL; - if( GLimp_HaveExtension( extension ) ) - { - qglDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB"); - qglGetHandleARB = (PFNGLGETHANDLEARBPROC) SDL_GL_GetProcAddress("glGetHandleARB"); - qglDetachObjectARB = (PFNGLDETACHOBJECTARBPROC) SDL_GL_GetProcAddress("glDetachObjectARB"); - qglCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB"); - qglShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB"); - qglCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB"); - qglCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB"); - qglAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB"); - qglLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB"); - qglUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB"); - qglValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC) SDL_GL_GetProcAddress("glValidateProgramARB"); - qglUniform1fARB = (PFNGLUNIFORM1FARBPROC) SDL_GL_GetProcAddress("glUniform1fARB"); - qglUniform2fARB = (PFNGLUNIFORM2FARBPROC) SDL_GL_GetProcAddress("glUniform2fARB"); - qglUniform3fARB = (PFNGLUNIFORM3FARBPROC) SDL_GL_GetProcAddress("glUniform3fARB"); - qglUniform4fARB = (PFNGLUNIFORM4FARBPROC) SDL_GL_GetProcAddress("glUniform4fARB"); - qglUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB"); - qglUniform2iARB = (PFNGLUNIFORM2IARBPROC) SDL_GL_GetProcAddress("glUniform2iARB"); - qglUniform3iARB = (PFNGLUNIFORM3IARBPROC) SDL_GL_GetProcAddress("glUniform3iARB"); - qglUniform4iARB = (PFNGLUNIFORM4IARBPROC) SDL_GL_GetProcAddress("glUniform4iARB"); - qglUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) SDL_GL_GetProcAddress("glUniform1fvARB"); - qglUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) SDL_GL_GetProcAddress("glUniform2fvARB"); - qglUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) SDL_GL_GetProcAddress("glUniform3fvARB"); - qglUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) SDL_GL_GetProcAddress("glUniform4fvARB"); - qglUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) SDL_GL_GetProcAddress("glUniform2ivARB"); - qglUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) SDL_GL_GetProcAddress("glUniform3ivARB"); - qglUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) SDL_GL_GetProcAddress("glUniform4ivARB"); - qglUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) SDL_GL_GetProcAddress("glUniformMatrix2fvARB"); - qglUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) SDL_GL_GetProcAddress("glUniformMatrix3fvARB"); - qglUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) SDL_GL_GetProcAddress("glUniformMatrix4fvARB"); - qglGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterfvARB"); - qglGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB"); - qglGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB"); - qglGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC) SDL_GL_GetProcAddress("glGetAttachedObjectsARB"); - qglGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB"); - qglGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC) SDL_GL_GetProcAddress("glGetActiveUniformARB"); - qglGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC) SDL_GL_GetProcAddress("glGetUniformfvARB"); - qglGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC) SDL_GL_GetProcAddress("glGetUniformivARB"); - qglGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glGetShaderSourceARB"); - ri.Printf(PRINT_ALL, result[1], extension); - //glRefConfig.shaderObjects = qtrue; - } - else - { - ri.Error(ERR_FATAL, result[2], extension); - } - - // GL_ARB_vertex_shader - //glRefConfig.vertexShader = qfalse; - extension = "GL_ARB_vertex_shader"; - qglBindAttribLocationARB = NULL; - qglGetActiveAttribARB = NULL; - qglGetAttribLocationARB = NULL; - if( GLimp_HaveExtension( extension ) ) - { - //int reservedComponents; - - //qglGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig.maxVertexUniforms); - //qglGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, &glConfig.maxVaryingFloats); - //qglGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig.maxVertexAttribs); - - //reservedComponents = 16 * 10; // approximation how many uniforms we have besides the bone matrices - -#if 0 - if(glConfig.driverType == GLDRV_MESA) - { - // HACK - // restrict to number of vertex uniforms to 512 because of: - // xreal.x86_64: nv50_program.c:4181: nv50_program_validate_data: Assertion `p->param_nr <= 512' failed - - glConfig.maxVertexUniforms = Q_bound(0, glConfig.maxVertexUniforms, 512); - } -#endif - - //glConfig.maxVertexSkinningBones = (int) Q_bound(0.0, (Q_max(glConfig.maxVertexUniforms - reservedComponents, 0) / 16), MAX_BONES); - //glConfig.vboVertexSkinningAvailable = r_vboVertexSkinning->integer && ((glConfig.maxVertexSkinningBones >= 12) ? qtrue : qfalse); - - qglBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) SDL_GL_GetProcAddress("glBindAttribLocationARB"); - qglGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC) SDL_GL_GetProcAddress("glGetActiveAttribARB"); - qglGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetAttribLocationARB"); - ri.Printf(PRINT_ALL, result[1], extension); - //glRefConfig.vertexShader = qtrue; - } - else - { - ri.Error(ERR_FATAL, result[2], extension); - } - - // GL_ARB_shading_language_100 - extension = "GL_ARB_shading_language_100"; - glRefConfig.textureFloat = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - char version[256]; - - Q_strncpyz( version, (char *) qglGetString (GL_SHADING_LANGUAGE_VERSION_ARB), sizeof( version ) ); - - sscanf(version, "%d.%d", &glRefConfig.glslMajorVersion, &glRefConfig.glslMinorVersion); - - ri.Printf(PRINT_ALL, "...using GLSL version %s\n", version); - } - else - { - ri.Error(ERR_FATAL, result[2], extension); - } - - glRefConfig.memInfo = MI_NONE; - - if( GLimp_HaveExtension( "GL_NVX_gpu_memory_info" ) ) - { - glRefConfig.memInfo = MI_NVX; - } - else if( GLimp_HaveExtension( "GL_ATI_meminfo" ) ) - { - glRefConfig.memInfo = MI_ATI; - } - - extension = "GL_ARB_texture_non_power_of_two"; - glRefConfig.textureNonPowerOfTwo = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - if(1) //(r_ext_texture_non_power_of_two->integer) - { - glRefConfig.textureNonPowerOfTwo = qtrue; - } - - ri.Printf(PRINT_ALL, result[glRefConfig.textureNonPowerOfTwo], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_texture_float - extension = "GL_ARB_texture_float"; - glRefConfig.textureFloat = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - if( r_ext_texture_float->integer ) - { - glRefConfig.textureFloat = qtrue; - } - - ri.Printf(PRINT_ALL, result[glRefConfig.textureFloat], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_half_float_pixel - extension = "GL_ARB_half_float_pixel"; - glRefConfig.halfFloatPixel = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - if( r_arb_half_float_pixel->integer ) - glRefConfig.halfFloatPixel = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.halfFloatPixel], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_EXT_framebuffer_object - extension = "GL_EXT_framebuffer_object"; - glRefConfig.framebufferObject = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &glRefConfig.maxRenderbufferSize); - glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &glRefConfig.maxColorAttachments); - - qglIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC) SDL_GL_GetProcAddress("glIsRenderbufferEXT"); - qglBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC) SDL_GL_GetProcAddress("glBindRenderbufferEXT"); - qglDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC) SDL_GL_GetProcAddress("glDeleteRenderbuffersEXT"); - qglGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC) SDL_GL_GetProcAddress("glGenRenderbuffersEXT"); - qglRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC) SDL_GL_GetProcAddress("glRenderbufferStorageEXT"); - qglGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) SDL_GL_GetProcAddress("glGetRenderbufferParameterivEXT"); - qglIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC) SDL_GL_GetProcAddress("glIsFramebufferEXT"); - qglBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) SDL_GL_GetProcAddress("glBindFramebufferEXT"); - qglDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC) SDL_GL_GetProcAddress("glDeleteFramebuffersEXT"); - qglGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) SDL_GL_GetProcAddress("glGenFramebuffersEXT"); - qglCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT"); - qglFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) SDL_GL_GetProcAddress("glFramebufferTexture1DEXT"); - qglFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) SDL_GL_GetProcAddress("glFramebufferTexture2DEXT"); - qglFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) SDL_GL_GetProcAddress("glFramebufferTexture3DEXT"); - qglFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) SDL_GL_GetProcAddress("glFramebufferRenderbufferEXT"); - qglGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) SDL_GL_GetProcAddress("glGetFramebufferAttachmentParameterivEXT"); - qglGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) SDL_GL_GetProcAddress("glGenerateMipmapEXT"); - - if(r_ext_framebuffer_object->value) - glRefConfig.framebufferObject = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.framebufferObject], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_EXT_packed_depth_stencil - extension = "GL_EXT_packed_depth_stencil"; - glRefConfig.packedDepthStencil = qfalse; - if( GLimp_HaveExtension(extension)) - { - glRefConfig.packedDepthStencil = qtrue; - ri.Printf(PRINT_ALL, result[glRefConfig.packedDepthStencil], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_occlusion_query - extension = "GL_ARB_occlusion_query"; - glRefConfig.occlusionQuery = qfalse; - if (GLimp_HaveExtension(extension)) - { - qglGenQueriesARB = (PFNGLGENQUERIESARBPROC) SDL_GL_GetProcAddress("glGenQueriesARB"); - qglDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC) SDL_GL_GetProcAddress("glDeleteQueriesARB"); - qglIsQueryARB = (PFNGLISQUERYARBPROC) SDL_GL_GetProcAddress("glIsQueryARB"); - qglBeginQueryARB = (PFNGLBEGINQUERYARBPROC) SDL_GL_GetProcAddress("glBeginQueryARB"); - qglEndQueryARB = (PFNGLENDQUERYARBPROC) SDL_GL_GetProcAddress("glEndQueryARB"); - qglGetQueryivARB = (PFNGLGETQUERYIVARBPROC) SDL_GL_GetProcAddress("glGetQueryivARB"); - qglGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC) SDL_GL_GetProcAddress("glGetQueryObjectivARB"); - qglGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC) SDL_GL_GetProcAddress("glGetQueryObjectuivARB"); - glRefConfig.occlusionQuery = qtrue; - ri.Printf(PRINT_ALL, result[glRefConfig.occlusionQuery], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_EXT_framebuffer_blit - extension = "GL_EXT_framebuffer_blit"; - glRefConfig.framebufferBlit = qfalse; - if (GLimp_HaveExtension(extension)) - { - qglBlitFramebufferEXT = (void *)SDL_GL_GetProcAddress("glBlitFramebufferEXT"); - glRefConfig.framebufferBlit = qtrue; - ri.Printf(PRINT_ALL, result[glRefConfig.framebufferBlit], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_EXT_framebuffer_multisample - extension = "GL_EXT_framebuffer_multisample"; - glRefConfig.framebufferMultisample = qfalse; - if (GLimp_HaveExtension(extension)) - { - qglRenderbufferStorageMultisampleEXT = (void *)SDL_GL_GetProcAddress("glRenderbufferStorageMultisampleEXT"); - glRefConfig.framebufferMultisample = qtrue; - ri.Printf(PRINT_ALL, result[glRefConfig.framebufferMultisample], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_EXT_texture_sRGB - extension = "GL_EXT_texture_sRGB"; - glRefConfig.textureSrgb = qfalse; - if (GLimp_HaveExtension(extension)) - { - if (r_srgb->integer) - glRefConfig.textureSrgb = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.textureSrgb], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_EXT_framebuffer_sRGB - extension = "GL_EXT_framebuffer_sRGB"; - glRefConfig.framebufferSrgb = qfalse; - if (GLimp_HaveExtension(extension)) - { - if (r_srgb->integer) - glRefConfig.framebufferSrgb = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.framebufferSrgb], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_EXT_texture_sRGB_decode - extension = "GL_EXT_texture_sRGB_decode"; - glRefConfig.textureSrgbDecode = qfalse; - if (GLimp_HaveExtension(extension)) - { - if (r_srgb->integer) - glRefConfig.textureSrgbDecode = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.textureSrgbDecode], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - - glRefConfig.textureCompression = TCR_NONE; - - // GL_EXT_texture_compression_latc - extension = "GL_EXT_texture_compression_latc"; - if (GLimp_HaveExtension(extension)) - { - if (r_ext_compressed_textures->integer) - glRefConfig.textureCompression |= TCR_LATC; - - ri.Printf(PRINT_ALL, result[r_ext_compressed_textures->integer ? 1 : 0], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_texture_compression_bptc - extension = "GL_ARB_texture_compression_bptc"; - if (GLimp_HaveExtension(extension)) - { - if (r_ext_compressed_textures->integer >= 2) - glRefConfig.textureCompression |= TCR_BPTC; - - ri.Printf(PRINT_ALL, result[(r_ext_compressed_textures->integer >= 2) ? 1 : 0], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_draw_buffers - extension = "GL_ARB_draw_buffers"; - qglDrawBuffersARB = NULL; - if( GLimp_HaveExtension( extension ) ) - { - qglDrawBuffersARB = (void *) SDL_GL_GetProcAddress("glDrawBuffersARB"); - - ri.Printf(PRINT_ALL, result[1], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_depth_clamp - extension = "GL_ARB_depth_clamp"; - glRefConfig.depthClamp = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - glRefConfig.depthClamp = qtrue; - ri.Printf(PRINT_ALL, result[1], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_seamless_cube_map - extension = "GL_ARB_seamless_cube_map"; - glRefConfig.seamlessCubeMap = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - if (r_arb_seamless_cube_map->integer) - glRefConfig.seamlessCubeMap = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.seamlessCubeMap], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_vertex_type_2_10_10_10_rev - extension = "GL_ARB_vertex_type_2_10_10_10_rev"; - glRefConfig.packedNormalDataType = GL_UNSIGNED_BYTE; - if( GLimp_HaveExtension( extension ) ) - { - if (r_arb_vertex_type_2_10_10_10_rev->integer) - glRefConfig.packedNormalDataType = GL_UNSIGNED_INT_2_10_10_10_REV; - - ri.Printf(PRINT_ALL, result[r_arb_vertex_type_2_10_10_10_rev->integer ? 1 : 0], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } -} diff --git a/code/renderergl2/tr_extramath.c b/code/renderergl2/tr_extramath.c deleted file mode 100644 index b844678f2e..0000000000 --- a/code/renderergl2/tr_extramath.c +++ /dev/null @@ -1,240 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2010 James Canete (use.less01@gmail.com) - -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_extramath.c - extra math needed by the renderer not in qmath.c - -#include "tr_local.h" - -// Some matrix helper functions -// FIXME: do these already exist in ioq3 and I don't know about them? - -void Mat4Zero( mat4_t out ) -{ - out[ 0] = 0.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = 0.0f; - out[ 1] = 0.0f; out[ 5] = 0.0f; out[ 9] = 0.0f; out[13] = 0.0f; - out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 0.0f; out[14] = 0.0f; - out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 0.0f; -} - -void Mat4Identity( mat4_t out ) -{ - out[ 0] = 1.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = 0.0f; - out[ 1] = 0.0f; out[ 5] = 1.0f; out[ 9] = 0.0f; out[13] = 0.0f; - out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 1.0f; out[14] = 0.0f; - out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f; -} - -void Mat4Copy( const mat4_t in, mat4_t out ) -{ - out[ 0] = in[ 0]; out[ 4] = in[ 4]; out[ 8] = in[ 8]; out[12] = in[12]; - out[ 1] = in[ 1]; out[ 5] = in[ 5]; out[ 9] = in[ 9]; out[13] = in[13]; - out[ 2] = in[ 2]; out[ 6] = in[ 6]; out[10] = in[10]; out[14] = in[14]; - out[ 3] = in[ 3]; out[ 7] = in[ 7]; out[11] = in[11]; out[15] = in[15]; -} - -void Mat4Multiply( const mat4_t in1, const mat4_t in2, mat4_t out ) -{ - out[ 0] = in1[ 0] * in2[ 0] + in1[ 4] * in2[ 1] + in1[ 8] * in2[ 2] + in1[12] * in2[ 3]; - out[ 1] = in1[ 1] * in2[ 0] + in1[ 5] * in2[ 1] + in1[ 9] * in2[ 2] + in1[13] * in2[ 3]; - out[ 2] = in1[ 2] * in2[ 0] + in1[ 6] * in2[ 1] + in1[10] * in2[ 2] + in1[14] * in2[ 3]; - out[ 3] = in1[ 3] * in2[ 0] + in1[ 7] * in2[ 1] + in1[11] * in2[ 2] + in1[15] * in2[ 3]; - - out[ 4] = in1[ 0] * in2[ 4] + in1[ 4] * in2[ 5] + in1[ 8] * in2[ 6] + in1[12] * in2[ 7]; - out[ 5] = in1[ 1] * in2[ 4] + in1[ 5] * in2[ 5] + in1[ 9] * in2[ 6] + in1[13] * in2[ 7]; - out[ 6] = in1[ 2] * in2[ 4] + in1[ 6] * in2[ 5] + in1[10] * in2[ 6] + in1[14] * in2[ 7]; - out[ 7] = in1[ 3] * in2[ 4] + in1[ 7] * in2[ 5] + in1[11] * in2[ 6] + in1[15] * in2[ 7]; - - out[ 8] = in1[ 0] * in2[ 8] + in1[ 4] * in2[ 9] + in1[ 8] * in2[10] + in1[12] * in2[11]; - out[ 9] = in1[ 1] * in2[ 8] + in1[ 5] * in2[ 9] + in1[ 9] * in2[10] + in1[13] * in2[11]; - out[10] = in1[ 2] * in2[ 8] + in1[ 6] * in2[ 9] + in1[10] * in2[10] + in1[14] * in2[11]; - out[11] = in1[ 3] * in2[ 8] + in1[ 7] * in2[ 9] + in1[11] * in2[10] + in1[15] * in2[11]; - - out[12] = in1[ 0] * in2[12] + in1[ 4] * in2[13] + in1[ 8] * in2[14] + in1[12] * in2[15]; - out[13] = in1[ 1] * in2[12] + in1[ 5] * in2[13] + in1[ 9] * in2[14] + in1[13] * in2[15]; - out[14] = in1[ 2] * in2[12] + in1[ 6] * in2[13] + in1[10] * in2[14] + in1[14] * in2[15]; - out[15] = in1[ 3] * in2[12] + in1[ 7] * in2[13] + in1[11] * in2[14] + in1[15] * in2[15]; -} - -void Mat4Transform( const mat4_t in1, const vec4_t in2, vec4_t out ) -{ - out[ 0] = in1[ 0] * in2[ 0] + in1[ 4] * in2[ 1] + in1[ 8] * in2[ 2] + in1[12] * in2[ 3]; - out[ 1] = in1[ 1] * in2[ 0] + in1[ 5] * in2[ 1] + in1[ 9] * in2[ 2] + in1[13] * in2[ 3]; - out[ 2] = in1[ 2] * in2[ 0] + in1[ 6] * in2[ 1] + in1[10] * in2[ 2] + in1[14] * in2[ 3]; - out[ 3] = in1[ 3] * in2[ 0] + in1[ 7] * in2[ 1] + in1[11] * in2[ 2] + in1[15] * in2[ 3]; -} - -qboolean Mat4Compare( const mat4_t a, const mat4_t b ) -{ - return !(a[ 0] != b[ 0] || a[ 4] != b[ 4] || a[ 8] != b[ 8] || a[12] != b[12] || - a[ 1] != b[ 1] || a[ 5] != b[ 5] || a[ 9] != b[ 9] || a[13] != b[13] || - a[ 2] != b[ 2] || a[ 6] != b[ 6] || a[10] != b[10] || a[14] != b[14] || - a[ 3] != b[ 3] || a[ 7] != b[ 7] || a[11] != b[11] || a[15] != b[15]); -} - -void Mat4Dump( const mat4_t in ) -{ - ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 0], in[ 4], in[ 8], in[12]); - ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 1], in[ 5], in[ 9], in[13]); - ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 2], in[ 6], in[10], in[14]); - ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 3], in[ 7], in[11], in[15]); -} - -void Mat4Translation( vec3_t vec, mat4_t out ) -{ - out[ 0] = 1.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = vec[0]; - out[ 1] = 0.0f; out[ 5] = 1.0f; out[ 9] = 0.0f; out[13] = vec[1]; - out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 1.0f; out[14] = vec[2]; - out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f; -} - -void Mat4Ortho( float left, float right, float bottom, float top, float znear, float zfar, mat4_t out ) -{ - out[ 0] = 2.0f / (right - left); out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = -(right + left) / (right - left); - out[ 1] = 0.0f; out[ 5] = 2.0f / (top - bottom); out[ 9] = 0.0f; out[13] = -(top + bottom) / (top - bottom); - out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 2.0f / (zfar - znear); out[14] = -(zfar + znear) / (zfar - znear); - out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f; -} - -void Mat4View(vec3_t axes[3], vec3_t origin, mat4_t out) -{ - out[0] = axes[0][0]; - out[1] = axes[1][0]; - out[2] = axes[2][0]; - out[3] = 0; - - out[4] = axes[0][1]; - out[5] = axes[1][1]; - out[6] = axes[2][1]; - out[7] = 0; - - out[8] = axes[0][2]; - out[9] = axes[1][2]; - out[10] = axes[2][2]; - out[11] = 0; - - out[12] = -DotProduct(origin, axes[0]); - out[13] = -DotProduct(origin, axes[1]); - out[14] = -DotProduct(origin, axes[2]); - out[15] = 1; -} - -void Mat4SimpleInverse( const mat4_t in, mat4_t out) -{ - vec3_t v; - float invSqrLen; - - VectorCopy(in + 0, v); - invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v); - out[ 0] = v[0]; out[ 4] = v[1]; out[ 8] = v[2]; out[12] = -DotProduct(v, &in[12]); - - VectorCopy(in + 4, v); - invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v); - out[ 1] = v[0]; out[ 5] = v[1]; out[ 9] = v[2]; out[13] = -DotProduct(v, &in[12]); - - VectorCopy(in + 8, v); - invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v); - out[ 2] = v[0]; out[ 6] = v[1]; out[10] = v[2]; out[14] = -DotProduct(v, &in[12]); - - out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f; -} - -void VectorLerp( vec3_t a, vec3_t b, float lerp, vec3_t c) -{ - c[0] = a[0] * (1.0f - lerp) + b[0] * lerp; - c[1] = a[1] * (1.0f - lerp) + b[1] * lerp; - c[2] = a[2] * (1.0f - lerp) + b[2] * lerp; -} - -qboolean SpheresIntersect(vec3_t origin1, float radius1, vec3_t origin2, float radius2) -{ - float radiusSum = radius1 + radius2; - vec3_t diff; - - VectorSubtract(origin1, origin2, diff); - - if (DotProduct(diff, diff) <= radiusSum * radiusSum) - { - return qtrue; - } - - return qfalse; -} - -void BoundingSphereOfSpheres(vec3_t origin1, float radius1, vec3_t origin2, float radius2, vec3_t origin3, float *radius3) -{ - vec3_t diff; - - VectorScale(origin1, 0.5f, origin3); - VectorMA(origin3, 0.5f, origin2, origin3); - - VectorSubtract(origin1, origin2, diff); - *radius3 = VectorLength(diff) * 0.5f + MAX(radius1, radius2); -} - -int NextPowerOfTwo(int in) -{ - int out; - - for (out = 1; out < in; out <<= 1) - ; - - return out; -} - -unsigned short FloatToHalf(float in) -{ - unsigned short out; - - union - { - float f; - unsigned int i; - } f32; - - int sign, inExponent, inFraction; - int outExponent, outFraction; - - f32.f = in; - - sign = (f32.i & 0x80000000) >> 31; - inExponent = (f32.i & 0x7F800000) >> 23; - inFraction = f32.i & 0x007FFFFF; - - outExponent = CLAMP(inExponent - 127, -15, 16) + 15; - - outFraction = 0; - if (outExponent == 0x1F) - { - if (inExponent == 0xFF && inFraction != 0) - outFraction = 0x3FF; - } - else if (outExponent == 0x00) - { - if (inExponent == 0x00 && inFraction != 0) - outFraction = 0x3FF; - } - else - outFraction = inFraction >> 13; - - out = (sign << 15) | (outExponent << 10) | outFraction; - - return out; -} diff --git a/code/renderergl2/tr_extramath.h b/code/renderergl2/tr_extramath.h deleted file mode 100644 index 0223c640bd..0000000000 --- a/code/renderergl2/tr_extramath.h +++ /dev/null @@ -1,105 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2010 James Canete (use.less01@gmail.com) - -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_extramath.h - -#ifndef __TR_EXTRAMATH_H__ -#define __TR_EXTRAMATH_H__ - -typedef vec_t mat4_t[16]; -typedef int ivec2_t[2]; -typedef int ivec3_t[3]; -typedef int ivec4_t[4]; - -void Mat4Zero( mat4_t out ); -void Mat4Identity( mat4_t out ); -void Mat4Copy( const mat4_t in, mat4_t out ); -void Mat4Multiply( const mat4_t in1, const mat4_t in2, mat4_t out ); -void Mat4Transform( const mat4_t in1, const vec4_t in2, vec4_t out ); -qboolean Mat4Compare(const mat4_t a, const mat4_t b); -void Mat4Dump( const mat4_t in ); -void Mat4Translation( vec3_t vec, mat4_t out ); -void Mat4Ortho( float left, float right, float bottom, float top, float znear, float zfar, mat4_t out ); -void Mat4View(vec3_t axes[3], vec3_t origin, mat4_t out); -void Mat4SimpleInverse( const mat4_t in, mat4_t out); - -#define VectorCopy2(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1]) -#define VectorSet2(v,x,y) ((v)[0]=(x),(v)[1]=(y)); - -#define VectorCopy4(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) -#define VectorSet4(v,x,y,z,w) ((v)[0]=(x),(v)[1]=(y),(v)[2]=(z),(v)[3]=(w)) -#define DotProduct4(a,b) ((a)[0]*(b)[0] + (a)[1]*(b)[1] + (a)[2]*(b)[2] + (a)[3]*(b)[3]) -#define VectorScale4(a,b,c) ((c)[0]=(a)[0]*(b),(c)[1]=(a)[1]*(b),(c)[2]=(a)[2]*(b),(c)[3]=(a)[3]*(b)) - -#define VectorCopy5(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3],(b)[4]=(a)[4]) - -#define OffsetByteToFloat(a) ((float)(a) * 1.0f/127.5f - 1.0f) -#define FloatToOffsetByte(a) (byte)((a) * 127.5f + 128.0f) -#define ByteToFloat(a) ((float)(a) * 1.0f/255.0f) -#define FloatToByte(a) (byte)((a) * 255.0f) - -#define RGBtosRGB(a) (((a) < 0.0031308f) ? (12.92f * (a)) : (1.055f * pow((a), 0.41666f) - 0.055f)) -#define sRGBtoRGB(a) (((a) <= 0.04045f) ? ((a) / 12.92f) : (pow((((a) + 0.055f) / 1.055f), 2.4)) ) - -static ID_INLINE int VectorCompare4(const vec4_t v1, const vec4_t v2) -{ - if(v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2] || v1[3] != v2[3]) - { - return 0; - } - return 1; -} - -static ID_INLINE int VectorCompare5(const vec5_t v1, const vec5_t v2) -{ - if(v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2] || v1[3] != v2[3] || v1[4] != v2[4]) - { - return 0; - } - return 1; -} - -void VectorLerp( vec3_t a, vec3_t b, float lerp, vec3_t c); - - -qboolean SpheresIntersect(vec3_t origin1, float radius1, vec3_t origin2, float radius2); -void BoundingSphereOfSpheres(vec3_t origin1, float radius1, vec3_t origin2, float radius2, vec3_t origin3, float *radius3); - -#ifndef SGN -#define SGN(x) (((x) >= 0) ? !!(x) : -1) -#endif - -#ifndef MAX -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#endif - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -#ifndef CLAMP -#define CLAMP(a,b,c) MIN(MAX((a),(b)),(c)) -#endif - -int NextPowerOfTwo(int in); -unsigned short FloatToHalf(float in); - -#endif diff --git a/code/renderergl2/tr_extratypes.h b/code/renderergl2/tr_extratypes.h deleted file mode 100644 index 84e39a76ef..0000000000 --- a/code/renderergl2/tr_extratypes.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2009-2011 Andrei Drexler, Richard Allen, James Canete - -This file is part of Reaction source code. - -Reaction 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. - -Reaction 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 Reaction source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#ifndef __TR_EXTRATYPES_H__ -#define __TR_EXTRATYPES_H__ - -// tr_extratypes.h, for mods that want to extend tr_types.h without losing compatibility with original VMs - -// extra refdef flags start at 0x0008 -#define RDF_NOFOG 0x0008 // don't apply fog to polys added using RE_AddPolyToScene -#define RDF_EXTRA 0x0010 // Makro - refdefex_t to follow after refdef_t -#define RDF_SUNLIGHT 0x0020 // SmileTheory - render sunlight and shadows - -typedef struct { - float blurFactor; - float sunDir[3]; - float sunCol[3]; - float sunAmbCol[3]; -} refdefex_t; - -#endif diff --git a/code/renderergl2/tr_fbo.c b/code/renderergl2/tr_fbo.c deleted file mode 100644 index c642b73237..0000000000 --- a/code/renderergl2/tr_fbo.c +++ /dev/null @@ -1,867 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2006 Kirk Barnes -Copyright (C) 2006-2008 Robert Beckebans - -This file is part of XreaL source code. - -XreaL 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. - -XreaL 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 XreaL source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_fbo.c -#include "tr_local.h" - -/* -============= -R_CheckFBO -============= -*/ -qboolean R_CheckFBO(const FBO_t * fbo) -{ - int code; - int id; - - qglGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &id); - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->frameBuffer); - - code = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - - if(code == GL_FRAMEBUFFER_COMPLETE_EXT) - { - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id); - return qtrue; - } - - // an error occured - switch (code) - { - case GL_FRAMEBUFFER_COMPLETE_EXT: - break; - - case GL_FRAMEBUFFER_UNSUPPORTED_EXT: - ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Unsupported framebuffer format\n", fbo->name); - break; - - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: - ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete attachment\n", fbo->name); - break; - - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: - ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing attachment\n", fbo->name); - break; - - //case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT: - // ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, duplicate attachment\n", fbo->name); - // break; - - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: - ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, attached images must have same dimensions\n", - fbo->name); - break; - - case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: - ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, attached images must have same format\n", - fbo->name); - break; - - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: - ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing draw buffer\n", fbo->name); - break; - - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: - ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing read buffer\n", fbo->name); - break; - - default: - ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) unknown error 0x%X\n", fbo->name, code); - //ri.Error(ERR_FATAL, "R_CheckFBO: (%s) unknown error 0x%X", fbo->name, code); - //assert(0); - break; - } - - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id); - - return qfalse; -} - -/* -============ -FBO_Create -============ -*/ -FBO_t *FBO_Create(const char *name, int width, int height) -{ - FBO_t *fbo; - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "FBO_Create: \"%s\" is too long", name); - } - - if(width <= 0 || width > glRefConfig.maxRenderbufferSize) - { - ri.Error(ERR_DROP, "FBO_Create: bad width %i", width); - } - - if(height <= 0 || height > glRefConfig.maxRenderbufferSize) - { - ri.Error(ERR_DROP, "FBO_Create: bad height %i", height); - } - - if(tr.numFBOs == MAX_FBOS) - { - ri.Error(ERR_DROP, "FBO_Create: MAX_FBOS hit"); - } - - fbo = tr.fbos[tr.numFBOs] = ri.Hunk_Alloc(sizeof(*fbo), h_low); - Q_strncpyz(fbo->name, name, sizeof(fbo->name)); - fbo->index = tr.numFBOs++; - fbo->width = width; - fbo->height = height; - - qglGenFramebuffersEXT(1, &fbo->frameBuffer); - - return fbo; -} - -void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample) -{ - uint32_t *pRenderBuffer; - GLenum attachment; - qboolean absent; - - switch(format) - { - case GL_RGB: - case GL_RGBA: - case GL_RGB8: - case GL_RGBA8: - case GL_RGB16F_ARB: - case GL_RGBA16F_ARB: - case GL_RGB32F_ARB: - case GL_RGBA32F_ARB: - fbo->colorFormat = format; - pRenderBuffer = &fbo->colorBuffers[index]; - attachment = GL_COLOR_ATTACHMENT0_EXT + index; - break; - - case GL_DEPTH_COMPONENT: - case GL_DEPTH_COMPONENT16_ARB: - case GL_DEPTH_COMPONENT24_ARB: - case GL_DEPTH_COMPONENT32_ARB: - fbo->depthFormat = format; - pRenderBuffer = &fbo->depthBuffer; - attachment = GL_DEPTH_ATTACHMENT_EXT; - break; - - case GL_STENCIL_INDEX: - case GL_STENCIL_INDEX1_EXT: - case GL_STENCIL_INDEX4_EXT: - case GL_STENCIL_INDEX8_EXT: - case GL_STENCIL_INDEX16_EXT: - fbo->stencilFormat = format; - pRenderBuffer = &fbo->stencilBuffer; - attachment = GL_STENCIL_ATTACHMENT_EXT; - break; - - case GL_DEPTH_STENCIL_EXT: - case GL_DEPTH24_STENCIL8_EXT: - fbo->packedDepthStencilFormat = format; - pRenderBuffer = &fbo->packedDepthStencilBuffer; - attachment = 0; // special for stencil and depth - break; - - default: - ri.Printf(PRINT_WARNING, "FBO_CreateBuffer: invalid format %d\n", format); - return; - } - - absent = *pRenderBuffer == 0; - if (absent) - qglGenRenderbuffersEXT(1, pRenderBuffer); - - qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, *pRenderBuffer); - if (multisample && glRefConfig.framebufferMultisample) - { - qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, multisample, format, fbo->width, fbo->height); - } - else - { - qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, format, fbo->width, fbo->height); - } - - if(absent) - { - if (attachment == 0) - { - qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer); - qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer); - } - else - qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment, GL_RENDERBUFFER_EXT, *pRenderBuffer); - } -} - - -/* -================= -R_AttachFBOTexture1D -================= -*/ -void R_AttachFBOTexture1D(int texId, int index) -{ - if(index < 0 || index >= glRefConfig.maxColorAttachments) - { - ri.Printf(PRINT_WARNING, "R_AttachFBOTexture1D: invalid attachment index %i\n", index); - return; - } - - qglFramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, GL_TEXTURE_1D, texId, 0); -} - -/* -================= -R_AttachFBOTexture2D -================= -*/ -void R_AttachFBOTexture2D(int target, int texId, int index) -{ - if(target != GL_TEXTURE_2D && (target < GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB || target > GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)) - { - ri.Printf(PRINT_WARNING, "R_AttachFBOTexture2D: invalid target %i\n", target); - return; - } - - if(index < 0 || index >= glRefConfig.maxColorAttachments) - { - ri.Printf(PRINT_WARNING, "R_AttachFBOTexture2D: invalid attachment index %i\n", index); - return; - } - - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, target, texId, 0); -} - -/* -================= -R_AttachFBOTexture3D -================= -*/ -void R_AttachFBOTexture3D(int texId, int index, int zOffset) -{ - if(index < 0 || index >= glRefConfig.maxColorAttachments) - { - ri.Printf(PRINT_WARNING, "R_AttachFBOTexture3D: invalid attachment index %i\n", index); - return; - } - - qglFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, GL_TEXTURE_3D_EXT, texId, 0, zOffset); -} - -/* -================= -R_AttachFBOTextureDepth -================= -*/ -void R_AttachFBOTextureDepth(int texId) -{ - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0); -} - -/* -================= -R_AttachFBOTexturePackedDepthStencil -================= -*/ -void R_AttachFBOTexturePackedDepthStencil(int texId) -{ - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0); - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0); -} - -void FBO_AttachTextureImage(image_t *img, int index) -{ - if (!glState.currentFBO) - { - ri.Printf(PRINT_WARNING, "FBO: attempted to attach a texture image with no FBO bound!\n"); - return; - } - - R_AttachFBOTexture2D(GL_TEXTURE_2D, img->texnum, index); - glState.currentFBO->colorImage[index] = img; -} - -/* -============ -FBO_Bind -============ -*/ -void FBO_Bind(FBO_t * fbo) -{ - if (glState.currentFBO == fbo) - return; - - if (r_logFile->integer) - { - // don't just call LogComment, or we will get a call to va() every frame! - if (fbo) - GLimp_LogComment(va("--- FBO_Bind( %s ) ---\n", fbo->name)); - else - GLimp_LogComment("--- FBO_Bind ( NULL ) ---\n"); - } - - if (!fbo) - { - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - //qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); - glState.currentFBO = NULL; - - return; - } - - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->frameBuffer); - - /* - if(fbo->colorBuffers[0]) - { - qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo->colorBuffers[0]); - } - */ - - /* - if(fbo->depthBuffer) - { - qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo->depthBuffer); - qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->depthBuffer); - } - */ - - glState.currentFBO = fbo; -} - -/* -============ -FBO_Init -============ -*/ -void FBO_Init(void) -{ - int i; - // int width, height, hdrFormat, multisample; - int hdrFormat, multisample; - - ri.Printf(PRINT_ALL, "------- FBO_Init -------\n"); - - if(!glRefConfig.framebufferObject) - return; - - tr.numFBOs = 0; - - GL_CheckErrors(); - - R_IssuePendingRenderCommands(); - -/* if(glRefConfig.textureNonPowerOfTwo) - { - width = glConfig.vidWidth; - height = glConfig.vidHeight; - } - else - { - width = NextPowerOfTwo(glConfig.vidWidth); - height = NextPowerOfTwo(glConfig.vidHeight); - } */ - - hdrFormat = GL_RGBA8; - if (r_hdr->integer && glRefConfig.framebufferObject && glRefConfig.textureFloat) - { - hdrFormat = GL_RGBA16F_ARB; - } - - qglGetIntegerv(GL_MAX_SAMPLES_EXT, &multisample); - - if (r_ext_framebuffer_multisample->integer < multisample) - { - multisample = r_ext_framebuffer_multisample->integer; - } - - if (multisample < 2 || !glRefConfig.framebufferBlit) - multisample = 0; - - if (multisample != r_ext_framebuffer_multisample->integer) - { - ri.Cvar_SetValue("r_ext_framebuffer_multisample", (float)multisample); - } - - // only create a render FBO if we need to resolve MSAA or do HDR - // otherwise just render straight to the screen (tr.renderFbo = NULL) - if (multisample && glRefConfig.framebufferMultisample) - { - tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height); - FBO_Bind(tr.renderFbo); - - FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, multisample); - FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, multisample); - - R_CheckFBO(tr.renderFbo); - - - tr.msaaResolveFbo = FBO_Create("_msaaResolve", tr.renderDepthImage->width, tr.renderDepthImage->height); - FBO_Bind(tr.msaaResolveFbo); - - //FBO_CreateBuffer(tr.msaaResolveFbo, hdrFormat, 0, 0); - FBO_AttachTextureImage(tr.renderImage, 0); - - //FBO_CreateBuffer(tr.msaaResolveFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); - R_AttachFBOTextureDepth(tr.renderDepthImage->texnum); - - R_CheckFBO(tr.msaaResolveFbo); - } - else if (r_hdr->integer) - { - tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height); - FBO_Bind(tr.renderFbo); - - //FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, 0); - FBO_AttachTextureImage(tr.renderImage, 0); - - //FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); - R_AttachFBOTextureDepth(tr.renderDepthImage->texnum); - - R_CheckFBO(tr.renderFbo); - } - - // clear render buffer - // this fixes the corrupt screen bug with r_hdr 1 on older hardware - if (tr.renderFbo) - { - FBO_Bind(tr.renderFbo); - qglClearColor( 1, 0, 0.5, 1 ); - qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - FBO_Bind(NULL); - } - - if (r_drawSunRays->integer) - { - tr.sunRaysFbo = FBO_Create("_sunRays", tr.renderDepthImage->width, tr.renderDepthImage->height); - FBO_Bind(tr.sunRaysFbo); - - FBO_AttachTextureImage(tr.sunRaysImage, 0); - - R_AttachFBOTextureDepth(tr.renderDepthImage->texnum); - - R_CheckFBO(tr.sunRaysFbo); - } - - // FIXME: Don't use separate color/depth buffers for a shadow buffer - if (MAX_DRAWN_PSHADOWS && tr.pshadowMaps[0]) - { - for( i = 0; i < MAX_DRAWN_PSHADOWS; i++) - { - tr.pshadowFbos[i] = FBO_Create(va("_shadowmap%d", i), tr.pshadowMaps[i]->width, tr.pshadowMaps[i]->height); - FBO_Bind(tr.pshadowFbos[i]); - - //FBO_CreateBuffer(tr.pshadowFbos[i], GL_RGBA8, 0, 0); - FBO_AttachTextureImage(tr.pshadowMaps[i], 0); - - FBO_CreateBuffer(tr.pshadowFbos[i], GL_DEPTH_COMPONENT24_ARB, 0, 0); - //R_AttachFBOTextureDepth(tr.textureDepthImage->texnum); - - R_CheckFBO(tr.pshadowFbos[i]); - } - } - - if (tr.sunShadowDepthImage[0]) - { - for ( i = 0; i < 3; i++) - { - tr.sunShadowFbo[i] = FBO_Create("_sunshadowmap", tr.sunShadowDepthImage[i]->width, tr.sunShadowDepthImage[i]->height); - FBO_Bind(tr.sunShadowFbo[i]); - - //FBO_CreateBuffer(tr.sunShadowFbo[i], GL_RGBA8, 0, 0); - //FBO_AttachTextureImage(tr.sunShadowImage, 0); - qglDrawBuffer(GL_NONE); - qglReadBuffer(GL_NONE); - - //FBO_CreateBuffer(tr.sunShadowFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); - R_AttachFBOTextureDepth(tr.sunShadowDepthImage[i]->texnum); - - R_CheckFBO(tr.sunShadowFbo[i]); - - } - - tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height); - FBO_Bind(tr.screenShadowFbo); - - FBO_AttachTextureImage(tr.screenShadowImage, 0); - - R_CheckFBO(tr.screenShadowFbo); - } - - for (i = 0; i < 2; i++) - { - tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height); - FBO_Bind(tr.textureScratchFbo[i]); - - //FBO_CreateBuffer(tr.textureScratchFbo[i], GL_RGBA8, 0, 0); - FBO_AttachTextureImage(tr.textureScratchImage[i], 0); - - R_CheckFBO(tr.textureScratchFbo[i]); - } - - { - tr.calcLevelsFbo = FBO_Create("_calclevels", tr.calcLevelsImage->width, tr.calcLevelsImage->height); - FBO_Bind(tr.calcLevelsFbo); - - //FBO_CreateBuffer(tr.calcLevelsFbo, hdrFormat, 0, 0); - FBO_AttachTextureImage(tr.calcLevelsImage, 0); - - R_CheckFBO(tr.calcLevelsFbo); - } - - { - tr.targetLevelsFbo = FBO_Create("_targetlevels", tr.targetLevelsImage->width, tr.targetLevelsImage->height); - FBO_Bind(tr.targetLevelsFbo); - - //FBO_CreateBuffer(tr.targetLevelsFbo, hdrFormat, 0, 0); - FBO_AttachTextureImage(tr.targetLevelsImage, 0); - - R_CheckFBO(tr.targetLevelsFbo); - } - - for (i = 0; i < 2; i++) - { - tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height); - FBO_Bind(tr.quarterFbo[i]); - - //FBO_CreateBuffer(tr.quarterFbo[i], hdrFormat, 0, 0); - FBO_AttachTextureImage(tr.quarterImage[i], 0); - - R_CheckFBO(tr.quarterFbo[i]); - } - - if (r_ssao->integer) - { - tr.hdrDepthFbo = FBO_Create("_hdrDepth", tr.hdrDepthImage->width, tr.hdrDepthImage->height); - FBO_Bind(tr.hdrDepthFbo); - - FBO_AttachTextureImage(tr.hdrDepthImage, 0); - - R_CheckFBO(tr.hdrDepthFbo); - - tr.screenSsaoFbo = FBO_Create("_screenssao", tr.screenSsaoImage->width, tr.screenSsaoImage->height); - FBO_Bind(tr.screenSsaoFbo); - - FBO_AttachTextureImage(tr.screenSsaoImage, 0); - - R_CheckFBO(tr.screenSsaoFbo); - } - - if (tr.renderCubeImage) - { - tr.renderCubeFbo = FBO_Create("_renderCubeFbo", tr.renderCubeImage->width, tr.renderCubeImage->height); - FBO_Bind(tr.renderCubeFbo); - - //FBO_AttachTextureImage(tr.renderCubeImage, 0); - R_AttachFBOTexture2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, tr.renderCubeImage->texnum, 0); - glState.currentFBO->colorImage[0] = tr.renderCubeImage; - - FBO_CreateBuffer(tr.renderCubeFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); - - R_CheckFBO(tr.renderCubeFbo); - } - - GL_CheckErrors(); - - FBO_Bind(NULL); -} - -/* -============ -FBO_Shutdown -============ -*/ -void FBO_Shutdown(void) -{ - int i, j; - FBO_t *fbo; - - ri.Printf(PRINT_ALL, "------- FBO_Shutdown -------\n"); - - if(!glRefConfig.framebufferObject) - return; - - FBO_Bind(NULL); - - for(i = 0; i < tr.numFBOs; i++) - { - fbo = tr.fbos[i]; - - for(j = 0; j < glRefConfig.maxColorAttachments; j++) - { - if(fbo->colorBuffers[j]) - qglDeleteRenderbuffersEXT(1, &fbo->colorBuffers[j]); - } - - if(fbo->depthBuffer) - qglDeleteRenderbuffersEXT(1, &fbo->depthBuffer); - - if(fbo->stencilBuffer) - qglDeleteRenderbuffersEXT(1, &fbo->stencilBuffer); - - if(fbo->frameBuffer) - qglDeleteFramebuffersEXT(1, &fbo->frameBuffer); - } -} - -/* -============ -R_FBOList_f -============ -*/ -void R_FBOList_f(void) -{ - int i; - FBO_t *fbo; - - if(!glRefConfig.framebufferObject) - { - ri.Printf(PRINT_ALL, "GL_EXT_framebuffer_object is not available.\n"); - return; - } - - ri.Printf(PRINT_ALL, " size name\n"); - ri.Printf(PRINT_ALL, "----------------------------------------------------------\n"); - - for(i = 0; i < tr.numFBOs; i++) - { - fbo = tr.fbos[i]; - - ri.Printf(PRINT_ALL, " %4i: %4i %4i %s\n", i, fbo->width, fbo->height, fbo->name); - } - - ri.Printf(PRINT_ALL, " %i FBOs\n", tr.numFBOs); -} - -// FIXME -extern void RB_SetGL2D (void); - -void FBO_BlitFromTexture(struct image_s *src, ivec4_t inSrcBox, vec2_t inSrcTexScale, FBO_t *dst, ivec4_t inDstBox, struct shaderProgram_s *shaderProgram, vec4_t inColor, int blend) -{ - ivec4_t dstBox, srcBox; - vec2_t srcTexScale; - vec4_t color; - vec4_t quadVerts[4]; - vec2_t texCoords[4]; - vec2_t invTexRes; - FBO_t *oldFbo = glState.currentFBO; - mat4_t projection; - int width, height; - - if (!src) - return; - - if (inSrcBox) - { - VectorSet4(srcBox, inSrcBox[0], inSrcBox[1], inSrcBox[0] + inSrcBox[2], inSrcBox[1] + inSrcBox[3]); - } - else - { - VectorSet4(srcBox, 0, 0, src->width, src->height); - } - - // framebuffers are 0 bottom, Y up. - if (inDstBox) - { - if (dst) - { - dstBox[0] = inDstBox[0]; - dstBox[1] = dst->height - inDstBox[1] - inDstBox[3]; - dstBox[2] = inDstBox[0] + inDstBox[2]; - dstBox[3] = dst->height - inDstBox[1]; - } - else - { - dstBox[0] = inDstBox[0]; - dstBox[1] = glConfig.vidHeight - inDstBox[1] - inDstBox[3]; - dstBox[2] = inDstBox[0] + inDstBox[2]; - dstBox[3] = glConfig.vidHeight - inDstBox[1]; - } - } - else if (dst) - { - VectorSet4(dstBox, 0, dst->height, dst->width, 0); - } - else - { - VectorSet4(dstBox, 0, glConfig.vidHeight, glConfig.vidWidth, 0); - } - - if (inSrcTexScale) - { - VectorCopy2(inSrcTexScale, srcTexScale); - } - else - { - srcTexScale[0] = srcTexScale[1] = 1.0f; - } - - if (inColor) - { - VectorCopy4(inColor, color); - } - else - { - VectorCopy4(colorWhite, color); - } - - if (!shaderProgram) - { - shaderProgram = &tr.textureColorShader; - } - - FBO_Bind(dst); - - if (glState.currentFBO) - { - width = glState.currentFBO->width; - height = glState.currentFBO->height; - } - else - { - width = glConfig.vidWidth; - height = glConfig.vidHeight; - } - - qglViewport( 0, 0, width, height ); - qglScissor( 0, 0, width, height ); - - Mat4Ortho(0, width, height, 0, 0, 1, projection); - - qglDisable( GL_CULL_FACE ); - - GL_BindToTMU(src, TB_COLORMAP); - - VectorSet4(quadVerts[0], dstBox[0], dstBox[1], 0, 1); - VectorSet4(quadVerts[1], dstBox[2], dstBox[1], 0, 1); - VectorSet4(quadVerts[2], dstBox[2], dstBox[3], 0, 1); - VectorSet4(quadVerts[3], dstBox[0], dstBox[3], 0, 1); - - texCoords[0][0] = srcBox[0] / (float)src->width; texCoords[0][1] = 1.0f - srcBox[1] / (float)src->height; - texCoords[1][0] = srcBox[2] / (float)src->width; texCoords[1][1] = 1.0f - srcBox[1] / (float)src->height; - texCoords[2][0] = srcBox[2] / (float)src->width; texCoords[2][1] = 1.0f - srcBox[3] / (float)src->height; - texCoords[3][0] = srcBox[0] / (float)src->width; texCoords[3][1] = 1.0f - srcBox[3] / (float)src->height; - - invTexRes[0] = 1.0f / src->width * srcTexScale[0]; - invTexRes[1] = 1.0f / src->height * srcTexScale[1]; - - GL_State( blend ); - - GLSL_BindProgram(shaderProgram); - - GLSL_SetUniformMat4(shaderProgram, UNIFORM_MODELVIEWPROJECTIONMATRIX, projection); - GLSL_SetUniformVec4(shaderProgram, UNIFORM_COLOR, color); - GLSL_SetUniformVec2(shaderProgram, UNIFORM_INVTEXRES, invTexRes); - GLSL_SetUniformVec2(shaderProgram, UNIFORM_AUTOEXPOSUREMINMAX, tr.refdef.autoExposureMinMax); - GLSL_SetUniformVec3(shaderProgram, UNIFORM_TONEMINAVGMAXLINEAR, tr.refdef.toneMinAvgMaxLinear); - - RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); - - FBO_Bind(oldFbo); -} - -void FBO_Blit(FBO_t *src, ivec4_t inSrcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend) -{ - ivec4_t srcBox; - - if (!src) - { - ri.Printf(PRINT_WARNING, "Tried to blit from a NULL FBO!\n"); - return; - } - - // framebuffers are 0 bottom, Y up. - if (inSrcBox) - { - srcBox[0] = inSrcBox[0]; - srcBox[1] = src->height - inSrcBox[1] - inSrcBox[3]; - srcBox[2] = inSrcBox[2]; - srcBox[3] = inSrcBox[3]; - } - else - { - VectorSet4(srcBox, 0, src->height, src->width, -src->height); - } - - FBO_BlitFromTexture(src->colorImage[0], srcBox, srcTexScale, dst, dstBox, shaderProgram, color, blend | GLS_DEPTHTEST_DISABLE); -} - -void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int buffers, int filter) -{ - ivec4_t srcBoxFinal, dstBoxFinal; - GLuint srcFb, dstFb; - - if (!glRefConfig.framebufferBlit) - { - FBO_Blit(src, srcBox, NULL, dst, dstBox, NULL, NULL, 0); - return; - } - - // get to a neutral state first - //FBO_Bind(NULL); - - srcFb = src ? src->frameBuffer : 0; - dstFb = dst ? dst->frameBuffer : 0; - - if (!srcBox) - { - if (src) - { - VectorSet4(srcBoxFinal, 0, 0, src->width, src->height); - } - else - { - VectorSet4(srcBoxFinal, 0, 0, glConfig.vidWidth, glConfig.vidHeight); - } - } - else - { - VectorSet4(srcBoxFinal, srcBox[0], srcBox[1], srcBox[0] + srcBox[2], srcBox[1] + srcBox[3]); - } - - if (!dstBox) - { - if (dst) - { - VectorSet4(dstBoxFinal, 0, 0, dst->width, dst->height); - } - else - { - VectorSet4(dstBoxFinal, 0, 0, glConfig.vidWidth, glConfig.vidHeight); - } - } - else - { - VectorSet4(dstBoxFinal, dstBox[0], dstBox[1], dstBox[0] + dstBox[2], dstBox[1] + dstBox[3]); - } - - qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, srcFb); - qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, dstFb); - qglBlitFramebufferEXT(srcBoxFinal[0], srcBoxFinal[1], srcBoxFinal[2], srcBoxFinal[3], - dstBoxFinal[0], dstBoxFinal[1], dstBoxFinal[2], dstBoxFinal[3], - buffers, filter); - - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - glState.currentFBO = NULL; -} diff --git a/code/renderergl2/tr_fbo.h b/code/renderergl2/tr_fbo.h deleted file mode 100644 index b5ab18c19f..0000000000 --- a/code/renderergl2/tr_fbo.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2010 James Canete (use.less01@gmail.com) - -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_fbo.h - -#ifndef __TR_FBO_H__ -#define __TR_FBO_H__ - -struct image_s; -struct shaderProgram_s; - -typedef struct FBO_s -{ - char name[MAX_QPATH]; - - int index; - - uint32_t frameBuffer; - - uint32_t colorBuffers[16]; - int colorFormat; - struct image_s *colorImage[16]; - - uint32_t depthBuffer; - int depthFormat; - - uint32_t stencilBuffer; - int stencilFormat; - - uint32_t packedDepthStencilBuffer; - int packedDepthStencilFormat; - - int width; - int height; -} FBO_t; - -void FBO_Bind(FBO_t *fbo); -void FBO_Init(void); -void FBO_Shutdown(void); - -void FBO_BlitFromTexture(struct image_s *src, ivec4_t srcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend); -void FBO_Blit(FBO_t *src, ivec4_t srcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend); -void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int buffers, int filter); - - -#endif diff --git a/code/renderergl2/tr_flares.c b/code/renderergl2/tr_flares.c deleted file mode 100644 index e1d46d544b..0000000000 --- a/code/renderergl2/tr_flares.c +++ /dev/null @@ -1,557 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_flares.c - -#include "tr_local.h" - -/* -============================================================================= - -LIGHT FLARES - -A light flare is an effect that takes place inside the eye when bright light -sources are visible. The size of the flare reletive to the screen is nearly -constant, irrespective of distance, but the intensity should be proportional to the -projected area of the light source. - -A surface that has been flagged as having a light flare will calculate the depth -buffer value that its midpoint should have when the surface is added. - -After all opaque surfaces have been rendered, the depth buffer is read back for -each flare in view. If the point has not been obscured by a closer surface, the -flare should be drawn. - -Surfaces that have a repeated texture should never be flagged as flaring, because -there will only be a single flare added at the midpoint of the polygon. - -To prevent abrupt popping, the intensity of the flare is interpolated up and -down as it changes visibility. This involves scene to scene state, unlike almost -all other aspects of the renderer, and is complicated by the fact that a single -frame may have multiple scenes. - -RB_RenderFlares() will be called once per view (twice in a mirrored scene, potentially -up to five or more times in a frame with 3D status bar icons). - -============================================================================= -*/ - - -// flare states maintain visibility over multiple frames for fading -// layers: view, mirror, menu -typedef struct flare_s { - struct flare_s *next; // for active chain - - int addedFrame; - - qboolean inPortal; // true if in a portal view of the scene - int frameSceneNum; - void *surface; - int fogNum; - - int fadeTime; - - qboolean visible; // state of last test - float drawIntensity; // may be non 0 even if !visible due to fading - - int windowX, windowY; - float eyeZ; - - vec3_t origin; - vec3_t color; -} flare_t; - -#define MAX_FLARES 128 - -flare_t r_flareStructs[MAX_FLARES]; -flare_t *r_activeFlares, *r_inactiveFlares; - -int flareCoeff; - -/* -================== -R_SetFlareCoeff -================== -*/ -static void R_SetFlareCoeff( void ) { - - if(r_flareCoeff->value == 0.0f) - flareCoeff = atof(FLARE_STDCOEFF); - else - flareCoeff = r_flareCoeff->value; -} - -/* -================== -R_ClearFlares -================== -*/ -void R_ClearFlares( void ) { - int i; - - Com_Memset( r_flareStructs, 0, sizeof( r_flareStructs ) ); - r_activeFlares = NULL; - r_inactiveFlares = NULL; - - for ( i = 0 ; i < MAX_FLARES ; i++ ) { - r_flareStructs[i].next = r_inactiveFlares; - r_inactiveFlares = &r_flareStructs[i]; - } - - R_SetFlareCoeff(); -} - - -/* -================== -RB_AddFlare - -This is called at surface tesselation time -================== -*/ -void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ) { - int i; - flare_t *f; - vec3_t local; - float d = 1; - vec4_t eye, clip, normalized, window; - - backEnd.pc.c_flareAdds++; - - if(normal && (normal[0] || normal[1] || normal[2])) - { - VectorSubtract( backEnd.viewParms.or.origin, point, local ); - VectorNormalizeFast(local); - d = DotProduct(local, normal); - - // If the viewer is behind the flare don't add it. - if(d < 0) - return; - } - - // if the point is off the screen, don't bother adding it - // calculate screen coordinates and depth - R_TransformModelToClip( point, backEnd.or.modelMatrix, - backEnd.viewParms.projectionMatrix, eye, clip ); - - // check to see if the point is completely off screen - for ( i = 0 ; i < 3 ; i++ ) { - if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) { - return; - } - } - - R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window ); - - if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth - || window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) { - return; // shouldn't happen, since we check the clip[] above, except for FP rounding - } - - // see if a flare with a matching surface, scene, and view exists - for ( f = r_activeFlares ; f ; f = f->next ) { - if ( f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum - && f->inPortal == backEnd.viewParms.isPortal ) { - break; - } - } - - // allocate a new one - if (!f ) { - if ( !r_inactiveFlares ) { - // the list is completely full - return; - } - f = r_inactiveFlares; - r_inactiveFlares = r_inactiveFlares->next; - f->next = r_activeFlares; - r_activeFlares = f; - - f->surface = surface; - f->frameSceneNum = backEnd.viewParms.frameSceneNum; - f->inPortal = backEnd.viewParms.isPortal; - f->addedFrame = -1; - } - - if ( f->addedFrame != backEnd.viewParms.frameCount - 1 ) { - f->visible = qfalse; - f->fadeTime = backEnd.refdef.time - 2000; - } - - f->addedFrame = backEnd.viewParms.frameCount; - f->fogNum = fogNum; - - VectorCopy(point, f->origin); - VectorCopy( color, f->color ); - - // fade the intensity of the flare down as the - // light surface turns away from the viewer - VectorScale( f->color, d, f->color ); - - // save info needed to test - f->windowX = backEnd.viewParms.viewportX + window[0]; - f->windowY = backEnd.viewParms.viewportY + window[1]; - - f->eyeZ = eye[2]; -} - -/* -================== -RB_AddDlightFlares -================== -*/ -void RB_AddDlightFlares( void ) { - dlight_t *l; - int i, j, k; - fog_t *fog = NULL; - - if ( !r_flares->integer ) { - return; - } - - l = backEnd.refdef.dlights; - - if(tr.world) - fog = tr.world->fogs; - - for (i=0 ; inumfogs ; j++ ) { - fog = &tr.world->fogs[j]; - for ( k = 0 ; k < 3 ; k++ ) { - if ( l->origin[k] < fog->bounds[0][k] || l->origin[k] > fog->bounds[1][k] ) { - break; - } - } - if ( k == 3 ) { - break; - } - } - if ( j == tr.world->numfogs ) { - j = 0; - } - } - else - j = 0; - - RB_AddFlare( (void *)l, j, l->origin, l->color, NULL ); - } -} - -/* -=============================================================================== - -FLARE BACK END - -=============================================================================== -*/ - -/* -================== -RB_TestFlare -================== -*/ -void RB_TestFlare( flare_t *f ) { - float depth; - qboolean visible; - float fade; - float screenZ; - FBO_t *oldFbo; - - backEnd.pc.c_flareTests++; - - // doing a readpixels is as good as doing a glFinish(), so - // don't bother with another sync - glState.finishCalled = qfalse; - - // if we're doing multisample rendering, read from the correct FBO - oldFbo = glState.currentFBO; - if (tr.msaaResolveFbo) - { - FBO_Bind(tr.msaaResolveFbo); - } - - // read back the z buffer contents - qglReadPixels( f->windowX, f->windowY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth ); - - // if we're doing multisample rendering, switch to the old FBO - if (tr.msaaResolveFbo) - { - FBO_Bind(oldFbo); - } - - screenZ = backEnd.viewParms.projectionMatrix[14] / - ( ( 2*depth - 1 ) * backEnd.viewParms.projectionMatrix[11] - backEnd.viewParms.projectionMatrix[10] ); - - visible = ( -f->eyeZ - -screenZ ) < 24; - - if ( visible ) { - if ( !f->visible ) { - f->visible = qtrue; - f->fadeTime = backEnd.refdef.time - 1; - } - fade = ( ( backEnd.refdef.time - f->fadeTime ) /1000.0f ) * r_flareFade->value; - } else { - if ( f->visible ) { - f->visible = qfalse; - f->fadeTime = backEnd.refdef.time - 1; - } - fade = 1.0f - ( ( backEnd.refdef.time - f->fadeTime ) / 1000.0f ) * r_flareFade->value; - } - - if ( fade < 0 ) { - fade = 0; - } - if ( fade > 1 ) { - fade = 1; - } - - f->drawIntensity = fade; -} - - -/* -================== -RB_RenderFlare -================== -*/ -void RB_RenderFlare( flare_t *f ) { - float size; - vec3_t color; - int iColor[3]; - float distance, intensity, factor; - byte fogFactors[3] = {255, 255, 255}; - - backEnd.pc.c_flareRenders++; - - // We don't want too big values anyways when dividing by distance. - if(f->eyeZ > -1.0f) - distance = 1.0f; - else - distance = -f->eyeZ; - - // calculate the flare size.. - size = backEnd.viewParms.viewportWidth * ( r_flareSize->value/640.0f + 8 / distance ); - -/* - * This is an alternative to intensity scaling. It changes the size of the flare on screen instead - * with growing distance. See in the description at the top why this is not the way to go. - // size will change ~ 1/r. - size = backEnd.viewParms.viewportWidth * (r_flareSize->value / (distance * -2.0f)); -*/ - -/* - * As flare sizes stay nearly constant with increasing distance we must decrease the intensity - * to achieve a reasonable visual result. The intensity is ~ (size^2 / distance^2) which can be - * got by considering the ratio of - * (flaresurface on screen) : (Surface of sphere defined by flare origin and distance from flare) - * An important requirement is: - * intensity <= 1 for all distances. - * - * The formula used here to compute the intensity is as follows: - * intensity = flareCoeff * size^2 / (distance + size*sqrt(flareCoeff))^2 - * As you can see, the intensity will have a max. of 1 when the distance is 0. - * The coefficient flareCoeff will determine the falloff speed with increasing distance. - */ - - factor = distance + size * sqrt(flareCoeff); - - intensity = flareCoeff * size * size / (factor * factor); - - VectorScale(f->color, f->drawIntensity * intensity, color); - - // Calculations for fogging - if(tr.world && f->fogNum > 0 && f->fogNum < tr.world->numfogs) - { - tess.numVertexes = 1; - VectorCopy(f->origin, tess.xyz[0]); - tess.fogNum = f->fogNum; - - RB_CalcModulateColorsByFog(fogFactors); - - // We don't need to render the flare if colors are 0 anyways. - if(!(fogFactors[0] || fogFactors[1] || fogFactors[2])) - return; - } - - iColor[0] = color[0] * fogFactors[0]; - iColor[1] = color[1] * fogFactors[1]; - iColor[2] = color[2] * fogFactors[2]; - - RB_BeginSurface( tr.flareShader, f->fogNum, 0 ); - - // FIXME: use quadstamp? - tess.xyz[tess.numVertexes][0] = f->windowX - size; - tess.xyz[tess.numVertexes][1] = f->windowY - size; - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f; - tess.vertexColors[tess.numVertexes][3] = 1.0f; - tess.numVertexes++; - - tess.xyz[tess.numVertexes][0] = f->windowX - size; - tess.xyz[tess.numVertexes][1] = f->windowY + size; - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f; - tess.vertexColors[tess.numVertexes][3] = 1.0f; - tess.numVertexes++; - - tess.xyz[tess.numVertexes][0] = f->windowX + size; - tess.xyz[tess.numVertexes][1] = f->windowY + size; - tess.texCoords[tess.numVertexes][0][0] = 1; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f; - tess.vertexColors[tess.numVertexes][3] = 1.0f; - tess.numVertexes++; - - tess.xyz[tess.numVertexes][0] = f->windowX + size; - tess.xyz[tess.numVertexes][1] = f->windowY - size; - tess.texCoords[tess.numVertexes][0][0] = 1; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f; - tess.vertexColors[tess.numVertexes][3] = 1.0f; - tess.numVertexes++; - - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 1; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 3; - - RB_EndSurface(); -} - -/* -================== -RB_RenderFlares - -Because flares are simulating an occular effect, they should be drawn after -everything (all views) in the entire frame has been drawn. - -Because of the way portals use the depth buffer to mark off areas, the -needed information would be lost after each view, so we are forced to draw -flares after each view. - -The resulting artifact is that flares in mirrors or portals don't dim properly -when occluded by something in the main view, and portal flares that should -extend past the portal edge will be overwritten. -================== -*/ -void RB_RenderFlares (void) { - flare_t *f; - flare_t **prev; - qboolean draw; - mat4_t oldmodelview, oldprojection, matrix; - - if ( !r_flares->integer ) { - return; - } - - if(r_flareCoeff->modified) - { - R_SetFlareCoeff(); - r_flareCoeff->modified = qfalse; - } - - // Reset currentEntity to world so that any previously referenced entities - // don't have influence on the rendering of these flares (i.e. RF_ renderer flags). - backEnd.currentEntity = &tr.worldEntity; - backEnd.or = backEnd.viewParms.world; - -// RB_AddDlightFlares(); - - // perform z buffer readback on each flare in this view - draw = qfalse; - prev = &r_activeFlares; - while ( ( f = *prev ) != NULL ) { - // throw out any flares that weren't added last frame - if ( f->addedFrame < backEnd.viewParms.frameCount - 1 ) { - *prev = f->next; - f->next = r_inactiveFlares; - r_inactiveFlares = f; - continue; - } - - // don't draw any here that aren't from this scene / portal - f->drawIntensity = 0; - if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum - && f->inPortal == backEnd.viewParms.isPortal ) { - RB_TestFlare( f ); - if ( f->drawIntensity ) { - draw = qtrue; - } else { - // this flare has completely faded out, so remove it from the chain - *prev = f->next; - f->next = r_inactiveFlares; - r_inactiveFlares = f; - continue; - } - } - - prev = &f->next; - } - - if ( !draw ) { - return; // none visible - } - - if ( backEnd.viewParms.isPortal ) { - qglDisable (GL_CLIP_PLANE0); - } - - Mat4Copy(glState.projection, oldprojection); - Mat4Copy(glState.modelview, oldmodelview); - Mat4Identity(matrix); - GL_SetModelviewMatrix(matrix); - Mat4Ortho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth, - backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight, - -99999, 99999, matrix ); - GL_SetProjectionMatrix(matrix); - - for ( f = r_activeFlares ; f ; f = f->next ) { - if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum - && f->inPortal == backEnd.viewParms.isPortal - && f->drawIntensity ) { - RB_RenderFlare( f ); - } - } - - GL_SetProjectionMatrix(oldprojection); - GL_SetModelviewMatrix(oldmodelview); -} - - - - - diff --git a/code/renderergl2/tr_glsl.c b/code/renderergl2/tr_glsl.c deleted file mode 100644 index 2212c4fe81..0000000000 --- a/code/renderergl2/tr_glsl.c +++ /dev/null @@ -1,1802 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2006-2009 Robert Beckebans - -This file is part of XreaL source code. - -XreaL 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. - -XreaL 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 XreaL source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_glsl.c -#include "tr_local.h" - -void GLSL_BindNullProgram(void); - -extern const char *fallbackShader_bokeh_vp; -extern const char *fallbackShader_bokeh_fp; -extern const char *fallbackShader_calclevels4x_vp; -extern const char *fallbackShader_calclevels4x_fp; -extern const char *fallbackShader_depthblur_vp; -extern const char *fallbackShader_depthblur_fp; -extern const char *fallbackShader_dlight_vp; -extern const char *fallbackShader_dlight_fp; -extern const char *fallbackShader_down4x_vp; -extern const char *fallbackShader_down4x_fp; -extern const char *fallbackShader_fogpass_vp; -extern const char *fallbackShader_fogpass_fp; -extern const char *fallbackShader_generic_vp; -extern const char *fallbackShader_generic_fp; -extern const char *fallbackShader_lightall_vp; -extern const char *fallbackShader_lightall_fp; -extern const char *fallbackShader_pshadow_vp; -extern const char *fallbackShader_pshadow_fp; -extern const char *fallbackShader_shadowfill_vp; -extern const char *fallbackShader_shadowfill_fp; -extern const char *fallbackShader_shadowmask_vp; -extern const char *fallbackShader_shadowmask_fp; -extern const char *fallbackShader_ssao_vp; -extern const char *fallbackShader_ssao_fp; -extern const char *fallbackShader_texturecolor_vp; -extern const char *fallbackShader_texturecolor_fp; -extern const char *fallbackShader_tonemap_vp; -extern const char *fallbackShader_tonemap_fp; - -typedef struct uniformInfo_s -{ - char *name; - int type; -} -uniformInfo_t; - -// These must be in the same order as in uniform_t in tr_local.h. -static uniformInfo_t uniformsInfo[] = -{ - { "u_DiffuseMap", GLSL_INT }, - { "u_LightMap", GLSL_INT }, - { "u_NormalMap", GLSL_INT }, - { "u_DeluxeMap", GLSL_INT }, - { "u_SpecularMap", GLSL_INT }, - - { "u_TextureMap", GLSL_INT }, - { "u_LevelsMap", GLSL_INT }, - { "u_CubeMap", GLSL_INT }, - - { "u_ScreenImageMap", GLSL_INT }, - { "u_ScreenDepthMap", GLSL_INT }, - - { "u_ShadowMap", GLSL_INT }, - { "u_ShadowMap2", GLSL_INT }, - { "u_ShadowMap3", GLSL_INT }, - - { "u_ShadowMvp", GLSL_MAT16 }, - { "u_ShadowMvp2", GLSL_MAT16 }, - { "u_ShadowMvp3", GLSL_MAT16 }, - - { "u_EnableTextures", GLSL_VEC4 }, - - { "u_DiffuseTexMatrix", GLSL_VEC4 }, - { "u_DiffuseTexOffTurb", GLSL_VEC4 }, - { "u_Texture1Env", GLSL_INT }, - - { "u_TCGen0", GLSL_INT }, - { "u_TCGen0Vector0", GLSL_VEC3 }, - { "u_TCGen0Vector1", GLSL_VEC3 }, - - { "u_DeformGen", GLSL_INT }, - { "u_DeformParams", GLSL_FLOAT5 }, - - { "u_ColorGen", GLSL_INT }, - { "u_AlphaGen", GLSL_INT }, - { "u_Color", GLSL_VEC4 }, - { "u_BaseColor", GLSL_VEC4 }, - { "u_VertColor", GLSL_VEC4 }, - - { "u_DlightInfo", GLSL_VEC4 }, - { "u_LightForward", GLSL_VEC3 }, - { "u_LightUp", GLSL_VEC3 }, - { "u_LightRight", GLSL_VEC3 }, - { "u_LightOrigin", GLSL_VEC4 }, - { "u_ModelLightDir", GLSL_VEC3 }, - { "u_LightRadius", GLSL_FLOAT }, - { "u_AmbientLight", GLSL_VEC3 }, - { "u_DirectedLight", GLSL_VEC3 }, - - { "u_PortalRange", GLSL_FLOAT }, - - { "u_FogDistance", GLSL_VEC4 }, - { "u_FogDepth", GLSL_VEC4 }, - { "u_FogEyeT", GLSL_FLOAT }, - { "u_FogColorMask", GLSL_VEC4 }, - - { "u_ModelMatrix", GLSL_MAT16 }, - { "u_ModelViewProjectionMatrix", GLSL_MAT16 }, - - { "u_Time", GLSL_FLOAT }, - { "u_VertexLerp" , GLSL_FLOAT }, - { "u_MaterialInfo", GLSL_VEC2 }, - - { "u_ViewInfo", GLSL_VEC4 }, - { "u_ViewOrigin", GLSL_VEC3 }, - { "u_LocalViewOrigin", GLSL_VEC3 }, - { "u_ViewForward", GLSL_VEC3 }, - { "u_ViewLeft", GLSL_VEC3 }, - { "u_ViewUp", GLSL_VEC3 }, - - { "u_InvTexRes", GLSL_VEC2 }, - { "u_AutoExposureMinMax", GLSL_VEC2 }, - { "u_ToneMinAvgMaxLinear", GLSL_VEC3 }, - - { "u_PrimaryLightOrigin", GLSL_VEC4 }, - { "u_PrimaryLightColor", GLSL_VEC3 }, - { "u_PrimaryLightAmbient", GLSL_VEC3 }, - { "u_PrimaryLightRadius", GLSL_FLOAT } -}; - - -static void GLSL_PrintInfoLog(GLhandleARB object, qboolean developerOnly) -{ - char *msg; - static char msgPart[1024]; - int maxLength = 0; - int i; - int printLevel = developerOnly ? PRINT_DEVELOPER : PRINT_ALL; - - qglGetObjectParameterivARB(object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &maxLength); - - if (maxLength <= 0) - { - ri.Printf(printLevel, "No compile log.\n"); - return; - } - - ri.Printf(printLevel, "compile log:\n"); - - if (maxLength < 1023) - { - qglGetInfoLogARB(object, maxLength, &maxLength, msgPart); - - msgPart[maxLength + 1] = '\0'; - - ri.Printf(printLevel, "%s\n", msgPart); - } - else - { - msg = ri.Malloc(maxLength); - - qglGetInfoLogARB(object, maxLength, &maxLength, msg); - - for(i = 0; i < maxLength; i += 1024) - { - Q_strncpyz(msgPart, msg + i, sizeof(msgPart)); - - ri.Printf(printLevel, "%s\n", msgPart); - } - - ri.Free(msg); - } -} - -static void GLSL_PrintShaderSource(GLhandleARB object) -{ - char *msg; - static char msgPart[1024]; - int maxLength = 0; - int i; - - qglGetObjectParameterivARB(object, GL_OBJECT_SHADER_SOURCE_LENGTH_ARB, &maxLength); - - msg = ri.Malloc(maxLength); - - qglGetShaderSourceARB(object, maxLength, &maxLength, msg); - - for(i = 0; i < maxLength; i += 1024) - { - Q_strncpyz(msgPart, msg + i, sizeof(msgPart)); - ri.Printf(PRINT_ALL, "%s\n", msgPart); - } - - ri.Free(msg); -} - -static void GLSL_GetShaderHeader( GLenum shaderType, const GLcharARB *extra, char *dest, int size ) -{ - float fbufWidthScale, fbufHeightScale; - - dest[0] = '\0'; - - // HACK: abuse the GLSL preprocessor to turn GLSL 1.20 shaders into 1.30 ones - if(glRefConfig.glslMajorVersion > 1 || (glRefConfig.glslMajorVersion == 1 && glRefConfig.glslMinorVersion >= 30)) - { - Q_strcat(dest, size, "#version 130\n"); - - if(shaderType == GL_VERTEX_SHADER_ARB) - { - Q_strcat(dest, size, "#define attribute in\n"); - Q_strcat(dest, size, "#define varying out\n"); - } - else - { - Q_strcat(dest, size, "#define varying in\n"); - - Q_strcat(dest, size, "out vec4 out_Color;\n"); - Q_strcat(dest, size, "#define gl_FragColor out_Color\n"); - } - } - else - { - Q_strcat(dest, size, "#version 120\n"); - } - - // HACK: add some macros to avoid extra uniforms and save speed and code maintenance - //Q_strcat(dest, size, - // va("#ifndef r_SpecularExponent\n#define r_SpecularExponent %f\n#endif\n", r_specularExponent->value)); - //Q_strcat(dest, size, - // va("#ifndef r_SpecularScale\n#define r_SpecularScale %f\n#endif\n", r_specularScale->value)); - //Q_strcat(dest, size, - // va("#ifndef r_NormalScale\n#define r_NormalScale %f\n#endif\n", r_normalScale->value)); - - - Q_strcat(dest, size, "#ifndef M_PI\n#define M_PI 3.14159265358979323846f\n#endif\n"); - - //Q_strcat(dest, size, va("#ifndef MAX_SHADOWMAPS\n#define MAX_SHADOWMAPS %i\n#endif\n", MAX_SHADOWMAPS)); - - Q_strcat(dest, size, - va("#ifndef deformGen_t\n" - "#define deformGen_t\n" - "#define DGEN_WAVE_SIN %i\n" - "#define DGEN_WAVE_SQUARE %i\n" - "#define DGEN_WAVE_TRIANGLE %i\n" - "#define DGEN_WAVE_SAWTOOTH %i\n" - "#define DGEN_WAVE_INVERSE_SAWTOOTH %i\n" - "#define DGEN_BULGE %i\n" - "#define DGEN_MOVE %i\n" - "#endif\n", - DGEN_WAVE_SIN, - DGEN_WAVE_SQUARE, - DGEN_WAVE_TRIANGLE, - DGEN_WAVE_SAWTOOTH, - DGEN_WAVE_INVERSE_SAWTOOTH, - DGEN_BULGE, - DGEN_MOVE)); - - Q_strcat(dest, size, - va("#ifndef tcGen_t\n" - "#define tcGen_t\n" - "#define TCGEN_LIGHTMAP %i\n" - "#define TCGEN_TEXTURE %i\n" - "#define TCGEN_ENVIRONMENT_MAPPED %i\n" - "#define TCGEN_FOG %i\n" - "#define TCGEN_VECTOR %i\n" - "#endif\n", - TCGEN_LIGHTMAP, - TCGEN_TEXTURE, - TCGEN_ENVIRONMENT_MAPPED, - TCGEN_FOG, - TCGEN_VECTOR)); - - Q_strcat(dest, size, - va("#ifndef colorGen_t\n" - "#define colorGen_t\n" - "#define CGEN_LIGHTING_DIFFUSE %i\n" - "#endif\n", - CGEN_LIGHTING_DIFFUSE)); - - Q_strcat(dest, size, - va("#ifndef alphaGen_t\n" - "#define alphaGen_t\n" - "#define AGEN_LIGHTING_SPECULAR %i\n" - "#define AGEN_PORTAL %i\n" - "#endif\n", - AGEN_LIGHTING_SPECULAR, - AGEN_PORTAL)); - - Q_strcat(dest, size, - va("#ifndef texenv_t\n" - "#define texenv_t\n" - "#define TEXENV_MODULATE %i\n" - "#define TEXENV_ADD %i\n" - "#define TEXENV_REPLACE %i\n" - "#endif\n", - GL_MODULATE, - GL_ADD, - GL_REPLACE)); - - fbufWidthScale = 1.0f / ((float)glConfig.vidWidth); - fbufHeightScale = 1.0f / ((float)glConfig.vidHeight); - Q_strcat(dest, size, - va("#ifndef r_FBufScale\n#define r_FBufScale vec2(%f, %f)\n#endif\n", fbufWidthScale, fbufHeightScale)); - - if (extra) - { - Q_strcat(dest, size, extra); - } - - // OK we added a lot of stuff but if we do something bad in the GLSL shaders then we want the proper line - // so we have to reset the line counting - Q_strcat(dest, size, "#line 0\n"); -} - -static int GLSL_CompileGPUShader(GLhandleARB program, GLhandleARB *prevShader, const GLcharARB *buffer, int size, GLenum shaderType) -{ - GLint compiled; - GLhandleARB shader; - - shader = qglCreateShaderObjectARB(shaderType); - - qglShaderSourceARB(shader, 1, (const GLcharARB **)&buffer, &size); - - // compile shader - qglCompileShaderARB(shader); - - // check if shader compiled - qglGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &compiled); - if(!compiled) - { - GLSL_PrintShaderSource(shader); - GLSL_PrintInfoLog(shader, qfalse); - ri.Error(ERR_DROP, "Couldn't compile shader"); - return 0; - } - - //GLSL_PrintInfoLog(shader, qtrue); - //GLSL_PrintShaderSource(shader); - - if (*prevShader) - { - qglDetachObjectARB(program, *prevShader); - qglDeleteObjectARB(*prevShader); - } - - // attach shader to program - qglAttachObjectARB(program, shader); - - *prevShader = shader; - - return 1; -} - -static int GLSL_LoadGPUShaderText(const char *name, const char *fallback, - GLenum shaderType, char *dest, int destSize) -{ - char filename[MAX_QPATH]; - GLcharARB *buffer = NULL; - const GLcharARB *shaderText = NULL; - int size; - int result; - - if(shaderType == GL_VERTEX_SHADER_ARB) - { - Com_sprintf(filename, sizeof(filename), "glsl/%s_vp.glsl", name); - } - else - { - Com_sprintf(filename, sizeof(filename), "glsl/%s_fp.glsl", name); - } - - ri.Printf(PRINT_DEVELOPER, "...loading '%s'\n", filename); - size = ri.FS_ReadFile(filename, (void **)&buffer); - if(!buffer) - { - if (fallback) - { - ri.Printf(PRINT_DEVELOPER, "couldn't load, using fallback\n"); - shaderText = fallback; - size = strlen(shaderText); - } - else - { - ri.Printf(PRINT_DEVELOPER, "couldn't load!\n"); - return 0; - } - } - else - { - shaderText = buffer; - } - - if (size > destSize) - { - result = 0; - } - else - { - Q_strncpyz(dest, shaderText, size + 1); - result = 1; - } - - if (buffer) - { - ri.FS_FreeFile(buffer); - } - - return result; -} - -static void GLSL_LinkProgram(GLhandleARB program) -{ - GLint linked; - - qglLinkProgramARB(program); - - qglGetObjectParameterivARB(program, GL_OBJECT_LINK_STATUS_ARB, &linked); - if(!linked) - { - GLSL_PrintInfoLog(program, qfalse); - ri.Printf(PRINT_ALL, "\n"); - ri.Error(ERR_DROP, "shaders failed to link"); - } -} - -static void GLSL_ValidateProgram(GLhandleARB program) -{ - GLint validated; - - qglValidateProgramARB(program); - - qglGetObjectParameterivARB(program, GL_OBJECT_VALIDATE_STATUS_ARB, &validated); - if(!validated) - { - GLSL_PrintInfoLog(program, qfalse); - ri.Printf(PRINT_ALL, "\n"); - ri.Error(ERR_DROP, "shaders failed to validate"); - } -} - -static void GLSL_ShowProgramUniforms(GLhandleARB program) -{ - int i, count, size; - GLenum type; - char uniformName[1000]; - - // install the executables in the program object as part of current state. - qglUseProgramObjectARB(program); - - // check for GL Errors - - // query the number of active uniforms - qglGetObjectParameterivARB(program, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &count); - - // Loop over each of the active uniforms, and set their value - for(i = 0; i < count; i++) - { - qglGetActiveUniformARB(program, i, sizeof(uniformName), NULL, &size, &type, uniformName); - - ri.Printf(PRINT_DEVELOPER, "active uniform: '%s'\n", uniformName); - } - - qglUseProgramObjectARB(0); -} - -static int GLSL_InitGPUShader2(shaderProgram_t * program, const char *name, int attribs, const char *vpCode, const char *fpCode) -{ - ri.Printf(PRINT_DEVELOPER, "------- GPU shader -------\n"); - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "GLSL_InitGPUShader2: \"%s\" is too long", name); - } - - Q_strncpyz(program->name, name, sizeof(program->name)); - - program->program = qglCreateProgramObjectARB(); - program->attribs = attribs; - - if (!(GLSL_CompileGPUShader(program->program, &program->vertexShader, vpCode, strlen(vpCode), GL_VERTEX_SHADER_ARB))) - { - ri.Printf(PRINT_ALL, "GLSL_InitGPUShader2: Unable to load \"%s\" as GL_VERTEX_SHADER_ARB\n", name); - qglDeleteObjectARB(program->program); - return 0; - } - - if(fpCode) - { - if(!(GLSL_CompileGPUShader(program->program, &program->fragmentShader, fpCode, strlen(fpCode), GL_FRAGMENT_SHADER_ARB))) - { - ri.Printf(PRINT_ALL, "GLSL_InitGPUShader2: Unable to load \"%s\" as GL_FRAGMENT_SHADER_ARB\n", name); - qglDeleteObjectARB(program->program); - return 0; - } - } - - if(attribs & ATTR_POSITION) - qglBindAttribLocationARB(program->program, ATTR_INDEX_POSITION, "attr_Position"); - - if(attribs & ATTR_TEXCOORD) - qglBindAttribLocationARB(program->program, ATTR_INDEX_TEXCOORD0, "attr_TexCoord0"); - - if(attribs & ATTR_LIGHTCOORD) - qglBindAttribLocationARB(program->program, ATTR_INDEX_TEXCOORD1, "attr_TexCoord1"); - -// if(attribs & ATTR_TEXCOORD2) -// qglBindAttribLocationARB(program->program, ATTR_INDEX_TEXCOORD2, "attr_TexCoord2"); - -// if(attribs & ATTR_TEXCOORD3) -// qglBindAttribLocationARB(program->program, ATTR_INDEX_TEXCOORD3, "attr_TexCoord3"); - -#ifdef USE_VERT_TANGENT_SPACE - if(attribs & ATTR_TANGENT) - qglBindAttribLocationARB(program->program, ATTR_INDEX_TANGENT, "attr_Tangent"); -#endif - - if(attribs & ATTR_NORMAL) - qglBindAttribLocationARB(program->program, ATTR_INDEX_NORMAL, "attr_Normal"); - - if(attribs & ATTR_COLOR) - qglBindAttribLocationARB(program->program, ATTR_INDEX_COLOR, "attr_Color"); - - if(attribs & ATTR_PAINTCOLOR) - qglBindAttribLocationARB(program->program, ATTR_INDEX_PAINTCOLOR, "attr_PaintColor"); - - if(attribs & ATTR_LIGHTDIRECTION) - qglBindAttribLocationARB(program->program, ATTR_INDEX_LIGHTDIRECTION, "attr_LightDirection"); - - if(attribs & ATTR_POSITION2) - qglBindAttribLocationARB(program->program, ATTR_INDEX_POSITION2, "attr_Position2"); - - if(attribs & ATTR_NORMAL2) - qglBindAttribLocationARB(program->program, ATTR_INDEX_NORMAL2, "attr_Normal2"); - -#ifdef USE_VERT_TANGENT_SPACE - if(attribs & ATTR_TANGENT2) - qglBindAttribLocationARB(program->program, ATTR_INDEX_TANGENT2, "attr_Tangent2"); -#endif - - GLSL_LinkProgram(program->program); - - return 1; -} - -static int GLSL_InitGPUShader(shaderProgram_t * program, const char *name, - int attribs, qboolean fragmentShader, const GLcharARB *extra, qboolean addHeader, - const char *fallback_vp, const char *fallback_fp) -{ - char vpCode[32000]; - char fpCode[32000]; - char *postHeader; - int size; - int result; - - size = sizeof(vpCode); - if (addHeader) - { - GLSL_GetShaderHeader(GL_VERTEX_SHADER_ARB, extra, vpCode, size); - postHeader = &vpCode[strlen(vpCode)]; - size -= strlen(vpCode); - } - else - { - postHeader = &vpCode[0]; - } - - if (!GLSL_LoadGPUShaderText(name, fallback_vp, GL_VERTEX_SHADER_ARB, postHeader, size)) - { - return 0; - } - - if (fragmentShader) - { - size = sizeof(fpCode); - if (addHeader) - { - GLSL_GetShaderHeader(GL_FRAGMENT_SHADER_ARB, extra, fpCode, size); - postHeader = &fpCode[strlen(fpCode)]; - size -= strlen(fpCode); - } - else - { - postHeader = &fpCode[0]; - } - - if (!GLSL_LoadGPUShaderText(name, fallback_fp, GL_FRAGMENT_SHADER_ARB, postHeader, size)) - { - return 0; - } - } - - result = GLSL_InitGPUShader2(program, name, attribs, vpCode, fragmentShader ? fpCode : NULL); - - return result; -} - -void GLSL_InitUniforms(shaderProgram_t *program) -{ - int i, size; - - GLint *uniforms = program->uniforms; - - size = 0; - for (i = 0; i < UNIFORM_COUNT; i++) - { - uniforms[i] = qglGetUniformLocationARB(program->program, uniformsInfo[i].name); - - if (uniforms[i] == -1) - continue; - - program->uniformBufferOffsets[i] = size; - - switch(uniformsInfo[i].type) - { - case GLSL_INT: - size += sizeof(GLint); - break; - case GLSL_FLOAT: - size += sizeof(GLfloat); - break; - case GLSL_FLOAT5: - size += sizeof(vec_t) * 5; - break; - case GLSL_VEC2: - size += sizeof(vec_t) * 2; - break; - case GLSL_VEC3: - size += sizeof(vec_t) * 3; - break; - case GLSL_VEC4: - size += sizeof(vec_t) * 4; - break; - case GLSL_MAT16: - size += sizeof(vec_t) * 16; - break; - default: - break; - } - } - - program->uniformBuffer = ri.Malloc(size); -} - -void GLSL_FinishGPUShader(shaderProgram_t *program) -{ - GLSL_ValidateProgram(program->program); - GLSL_ShowProgramUniforms(program->program); - GL_CheckErrors(); -} - -void GLSL_SetUniformInt(shaderProgram_t *program, int uniformNum, GLint value) -{ - GLint *uniforms = program->uniforms; - GLint *compare = (GLint *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (uniformsInfo[uniformNum].type != GLSL_INT) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformInt: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (value == *compare) - { - return; - } - - *compare = value; - - qglUniform1iARB(uniforms[uniformNum], value); -} - -void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat value) -{ - GLint *uniforms = program->uniforms; - GLfloat *compare = (GLfloat *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (uniformsInfo[uniformNum].type != GLSL_FLOAT) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformFloat: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (value == *compare) - { - return; - } - - *compare = value; - - qglUniform1fARB(uniforms[uniformNum], value); -} - -void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t v) -{ - GLint *uniforms = program->uniforms; - vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (uniformsInfo[uniformNum].type != GLSL_VEC2) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformVec2: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (v[0] == compare[0] && v[1] == compare[1]) - { - return; - } - - compare[0] = v[0]; - compare[1] = v[1]; - - qglUniform2fARB(uniforms[uniformNum], v[0], v[1]); -} - -void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t v) -{ - GLint *uniforms = program->uniforms; - vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (uniformsInfo[uniformNum].type != GLSL_VEC3) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformVec3: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (VectorCompare(v, compare)) - { - return; - } - - VectorCopy(v, compare); - - qglUniform3fARB(uniforms[uniformNum], v[0], v[1], v[2]); -} - -void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t v) -{ - GLint *uniforms = program->uniforms; - vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (uniformsInfo[uniformNum].type != GLSL_VEC4) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformVec4: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (VectorCompare4(v, compare)) - { - return; - } - - VectorCopy4(v, compare); - - qglUniform4fARB(uniforms[uniformNum], v[0], v[1], v[2], v[3]); -} - -void GLSL_SetUniformFloat5(shaderProgram_t *program, int uniformNum, const vec5_t v) -{ - GLint *uniforms = program->uniforms; - vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (uniformsInfo[uniformNum].type != GLSL_FLOAT5) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformFloat5: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (VectorCompare5(v, compare)) - { - return; - } - - VectorCopy5(v, compare); - - qglUniform1fvARB(uniforms[uniformNum], 5, v); -} - -void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t matrix) -{ - GLint *uniforms = program->uniforms; - vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (uniformsInfo[uniformNum].type != GLSL_MAT16) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformMat4: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (Mat4Compare(matrix, compare)) - { - return; - } - - Mat4Copy(matrix, compare); - - qglUniformMatrix4fvARB(uniforms[uniformNum], 1, GL_FALSE, matrix); -} - -void GLSL_DeleteGPUShader(shaderProgram_t *program) -{ - if(program->program) - { - if (program->vertexShader) - { - qglDetachObjectARB(program->program, program->vertexShader); - qglDeleteObjectARB(program->vertexShader); - } - - if (program->fragmentShader) - { - qglDetachObjectARB(program->program, program->fragmentShader); - qglDeleteObjectARB(program->fragmentShader); - } - - qglDeleteObjectARB(program->program); - - if (program->uniformBuffer) - { - ri.Free(program->uniformBuffer); - } - - Com_Memset(program, 0, sizeof(*program)); - } -} - -void GLSL_InitGPUShaders(void) -{ - int startTime, endTime; - int i; - char extradefines[1024]; - int attribs; - int numGenShaders = 0, numLightShaders = 0, numEtcShaders = 0; - - ri.Printf(PRINT_ALL, "------- GLSL_InitGPUShaders -------\n"); - - R_IssuePendingRenderCommands(); - - startTime = ri.Milliseconds(); - - for (i = 0; i < GENERICDEF_COUNT; i++) - { - attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_NORMAL | ATTR_COLOR; - extradefines[0] = '\0'; - - if (i & GENERICDEF_USE_DEFORM_VERTEXES) - Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n"); - - if (i & GENERICDEF_USE_TCGEN_AND_TCMOD) - { - Q_strcat(extradefines, 1024, "#define USE_TCGEN\n"); - Q_strcat(extradefines, 1024, "#define USE_TCMOD\n"); - } - - if (i & GENERICDEF_USE_VERTEX_ANIMATION) - { - Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n"); - attribs |= ATTR_POSITION2 | ATTR_NORMAL2; - } - - if (i & GENERICDEF_USE_FOG) - Q_strcat(extradefines, 1024, "#define USE_FOG\n"); - - if (i & GENERICDEF_USE_RGBAGEN) - Q_strcat(extradefines, 1024, "#define USE_RGBAGEN\n"); - - if (i & GENERICDEF_USE_LIGHTMAP) - Q_strcat(extradefines, 1024, "#define USE_LIGHTMAP\n"); - - if (r_hdr->integer && !(glRefConfig.textureFloat && glRefConfig.halfFloatPixel && r_floatLightmap->integer)) - Q_strcat(extradefines, 1024, "#define RGBM_LIGHTMAP\n"); - - if (!GLSL_InitGPUShader(&tr.genericShader[i], "generic", attribs, qtrue, extradefines, qtrue, fallbackShader_generic_vp, fallbackShader_generic_fp)) - { - ri.Error(ERR_FATAL, "Could not load generic shader!"); - } - - GLSL_InitUniforms(&tr.genericShader[i]); - - qglUseProgramObjectARB(tr.genericShader[i].program); - GLSL_SetUniformInt(&tr.genericShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); - GLSL_SetUniformInt(&tr.genericShader[i], UNIFORM_LIGHTMAP, TB_LIGHTMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.genericShader[i]); - - numGenShaders++; - } - - - attribs = ATTR_POSITION | ATTR_TEXCOORD; - - if (!GLSL_InitGPUShader(&tr.textureColorShader, "texturecolor", attribs, qtrue, NULL, qfalse, fallbackShader_texturecolor_vp, fallbackShader_texturecolor_fp)) - { - ri.Error(ERR_FATAL, "Could not load texturecolor shader!"); - } - - GLSL_InitUniforms(&tr.textureColorShader); - - qglUseProgramObjectARB(tr.textureColorShader.program); - GLSL_SetUniformInt(&tr.textureColorShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.textureColorShader); - - numEtcShaders++; - - for (i = 0; i < FOGDEF_COUNT; i++) - { - attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (i & FOGDEF_USE_DEFORM_VERTEXES) - Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n"); - - if (i & FOGDEF_USE_VERTEX_ANIMATION) - Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n"); - - if (!GLSL_InitGPUShader(&tr.fogShader[i], "fogpass", attribs, qtrue, extradefines, qtrue, fallbackShader_fogpass_vp, fallbackShader_fogpass_fp)) - { - ri.Error(ERR_FATAL, "Could not load fogpass shader!"); - } - - GLSL_InitUniforms(&tr.fogShader[i]); - GLSL_FinishGPUShader(&tr.fogShader[i]); - - numEtcShaders++; - } - - - for (i = 0; i < DLIGHTDEF_COUNT; i++) - { - attribs = ATTR_POSITION | ATTR_NORMAL | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (i & DLIGHTDEF_USE_DEFORM_VERTEXES) - { - Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n"); - } - - if (!GLSL_InitGPUShader(&tr.dlightShader[i], "dlight", attribs, qtrue, extradefines, qtrue, fallbackShader_dlight_vp, fallbackShader_dlight_fp)) - { - ri.Error(ERR_FATAL, "Could not load dlight shader!"); - } - - GLSL_InitUniforms(&tr.dlightShader[i]); - - qglUseProgramObjectARB(tr.dlightShader[i].program); - GLSL_SetUniformInt(&tr.dlightShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.dlightShader[i]); - - numEtcShaders++; - } - - - for (i = 0; i < LIGHTDEF_COUNT; i++) - { - int lightType = i & LIGHTDEF_LIGHTTYPE_MASK; - qboolean fastLight = !(r_normalMapping->integer || r_specularMapping->integer); - - // skip impossible combos - if ((i & LIGHTDEF_USE_PARALLAXMAP) && !r_parallaxMapping->integer) - continue; - - if (!lightType && (i & LIGHTDEF_USE_PARALLAXMAP)) - continue; - - if (!lightType && (i & LIGHTDEF_USE_SHADOWMAP)) - continue; - - attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_COLOR | ATTR_NORMAL; - - extradefines[0] = '\0'; - - if (r_deluxeSpecular->value > 0.000001f) - Q_strcat(extradefines, 1024, va("#define r_deluxeSpecular %f\n", r_deluxeSpecular->value)); - - if (r_specularIsMetallic->value) - Q_strcat(extradefines, 1024, "#define SPECULAR_IS_METALLIC\n"); - - if (r_dlightMode->integer >= 2) - Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n"); - - if (1) - Q_strcat(extradefines, 1024, "#define SWIZZLE_NORMALMAP\n"); - - if (r_hdr->integer && !(glRefConfig.textureFloat && glRefConfig.halfFloatPixel && r_floatLightmap->integer)) - Q_strcat(extradefines, 1024, "#define RGBM_LIGHTMAP\n"); - - if (lightType) - { - Q_strcat(extradefines, 1024, "#define USE_LIGHT\n"); - - if (fastLight) - Q_strcat(extradefines, 1024, "#define USE_FAST_LIGHT\n"); - - switch (lightType) - { - case LIGHTDEF_USE_LIGHTMAP: - Q_strcat(extradefines, 1024, "#define USE_LIGHTMAP\n"); - if (r_deluxeMapping->integer && !fastLight) - Q_strcat(extradefines, 1024, "#define USE_DELUXEMAP\n"); - attribs |= ATTR_LIGHTCOORD | ATTR_LIGHTDIRECTION; - break; - case LIGHTDEF_USE_LIGHT_VECTOR: - Q_strcat(extradefines, 1024, "#define USE_LIGHT_VECTOR\n"); - break; - case LIGHTDEF_USE_LIGHT_VERTEX: - Q_strcat(extradefines, 1024, "#define USE_LIGHT_VERTEX\n"); - attribs |= ATTR_LIGHTDIRECTION; - break; - default: - break; - } - - if (r_normalMapping->integer) - { - Q_strcat(extradefines, 1024, "#define USE_NORMALMAP\n"); - - if (r_normalMapping->integer == 2) - Q_strcat(extradefines, 1024, "#define USE_OREN_NAYAR\n"); - - if (r_normalMapping->integer == 3) - Q_strcat(extradefines, 1024, "#define USE_TRIACE_OREN_NAYAR\n"); - -#ifdef USE_VERT_TANGENT_SPACE - Q_strcat(extradefines, 1024, "#define USE_VERT_TANGENT_SPACE\n"); - attribs |= ATTR_TANGENT; -#endif - - if ((i & LIGHTDEF_USE_PARALLAXMAP) && !(i & LIGHTDEF_ENTITY) && r_parallaxMapping->integer) - Q_strcat(extradefines, 1024, "#define USE_PARALLAXMAP\n"); - } - - if (r_specularMapping->integer) - { - Q_strcat(extradefines, 1024, "#define USE_SPECULARMAP\n"); - - switch (r_specularMapping->integer) - { - case 1: - default: - Q_strcat(extradefines, 1024, "#define USE_BLINN\n"); - break; - - case 2: - Q_strcat(extradefines, 1024, "#define USE_BLINN_FRESNEL\n"); - break; - - case 3: - Q_strcat(extradefines, 1024, "#define USE_MCAULEY\n"); - break; - - case 4: - Q_strcat(extradefines, 1024, "#define USE_GOTANDA\n"); - break; - - case 5: - Q_strcat(extradefines, 1024, "#define USE_LAZAROV\n"); - break; - } - } - - if (r_cubeMapping->integer) - Q_strcat(extradefines, 1024, "#define USE_CUBEMAP\n"); - } - - if (i & LIGHTDEF_USE_SHADOWMAP) - { - Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n"); - - if (r_sunlightMode->integer == 1) - Q_strcat(extradefines, 1024, "#define SHADOWMAP_MODULATE\n"); - else if (r_sunlightMode->integer == 2) - Q_strcat(extradefines, 1024, "#define USE_PRIMARY_LIGHT\n"); - } - - if (i & LIGHTDEF_USE_TCGEN_AND_TCMOD) - { - Q_strcat(extradefines, 1024, "#define USE_TCGEN\n"); - Q_strcat(extradefines, 1024, "#define USE_TCMOD\n"); - } - - if (i & LIGHTDEF_ENTITY) - { - Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n#define USE_MODELMATRIX\n"); - attribs |= ATTR_POSITION2 | ATTR_NORMAL2; - -#ifdef USE_VERT_TANGENT_SPACE - if (r_normalMapping->integer) - { - attribs |= ATTR_TANGENT2; - } -#endif - } - - if (!GLSL_InitGPUShader(&tr.lightallShader[i], "lightall", attribs, qtrue, extradefines, qtrue, fallbackShader_lightall_vp, fallbackShader_lightall_fp)) - { - ri.Error(ERR_FATAL, "Could not load lightall shader!"); - } - - GLSL_InitUniforms(&tr.lightallShader[i]); - - qglUseProgramObjectARB(tr.lightallShader[i].program); - GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_LIGHTMAP, TB_LIGHTMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_NORMALMAP, TB_NORMALMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_DELUXEMAP, TB_DELUXEMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SPECULARMAP, TB_SPECULARMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SHADOWMAP, TB_SHADOWMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_CUBEMAP, TB_CUBEMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.lightallShader[i]); - - numLightShaders++; - } - - attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD; - - extradefines[0] = '\0'; - - if (!GLSL_InitGPUShader(&tr.shadowmapShader, "shadowfill", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowfill_vp, fallbackShader_shadowfill_fp)) - { - ri.Error(ERR_FATAL, "Could not load shadowfill shader!"); - } - - GLSL_InitUniforms(&tr.shadowmapShader); - GLSL_FinishGPUShader(&tr.shadowmapShader); - - numEtcShaders++; - - attribs = ATTR_POSITION | ATTR_NORMAL; - extradefines[0] = '\0'; - - Q_strcat(extradefines, 1024, "#define USE_PCF\n#define USE_DISCARD\n"); - - if (!GLSL_InitGPUShader(&tr.pshadowShader, "pshadow", attribs, qtrue, extradefines, qtrue, fallbackShader_pshadow_vp, fallbackShader_pshadow_fp)) - { - ri.Error(ERR_FATAL, "Could not load pshadow shader!"); - } - - GLSL_InitUniforms(&tr.pshadowShader); - - qglUseProgramObjectARB(tr.pshadowShader.program); - GLSL_SetUniformInt(&tr.pshadowShader, UNIFORM_SHADOWMAP, TB_DIFFUSEMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.pshadowShader); - - numEtcShaders++; - - - attribs = ATTR_POSITION | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (!GLSL_InitGPUShader(&tr.down4xShader, "down4x", attribs, qtrue, extradefines, qtrue, fallbackShader_down4x_vp, fallbackShader_down4x_fp)) - { - ri.Error(ERR_FATAL, "Could not load down4x shader!"); - } - - GLSL_InitUniforms(&tr.down4xShader); - - qglUseProgramObjectARB(tr.down4xShader.program); - GLSL_SetUniformInt(&tr.down4xShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.down4xShader); - - numEtcShaders++; - - - attribs = ATTR_POSITION | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (!GLSL_InitGPUShader(&tr.bokehShader, "bokeh", attribs, qtrue, extradefines, qtrue, fallbackShader_bokeh_vp, fallbackShader_bokeh_fp)) - { - ri.Error(ERR_FATAL, "Could not load bokeh shader!"); - } - - GLSL_InitUniforms(&tr.bokehShader); - - qglUseProgramObjectARB(tr.bokehShader.program); - GLSL_SetUniformInt(&tr.bokehShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.bokehShader); - - numEtcShaders++; - - - attribs = ATTR_POSITION | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (!GLSL_InitGPUShader(&tr.tonemapShader, "tonemap", attribs, qtrue, extradefines, qtrue, fallbackShader_tonemap_vp, fallbackShader_tonemap_fp)) - { - ri.Error(ERR_FATAL, "Could not load tonemap shader!"); - } - - GLSL_InitUniforms(&tr.tonemapShader); - - qglUseProgramObjectARB(tr.tonemapShader.program); - GLSL_SetUniformInt(&tr.tonemapShader, UNIFORM_TEXTUREMAP, TB_COLORMAP); - GLSL_SetUniformInt(&tr.tonemapShader, UNIFORM_LEVELSMAP, TB_LEVELSMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.tonemapShader); - - numEtcShaders++; - - - for (i = 0; i < 2; i++) - { - attribs = ATTR_POSITION | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (!i) - Q_strcat(extradefines, 1024, "#define FIRST_PASS\n"); - - if (!GLSL_InitGPUShader(&tr.calclevels4xShader[i], "calclevels4x", attribs, qtrue, extradefines, qtrue, fallbackShader_calclevels4x_vp, fallbackShader_calclevels4x_fp)) - { - ri.Error(ERR_FATAL, "Could not load calclevels4x shader!"); - } - - GLSL_InitUniforms(&tr.calclevels4xShader[i]); - - qglUseProgramObjectARB(tr.calclevels4xShader[i].program); - GLSL_SetUniformInt(&tr.calclevels4xShader[i], UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.calclevels4xShader[i]); - - numEtcShaders++; - } - - - attribs = ATTR_POSITION | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (r_shadowFilter->integer >= 1) - Q_strcat(extradefines, 1024, "#define USE_SHADOW_FILTER\n"); - - if (r_shadowFilter->integer >= 2) - Q_strcat(extradefines, 1024, "#define USE_SHADOW_FILTER2\n"); - - Q_strcat(extradefines, 1024, "#define USE_SHADOW_CASCADE\n"); - - Q_strcat(extradefines, 1024, va("#define r_shadowMapSize %d\n", r_shadowMapSize->integer)); - Q_strcat(extradefines, 1024, va("#define r_shadowCascadeZFar %f\n", r_shadowCascadeZFar->value)); - - - if (!GLSL_InitGPUShader(&tr.shadowmaskShader, "shadowmask", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowmask_vp, fallbackShader_shadowmask_fp)) - { - ri.Error(ERR_FATAL, "Could not load shadowmask shader!"); - } - - GLSL_InitUniforms(&tr.shadowmaskShader); - - qglUseProgramObjectARB(tr.shadowmaskShader.program); - GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SCREENDEPTHMAP, TB_COLORMAP); - GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP, TB_SHADOWMAP); - GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP2, TB_SHADOWMAP2); - GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP3, TB_SHADOWMAP3); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.shadowmaskShader); - - numEtcShaders++; - - - attribs = ATTR_POSITION | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (!GLSL_InitGPUShader(&tr.ssaoShader, "ssao", attribs, qtrue, extradefines, qtrue, fallbackShader_ssao_vp, fallbackShader_ssao_fp)) - { - ri.Error(ERR_FATAL, "Could not load ssao shader!"); - } - - GLSL_InitUniforms(&tr.ssaoShader); - - qglUseProgramObjectARB(tr.ssaoShader.program); - GLSL_SetUniformInt(&tr.ssaoShader, UNIFORM_SCREENDEPTHMAP, TB_COLORMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.ssaoShader); - - numEtcShaders++; - - - for (i = 0; i < 2; i++) - { - attribs = ATTR_POSITION | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (i & 1) - Q_strcat(extradefines, 1024, "#define USE_VERTICAL_BLUR\n"); - else - Q_strcat(extradefines, 1024, "#define USE_HORIZONTAL_BLUR\n"); - - - if (!GLSL_InitGPUShader(&tr.depthBlurShader[i], "depthBlur", attribs, qtrue, extradefines, qtrue, fallbackShader_depthblur_vp, fallbackShader_depthblur_fp)) - { - ri.Error(ERR_FATAL, "Could not load depthBlur shader!"); - } - - GLSL_InitUniforms(&tr.depthBlurShader[i]); - - qglUseProgramObjectARB(tr.depthBlurShader[i].program); - GLSL_SetUniformInt(&tr.depthBlurShader[i], UNIFORM_SCREENIMAGEMAP, TB_COLORMAP); - GLSL_SetUniformInt(&tr.depthBlurShader[i], UNIFORM_SCREENDEPTHMAP, TB_LIGHTMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.depthBlurShader[i]); - - numEtcShaders++; - } - -#if 0 - attribs = ATTR_POSITION | ATTR_TEXCOORD; - extradefines[0] = '\0'; - - if (!GLSL_InitGPUShader(&tr.testcubeShader, "testcube", attribs, qtrue, extradefines, qtrue, NULL, NULL)) - { - ri.Error(ERR_FATAL, "Could not load testcube shader!"); - } - - GLSL_InitUniforms(&tr.testcubeShader); - - qglUseProgramObjectARB(tr.testcubeShader.program); - GLSL_SetUniformInt(&tr.testcubeShader, UNIFORM_TEXTUREMAP, TB_COLORMAP); - qglUseProgramObjectARB(0); - - GLSL_FinishGPUShader(&tr.testcubeShader); - - numEtcShaders++; -#endif - - - endTime = ri.Milliseconds(); - - ri.Printf(PRINT_ALL, "loaded %i GLSL shaders (%i gen %i light %i etc) in %5.2f seconds\n", - numGenShaders + numLightShaders + numEtcShaders, numGenShaders, numLightShaders, - numEtcShaders, (endTime - startTime) / 1000.0); -} - -void GLSL_ShutdownGPUShaders(void) -{ - int i; - - ri.Printf(PRINT_ALL, "------- GLSL_ShutdownGPUShaders -------\n"); - - qglDisableVertexAttribArrayARB(ATTR_INDEX_TEXCOORD0); - qglDisableVertexAttribArrayARB(ATTR_INDEX_TEXCOORD1); - qglDisableVertexAttribArrayARB(ATTR_INDEX_POSITION); - qglDisableVertexAttribArrayARB(ATTR_INDEX_POSITION2); - qglDisableVertexAttribArrayARB(ATTR_INDEX_NORMAL); -#ifdef USE_VERT_TANGENT_SPACE - qglDisableVertexAttribArrayARB(ATTR_INDEX_TANGENT); -#endif - qglDisableVertexAttribArrayARB(ATTR_INDEX_NORMAL2); -#ifdef USE_VERT_TANGENT_SPACE - qglDisableVertexAttribArrayARB(ATTR_INDEX_TANGENT2); -#endif - qglDisableVertexAttribArrayARB(ATTR_INDEX_COLOR); - qglDisableVertexAttribArrayARB(ATTR_INDEX_LIGHTDIRECTION); - GLSL_BindNullProgram(); - - for ( i = 0; i < GENERICDEF_COUNT; i++) - GLSL_DeleteGPUShader(&tr.genericShader[i]); - - GLSL_DeleteGPUShader(&tr.textureColorShader); - - for ( i = 0; i < FOGDEF_COUNT; i++) - GLSL_DeleteGPUShader(&tr.fogShader[i]); - - for ( i = 0; i < DLIGHTDEF_COUNT; i++) - GLSL_DeleteGPUShader(&tr.dlightShader[i]); - - for ( i = 0; i < LIGHTDEF_COUNT; i++) - GLSL_DeleteGPUShader(&tr.lightallShader[i]); - - GLSL_DeleteGPUShader(&tr.shadowmapShader); - GLSL_DeleteGPUShader(&tr.pshadowShader); - GLSL_DeleteGPUShader(&tr.down4xShader); - GLSL_DeleteGPUShader(&tr.bokehShader); - GLSL_DeleteGPUShader(&tr.tonemapShader); - - for ( i = 0; i < 2; i++) - GLSL_DeleteGPUShader(&tr.calclevels4xShader[i]); - - GLSL_DeleteGPUShader(&tr.shadowmaskShader); - GLSL_DeleteGPUShader(&tr.ssaoShader); - - for ( i = 0; i < 2; i++) - GLSL_DeleteGPUShader(&tr.depthBlurShader[i]); - - glState.currentProgram = 0; - qglUseProgramObjectARB(0); -} - - -void GLSL_BindProgram(shaderProgram_t * program) -{ - if(!program) - { - GLSL_BindNullProgram(); - return; - } - - if(r_logFile->integer) - { - // don't just call LogComment, or we will get a call to va() every frame! - GLimp_LogComment(va("--- GL_BindProgram( %s ) ---\n", program->name)); - } - - if(glState.currentProgram != program) - { - qglUseProgramObjectARB(program->program); - glState.currentProgram = program; - backEnd.pc.c_glslShaderBinds++; - } -} - - -void GLSL_BindNullProgram(void) -{ - if(r_logFile->integer) - { - GLimp_LogComment("--- GL_BindNullProgram ---\n"); - } - - if(glState.currentProgram) - { - qglUseProgramObjectARB(0); - glState.currentProgram = NULL; - } -} - - -void GLSL_VertexAttribsState(uint32_t stateBits) -{ - uint32_t diff; - - GLSL_VertexAttribPointers(stateBits); - - diff = stateBits ^ glState.vertexAttribsState; - if(!diff) - { - return; - } - - if(diff & ATTR_POSITION) - { - if(stateBits & ATTR_POSITION) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_POSITION )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_POSITION); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_POSITION )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_POSITION); - } - } - - if(diff & ATTR_TEXCOORD) - { - if(stateBits & ATTR_TEXCOORD) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_TEXCOORD )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_TEXCOORD0); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_TEXCOORD )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_TEXCOORD0); - } - } - - if(diff & ATTR_LIGHTCOORD) - { - if(stateBits & ATTR_LIGHTCOORD) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_LIGHTCOORD )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_TEXCOORD1); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_LIGHTCOORD )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_TEXCOORD1); - } - } - - if(diff & ATTR_NORMAL) - { - if(stateBits & ATTR_NORMAL) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_NORMAL )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_NORMAL); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_NORMAL )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_NORMAL); - } - } - -#ifdef USE_VERT_TANGENT_SPACE - if(diff & ATTR_TANGENT) - { - if(stateBits & ATTR_TANGENT) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_TANGENT )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_TANGENT); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_TANGENT )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_TANGENT); - } - } -#endif - - if(diff & ATTR_COLOR) - { - if(stateBits & ATTR_COLOR) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_COLOR )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_COLOR); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_COLOR )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_COLOR); - } - } - - if(diff & ATTR_LIGHTDIRECTION) - { - if(stateBits & ATTR_LIGHTDIRECTION) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_LIGHTDIRECTION )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_LIGHTDIRECTION); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_LIGHTDIRECTION )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_LIGHTDIRECTION); - } - } - - if(diff & ATTR_POSITION2) - { - if(stateBits & ATTR_POSITION2) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_POSITION2 )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_POSITION2); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_POSITION2 )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_POSITION2); - } - } - - if(diff & ATTR_NORMAL2) - { - if(stateBits & ATTR_NORMAL2) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_NORMAL2 )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_NORMAL2); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_NORMAL2 )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_NORMAL2); - } - } - -#ifdef USE_VERT_TANGENT_SPACE - if(diff & ATTR_TANGENT2) - { - if(stateBits & ATTR_TANGENT2) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_TANGENT2 )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_TANGENT2); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_TANGENT2 )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_TANGENT2); - } - } -#endif - - glState.vertexAttribsState = stateBits; -} - -void GLSL_VertexAttribPointers(uint32_t attribBits) -{ - qboolean animated; - int newFrame, oldFrame; - VBO_t *vbo = glState.currentVBO; - - if(!vbo) - { - ri.Error(ERR_FATAL, "GL_VertexAttribPointers: no VBO bound"); - return; - } - - // don't just call LogComment, or we will get a call to va() every frame! - if(r_logFile->integer) - { - GLimp_LogComment(va("--- GL_VertexAttribPointers( %s ) ---\n", vbo->name)); - } - - // position/normal/tangent are always set in case of animation - oldFrame = glState.vertexAttribsOldFrame; - newFrame = glState.vertexAttribsNewFrame; - animated = glState.vertexAnimation; - - if((attribBits & ATTR_POSITION) && (!(glState.vertexAttribPointersSet & ATTR_POSITION) || animated)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_POSITION )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_POSITION, 3, GL_FLOAT, 0, vbo->stride_xyz, BUFFER_OFFSET(vbo->ofs_xyz + newFrame * vbo->size_xyz)); - glState.vertexAttribPointersSet |= ATTR_POSITION; - } - - if((attribBits & ATTR_TEXCOORD) && !(glState.vertexAttribPointersSet & ATTR_TEXCOORD)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_TEXCOORD )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_TEXCOORD0, 2, GL_FLOAT, 0, vbo->stride_st, BUFFER_OFFSET(vbo->ofs_st)); - glState.vertexAttribPointersSet |= ATTR_TEXCOORD; - } - - if((attribBits & ATTR_LIGHTCOORD) && !(glState.vertexAttribPointersSet & ATTR_LIGHTCOORD)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_LIGHTCOORD )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_TEXCOORD1, 2, GL_FLOAT, 0, vbo->stride_lightmap, BUFFER_OFFSET(vbo->ofs_lightmap)); - glState.vertexAttribPointersSet |= ATTR_LIGHTCOORD; - } - - if((attribBits & ATTR_NORMAL) && (!(glState.vertexAttribPointersSet & ATTR_NORMAL) || animated)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_NORMAL )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_NORMAL, 4, glRefConfig.packedNormalDataType, GL_TRUE, vbo->stride_normal, BUFFER_OFFSET(vbo->ofs_normal + newFrame * vbo->size_normal)); - glState.vertexAttribPointersSet |= ATTR_NORMAL; - } - -#ifdef USE_VERT_TANGENT_SPACE - if((attribBits & ATTR_TANGENT) && (!(glState.vertexAttribPointersSet & ATTR_TANGENT) || animated)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_TANGENT )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_TANGENT, 4, glRefConfig.packedNormalDataType, GL_TRUE, vbo->stride_tangent, BUFFER_OFFSET(vbo->ofs_tangent + newFrame * vbo->size_normal)); // FIXME - glState.vertexAttribPointersSet |= ATTR_TANGENT; - } -#endif - - if((attribBits & ATTR_COLOR) && !(glState.vertexAttribPointersSet & ATTR_COLOR)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_COLOR )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_COLOR, 4, GL_FLOAT, 0, vbo->stride_vertexcolor, BUFFER_OFFSET(vbo->ofs_vertexcolor)); - glState.vertexAttribPointersSet |= ATTR_COLOR; - } - - if((attribBits & ATTR_LIGHTDIRECTION) && !(glState.vertexAttribPointersSet & ATTR_LIGHTDIRECTION)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_LIGHTDIRECTION )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_LIGHTDIRECTION, 4, glRefConfig.packedNormalDataType, GL_TRUE, vbo->stride_lightdir, BUFFER_OFFSET(vbo->ofs_lightdir)); - glState.vertexAttribPointersSet |= ATTR_LIGHTDIRECTION; - } - - if((attribBits & ATTR_POSITION2) && (!(glState.vertexAttribPointersSet & ATTR_POSITION2) || animated)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_POSITION2 )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_POSITION2, 3, GL_FLOAT, 0, vbo->stride_xyz, BUFFER_OFFSET(vbo->ofs_xyz + oldFrame * vbo->size_xyz)); - glState.vertexAttribPointersSet |= ATTR_POSITION2; - } - - if((attribBits & ATTR_NORMAL2) && (!(glState.vertexAttribPointersSet & ATTR_NORMAL2) || animated)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_NORMAL2 )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_NORMAL2, 4, glRefConfig.packedNormalDataType, GL_TRUE, vbo->stride_normal, BUFFER_OFFSET(vbo->ofs_normal + oldFrame * vbo->size_normal)); - glState.vertexAttribPointersSet |= ATTR_NORMAL2; - } - -#ifdef USE_VERT_TANGENT_SPACE - if((attribBits & ATTR_TANGENT2) && (!(glState.vertexAttribPointersSet & ATTR_TANGENT2) || animated)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_TANGENT2 )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_TANGENT2, 4, glRefConfig.packedNormalDataType, GL_TRUE, vbo->stride_tangent, BUFFER_OFFSET(vbo->ofs_tangent + oldFrame * vbo->size_normal)); // FIXME - glState.vertexAttribPointersSet |= ATTR_TANGENT2; - } -#endif - -} - - -shaderProgram_t *GLSL_GetGenericShaderProgram(int stage) -{ - shaderStage_t *pStage = tess.xstages[stage]; - int shaderAttribs = 0; - - if (tess.fogNum && pStage->adjustColorsForFog) - { - shaderAttribs |= GENERICDEF_USE_FOG; - } - - if (pStage->bundle[1].image[0] && tess.shader->multitextureEnv) - { - shaderAttribs |= GENERICDEF_USE_LIGHTMAP; - } - - switch (pStage->rgbGen) - { - case CGEN_LIGHTING_DIFFUSE: - shaderAttribs |= GENERICDEF_USE_RGBAGEN; - break; - default: - break; - } - - switch (pStage->alphaGen) - { - case AGEN_LIGHTING_SPECULAR: - case AGEN_PORTAL: - shaderAttribs |= GENERICDEF_USE_RGBAGEN; - break; - default: - break; - } - - if (pStage->bundle[0].tcGen != TCGEN_TEXTURE) - { - shaderAttribs |= GENERICDEF_USE_TCGEN_AND_TCMOD; - } - - if (tess.shader->numDeforms && !ShaderRequiresCPUDeforms(tess.shader)) - { - shaderAttribs |= GENERICDEF_USE_DEFORM_VERTEXES; - } - - if (glState.vertexAnimation) - { - shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION; - } - - if (pStage->bundle[0].numTexMods) - { - shaderAttribs |= GENERICDEF_USE_TCGEN_AND_TCMOD; - } - - return &tr.genericShader[shaderAttribs]; -} diff --git a/code/renderergl2/tr_image.c b/code/renderergl2/tr_image.c deleted file mode 100644 index 243d27dff3..0000000000 --- a/code/renderergl2/tr_image.c +++ /dev/null @@ -1,3437 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_image.c -#include "tr_local.h" - -static byte s_intensitytable[256]; -static unsigned char s_gammatable[256]; - -int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST; -int gl_filter_max = GL_LINEAR; - -#define FILE_HASH_SIZE 1024 -static image_t* hashTable[FILE_HASH_SIZE]; - -/* -** R_GammaCorrect -*/ -void R_GammaCorrect( byte *buffer, int bufSize ) { - int i; - - for ( i = 0; i < bufSize; i++ ) { - buffer[i] = s_gammatable[buffer[i]]; - } -} - -typedef struct { - char *name; - int minimize, maximize; -} textureMode_t; - -textureMode_t modes[] = { - {"GL_NEAREST", GL_NEAREST, GL_NEAREST}, - {"GL_LINEAR", GL_LINEAR, GL_LINEAR}, - {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, - {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, - {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}, - {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} -}; - -/* -================ -return a hash value for the filename -================ -*/ -static long generateHashValue( const char *fname ) { - int i; - long hash; - char letter; - - hash = 0; - i = 0; - while (fname[i] != '\0') { - letter = tolower(fname[i]); - if (letter =='.') break; // don't include extension - if (letter =='\\') letter = '/'; // damn path names - hash+=(long)(letter)*(i+119); - i++; - } - hash &= (FILE_HASH_SIZE-1); - return hash; -} - -/* -=============== -GL_TextureMode -=============== -*/ -void GL_TextureMode( const char *string ) { - int i; - image_t *glt; - - for ( i=0 ; i< 6 ; i++ ) { - if ( !Q_stricmp( modes[i].name, string ) ) { - break; - } - } - - // hack to prevent trilinear from being set on voodoo, - // because their driver freaks... - if ( i == 5 && glConfig.hardwareType == GLHW_3DFX_2D3D ) { - ri.Printf( PRINT_ALL, "Refusing to set trilinear on a voodoo.\n" ); - i = 3; - } - - - if ( i == 6 ) { - ri.Printf (PRINT_ALL, "bad filter name\n"); - return; - } - - gl_filter_min = modes[i].minimize; - gl_filter_max = modes[i].maximize; - - // change all the existing mipmap texture objects - for ( i = 0 ; i < tr.numImages ; i++ ) { - glt = tr.images[ i ]; - if ( glt->flags & IMGFLAG_MIPMAP ) { - GL_Bind (glt); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); - } - } -} - -/* -=============== -R_SumOfUsedImages -=============== -*/ -int R_SumOfUsedImages( void ) { - int total; - int i; - - total = 0; - for ( i = 0; i < tr.numImages; i++ ) { - if ( tr.images[i]->frameUsed == tr.frameCount ) { - total += tr.images[i]->uploadWidth * tr.images[i]->uploadHeight; - } - } - - return total; -} - -/* -=============== -R_ImageList_f -=============== -*/ -void R_ImageList_f( void ) { - int i; - int estTotalSize = 0; - - ri.Printf(PRINT_ALL, "\n -w-- -h-- type -size- --name-------\n"); - - for ( i = 0 ; i < tr.numImages ; i++ ) - { - image_t *image = tr.images[i]; - char *format = "???? "; - char *sizeSuffix; - int estSize; - int displaySize; - - estSize = image->uploadHeight * image->uploadWidth; - - switch(image->internalFormat) - { - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: - format = "sDXT1"; - // 64 bits per 16 pixels, so 4 bits per pixel - estSize /= 2; - break; - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: - format = "sDXT5"; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB: - format = "sBPTC"; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: - format = "LATC "; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - format = "DXT1 "; - // 64 bits per 16 pixels, so 4 bits per pixel - estSize /= 2; - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - format = "DXT5 "; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB: - format = "BPTC "; - // 128 bits per 16 pixels, so 1 byte per pixel - break; - case GL_RGB4_S3TC: - format = "S3TC "; - // same as DXT1? - estSize /= 2; - break; - case GL_RGBA4: - case GL_RGBA8: - case GL_RGBA: - format = "RGBA "; - // 4 bytes per pixel - estSize *= 4; - break; - case GL_LUMINANCE8: - case GL_LUMINANCE16: - case GL_LUMINANCE: - format = "L "; - // 1 byte per pixel? - break; - case GL_RGB5: - case GL_RGB8: - case GL_RGB: - format = "RGB "; - // 3 bytes per pixel? - estSize *= 3; - break; - case GL_LUMINANCE8_ALPHA8: - case GL_LUMINANCE16_ALPHA16: - case GL_LUMINANCE_ALPHA: - format = "LA "; - // 2 bytes per pixel? - estSize *= 2; - break; - case GL_SRGB_EXT: - case GL_SRGB8_EXT: - format = "sRGB "; - // 3 bytes per pixel? - estSize *= 3; - break; - case GL_SRGB_ALPHA_EXT: - case GL_SRGB8_ALPHA8_EXT: - format = "sRGBA"; - // 4 bytes per pixel? - estSize *= 4; - break; - case GL_SLUMINANCE_EXT: - case GL_SLUMINANCE8_EXT: - format = "sL "; - // 1 byte per pixel? - break; - case GL_SLUMINANCE_ALPHA_EXT: - case GL_SLUMINANCE8_ALPHA8_EXT: - format = "sLA "; - // 2 byte per pixel? - estSize *= 2; - break; - } - - // mipmap adds about 50% - if (image->flags & IMGFLAG_MIPMAP) - estSize += estSize / 2; - - sizeSuffix = "b "; - displaySize = estSize; - - if (displaySize > 1024) - { - displaySize /= 1024; - sizeSuffix = "kb"; - } - - if (displaySize > 1024) - { - displaySize /= 1024; - sizeSuffix = "Mb"; - } - - if (displaySize > 1024) - { - displaySize /= 1024; - sizeSuffix = "Gb"; - } - - ri.Printf(PRINT_ALL, "%4i: %4ix%4i %s %4i%s %s\n", i, image->uploadWidth, image->uploadHeight, format, displaySize, sizeSuffix, image->imgName); - estTotalSize += estSize; - } - - ri.Printf (PRINT_ALL, " ---------\n"); - ri.Printf (PRINT_ALL, " approx %i bytes\n", estTotalSize); - ri.Printf (PRINT_ALL, " %i total images\n\n", tr.numImages ); -} - -//======================================================================= - -/* -================ -ResampleTexture - -Used to resample images in a more general than quartering fashion. - -This will only be filtered properly if the resampled size -is greater than half the original size. - -If a larger shrinking is needed, use the mipmap function -before or after. -================ -*/ -static void ResampleTexture( byte *in, int inwidth, int inheight, byte *out, - int outwidth, int outheight ) { - int i, j; - byte *inrow, *inrow2; - int frac, fracstep; - int p1[2048], p2[2048]; - byte *pix1, *pix2, *pix3, *pix4; - - if (outwidth>2048) - ri.Error(ERR_DROP, "ResampleTexture: max width"); - - fracstep = inwidth*0x10000/outwidth; - - frac = fracstep>>2; - for ( i=0 ; i>16); - frac += fracstep; - } - frac = 3*(fracstep>>2); - for ( i=0 ; i>16); - frac += fracstep; - } - - for (i=0 ; i>2; - *out++ = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2; - *out++ = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2; - *out++ = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2; - } - } -} - -static void RGBAtoYCoCgA(const byte *in, byte *out, int width, int height) -{ - int x, y; - - for (y = 0; y < height; y++) - { - const byte *inbyte = in + y * width * 4; - byte *outbyte = out + y * width * 4; - - for (x = 0; x < width; x++) - { - byte r, g, b, a, rb2; - - r = *inbyte++; - g = *inbyte++; - b = *inbyte++; - a = *inbyte++; - rb2 = (r + b) >> 1; - - *outbyte++ = (g + rb2) >> 1; // Y = R/4 + G/2 + B/4 - *outbyte++ = (r - b + 256) >> 1; // Co = R/2 - B/2 - *outbyte++ = (g - rb2 + 256) >> 1; // Cg = -R/4 + G/2 - B/4 - *outbyte++ = a; - } - } -} - -static void YCoCgAtoRGBA(const byte *in, byte *out, int width, int height) -{ - int x, y; - - for (y = 0; y < height; y++) - { - const byte *inbyte = in + y * width * 4; - byte *outbyte = out + y * width * 4; - - for (x = 0; x < width; x++) - { - byte _Y, Co, Cg, a; - - _Y = *inbyte++; - Co = *inbyte++; - Cg = *inbyte++; - a = *inbyte++; - - *outbyte++ = CLAMP(_Y + Co - Cg, 0, 255); // R = Y + Co - Cg - *outbyte++ = CLAMP(_Y + Cg - 128, 0, 255); // G = Y + Cg - *outbyte++ = CLAMP(_Y - Co - Cg + 256, 0, 255); // B = Y - Co - Cg - *outbyte++ = a; - } - } -} - - -// uses a sobel filter to change a texture to a normal map -static void RGBAtoNormal(const byte *in, byte *out, int width, int height, qboolean clampToEdge) -{ - int x, y, max; - - // convert to heightmap, storing in alpha - // same as converting to Y in YCoCg - max = 1; - for (y = 0; y < height; y++) - { - const byte *inbyte = in + y * width * 4; - byte *outbyte = out + y * width * 4 + 3; - - for (x = 0; x < width; x++) - { - byte result = (inbyte[0] >> 2) + (inbyte[1] >> 1) + (inbyte[2] >> 2); - result = result * result / 255; // Make linear - *outbyte = result; - max = MAX(max, *outbyte); - outbyte += 4; - inbyte += 4; - } - } - - // level out heights - if (max < 255) - { - for (y = 0; y < height; y++) - { - byte *outbyte = out + y * width * 4 + 3; - - for (x = 0; x < width; x++) - { - *outbyte = *outbyte + (255 - max); - outbyte += 4; - } - } - } - - - // now run sobel filter over height values to generate X and Y - // then normalize - for (y = 0; y < height; y++) - { - byte *outbyte = out + y * width * 4; - - for (x = 0; x < width; x++) - { - // 0 1 2 - // 3 4 5 - // 6 7 8 - - byte s[9]; - int x2, y2, i; - vec3_t normal; - - i = 0; - for (y2 = -1; y2 <= 1; y2++) - { - int src_y = y + y2; - - if (clampToEdge) - { - src_y = CLAMP(src_y, 0, height - 1); - } - else - { - src_y = (src_y + height) % height; - } - - - for (x2 = -1; x2 <= 1; x2++) - { - int src_x = x + x2; - - if (clampToEdge) - { - src_x = CLAMP(src_x, 0, height - 1); - } - else - { - src_x = (src_x + height) % height; - } - - s[i++] = *(out + (src_y * width + src_x) * 4 + 3); - } - } - - normal[0] = s[0] - s[2] - + 2 * s[3] - 2 * s[5] - + s[6] - s[8]; - - normal[1] = s[0] + 2 * s[1] + s[2] - - - s[6] - 2 * s[7] - s[8]; - - normal[2] = s[4] * 4; - - if (!VectorNormalize2(normal, normal)) - { - VectorSet(normal, 0, 0, 1); - } - - *outbyte++ = FloatToOffsetByte(normal[0]); - *outbyte++ = FloatToOffsetByte(normal[1]); - *outbyte++ = FloatToOffsetByte(normal[2]); - outbyte++; - } - } -} - -#define COPYSAMPLE(a,b) *(unsigned int *)(a) = *(unsigned int *)(b) - -// based on Fast Curve Based Interpolation -// from Fast Artifacts-Free Image Interpolation (http://www.andreagiachetti.it/icbi/) -// assumes data has a 2 pixel thick border of clamped or wrapped data -// expects data to be a grid with even (0, 0), (2, 0), (0, 2), (2, 2) etc pixels filled -// only performs FCBI on specified component -static void DoFCBI(byte *in, byte *out, int width, int height, int component) -{ - int x, y; - byte *outbyte, *inbyte; - - // copy in to out - for (y = 2; y < height - 2; y += 2) - { - inbyte = in + (y * width + 2) * 4 + component; - outbyte = out + (y * width + 2) * 4 + component; - - for (x = 2; x < width - 2; x += 2) - { - *outbyte = *inbyte; - outbyte += 8; - inbyte += 8; - } - } - - for (y = 3; y < height - 3; y += 2) - { - // diagonals - // - // NWp - northwest interpolated pixel - // NEp - northeast interpolated pixel - // NWd - northwest first derivative - // NEd - northeast first derivative - // NWdd - northwest second derivative - // NEdd - northeast second derivative - // - // Uses these samples: - // - // 0 - // - - a - b - - - // - - - - - - - - // c - d - e - f - // 0 - - - - - - - - // g - h - i - j - // - - - - - - - - // - - k - l - - - // - // x+2 uses these samples: - // - // 0 - // - - - - a - b - - - // - - - - - - - - - - // - - c - d - e - f - // 0 - - - - - - - - - - // - - g - h - i - j - // - - - - - - - - - - // - - - - k - l - - - // - // so we can reuse 8 of them on next iteration - // - // a=b, c=d, d=e, e=f, g=h, h=i, i=j, k=l - // - // only b, f, j, and l need to be sampled on next iteration - - byte sa, sb, sc, sd, se, sf, sg, sh, si, sj, sk, sl; - byte *line1, *line2, *line3, *line4; - - x = 3; - - // optimization one - // SAMPLE2(sa, x-1, y-3); - //SAMPLE2(sc, x-3, y-1); SAMPLE2(sd, x-1, y-1); SAMPLE2(se, x+1, y-1); - //SAMPLE2(sg, x-3, y+1); SAMPLE2(sh, x-1, y+1); SAMPLE2(si, x+1, y+1); - // SAMPLE2(sk, x-1, y+3); - - // optimization two - line1 = in + ((y - 3) * width + (x - 1)) * 4 + component; - line2 = in + ((y - 1) * width + (x - 3)) * 4 + component; - line3 = in + ((y + 1) * width + (x - 3)) * 4 + component; - line4 = in + ((y + 3) * width + (x - 1)) * 4 + component; - - // COPYSAMPLE(sa, line1); line1 += 8; - //COPYSAMPLE(sc, line2); line2 += 8; COPYSAMPLE(sd, line2); line2 += 8; COPYSAMPLE(se, line2); line2 += 8; - //COPYSAMPLE(sg, line3); line3 += 8; COPYSAMPLE(sh, line3); line3 += 8; COPYSAMPLE(si, line3); line3 += 8; - // COPYSAMPLE(sk, line4); line4 += 8; - - sa = *line1; line1 += 8; - sc = *line2; line2 += 8; sd = *line2; line2 += 8; se = *line2; line2 += 8; - sg = *line3; line3 += 8; sh = *line3; line3 += 8; si = *line3; line3 += 8; - sk = *line4; line4 += 8; - - outbyte = out + (y * width + x) * 4 + component; - - for ( ; x < width - 3; x += 2) - { - int NWd, NEd, NWp, NEp; - - // original - // SAMPLE2(sa, x-1, y-3); SAMPLE2(sb, x+1, y-3); - //SAMPLE2(sc, x-3, y-1); SAMPLE2(sd, x-1, y-1); SAMPLE2(se, x+1, y-1); SAMPLE2(sf, x+3, y-1); - //SAMPLE2(sg, x-3, y+1); SAMPLE2(sh, x-1, y+1); SAMPLE2(si, x+1, y+1); SAMPLE2(sj, x+3, y+1); - // SAMPLE2(sk, x-1, y+3); SAMPLE2(sl, x+1, y+3); - - // optimization one - //SAMPLE2(sb, x+1, y-3); - //SAMPLE2(sf, x+3, y-1); - //SAMPLE2(sj, x+3, y+1); - //SAMPLE2(sl, x+1, y+3); - - // optimization two - //COPYSAMPLE(sb, line1); line1 += 8; - //COPYSAMPLE(sf, line2); line2 += 8; - //COPYSAMPLE(sj, line3); line3 += 8; - //COPYSAMPLE(sl, line4); line4 += 8; - - sb = *line1; line1 += 8; - sf = *line2; line2 += 8; - sj = *line3; line3 += 8; - sl = *line4; line4 += 8; - - NWp = sd + si; - NEp = se + sh; - NWd = abs(sd - si); - NEd = abs(se - sh); - - if (NWd > 100 || NEd > 100 || abs(NWp-NEp) > 200) - { - if (NWd < NEd) - *outbyte = NWp >> 1; - else - *outbyte = NEp >> 1; - } - else - { - int NWdd, NEdd; - - //NEdd = abs(sg + sd + sb - 3 * (se + sh) + sk + si + sf); - //NWdd = abs(sa + se + sj - 3 * (sd + si) + sc + sh + sl); - NEdd = abs(sg + sb - 3 * NEp + sk + sf + NWp); - NWdd = abs(sa + sj - 3 * NWp + sc + sl + NEp); - - if (NWdd > NEdd) - *outbyte = NWp >> 1; - else - *outbyte = NEp >> 1; - } - - outbyte += 8; - - // COPYSAMPLE(sa, sb); - //COPYSAMPLE(sc, sd); COPYSAMPLE(sd, se); COPYSAMPLE(se, sf); - //COPYSAMPLE(sg, sh); COPYSAMPLE(sh, si); COPYSAMPLE(si, sj); - // COPYSAMPLE(sk, sl); - - sa = sb; - sc = sd; sd = se; se = sf; - sg = sh; sh = si; si = sj; - sk = sl; - } - } - - // hack: copy out to in again - for (y = 3; y < height - 3; y += 2) - { - inbyte = out + (y * width + 3) * 4 + component; - outbyte = in + (y * width + 3) * 4 + component; - - for (x = 3; x < width - 3; x += 2) - { - *outbyte = *inbyte; - outbyte += 8; - inbyte += 8; - } - } - - for (y = 2; y < height - 3; y++) - { - // horizontal & vertical - // - // hp - horizontally interpolated pixel - // vp - vertically interpolated pixel - // hd - horizontal first derivative - // vd - vertical first derivative - // hdd - horizontal second derivative - // vdd - vertical second derivative - // Uses these samples: - // - // 0 - // - a - b - - // c - d - e - // 0 - f - g - - // h - i - j - // - k - l - - // - // x+2 uses these samples: - // - // 0 - // - - - a - b - - // - - c - d - e - // 0 - - - f - g - - // - - h - i - j - // - - - k - l - - // - // so we can reuse 7 of them on next iteration - // - // a=b, c=d, d=e, f=g, h=i, i=j, k=l - // - // only b, e, g, j, and l need to be sampled on next iteration - - byte sa, sb, sc, sd, se, sf, sg, sh, si, sj, sk, sl; - byte *line1, *line2, *line3, *line4, *line5; - - //x = (y + 1) % 2; - x = (y + 1) % 2 + 2; - - // optimization one - // SAMPLE2(sa, x-1, y-2); - //SAMPLE2(sc, x-2, y-1); SAMPLE2(sd, x, y-1); - // SAMPLE2(sf, x-1, y ); - //SAMPLE2(sh, x-2, y+1); SAMPLE2(si, x, y+1); - // SAMPLE2(sk, x-1, y+2); - - line1 = in + ((y - 2) * width + (x - 1)) * 4 + component; - line2 = in + ((y - 1) * width + (x - 2)) * 4 + component; - line3 = in + ((y ) * width + (x - 1)) * 4 + component; - line4 = in + ((y + 1) * width + (x - 2)) * 4 + component; - line5 = in + ((y + 2) * width + (x - 1)) * 4 + component; - - // COPYSAMPLE(sa, line1); line1 += 8; - //COPYSAMPLE(sc, line2); line2 += 8; COPYSAMPLE(sd, line2); line2 += 8; - // COPYSAMPLE(sf, line3); line3 += 8; - //COPYSAMPLE(sh, line4); line4 += 8; COPYSAMPLE(si, line4); line4 += 8; - // COPYSAMPLE(sk, line5); line5 += 8; - - sa = *line1; line1 += 8; - sc = *line2; line2 += 8; sd = *line2; line2 += 8; - sf = *line3; line3 += 8; - sh = *line4; line4 += 8; si = *line4; line4 += 8; - sk = *line5; line5 += 8; - - outbyte = out + (y * width + x) * 4 + component; - - for ( ; x < width - 3; x+=2) - { - int hd, vd, hp, vp; - - // SAMPLE2(sa, x-1, y-2); SAMPLE2(sb, x+1, y-2); - //SAMPLE2(sc, x-2, y-1); SAMPLE2(sd, x, y-1); SAMPLE2(se, x+2, y-1); - // SAMPLE2(sf, x-1, y ); SAMPLE2(sg, x+1, y ); - //SAMPLE2(sh, x-2, y+1); SAMPLE2(si, x, y+1); SAMPLE2(sj, x+2, y+1); - // SAMPLE2(sk, x-1, y+2); SAMPLE2(sl, x+1, y+2); - - // optimization one - //SAMPLE2(sb, x+1, y-2); - //SAMPLE2(se, x+2, y-1); - //SAMPLE2(sg, x+1, y ); - //SAMPLE2(sj, x+2, y+1); - //SAMPLE2(sl, x+1, y+2); - - //COPYSAMPLE(sb, line1); line1 += 8; - //COPYSAMPLE(se, line2); line2 += 8; - //COPYSAMPLE(sg, line3); line3 += 8; - //COPYSAMPLE(sj, line4); line4 += 8; - //COPYSAMPLE(sl, line5); line5 += 8; - - sb = *line1; line1 += 8; - se = *line2; line2 += 8; - sg = *line3; line3 += 8; - sj = *line4; line4 += 8; - sl = *line5; line5 += 8; - - hp = sf + sg; - vp = sd + si; - hd = abs(sf - sg); - vd = abs(sd - si); - - if (hd > 100 || vd > 100 || abs(hp-vp) > 200) - { - if (hd < vd) - *outbyte = hp >> 1; - else - *outbyte = vp >> 1; - } - else - { - int hdd, vdd; - - //hdd = abs(sc[i] + sd[i] + se[i] - 3 * (sf[i] + sg[i]) + sh[i] + si[i] + sj[i]); - //vdd = abs(sa[i] + sf[i] + sk[i] - 3 * (sd[i] + si[i]) + sb[i] + sg[i] + sl[i]); - - hdd = abs(sc + se - 3 * hp + sh + sj + vp); - vdd = abs(sa + sk - 3 * vp + sb + sl + hp); - - if (hdd > vdd) - *outbyte = hp >> 1; - else - *outbyte = vp >> 1; - } - - outbyte += 8; - - // COPYSAMPLE(sa, sb); - //COPYSAMPLE(sc, sd); COPYSAMPLE(sd, se); - // COPYSAMPLE(sf, sg); - //COPYSAMPLE(sh, si); COPYSAMPLE(si, sj); - // COPYSAMPLE(sk, sl); - sa = sb; - sc = sd; sd = se; - sf = sg; - sh = si; si = sj; - sk = sl; - } - } -} - -// Similar to FCBI, but throws out the second order derivatives for speed -static void DoFCBIQuick(byte *in, byte *out, int width, int height, int component) -{ - int x, y; - byte *outbyte, *inbyte; - - // copy in to out - for (y = 2; y < height - 2; y += 2) - { - inbyte = in + (y * width + 2) * 4 + component; - outbyte = out + (y * width + 2) * 4 + component; - - for (x = 2; x < width - 2; x += 2) - { - *outbyte = *inbyte; - outbyte += 8; - inbyte += 8; - } - } - - for (y = 3; y < height - 4; y += 2) - { - byte sd, se, sh, si; - byte *line2, *line3; - - x = 3; - - line2 = in + ((y - 1) * width + (x - 1)) * 4 + component; - line3 = in + ((y + 1) * width + (x - 1)) * 4 + component; - - sd = *line2; line2 += 8; - sh = *line3; line3 += 8; - - outbyte = out + (y * width + x) * 4 + component; - - for ( ; x < width - 4; x += 2) - { - int NWd, NEd, NWp, NEp; - - se = *line2; line2 += 8; - si = *line3; line3 += 8; - - NWp = sd + si; - NEp = se + sh; - NWd = abs(sd - si); - NEd = abs(se - sh); - - if (NWd < NEd) - *outbyte = NWp >> 1; - else - *outbyte = NEp >> 1; - - outbyte += 8; - - sd = se; - sh = si; - } - } - - // hack: copy out to in again - for (y = 3; y < height - 3; y += 2) - { - inbyte = out + (y * width + 3) * 4 + component; - outbyte = in + (y * width + 3) * 4 + component; - - for (x = 3; x < width - 3; x += 2) - { - *outbyte = *inbyte; - outbyte += 8; - inbyte += 8; - } - } - - for (y = 2; y < height - 3; y++) - { - byte sd, sf, sg, si; - byte *line2, *line3, *line4; - - x = (y + 1) % 2 + 2; - - line2 = in + ((y - 1) * width + (x )) * 4 + component; - line3 = in + ((y ) * width + (x - 1)) * 4 + component; - line4 = in + ((y + 1) * width + (x )) * 4 + component; - - outbyte = out + (y * width + x) * 4 + component; - - sf = *line3; line3 += 8; - - for ( ; x < width - 3; x+=2) - { - int hd, vd, hp, vp; - - sd = *line2; line2 += 8; - sg = *line3; line3 += 8; - si = *line4; line4 += 8; - - hp = sf + sg; - vp = sd + si; - hd = abs(sf - sg); - vd = abs(sd - si); - - if (hd < vd) - *outbyte = hp >> 1; - else - *outbyte = vp >> 1; - - outbyte += 8; - - sf = sg; - } - } -} - -// Similar to DoFCBIQuick, but just takes the average instead of checking derivatives -// as well, this operates on all four components -static void DoLinear(byte *in, byte *out, int width, int height) -{ - int x, y, i; - byte *outbyte, *inbyte; - - // copy in to out - for (y = 2; y < height - 2; y += 2) - { - x = 2; - - inbyte = in + (y * width + x) * 4; - outbyte = out + (y * width + x) * 4; - - for ( ; x < width - 2; x += 2) - { - COPYSAMPLE(outbyte, inbyte); - outbyte += 8; - inbyte += 8; - } - } - - for (y = 1; y < height - 1; y += 2) - { - byte sd[4] = {0}, se[4] = {0}, sh[4] = {0}, si[4] = {0}; - byte *line2, *line3; - - x = 1; - - line2 = in + ((y - 1) * width + (x - 1)) * 4; - line3 = in + ((y + 1) * width + (x - 1)) * 4; - - COPYSAMPLE(sd, line2); line2 += 8; - COPYSAMPLE(sh, line3); line3 += 8; - - outbyte = out + (y * width + x) * 4; - - for ( ; x < width - 1; x += 2) - { - COPYSAMPLE(se, line2); line2 += 8; - COPYSAMPLE(si, line3); line3 += 8; - - for (i = 0; i < 4; i++) - { - *outbyte++ = (sd[i] + si[i] + se[i] + sh[i]) >> 2; - } - - outbyte += 4; - - COPYSAMPLE(sd, se); - COPYSAMPLE(sh, si); - } - } - - // hack: copy out to in again - for (y = 1; y < height - 1; y += 2) - { - x = 1; - - inbyte = out + (y * width + x) * 4; - outbyte = in + (y * width + x) * 4; - - for ( ; x < width - 1; x += 2) - { - COPYSAMPLE(outbyte, inbyte); - outbyte += 8; - inbyte += 8; - } - } - - for (y = 1; y < height - 1; y++) - { - byte sd[4], sf[4], sg[4], si[4]; - byte *line2, *line3, *line4; - - x = y % 2 + 1; - - line2 = in + ((y - 1) * width + (x )) * 4; - line3 = in + ((y ) * width + (x - 1)) * 4; - line4 = in + ((y + 1) * width + (x )) * 4; - - COPYSAMPLE(sf, line3); line3 += 8; - - outbyte = out + (y * width + x) * 4; - - for ( ; x < width - 1; x += 2) - { - COPYSAMPLE(sd, line2); line2 += 8; - COPYSAMPLE(sg, line3); line3 += 8; - COPYSAMPLE(si, line4); line4 += 8; - - for (i = 0; i < 4; i++) - { - *outbyte++ = (sf[i] + sg[i] + sd[i] + si[i]) >> 2; - } - - outbyte += 4; - - COPYSAMPLE(sf, sg); - } - } -} - - -static void ExpandHalfTextureToGrid( byte *data, int width, int height) -{ - int x, y; - - for (y = height / 2; y > 0; y--) - { - byte *outbyte = data + ((y * 2 - 1) * (width) - 2) * 4; - byte *inbyte = data + (y * (width / 2) - 1) * 4; - - for (x = width / 2; x > 0; x--) - { - COPYSAMPLE(outbyte, inbyte); - - outbyte -= 8; - inbyte -= 4; - } - } -} - -static void FillInNormalizedZ(const byte *in, byte *out, int width, int height) -{ - int x, y; - - for (y = 0; y < height; y++) - { - const byte *inbyte = in + y * width * 4; - byte *outbyte = out + y * width * 4; - - for (x = 0; x < width; x++) - { - byte nx, ny, nz, h; - float fnx, fny, fll, fnz; - - nx = *inbyte++; - ny = *inbyte++; - inbyte++; - h = *inbyte++; - - fnx = OffsetByteToFloat(nx); - fny = OffsetByteToFloat(ny); - fll = 1.0f - fnx * fnx - fny * fny; - if (fll >= 0.0f) - fnz = (float)sqrt(fll); - else - fnz = 0.0f; - - nz = FloatToOffsetByte(fnz); - - *outbyte++ = nx; - *outbyte++ = ny; - *outbyte++ = nz; - *outbyte++ = h; - } - } -} - - -// size must be even -#define WORKBLOCK_SIZE 128 -#define WORKBLOCK_BORDER 4 -#define WORKBLOCK_REALSIZE (WORKBLOCK_SIZE + WORKBLOCK_BORDER * 2) - -// assumes that data has already been expanded into a 2x2 grid -static void FCBIByBlock(byte *data, int width, int height, qboolean clampToEdge, qboolean normalized) -{ - byte workdata[WORKBLOCK_REALSIZE * WORKBLOCK_REALSIZE * 4]; - byte outdata[WORKBLOCK_REALSIZE * WORKBLOCK_REALSIZE * 4]; - byte *inbyte, *outbyte; - int x, y; - int srcx, srcy; - - ExpandHalfTextureToGrid(data, width, height); - - for (y = 0; y < height; y += WORKBLOCK_SIZE) - { - for (x = 0; x < width; x += WORKBLOCK_SIZE) - { - int x2, y2; - int workwidth, workheight, fullworkwidth, fullworkheight; - - workwidth = MIN(WORKBLOCK_SIZE, width - x); - workheight = MIN(WORKBLOCK_SIZE, height - y); - - fullworkwidth = workwidth + WORKBLOCK_BORDER * 2; - fullworkheight = workheight + WORKBLOCK_BORDER * 2; - - //memset(workdata, 0, WORKBLOCK_REALSIZE * WORKBLOCK_REALSIZE * 4); - - // fill in work block - for (y2 = 0; y2 < fullworkheight; y2 += 2) - { - srcy = y + y2 - WORKBLOCK_BORDER; - - if (clampToEdge) - { - srcy = CLAMP(srcy, 0, height - 2); - } - else - { - srcy = (srcy + height) % height; - } - - outbyte = workdata + y2 * fullworkwidth * 4; - inbyte = data + srcy * width * 4; - - for (x2 = 0; x2 < fullworkwidth; x2 += 2) - { - srcx = x + x2 - WORKBLOCK_BORDER; - - if (clampToEdge) - { - srcx = CLAMP(srcx, 0, width - 2); - } - else - { - srcx = (srcx + width) % width; - } - - COPYSAMPLE(outbyte, inbyte + srcx * 4); - outbyte += 8; - } - } - - // submit work block - DoLinear(workdata, outdata, fullworkwidth, fullworkheight); - - if (!normalized) - { - switch (r_imageUpsampleType->integer) - { - case 0: - break; - case 1: - DoFCBIQuick(workdata, outdata, fullworkwidth, fullworkheight, 0); - break; - case 2: - default: - DoFCBI(workdata, outdata, fullworkwidth, fullworkheight, 0); - break; - } - } - else - { - switch (r_imageUpsampleType->integer) - { - case 0: - break; - case 1: - DoFCBIQuick(workdata, outdata, fullworkwidth, fullworkheight, 0); - DoFCBIQuick(workdata, outdata, fullworkwidth, fullworkheight, 1); - break; - case 2: - default: - DoFCBI(workdata, outdata, fullworkwidth, fullworkheight, 0); - DoFCBI(workdata, outdata, fullworkwidth, fullworkheight, 1); - break; - } - } - - // copy back work block - for (y2 = 0; y2 < workheight; y2++) - { - inbyte = outdata + ((y2 + WORKBLOCK_BORDER) * fullworkwidth + WORKBLOCK_BORDER) * 4; - outbyte = data + ((y + y2) * width + x) * 4; - for (x2 = 0; x2 < workwidth; x2++) - { - COPYSAMPLE(outbyte, inbyte); - outbyte += 4; - inbyte += 4; - } - } - } - } -} -#undef COPYSAMPLE - -/* -================ -R_LightScaleTexture - -Scale up the pixel values in a texture to increase the -lighting range -================ -*/ -void R_LightScaleTexture (byte *in, int inwidth, int inheight, qboolean only_gamma ) -{ - if ( only_gamma ) - { - if ( !glConfig.deviceSupportsGamma ) - { - int i, c; - byte *p; - - p = in; - - c = inwidth*inheight; - for (i=0 ; i> 1; - outHeight = inHeight >> 1; - temp = ri.Hunk_AllocateTempMemory( outWidth * outHeight * 4 ); - - inWidthMask = inWidth - 1; - inHeightMask = inHeight - 1; - - for ( i = 0 ; i < outHeight ; i++ ) { - for ( j = 0 ; j < outWidth ; j++ ) { - outpix = (byte *) ( temp + i * outWidth + j ); - for ( k = 0 ; k < 4 ; k++ ) { - total = - 1 * (&in[ 4*(((i*2-1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask)) ])[k] + - 2 * (&in[ 4*(((i*2-1)&inHeightMask)*inWidth + ((j*2 )&inWidthMask)) ])[k] + - 2 * (&in[ 4*(((i*2-1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask)) ])[k] + - 1 * (&in[ 4*(((i*2-1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask)) ])[k] + - - 2 * (&in[ 4*(((i*2 )&inHeightMask)*inWidth + ((j*2-1)&inWidthMask)) ])[k] + - 4 * (&in[ 4*(((i*2 )&inHeightMask)*inWidth + ((j*2 )&inWidthMask)) ])[k] + - 4 * (&in[ 4*(((i*2 )&inHeightMask)*inWidth + ((j*2+1)&inWidthMask)) ])[k] + - 2 * (&in[ 4*(((i*2 )&inHeightMask)*inWidth + ((j*2+2)&inWidthMask)) ])[k] + - - 2 * (&in[ 4*(((i*2+1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask)) ])[k] + - 4 * (&in[ 4*(((i*2+1)&inHeightMask)*inWidth + ((j*2 )&inWidthMask)) ])[k] + - 4 * (&in[ 4*(((i*2+1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask)) ])[k] + - 2 * (&in[ 4*(((i*2+1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask)) ])[k] + - - 1 * (&in[ 4*(((i*2+2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask)) ])[k] + - 2 * (&in[ 4*(((i*2+2)&inHeightMask)*inWidth + ((j*2 )&inWidthMask)) ])[k] + - 2 * (&in[ 4*(((i*2+2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask)) ])[k] + - 1 * (&in[ 4*(((i*2+2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask)) ])[k]; - outpix[k] = total / 36; - } - } - } - - Com_Memcpy( in, temp, outWidth * outHeight * 4 ); - ri.Hunk_FreeTempMemory( temp ); -} - - -static void R_MipMapsRGB( byte *in, int inWidth, int inHeight) -{ - int i, j, k; - int outWidth, outHeight; - byte *temp; - - outWidth = inWidth >> 1; - outHeight = inHeight >> 1; - temp = ri.Hunk_AllocateTempMemory( outWidth * outHeight * 4 ); - - for ( i = 0 ; i < outHeight ; i++ ) { - byte *outbyte = temp + ( i * outWidth ) * 4; - byte *inbyte1 = in + ( i * 2 * inWidth ) * 4; - byte *inbyte2 = in + ( (i * 2 + 1) * inWidth ) * 4; - for ( j = 0 ; j < outWidth ; j++ ) { - for ( k = 0 ; k < 3 ; k++ ) { - float total, current; - - current = ByteToFloat(inbyte1[0]); total = sRGBtoRGB(current); - current = ByteToFloat(inbyte1[4]); total += sRGBtoRGB(current); - current = ByteToFloat(inbyte2[0]); total += sRGBtoRGB(current); - current = ByteToFloat(inbyte2[4]); total += sRGBtoRGB(current); - - total *= 0.25f; - - inbyte1++; - inbyte2++; - - current = RGBtosRGB(total); - *outbyte++ = FloatToByte(current); - } - *outbyte++ = (inbyte1[0] + inbyte1[4] + inbyte2[0] + inbyte2[4]) >> 2; - inbyte1 += 5; - inbyte2 += 5; - } - } - - Com_Memcpy( in, temp, outWidth * outHeight * 4 ); - ri.Hunk_FreeTempMemory( temp ); -} - -/* -================ -R_MipMap - -Operates in place, quartering the size of the texture -================ -*/ -static void R_MipMap (byte *in, int width, int height) { - int i, j; - byte *out; - int row; - - if ( !r_simpleMipMaps->integer ) { - R_MipMap2( in, width, height ); - return; - } - - if ( width == 1 && height == 1 ) { - return; - } - - row = width * 4; - out = in; - width >>= 1; - height >>= 1; - - if ( width == 0 || height == 0 ) { - width += height; // get largest - for (i=0 ; i>1; - out[1] = ( in[1] + in[5] )>>1; - out[2] = ( in[2] + in[6] )>>1; - out[3] = ( in[3] + in[7] )>>1; - } - return; - } - - for (i=0 ; i>2; - out[1] = (in[1] + in[5] + in[row+1] + in[row+5])>>2; - out[2] = (in[2] + in[6] + in[row+2] + in[row+6])>>2; - out[3] = (in[3] + in[7] + in[row+3] + in[row+7])>>2; - } - } -} - - -static void R_MipMapLuminanceAlpha (const byte *in, byte *out, int width, int height) -{ - int i, j, row; - - if ( width == 1 && height == 1 ) { - return; - } - - row = width * 4; - width >>= 1; - height >>= 1; - - if ( width == 0 || height == 0 ) { - width += height; // get largest - for (i=0 ; i> 1; - out[3] = (in[3] + in[7]) >> 1; - } - return; - } - - for (i=0 ; i> 2; - out[3] = (in[3] + in[7] + in[row+3] + in[row+7]) >> 2; - } - } - -} - - -static void R_MipMapNormalHeight (const byte *in, byte *out, int width, int height, qboolean swizzle) -{ - int i, j; - int row; - int sx = swizzle ? 3 : 0; - int sa = swizzle ? 0 : 3; - - if ( width == 1 && height == 1 ) { - return; - } - - row = width * 4; - width >>= 1; - height >>= 1; - - for (i=0 ; i> 9; - data[1] = ( data[1] * inverseAlpha + premult[1] ) >> 9; - data[2] = ( data[2] * inverseAlpha + premult[2] ) >> 9; - } -} - -byte mipBlendColors[16][4] = { - {0,0,0,0}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, -}; - -static void RawImage_SwizzleRA( byte *data, int width, int height ) -{ - int i; - byte *ptr = data, swap; - - for (i=0; iinteger && scaled_width > width ) - scaled_width >>= 1; - if ( r_roundImagesDown->integer && scaled_height > height ) - scaled_height >>= 1; - - if ( picmip && data && resampledBuffer && r_imageUpsample->integer && - scaled_width < r_imageUpsampleMaxSize->integer && scaled_height < r_imageUpsampleMaxSize->integer) - { - int finalwidth, finalheight; - //int startTime, endTime; - - //startTime = ri.Milliseconds(); - - finalwidth = scaled_width << r_imageUpsample->integer; - finalheight = scaled_height << r_imageUpsample->integer; - - while ( finalwidth > r_imageUpsampleMaxSize->integer - || finalheight > r_imageUpsampleMaxSize->integer ) { - finalwidth >>= 1; - finalheight >>= 1; - } - - while ( finalwidth > glConfig.maxTextureSize - || finalheight > glConfig.maxTextureSize ) { - finalwidth >>= 1; - finalheight >>= 1; - } - - *resampledBuffer = ri.Hunk_AllocateTempMemory( finalwidth * finalheight * 4 ); - - if (scaled_width != width || scaled_height != height) - { - ResampleTexture (*data, width, height, *resampledBuffer, scaled_width, scaled_height); - } - else - { - byte *inbyte, *outbyte; - int i; - - inbyte = *data; - outbyte = *resampledBuffer; - - for (i = width * height * 4; i > 0; i--) - { - *outbyte++ = *inbyte++; - } - } - - if (type == IMGTYPE_COLORALPHA) - RGBAtoYCoCgA(*resampledBuffer, *resampledBuffer, scaled_width, scaled_height); - - while (scaled_width < finalwidth || scaled_height < finalheight) - { - scaled_width <<= 1; - scaled_height <<= 1; - - FCBIByBlock(*resampledBuffer, scaled_width, scaled_height, clampToEdge, (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT)); - } - - if (type == IMGTYPE_COLORALPHA) - { - YCoCgAtoRGBA(*resampledBuffer, *resampledBuffer, scaled_width, scaled_height); - } - else if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT) - { - FillInNormalizedZ(*resampledBuffer, *resampledBuffer, scaled_width, scaled_height); - } - - - //endTime = ri.Milliseconds(); - - //ri.Printf(PRINT_ALL, "upsampled %dx%d to %dx%d in %dms\n", width, height, scaled_width, scaled_height, endTime - startTime); - - *data = *resampledBuffer; - width = scaled_width; - height = scaled_height; - } - else if ( scaled_width != width || scaled_height != height ) { - if (data && resampledBuffer) - { - *resampledBuffer = ri.Hunk_AllocateTempMemory( scaled_width * scaled_height * 4 ); - ResampleTexture (*data, width, height, *resampledBuffer, scaled_width, scaled_height); - *data = *resampledBuffer; - } - width = scaled_width; - height = scaled_height; - } - - // - // perform optional picmip operation - // - if ( picmip ) { - scaled_width >>= r_picmip->integer; - scaled_height >>= r_picmip->integer; - } - - // - // clamp to minimum size - // - if (scaled_width < 1) { - scaled_width = 1; - } - if (scaled_height < 1) { - scaled_height = 1; - } - - // - // clamp to the current upper OpenGL limit - // scale both axis down equally so we don't have to - // deal with a half mip resampling - // - while ( scaled_width > glConfig.maxTextureSize - || scaled_height > glConfig.maxTextureSize ) { - scaled_width >>= 1; - scaled_height >>= 1; - } - - *inout_width = width; - *inout_height = height; - *inout_scaled_width = scaled_width; - *inout_scaled_height = scaled_height; -} - - -static qboolean RawImage_HasAlpha(const byte *scan, int numPixels) -{ - int i; - - if (!scan) - return qtrue; - - for ( i = 0; i < numPixels; i++ ) - { - if ( scan[i*4 + 3] != 255 ) - { - return qtrue; - } - } - - return qfalse; -} - -static GLenum RawImage_GetFormat(const byte *data, int numPixels, qboolean lightMap, imgType_t type, imgFlags_t flags) -{ - int samples = 3; - GLenum internalFormat = GL_RGB; - qboolean forceNoCompression = (flags & IMGFLAG_NO_COMPRESSION); - qboolean normalmap = (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT); - - if(normalmap) - { - if ((!RawImage_HasAlpha(data, numPixels) || (type == IMGTYPE_NORMAL)) && !forceNoCompression && (glRefConfig.textureCompression & TCR_LATC)) - { - internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT; - } - else - { - if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB ) - { - internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - } - else if ( r_texturebits->integer == 16 ) - { - internalFormat = GL_RGBA4; - } - else if ( r_texturebits->integer == 32 ) - { - internalFormat = GL_RGBA8; - } - else - { - internalFormat = GL_RGBA; - } - } - } - else if(lightMap) - { - if(r_greyscale->integer) - internalFormat = GL_LUMINANCE; - else - internalFormat = GL_RGBA; - } - else - { - if (RawImage_HasAlpha(data, numPixels)) - { - samples = 4; - } - - // select proper internal format - if ( samples == 3 ) - { - if(r_greyscale->integer) - { - if(r_texturebits->integer == 16) - internalFormat = GL_LUMINANCE8; - else if(r_texturebits->integer == 32) - internalFormat = GL_LUMINANCE16; - else - internalFormat = GL_LUMINANCE; - } - else - { - if ( !forceNoCompression && (glRefConfig.textureCompression & TCR_BPTC) ) - { - internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; - } - else if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB ) - { - internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - } - else if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC ) - { - internalFormat = GL_RGB4_S3TC; - } - else if ( r_texturebits->integer == 16 ) - { - internalFormat = GL_RGB5; - } - else if ( r_texturebits->integer == 32 ) - { - internalFormat = GL_RGB8; - } - else - { - internalFormat = GL_RGB; - } - } - } - else if ( samples == 4 ) - { - if(r_greyscale->integer) - { - if(r_texturebits->integer == 16) - internalFormat = GL_LUMINANCE8_ALPHA8; - else if(r_texturebits->integer == 32) - internalFormat = GL_LUMINANCE16_ALPHA16; - else - internalFormat = GL_LUMINANCE_ALPHA; - } - else - { - if ( !forceNoCompression && (glRefConfig.textureCompression & TCR_BPTC) ) - { - internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; - } - else if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB ) - { - internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - } - else if ( r_texturebits->integer == 16 ) - { - internalFormat = GL_RGBA4; - } - else if ( r_texturebits->integer == 32 ) - { - internalFormat = GL_RGBA8; - } - else - { - internalFormat = GL_RGBA; - } - } - } - - if (glRefConfig.textureSrgb && (flags & IMGFLAG_SRGB)) - { - switch(internalFormat) - { - case GL_RGB: - internalFormat = GL_SRGB_EXT; - break; - - case GL_RGB4: - case GL_RGB5: - case GL_RGB8: - internalFormat = GL_SRGB8_EXT; - break; - - case GL_RGBA: - internalFormat = GL_SRGB_ALPHA_EXT; - break; - - case GL_RGBA4: - case GL_RGBA8: - internalFormat = GL_SRGB8_ALPHA8_EXT; - break; - - case GL_LUMINANCE: - internalFormat = GL_SLUMINANCE_EXT; - break; - - case GL_LUMINANCE8: - case GL_LUMINANCE16: - internalFormat = GL_SLUMINANCE8_EXT; - break; - - case GL_LUMINANCE_ALPHA: - internalFormat = GL_SLUMINANCE_ALPHA_EXT; - break; - - case GL_LUMINANCE8_ALPHA8: - case GL_LUMINANCE16_ALPHA16: - internalFormat = GL_SLUMINANCE8_ALPHA8_EXT; - break; - - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - internalFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; - break; - - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - internalFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; - break; - - case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB: - internalFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB; - break; - } - } - } - - return internalFormat; -} - - -static void RawImage_UploadTexture( byte *data, int x, int y, int width, int height, GLenum internalFormat, imgType_t type, imgFlags_t flags, qboolean subtexture ) -{ - int dataFormat, dataType; - - switch(internalFormat) - { - case GL_DEPTH_COMPONENT: - case GL_DEPTH_COMPONENT16_ARB: - case GL_DEPTH_COMPONENT24_ARB: - case GL_DEPTH_COMPONENT32_ARB: - dataFormat = GL_DEPTH_COMPONENT; - dataType = GL_UNSIGNED_BYTE; - break; - case GL_RGBA16F_ARB: - dataFormat = GL_RGBA; - dataType = GL_HALF_FLOAT_ARB; - break; - default: - dataFormat = GL_RGBA; - dataType = GL_UNSIGNED_BYTE; - break; - } - - if ( subtexture ) - qglTexSubImage2D( GL_TEXTURE_2D, 0, x, y, width, height, dataFormat, dataType, data ); - else - qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, width, height, 0, dataFormat, dataType, data ); - - if (flags & IMGFLAG_MIPMAP) - { - int miplevel; - - miplevel = 0; - while (width > 1 || height > 1) - { - if (data) - { - if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT) - { - if (internalFormat == GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT) - { - R_MipMapLuminanceAlpha( data, data, width, height ); - } - else - { - R_MipMapNormalHeight( data, data, width, height, qtrue); - } - } - else if (flags & IMGFLAG_SRGB) - { - R_MipMapsRGB( data, width, height ); - } - else - { - R_MipMap( data, width, height ); - } - } - - width >>= 1; - height >>= 1; - if (width < 1) - width = 1; - if (height < 1) - height = 1; - miplevel++; - - if ( data && r_colorMipLevels->integer ) - R_BlendOverTexture( (byte *)data, width * height, mipBlendColors[miplevel] ); - - if ( subtexture ) - { - x >>= 1; - y >>= 1; - qglTexSubImage2D( GL_TEXTURE_2D, miplevel, x, y, width, height, dataFormat, dataType, data ); - } - else - { - qglTexImage2D (GL_TEXTURE_2D, miplevel, internalFormat, width, height, 0, dataFormat, dataType, data ); - } - } - } -} - - -/* -=============== -Upload32 - -=============== -*/ -extern qboolean charSet; -static void Upload32( byte *data, int width, int height, imgType_t type, imgFlags_t flags, - qboolean lightMap, GLenum internalFormat, int *pUploadWidth, int *pUploadHeight) -{ - byte *scaledBuffer = NULL; - byte *resampledBuffer = NULL; - int scaled_width, scaled_height; - int i, c; - byte *scan; - - RawImage_ScaleToPower2(&data, &width, &height, &scaled_width, &scaled_height, type, flags, &resampledBuffer); - - scaledBuffer = ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height ); - - // - // scan the texture for each channel's max values - // and verify if the alpha channel is being used or not - // - c = width*height; - scan = data; - - if( r_greyscale->integer ) - { - for ( i = 0; i < c; i++ ) - { - byte luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]); - scan[i*4] = luma; - scan[i*4 + 1] = luma; - scan[i*4 + 2] = luma; - } - } - else if( r_greyscale->value ) - { - for ( i = 0; i < c; i++ ) - { - float luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]); - scan[i*4] = LERP(scan[i*4], luma, r_greyscale->value); - scan[i*4 + 1] = LERP(scan[i*4 + 1], luma, r_greyscale->value); - scan[i*4 + 2] = LERP(scan[i*4 + 2], luma, r_greyscale->value); - } - } - - // Convert to RGB if sRGB textures aren't supported in hardware - if (!glRefConfig.textureSrgb && (flags & IMGFLAG_SRGB)) - { - byte *in = data; - int c = width * height; - while (c--) - { - for (i = 0; i < 3; i++) - { - float x = ByteToFloat(in[i]); - x = sRGBtoRGB(x); - in[i] = FloatToByte(x); - } - in += 4; - } - - // FIXME: Probably should mark the image as non-sRGB as well - flags &= ~IMGFLAG_SRGB; - } - - // normals are always swizzled - if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT) - { - RawImage_SwizzleRA(data, width, height); - } - - // LATC2 is only used for normals - if (internalFormat == GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT) - { - byte *in = data; - int c = width * height; - while (c--) - { - in[0] = in[1]; - in[2] = in[1]; - in += 4; - } - } - - // copy or resample data as appropriate for first MIP level - if ( ( scaled_width == width ) && - ( scaled_height == height ) ) { - if (!(flags & IMGFLAG_MIPMAP)) - { - RawImage_UploadTexture( data, 0, 0, scaled_width, scaled_height, internalFormat, type, flags, qfalse ); - //qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - *pUploadWidth = scaled_width; - *pUploadHeight = scaled_height; - - goto done; - } - Com_Memcpy (scaledBuffer, data, width*height*4); - } - else - { - // use the normal mip-mapping function to go down from here - while ( width > scaled_width || height > scaled_height ) { - - if (flags & IMGFLAG_SRGB) - { - R_MipMapsRGB( (byte *)data, width, height ); - } - else - { - R_MipMap( (byte *)data, width, height ); - } - - width >>= 1; - height >>= 1; - if ( width < 1 ) { - width = 1; - } - if ( height < 1 ) { - height = 1; - } - } - Com_Memcpy( scaledBuffer, data, width * height * 4 ); - } - - if (!(flags & IMGFLAG_NOLIGHTSCALE)) - R_LightScaleTexture (scaledBuffer, scaled_width, scaled_height, !(flags & IMGFLAG_MIPMAP) ); - - *pUploadWidth = scaled_width; - *pUploadHeight = scaled_height; - - RawImage_UploadTexture(scaledBuffer, 0, 0, scaled_width, scaled_height, internalFormat, type, flags, qfalse); - -done: - - if (flags & IMGFLAG_MIPMAP) - { - if ( textureFilterAnisotropic ) - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, - (GLint)Com_Clamp( 1, maxAnisotropy, r_ext_max_anisotropy->integer ) ); - - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); - } - else - { - if ( textureFilterAnisotropic ) - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 ); - - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - } - - GL_CheckErrors(); - - if ( scaledBuffer != 0 ) - ri.Hunk_FreeTempMemory( scaledBuffer ); - if ( resampledBuffer != 0 ) - ri.Hunk_FreeTempMemory( resampledBuffer ); -} - - -static void EmptyTexture( int width, int height, imgType_t type, imgFlags_t flags, - qboolean lightMap, GLenum internalFormat, int *pUploadWidth, int *pUploadHeight ) -{ - int scaled_width, scaled_height; - - RawImage_ScaleToPower2(NULL, &width, &height, &scaled_width, &scaled_height, type, flags, NULL); - - *pUploadWidth = scaled_width; - *pUploadHeight = scaled_height; - - RawImage_UploadTexture(NULL, 0, 0, scaled_width, scaled_height, internalFormat, type, flags, qfalse); - - if (flags & IMGFLAG_MIPMAP) - { - if ( textureFilterAnisotropic ) - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, - (GLint)Com_Clamp( 1, maxAnisotropy, r_ext_max_anisotropy->integer ) ); - - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); - } - else - { - if ( textureFilterAnisotropic ) - qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 ); - - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - } - - // Fix for sampling depth buffer on old nVidia cards - // from http://www.idevgames.com/forums/thread-4141-post-34844.html#pid34844 - switch(internalFormat) - { - case GL_DEPTH_COMPONENT: - case GL_DEPTH_COMPONENT16_ARB: - case GL_DEPTH_COMPONENT24_ARB: - case GL_DEPTH_COMPONENT32_ARB: - qglTexParameterf(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - break; - default: - break; - } - - GL_CheckErrors(); -} - - -/* -================ -R_CreateImage - -This is the only way any image_t are created -================ -*/ -image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgType_t type, imgFlags_t flags, int internalFormat ) { - image_t *image; - qboolean isLightmap = qfalse; - long hash; - int glWrapClampMode; - - if (strlen(name) >= MAX_QPATH ) { - ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long", name); - } - if ( !strncmp( name, "*lightmap", 9 ) ) { - isLightmap = qtrue; - } - - if ( tr.numImages == MAX_DRAWIMAGES ) { - ri.Error( ERR_DROP, "R_CreateImage: MAX_DRAWIMAGES hit"); - } - - image = tr.images[tr.numImages] = ri.Hunk_Alloc( sizeof( image_t ), h_low ); - image->texnum = 1024 + tr.numImages; - tr.numImages++; - - image->type = type; - image->flags = flags; - - strcpy (image->imgName, name); - - image->width = width; - image->height = height; - if (flags & IMGFLAG_CLAMPTOEDGE) - glWrapClampMode = GL_CLAMP_TO_EDGE; - else - glWrapClampMode = GL_REPEAT; - - if (!internalFormat) - { - if (image->flags & IMGFLAG_CUBEMAP) - internalFormat = GL_RGBA8; - else - internalFormat = RawImage_GetFormat(pic, width * height, isLightmap, image->type, image->flags); - } - - image->internalFormat = internalFormat; - - - // lightmaps are always allocated on TMU 1 - if ( qglActiveTextureARB && isLightmap ) { - image->TMU = 1; - } else { - image->TMU = 0; - } - - if ( qglActiveTextureARB ) { - GL_SelectTexture( image->TMU ); - } - - if (image->flags & IMGFLAG_CUBEMAP) - { - GL_Bind(image); - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - if (image->flags & IMGFLAG_MIPMAP) - { - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } - else - { - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - - qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); - - if (image->flags & IMGFLAG_MIPMAP) - qglGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP); - - image->uploadWidth = width; - image->uploadHeight = height; - } - else - { - GL_Bind(image); - - if (pic) - { - Upload32( pic, image->width, image->height, image->type, image->flags, - isLightmap, image->internalFormat, &image->uploadWidth, - &image->uploadHeight ); - } - else - { - EmptyTexture(image->width, image->height, image->type, image->flags, - isLightmap, image->internalFormat, &image->uploadWidth, - &image->uploadHeight ); - } - - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode ); - } - - GL_SelectTexture( 0 ); - - hash = generateHashValue(name); - image->next = hashTable[hash]; - hashTable[hash] = image; - - return image; -} - -void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height ) -{ - byte *scaledBuffer = NULL; - byte *resampledBuffer = NULL; - int scaled_width, scaled_height, scaled_x, scaled_y; - byte *data = pic; - - // normals are always swizzled - if (image->type == IMGTYPE_NORMAL || image->type == IMGTYPE_NORMALHEIGHT) - { - RawImage_SwizzleRA(pic, width, height); - } - - // LATC2 is only used for normals - if (image->internalFormat == GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT) - { - byte *in = data; - int c = width * height; - while (c--) - { - in[0] = in[1]; - in[2] = in[1]; - in += 4; - } - } - - - RawImage_ScaleToPower2(&pic, &width, &height, &scaled_width, &scaled_height, image->type, image->flags, &resampledBuffer); - - scaledBuffer = ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height ); - - if ( qglActiveTextureARB ) { - GL_SelectTexture( image->TMU ); - } - - GL_Bind(image); - - // copy or resample data as appropriate for first MIP level - if ( ( scaled_width == width ) && - ( scaled_height == height ) ) { - if (!(image->flags & IMGFLAG_MIPMAP)) - { - scaled_x = x * scaled_width / width; - scaled_y = y * scaled_height / height; - RawImage_UploadTexture( data, scaled_x, scaled_y, scaled_width, scaled_height, image->internalFormat, image->type, image->flags, qtrue ); - //qglTexSubImage2D( GL_TEXTURE_2D, 0, scaled_x, scaled_y, scaled_width, scaled_height, GL_RGBA, GL_UNSIGNED_BYTE, data ); - - GL_CheckErrors(); - goto done; - } - Com_Memcpy (scaledBuffer, data, width*height*4); - } - else - { - // use the normal mip-mapping function to go down from here - while ( width > scaled_width || height > scaled_height ) { - - if (image->flags & IMGFLAG_SRGB) - { - R_MipMapsRGB( (byte *)data, width, height ); - } - else - { - R_MipMap( (byte *)data, width, height ); - } - - width >>= 1; - height >>= 1; - x >>= 1; - y >>= 1; - if ( width < 1 ) { - width = 1; - } - if ( height < 1 ) { - height = 1; - } - } - Com_Memcpy( scaledBuffer, data, width * height * 4 ); - } - - if (!(image->flags & IMGFLAG_NOLIGHTSCALE)) - R_LightScaleTexture (scaledBuffer, scaled_width, scaled_height, !(image->flags & IMGFLAG_MIPMAP) ); - - scaled_x = x * scaled_width / width; - scaled_y = y * scaled_height / height; - RawImage_UploadTexture( (byte *)data, scaled_x, scaled_y, scaled_width, scaled_height, image->internalFormat, image->type, image->flags, qtrue ); - -done: - - GL_SelectTexture( 0 ); - - GL_CheckErrors(); - - if ( scaledBuffer != 0 ) - ri.Hunk_FreeTempMemory( scaledBuffer ); - if ( resampledBuffer != 0 ) - ri.Hunk_FreeTempMemory( resampledBuffer ); -} - -//=================================================================== - -typedef struct -{ - char *ext; - void (*ImageLoader)( const char *, unsigned char **, int *, int * ); -} imageExtToLoaderMap_t; - -// Note that the ordering indicates the order of preference used -// when there are multiple images of different formats available -static imageExtToLoaderMap_t imageLoaders[ ] = -{ - { "tga", R_LoadTGA }, - { "jpg", R_LoadJPG }, - { "jpeg", R_LoadJPG }, - { "png", R_LoadPNG }, - { "pcx", R_LoadPCX }, - { "bmp", R_LoadBMP } -}; - -static int numImageLoaders = ARRAY_LEN( imageLoaders ); - -/* -================= -R_LoadImage - -Loads any of the supported image types into a cannonical -32 bit format. -================= -*/ -void R_LoadImage( const char *name, byte **pic, int *width, int *height ) -{ - qboolean orgNameFailed = qfalse; - int orgLoader = -1; - int i; - char localName[ MAX_QPATH ]; - const char *ext; - char *altName; - - *pic = NULL; - *width = 0; - *height = 0; - - Q_strncpyz( localName, name, MAX_QPATH ); - - ext = COM_GetExtension( localName ); - - if( *ext ) - { - // Look for the correct loader and use it - for( i = 0; i < numImageLoaders; i++ ) - { - if( !Q_stricmp( ext, imageLoaders[ i ].ext ) ) - { - // Load - imageLoaders[ i ].ImageLoader( localName, pic, width, height ); - break; - } - } - - // A loader was found - if( i < numImageLoaders ) - { - if( *pic == NULL ) - { - // Loader failed, most likely because the file isn't there; - // try again without the extension - orgNameFailed = qtrue; - orgLoader = i; - COM_StripExtension( name, localName, MAX_QPATH ); - } - else - { - // Something loaded - return; - } - } - } - - // Try and find a suitable match using all - // the image formats supported - for( i = 0; i < numImageLoaders; i++ ) - { - if (i == orgLoader) - continue; - - altName = va( "%s.%s", localName, imageLoaders[ i ].ext ); - - // Load - imageLoaders[ i ].ImageLoader( altName, pic, width, height ); - - if( *pic ) - { - if( orgNameFailed ) - { - ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n", - name, altName ); - } - - break; - } - } -} - - -/* -=============== -R_FindImageFile - -Finds or loads the given image. -Returns NULL if it fails, not a default image. -============== -*/ -image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ) -{ - image_t *image; - int width, height; - byte *pic; - long hash; - - if (!name) { - return NULL; - } - - hash = generateHashValue(name); - - // - // see if the image is already loaded - // - for (image=hashTable[hash]; image; image=image->next) { - if ( !strcmp( name, image->imgName ) ) { - // the white image can be used with any set of parms, but other mismatches are errors - if ( strcmp( name, "*white" ) ) { - if ( image->flags != flags ) { - ri.Printf( PRINT_DEVELOPER, "WARNING: reused image %s with mixed flags (%i vs %i)\n", name, image->flags, flags ); - } - } - return image; - } - } - - // - // load the pic from disk - // - R_LoadImage( name, &pic, &width, &height ); - if ( pic == NULL ) { - return NULL; - } - - if (r_normalMapping->integer && !(type == IMGTYPE_NORMAL) && (flags & IMGFLAG_PICMIP) && (flags & IMGFLAG_MIPMAP) && (flags & IMGFLAG_GENNORMALMAP)) - { - char normalName[MAX_QPATH]; - image_t *normalImage; - int normalWidth, normalHeight; - imgFlags_t normalFlags; - - normalFlags = (flags & ~(IMGFLAG_GENNORMALMAP | IMGFLAG_SRGB)) | IMGFLAG_NOLIGHTSCALE; - - COM_StripExtension(name, normalName, MAX_QPATH); - Q_strcat(normalName, MAX_QPATH, "_n"); - - // find normalmap in case it's there - normalImage = R_FindImageFile(normalName, IMGTYPE_NORMAL, normalFlags); - - // if not, generate it - if (normalImage == NULL) - { - byte *normalPic; - int x, y; - - normalWidth = width; - normalHeight = height; - normalPic = ri.Malloc(width * height * 4); - RGBAtoNormal(pic, normalPic, width, height, flags & IMGFLAG_CLAMPTOEDGE); - -#if 1 - // Brighten up the original image to work with the normal map - RGBAtoYCoCgA(pic, pic, width, height); - for (y = 0; y < height; y++) - { - byte *picbyte = pic + y * width * 4; - byte *normbyte = normalPic + y * width * 4; - for (x = 0; x < width; x++) - { - int div = MAX(normbyte[2] - 127, 16); - picbyte[0] = CLAMP(picbyte[0] * 128 / div, 0, 255); - picbyte += 4; - normbyte += 4; - } - } - YCoCgAtoRGBA(pic, pic, width, height); -#else - // Blur original image's luma to work with the normal map - { - byte *blurPic; - - RGBAtoYCoCgA(pic, pic, width, height); - blurPic = ri.Malloc(width * height); - - for (y = 1; y < height - 1; y++) - { - byte *picbyte = pic + y * width * 4; - byte *blurbyte = blurPic + y * width; - - picbyte += 4; - blurbyte += 1; - - for (x = 1; x < width - 1; x++) - { - int result; - - result = *(picbyte - (width + 1) * 4) + *(picbyte - width * 4) + *(picbyte - (width - 1) * 4) + - *(picbyte - 1 * 4) + *(picbyte ) + *(picbyte + 1 * 4) + - *(picbyte + (width - 1) * 4) + *(picbyte + width * 4) + *(picbyte + (width + 1) * 4); - - result /= 9; - - *blurbyte = result; - picbyte += 4; - blurbyte += 1; - } - } - - // FIXME: do borders - - for (y = 1; y < height - 1; y++) - { - byte *picbyte = pic + y * width * 4; - byte *blurbyte = blurPic + y * width; - - picbyte += 4; - blurbyte += 1; - - for (x = 1; x < width - 1; x++) - { - picbyte[0] = *blurbyte; - picbyte += 4; - blurbyte += 1; - } - } - - ri.Free(blurPic); - - YCoCgAtoRGBA(pic, pic, width, height); - } -#endif - - R_CreateImage( normalName, normalPic, normalWidth, normalHeight, IMGTYPE_NORMAL, normalFlags, 0 ); - ri.Free( normalPic ); - } - } - - image = R_CreateImage( ( char * ) name, pic, width, height, type, flags, 0 ); - ri.Free( pic ); - return image; -} - - -/* -================ -R_CreateDlightImage -================ -*/ -#define DLIGHT_SIZE 16 -static void R_CreateDlightImage( void ) { - int x,y; - byte data[DLIGHT_SIZE][DLIGHT_SIZE][4]; - int b; - - // make a centered inverse-square falloff blob for dynamic lighting - for (x=0 ; x 255) { - b = 255; - } else if ( b < 75 ) { - b = 0; - } - data[y][x][0] = - data[y][x][1] = - data[y][x][2] = b; - data[y][x][3] = 255; - } - } - tr.dlightImage = R_CreateImage("*dlight", (byte *)data, DLIGHT_SIZE, DLIGHT_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_CLAMPTOEDGE, 0 ); -} - - -/* -================= -R_InitFogTable -================= -*/ -void R_InitFogTable( void ) { - int i; - float d; - float exp; - - exp = 0.5; - - for ( i = 0 ; i < FOG_TABLE_SIZE ; i++ ) { - d = pow ( (float)i/(FOG_TABLE_SIZE-1), exp ); - - tr.fogTable[i] = d; - } -} - -/* -================ -R_FogFactor - -Returns a 0.0 to 1.0 fog density value -This is called for each texel of the fog texture on startup -and for each vertex of transparent shaders in fog dynamically -================ -*/ -float R_FogFactor( float s, float t ) { - float d; - - s -= 1.0/512; - if ( s < 0 ) { - return 0; - } - if ( t < 1.0/32 ) { - return 0; - } - if ( t < 31.0/32 ) { - s *= (t - 1.0f/32.0f) / (30.0f/32.0f); - } - - // we need to leave a lot of clamp range - s *= 8; - - if ( s > 1.0 ) { - s = 1.0; - } - - d = tr.fogTable[ (int)(s * (FOG_TABLE_SIZE-1)) ]; - - return d; -} - -/* -================ -R_CreateFogImage -================ -*/ -#define FOG_S 256 -#define FOG_T 32 -static void R_CreateFogImage( void ) { - int x,y; - byte *data; - float d; - float borderColor[4]; - - data = ri.Hunk_AllocateTempMemory( FOG_S * FOG_T * 4 ); - - // S is distance, T is depth - for (x=0 ; xinteger >= 2) - { - for( x = 0; x < MAX_DLIGHTS; x++) - { - tr.shadowCubemaps[x] = R_CreateImage(va("*shadowcubemap%i", x), (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_CLAMPTOEDGE | IMGFLAG_CUBEMAP, 0); - } - } - - // with overbright bits active, we need an image which is some fraction of full color, - // for default lightmaps, etc - for (x=0 ; xinteger && glRefConfig.framebufferObject && glRefConfig.textureFloat) - hdrFormat = GL_RGBA16F_ARB; - - rgbFormat = GL_RGBA8; - - tr.renderImage = R_CreateImage("_render", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat); - - if (r_drawSunRays->integer) - tr.sunRaysImage = R_CreateImage("*sunRays", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, rgbFormat); - - if (glRefConfig.framebufferObject) - { - tr.renderDepthImage = R_CreateImage("*renderdepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB); - tr.textureDepthImage = R_CreateImage("*texturedepth", NULL, PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB); - } - - { - unsigned short sdata[4]; - void *p; - - if (hdrFormat == GL_RGBA16F_ARB) - { - sdata[0] = FloatToHalf(0.0f); - sdata[1] = FloatToHalf(0.45f); - sdata[2] = FloatToHalf(1.0f); - sdata[3] = FloatToHalf(1.0f); - p = &sdata[0]; - } - else - { - data[0][0][0] = 0; - data[0][0][1] = 0.45f * 255; - data[0][0][2] = 255; - data[0][0][3] = 255; - p = data; - } - - tr.calcLevelsImage = R_CreateImage("*calcLevels", p, 1, 1, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat); - tr.targetLevelsImage = R_CreateImage("*targetLevels", p, 1, 1, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat); - tr.fixedLevelsImage = R_CreateImage("*fixedLevels", p, 1, 1, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat); - } - - for (x = 0; x < 2; x++) - { - tr.textureScratchImage[x] = R_CreateImage(va("*textureScratch%d", x), NULL, 256, 256, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); - } - for (x = 0; x < 2; x++) - { - tr.quarterImage[x] = R_CreateImage(va("*quarter%d", x), NULL, width / 2, height / 2, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); - } - - if (r_ssao->integer) - { - tr.screenSsaoImage = R_CreateImage("*screenSsao", NULL, width / 2, height / 2, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); - tr.hdrDepthImage = R_CreateImage("*hdrDepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_INTENSITY32F_ARB); - } - - if (r_shadows->integer == 4) - { - for( x = 0; x < MAX_DRAWN_PSHADOWS; x++) - { - tr.pshadowMaps[x] = R_CreateImage(va("*shadowmap%i", x), NULL, PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); - } - } - - if (r_sunlightMode->integer) - { - for ( x = 0; x < 3; x++) - { - tr.sunShadowDepthImage[x] = R_CreateImage(va("*sunshadowdepth%i", x), NULL, r_shadowMapSize->integer, r_shadowMapSize->integer, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB); - } - - tr.screenShadowImage = R_CreateImage("*screenShadow", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); - } - - if (r_cubeMapping->integer) - { - tr.renderCubeImage = R_CreateImage("*renderCube", NULL, CUBE_MAP_SIZE, CUBE_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_CUBEMAP, rgbFormat); - } - } -} - - -/* -=============== -R_SetColorMappings -=============== -*/ -void R_SetColorMappings( void ) { - int i, j; - float g; - int inf; - int shift; - - // setup the overbright lighting - tr.overbrightBits = r_overBrightBits->integer; - if ( !glConfig.deviceSupportsGamma ) { - tr.overbrightBits = 0; // need hardware gamma for overbright - } - - // never overbright in windowed mode without soft overbright - if ( !glConfig.isFullscreen && !r_softOverbright->integer ) - { - tr.overbrightBits = 0; - } - - // never overbright with tonemapping - if ( r_toneMap->integer && r_hdr->integer ) - { - tr.overbrightBits = 0; - } - - // allow 2 overbright bits in 24 bit, but only 1 in 16 bit - if ( glConfig.colorBits > 16 ) { - if ( tr.overbrightBits > 2 ) { - tr.overbrightBits = 2; - } - } else { - if ( tr.overbrightBits > 1 ) { - tr.overbrightBits = 1; - } - } - if ( tr.overbrightBits < 0 ) { - tr.overbrightBits = 0; - } - - tr.identityLight = 1.0f / ( 1 << tr.overbrightBits ); - tr.identityLightByte = 255 * tr.identityLight; - - - if ( r_intensity->value <= 1 ) { - ri.Cvar_Set( "r_intensity", "1" ); - } - - if ( r_gamma->value < 0.5f ) { - ri.Cvar_Set( "r_gamma", "0.5" ); - } else if ( r_gamma->value > 3.0f ) { - ri.Cvar_Set( "r_gamma", "3.0" ); - } - - g = r_gamma->value; - - shift = tr.overbrightBits; - - // no shift with soft overbright - if (r_softOverbright->integer) - { - shift = 0; - } - - for ( i = 0; i < 256; i++ ) { - int i2; - - if (r_srgb->integer) - { - i2 = 255 * RGBtosRGB(i/255.0f) + 0.5f; - } - else - { - i2 = i; - } - - if ( g == 1 ) { - inf = i2; - } else { - inf = 255 * pow ( i2/255.0f, 1.0f / g ) + 0.5f; - } - inf <<= shift; - if (inf < 0) { - inf = 0; - } - if (inf > 255) { - inf = 255; - } - s_gammatable[i] = inf; - } - - for (i=0 ; i<256 ; i++) { - j = i * r_intensity->value; - if (j > 255) { - j = 255; - } - s_intensitytable[i] = j; - } - - if ( glConfig.deviceSupportsGamma ) - { - GLimp_SetGamma( s_gammatable, s_gammatable, s_gammatable ); - } -} - -/* -=============== -R_InitImages -=============== -*/ -void R_InitImages( void ) { - Com_Memset(hashTable, 0, sizeof(hashTable)); - // build brightness translation tables - R_SetColorMappings(); - - // create default texture and white texture - R_CreateBuiltinImages(); -} - -/* -=============== -R_DeleteTextures -=============== -*/ -void R_DeleteTextures( void ) { - int i; - - for ( i=0; itexnum ); - } - Com_Memset( tr.images, 0, sizeof( tr.images ) ); - - tr.numImages = 0; - - Com_Memset( glState.currenttextures, 0, sizeof( glState.currenttextures ) ); - if ( qglActiveTextureARB ) { - GL_SelectTexture( 1 ); - qglBindTexture( GL_TEXTURE_2D, 0 ); - GL_SelectTexture( 0 ); - qglBindTexture( GL_TEXTURE_2D, 0 ); - } else { - qglBindTexture( GL_TEXTURE_2D, 0 ); - } -} - -/* -============================================================================ - -SKINS - -============================================================================ -*/ - -/* -================== -CommaParse - -This is unfortunate, but the skin files aren't -compatable with our normal parsing rules. -================== -*/ -static char *CommaParse( char **data_p ) { - int c = 0, len; - char *data; - static char com_token[MAX_TOKEN_CHARS]; - - data = *data_p; - len = 0; - com_token[0] = 0; - - // make sure incoming data is valid - if ( !data ) { - *data_p = NULL; - return com_token; - } - - while ( 1 ) { - // skip whitespace - while( (c = *data) <= ' ') { - if( !c ) { - break; - } - data++; - } - - - c = *data; - - // skip double slash comments - if ( c == '/' && data[1] == '/' ) - { - while (*data && *data != '\n') - data++; - } - // skip /* */ comments - else if ( c=='/' && data[1] == '*' ) - { - while ( *data && ( *data != '*' || data[1] != '/' ) ) - { - data++; - } - if ( *data ) - { - data += 2; - } - } - else - { - break; - } - } - - if ( c == 0 ) { - return ""; - } - - // handle quoted strings - if (c == '\"') - { - data++; - while (1) - { - c = *data++; - if (c=='\"' || !c) - { - com_token[len] = 0; - *data_p = ( char * ) data; - return com_token; - } - if (len < MAX_TOKEN_CHARS) - { - com_token[len] = c; - len++; - } - } - } - - // parse a regular word - do - { - if (len < MAX_TOKEN_CHARS) - { - com_token[len] = c; - len++; - } - data++; - c = *data; - } while (c>32 && c != ',' ); - - if (len == MAX_TOKEN_CHARS) - { -// ri.Printf (PRINT_DEVELOPER, "Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS); - len = 0; - } - com_token[len] = 0; - - *data_p = ( char * ) data; - return com_token; -} - - -/* -=============== -RE_RegisterSkin - -=============== -*/ -qhandle_t RE_RegisterSkin( const char *name ) { - qhandle_t hSkin; - skin_t *skin; - skinSurface_t *surf; - union { - char *c; - void *v; - } text; - char *text_p; - char *token; - char surfName[MAX_QPATH]; - - if ( !name || !name[0] ) { - ri.Printf( PRINT_DEVELOPER, "Empty name passed to RE_RegisterSkin\n" ); - return 0; - } - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_DEVELOPER, "Skin name exceeds MAX_QPATH\n" ); - return 0; - } - - - // see if the skin is already loaded - for ( hSkin = 1; hSkin < tr.numSkins ; hSkin++ ) { - skin = tr.skins[hSkin]; - if ( !Q_stricmp( skin->name, name ) ) { - if( skin->numSurfaces == 0 ) { - return 0; // default skin - } - return hSkin; - } - } - - // allocate a new skin - if ( tr.numSkins == MAX_SKINS ) { - ri.Printf( PRINT_WARNING, "WARNING: RE_RegisterSkin( '%s' ) MAX_SKINS hit\n", name ); - return 0; - } - tr.numSkins++; - skin = ri.Hunk_Alloc( sizeof( skin_t ), h_low ); - tr.skins[hSkin] = skin; - Q_strncpyz( skin->name, name, sizeof( skin->name ) ); - skin->numSurfaces = 0; - - R_IssuePendingRenderCommands(); - - // If not a .skin file, load as a single shader - if ( strcmp( name + strlen( name ) - 5, ".skin" ) ) { - skin->numSurfaces = 1; - skin->surfaces[0] = ri.Hunk_Alloc( sizeof(skin->surfaces[0]), h_low ); - skin->surfaces[0]->shader = R_FindShader( name, LIGHTMAP_NONE, qtrue ); - return hSkin; - } - - // load and parse the skin file - ri.FS_ReadFile( name, &text.v ); - if ( !text.c ) { - return 0; - } - - text_p = text.c; - while ( text_p && *text_p ) { - // get surface name - token = CommaParse( &text_p ); - Q_strncpyz( surfName, token, sizeof( surfName ) ); - - if ( !token[0] ) { - break; - } - // lowercase the surface name so skin compares are faster - Q_strlwr( surfName ); - - if ( *text_p == ',' ) { - text_p++; - } - - if ( strstr( token, "tag_" ) ) { - continue; - } - - // parse the shader name - token = CommaParse( &text_p ); - - if ( skin->numSurfaces >= MD3_MAX_SURFACES ) { - ri.Printf( PRINT_WARNING, "WARNING: Ignoring surfaces in '%s', the max is %d surfaces!\n", name, MD3_MAX_SURFACES ); - break; - } - - surf = skin->surfaces[ skin->numSurfaces ] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low ); - Q_strncpyz( surf->name, surfName, sizeof( surf->name ) ); - surf->shader = R_FindShader( token, LIGHTMAP_NONE, qtrue ); - skin->numSurfaces++; - } - - ri.FS_FreeFile( text.v ); - - - // never let a skin have 0 shaders - if ( skin->numSurfaces == 0 ) { - return 0; // use default skin - } - - return hSkin; -} - - -/* -=============== -R_InitSkins -=============== -*/ -void R_InitSkins( void ) { - skin_t *skin; - - tr.numSkins = 1; - - // make the default skin have all default shaders - skin = tr.skins[0] = ri.Hunk_Alloc( sizeof( skin_t ), h_low ); - Q_strncpyz( skin->name, "", sizeof( skin->name ) ); - skin->numSurfaces = 1; - skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces ), h_low ); - skin->surfaces[0]->shader = tr.defaultShader; -} - -/* -=============== -R_GetSkinByHandle -=============== -*/ -skin_t *R_GetSkinByHandle( qhandle_t hSkin ) { - if ( hSkin < 1 || hSkin >= tr.numSkins ) { - return tr.skins[0]; - } - return tr.skins[ hSkin ]; -} - -/* -=============== -R_SkinList_f -=============== -*/ -void R_SkinList_f( void ) { - int i, j; - skin_t *skin; - - ri.Printf (PRINT_ALL, "------------------\n"); - - for ( i = 0 ; i < tr.numSkins ; i++ ) { - skin = tr.skins[i]; - - ri.Printf( PRINT_ALL, "%3i:%s\n", i, skin->name ); - for ( j = 0 ; j < skin->numSurfaces ; j++ ) { - ri.Printf( PRINT_ALL, " %s = %s\n", - skin->surfaces[j]->name, skin->surfaces[j]->shader->name ); - } - } - ri.Printf (PRINT_ALL, "------------------\n"); -} - - diff --git a/code/renderergl2/tr_init.c b/code/renderergl2/tr_init.c deleted file mode 100644 index 00646be2ed..0000000000 --- a/code/renderergl2/tr_init.c +++ /dev/null @@ -1,1580 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_init.c -- functions that are not called every frame - -#include "tr_local.h" - -glconfig_t glConfig; -glRefConfig_t glRefConfig; -qboolean textureFilterAnisotropic = qfalse; -int maxAnisotropy = 0; -float displayAspect = 0.0f; - -glstate_t glState; - -static void GfxInfo_f( void ); -static void GfxMemInfo_f( void ); - -#ifdef USE_RENDERER_DLOPEN -cvar_t *com_altivec; -#endif - -cvar_t *r_flareSize; -cvar_t *r_flareFade; -cvar_t *r_flareCoeff; - -cvar_t *r_railWidth; -cvar_t *r_railCoreWidth; -cvar_t *r_railSegmentLength; - -cvar_t *r_verbose; -cvar_t *r_ignore; - -cvar_t *r_detailTextures; - -cvar_t *r_znear; -cvar_t *r_zproj; -cvar_t *r_stereoSeparation; - -cvar_t *r_skipBackEnd; - -cvar_t *r_stereoEnabled; -cvar_t *r_anaglyphMode; - -cvar_t *r_greyscale; - -cvar_t *r_ignorehwgamma; -cvar_t *r_measureOverdraw; - -cvar_t *r_inGameVideo; -cvar_t *r_fastsky; -cvar_t *r_drawSun; -cvar_t *r_dynamiclight; -cvar_t *r_dlightBacks; - -cvar_t *r_lodbias; -cvar_t *r_lodscale; - -cvar_t *r_norefresh; -cvar_t *r_drawentities; -cvar_t *r_drawworld; -cvar_t *r_speeds; -cvar_t *r_fullbright; -cvar_t *r_novis; -cvar_t *r_nocull; -cvar_t *r_facePlaneCull; -cvar_t *r_showcluster; -cvar_t *r_nocurves; - -cvar_t *r_allowExtensions; - -cvar_t *r_ext_compressed_textures; -cvar_t *r_ext_multitexture; -cvar_t *r_ext_compiled_vertex_array; -cvar_t *r_ext_texture_env_add; -cvar_t *r_ext_texture_filter_anisotropic; -cvar_t *r_ext_max_anisotropy; - -cvar_t *r_ext_draw_range_elements; -cvar_t *r_ext_multi_draw_arrays; -cvar_t *r_ext_framebuffer_object; -cvar_t *r_ext_texture_float; -cvar_t *r_arb_half_float_pixel; -cvar_t *r_ext_framebuffer_multisample; -cvar_t *r_arb_seamless_cube_map; -cvar_t *r_arb_vertex_type_2_10_10_10_rev; - -cvar_t *r_mergeMultidraws; -cvar_t *r_mergeLeafSurfaces; - -cvar_t *r_cameraExposure; - -cvar_t *r_softOverbright; - -cvar_t *r_hdr; -cvar_t *r_floatLightmap; -cvar_t *r_postProcess; - -cvar_t *r_toneMap; -cvar_t *r_forceToneMap; -cvar_t *r_forceToneMapMin; -cvar_t *r_forceToneMapAvg; -cvar_t *r_forceToneMapMax; - -cvar_t *r_autoExposure; -cvar_t *r_forceAutoExposure; -cvar_t *r_forceAutoExposureMin; -cvar_t *r_forceAutoExposureMax; - -cvar_t *r_srgb; - -cvar_t *r_depthPrepass; -cvar_t *r_ssao; - -cvar_t *r_normalMapping; -cvar_t *r_specularMapping; -cvar_t *r_deluxeMapping; -cvar_t *r_parallaxMapping; -cvar_t *r_cubeMapping; -cvar_t *r_deluxeSpecular; -cvar_t *r_specularIsMetallic; -cvar_t *r_baseSpecular; -cvar_t *r_baseGloss; -cvar_t *r_recalcMD3Normals; -cvar_t *r_mergeLightmaps; -cvar_t *r_dlightMode; -cvar_t *r_pshadowDist; -cvar_t *r_imageUpsample; -cvar_t *r_imageUpsampleMaxSize; -cvar_t *r_imageUpsampleType; -cvar_t *r_genNormalMaps; -cvar_t *r_forceSun; -cvar_t *r_forceSunMapLightScale; -cvar_t *r_forceSunLightScale; -cvar_t *r_forceSunAmbientScale; -cvar_t *r_sunlightMode; -cvar_t *r_drawSunRays; -cvar_t *r_sunShadows; -cvar_t *r_shadowFilter; -cvar_t *r_shadowMapSize; -cvar_t *r_shadowCascadeZNear; -cvar_t *r_shadowCascadeZFar; -cvar_t *r_shadowCascadeZBias; -cvar_t *r_ignoreDstAlpha; - -cvar_t *r_ignoreGLErrors; -cvar_t *r_logFile; - -cvar_t *r_stencilbits; -cvar_t *r_depthbits; -cvar_t *r_colorbits; -cvar_t *r_texturebits; -cvar_t *r_ext_multisample; - -cvar_t *r_drawBuffer; -cvar_t *r_lightmap; -cvar_t *r_vertexLight; -cvar_t *r_uiFullScreen; -cvar_t *r_shadows; -cvar_t *r_flares; -cvar_t *r_mode; -cvar_t *r_nobind; -cvar_t *r_singleShader; -cvar_t *r_roundImagesDown; -cvar_t *r_colorMipLevels; -cvar_t *r_picmip; -cvar_t *r_showtris; -cvar_t *r_showsky; -cvar_t *r_shownormals; -cvar_t *r_finish; -cvar_t *r_clear; -cvar_t *r_swapInterval; -cvar_t *r_textureMode; -cvar_t *r_offsetFactor; -cvar_t *r_offsetUnits; -cvar_t *r_gamma; -cvar_t *r_intensity; -cvar_t *r_lockpvs; -cvar_t *r_noportals; -cvar_t *r_portalOnly; - -cvar_t *r_subdivisions; -cvar_t *r_lodCurveError; - -cvar_t *r_fullscreen; -cvar_t *r_noborder; - -cvar_t *r_customwidth; -cvar_t *r_customheight; -cvar_t *r_customPixelAspect; - -cvar_t *r_overBrightBits; -cvar_t *r_mapOverBrightBits; - -cvar_t *r_debugSurface; -cvar_t *r_simpleMipMaps; - -cvar_t *r_showImages; - -cvar_t *r_ambientScale; -cvar_t *r_directedScale; -cvar_t *r_debugLight; -cvar_t *r_debugSort; -cvar_t *r_printShaders; -cvar_t *r_saveFontData; - -cvar_t *r_marksOnTriangleMeshes; - -cvar_t *r_aviMotionJpegQuality; -cvar_t *r_screenshotJpegQuality; - -cvar_t *r_maxpolys; -int max_polys; -cvar_t *r_maxpolyverts; -int max_polyverts; - -/* -** InitOpenGL -** -** This function is responsible for initializing a valid OpenGL subsystem. This -** is done by calling GLimp_Init (which gives us a working OGL subsystem) then -** setting variables, checking GL constants, and reporting the gfx system config -** to the user. -*/ -static void InitOpenGL( void ) -{ - char renderer_buffer[1024]; - - // - // initialize OS specific portions of the renderer - // - // GLimp_Init directly or indirectly references the following cvars: - // - r_fullscreen - // - r_mode - // - r_(color|depth|stencil)bits - // - r_ignorehwgamma - // - r_gamma - // - - if ( glConfig.vidWidth == 0 ) - { - GLint temp; - - GLimp_Init(); - GLimp_InitExtraExtensions(); - - strcpy( renderer_buffer, glConfig.renderer_string ); - Q_strlwr( renderer_buffer ); - - // OpenGL driver constants - qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp ); - glConfig.maxTextureSize = temp; - - // stubbed or broken drivers may have reported 0... - if ( glConfig.maxTextureSize <= 0 ) - { - glConfig.maxTextureSize = 0; - } - } - - // set default state - GL_SetDefaultState(); -} - -/* -================== -GL_CheckErrors -================== -*/ -void GL_CheckErrs( char *file, int line ) { - int err; - char s[64]; - - err = qglGetError(); - if ( err == GL_NO_ERROR ) { - return; - } - if ( r_ignoreGLErrors->integer ) { - return; - } - switch( err ) { - case GL_INVALID_ENUM: - strcpy( s, "GL_INVALID_ENUM" ); - break; - case GL_INVALID_VALUE: - strcpy( s, "GL_INVALID_VALUE" ); - break; - case GL_INVALID_OPERATION: - strcpy( s, "GL_INVALID_OPERATION" ); - break; - case GL_STACK_OVERFLOW: - strcpy( s, "GL_STACK_OVERFLOW" ); - break; - case GL_STACK_UNDERFLOW: - strcpy( s, "GL_STACK_UNDERFLOW" ); - break; - case GL_OUT_OF_MEMORY: - strcpy( s, "GL_OUT_OF_MEMORY" ); - break; - default: - Com_sprintf( s, sizeof(s), "%i", err); - break; - } - - ri.Error( ERR_FATAL, "GL_CheckErrors: %s in %s at line %d", s , file, line); -} - - -/* -** R_GetModeInfo -*/ -typedef struct vidmode_s -{ - const char *description; - int width, height; - float pixelAspect; // pixel width / height -} vidmode_t; - -vidmode_t r_vidModes[] = -{ - { "Mode 0: 320x240", 320, 240, 1 }, - { "Mode 1: 400x300", 400, 300, 1 }, - { "Mode 2: 512x384", 512, 384, 1 }, - { "Mode 3: 640x480", 640, 480, 1 }, - { "Mode 4: 800x600", 800, 600, 1 }, - { "Mode 5: 960x720", 960, 720, 1 }, - { "Mode 6: 1024x768", 1024, 768, 1 }, - { "Mode 7: 1152x864", 1152, 864, 1 }, - { "Mode 8: 1280x1024", 1280, 1024, 1 }, - { "Mode 9: 1600x1200", 1600, 1200, 1 }, - { "Mode 10: 2048x1536", 2048, 1536, 1 }, - { "Mode 11: 856x480 (wide)",856, 480, 1 } -}; -static int s_numVidModes = ARRAY_LEN( r_vidModes ); - -qboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode ) { - vidmode_t *vm; - float pixelAspect; - - if ( mode < -1 ) { - return qfalse; - } - if ( mode >= s_numVidModes ) { - return qfalse; - } - - if ( mode == -1 ) { - *width = r_customwidth->integer; - *height = r_customheight->integer; - pixelAspect = r_customPixelAspect->value; - } else { - vm = &r_vidModes[mode]; - - *width = vm->width; - *height = vm->height; - pixelAspect = vm->pixelAspect; - } - - *windowAspect = (float)*width / ( *height * pixelAspect ); - - return qtrue; -} - -/* -** R_ModeList_f -*/ -static void R_ModeList_f( void ) -{ - int i; - - ri.Printf( PRINT_ALL, "\n" ); - for ( i = 0; i < s_numVidModes; i++ ) - { - ri.Printf( PRINT_ALL, "%s\n", r_vidModes[i].description ); - } - ri.Printf( PRINT_ALL, "\n" ); -} - - -/* -============================================================================== - - SCREEN SHOTS - -NOTE TTimo -some thoughts about the screenshots system: -screenshots get written in fs_homepath + fs_gamedir -vanilla q3 .. baseq3/screenshots/ *.tga -team arena .. missionpack/screenshots/ *.tga - -two commands: "screenshot" and "screenshotJPEG" -we use statics to store a count and start writing the first screenshot/screenshot????.tga (.jpg) available -(with FS_FileExists / FS_FOpenFileWrite calls) -FIXME: the statics don't get a reinit between fs_game changes - -============================================================================== -*/ - -/* -================== -RB_ReadPixels - -Reads an image but takes care of alignment issues for reading RGB images. - -Reads a minimum offset for where the RGB data starts in the image from -integer stored at pointer offset. When the function has returned the actual -offset was written back to address offset. This address will always have an -alignment of packAlign to ensure efficient copying. - -Stores the length of padding after a line of pixels to address padlen - -Return value must be freed with ri.Hunk_FreeTempMemory() -================== -*/ - -byte *RB_ReadPixels(int x, int y, int width, int height, size_t *offset, int *padlen) -{ - byte *buffer, *bufstart; - int padwidth, linelen; - GLint packAlign; - - qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign); - - linelen = width * 3; - padwidth = PAD(linelen, packAlign); - - // Allocate a few more bytes so that we can choose an alignment we like - buffer = ri.Hunk_AllocateTempMemory(padwidth * height + *offset + packAlign - 1); - - bufstart = PADP((intptr_t) buffer + *offset, packAlign); - qglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, bufstart); - - *offset = bufstart - buffer; - *padlen = padwidth - linelen; - - return buffer; -} - -/* -================== -RB_TakeScreenshot -================== -*/ -void RB_TakeScreenshot(int x, int y, int width, int height, char *fileName) -{ - byte *allbuf, *buffer; - byte *srcptr, *destptr; - byte *endline, *endmem; - byte temp; - - int linelen, padlen; - size_t offset = 18, memcount; - - allbuf = RB_ReadPixels(x, y, width, height, &offset, &padlen); - buffer = allbuf + offset - 18; - - Com_Memset (buffer, 0, 18); - buffer[2] = 2; // uncompressed type - buffer[12] = width & 255; - buffer[13] = width >> 8; - buffer[14] = height & 255; - buffer[15] = height >> 8; - buffer[16] = 24; // pixel size - - // swap rgb to bgr and remove padding from line endings - linelen = width * 3; - - srcptr = destptr = allbuf + offset; - endmem = srcptr + (linelen + padlen) * height; - - while(srcptr < endmem) - { - endline = srcptr + linelen; - - while(srcptr < endline) - { - temp = srcptr[0]; - *destptr++ = srcptr[2]; - *destptr++ = srcptr[1]; - *destptr++ = temp; - - srcptr += 3; - } - - // Skip the pad - srcptr += padlen; - } - - memcount = linelen * height; - - // gamma correct - if(glConfig.deviceSupportsGamma) - R_GammaCorrect(allbuf + offset, memcount); - - ri.FS_WriteFile(fileName, buffer, memcount + 18); - - ri.Hunk_FreeTempMemory(allbuf); -} - -/* -================== -RB_TakeScreenshotJPEG -================== -*/ - -void RB_TakeScreenshotJPEG(int x, int y, int width, int height, char *fileName) -{ - byte *buffer; - size_t offset = 0, memcount; - int padlen; - - buffer = RB_ReadPixels(x, y, width, height, &offset, &padlen); - memcount = (width * 3 + padlen) * height; - - // gamma correct - if(glConfig.deviceSupportsGamma) - R_GammaCorrect(buffer + offset, memcount); - - RE_SaveJPG(fileName, r_screenshotJpegQuality->integer, width, height, buffer + offset, padlen); - ri.Hunk_FreeTempMemory(buffer); -} - -/* -================== -RB_TakeScreenshotCmd -================== -*/ -const void *RB_TakeScreenshotCmd( const void *data ) { - const screenshotCommand_t *cmd; - - cmd = (const screenshotCommand_t *)data; - - // finish any 2D drawing if needed - if(tess.numIndexes) - RB_EndSurface(); - - if (cmd->jpeg) - RB_TakeScreenshotJPEG( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName); - else - RB_TakeScreenshot( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName); - - return (const void *)(cmd + 1); -} - -/* -================== -R_TakeScreenshot -================== -*/ -void R_TakeScreenshot( int x, int y, int width, int height, char *name, qboolean jpeg ) { - static char fileName[MAX_OSPATH]; // bad things if two screenshots per frame? - screenshotCommand_t *cmd; - - cmd = R_GetCommandBuffer( sizeof( *cmd ) ); - if ( !cmd ) { - return; - } - cmd->commandId = RC_SCREENSHOT; - - cmd->x = x; - cmd->y = y; - cmd->width = width; - cmd->height = height; - Q_strncpyz( fileName, name, sizeof(fileName) ); - cmd->fileName = fileName; - cmd->jpeg = jpeg; -} - -/* -================== -R_ScreenshotFilename -================== -*/ -void R_ScreenshotFilename( int lastNumber, char *fileName ) { - int a,b,c,d; - - if ( lastNumber < 0 || lastNumber > 9999 ) { - Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot9999.tga" ); - return; - } - - a = lastNumber / 1000; - lastNumber -= a*1000; - b = lastNumber / 100; - lastNumber -= b*100; - c = lastNumber / 10; - lastNumber -= c*10; - d = lastNumber; - - Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot%i%i%i%i.tga" - , a, b, c, d ); -} - -/* -================== -R_ScreenshotFilename -================== -*/ -void R_ScreenshotFilenameJPEG( int lastNumber, char *fileName ) { - int a,b,c,d; - - if ( lastNumber < 0 || lastNumber > 9999 ) { - Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot9999.jpg" ); - return; - } - - a = lastNumber / 1000; - lastNumber -= a*1000; - b = lastNumber / 100; - lastNumber -= b*100; - c = lastNumber / 10; - lastNumber -= c*10; - d = lastNumber; - - Com_sprintf( fileName, MAX_OSPATH, "screenshots/shot%i%i%i%i.jpg" - , a, b, c, d ); -} - -/* -==================== -R_LevelShot - -levelshots are specialized 128*128 thumbnails for -the menu system, sampled down from full screen distorted images -==================== -*/ -void R_LevelShot( void ) { - char checkname[MAX_OSPATH]; - byte *buffer; - byte *source, *allsource; - byte *src, *dst; - size_t offset = 0; - int padlen; - int x, y; - int r, g, b; - float xScale, yScale; - int xx, yy; - - Com_sprintf(checkname, sizeof(checkname), "levelshots/%s.tga", tr.world->baseName); - - allsource = RB_ReadPixels(0, 0, glConfig.vidWidth, glConfig.vidHeight, &offset, &padlen); - source = allsource + offset; - - buffer = ri.Hunk_AllocateTempMemory(128 * 128*3 + 18); - Com_Memset (buffer, 0, 18); - buffer[2] = 2; // uncompressed type - buffer[12] = 128; - buffer[14] = 128; - buffer[16] = 24; // pixel size - - // resample from source - xScale = glConfig.vidWidth / 512.0f; - yScale = glConfig.vidHeight / 384.0f; - for ( y = 0 ; y < 128 ; y++ ) { - for ( x = 0 ; x < 128 ; x++ ) { - r = g = b = 0; - for ( yy = 0 ; yy < 3 ; yy++ ) { - for ( xx = 0 ; xx < 4 ; xx++ ) { - src = source + (3 * glConfig.vidWidth + padlen) * (int)((y*3 + yy) * yScale) + - 3 * (int) ((x*4 + xx) * xScale); - r += src[0]; - g += src[1]; - b += src[2]; - } - } - dst = buffer + 18 + 3 * ( y * 128 + x ); - dst[0] = b / 12; - dst[1] = g / 12; - dst[2] = r / 12; - } - } - - // gamma correct - if ( glConfig.deviceSupportsGamma ) { - R_GammaCorrect( buffer + 18, 128 * 128 * 3 ); - } - - ri.FS_WriteFile( checkname, buffer, 128 * 128*3 + 18 ); - - ri.Hunk_FreeTempMemory(buffer); - ri.Hunk_FreeTempMemory(allsource); - - ri.Printf( PRINT_ALL, "Wrote %s\n", checkname ); -} - -/* -================== -R_ScreenShot_f - -screenshot -screenshot [silent] -screenshot [levelshot] -screenshot [filename] - -Doesn't print the pacifier message if there is a second arg -================== -*/ -void R_ScreenShot_f (void) { - char checkname[MAX_OSPATH]; - static int lastNumber = -1; - qboolean silent; - - if ( !strcmp( ri.Cmd_Argv(1), "levelshot" ) ) { - R_LevelShot(); - return; - } - - if ( !strcmp( ri.Cmd_Argv(1), "silent" ) ) { - silent = qtrue; - } else { - silent = qfalse; - } - - if ( ri.Cmd_Argc() == 2 && !silent ) { - // explicit filename - Com_sprintf( checkname, MAX_OSPATH, "screenshots/%s.tga", ri.Cmd_Argv( 1 ) ); - } else { - // scan for a free filename - - // if we have saved a previous screenshot, don't scan - // again, because recording demo avis can involve - // thousands of shots - if ( lastNumber == -1 ) { - lastNumber = 0; - } - // scan for a free number - for ( ; lastNumber <= 9999 ; lastNumber++ ) { - R_ScreenshotFilename( lastNumber, checkname ); - - if (!ri.FS_FileExists( checkname )) - { - break; // file doesn't exist - } - } - - if ( lastNumber >= 9999 ) { - ri.Printf (PRINT_ALL, "ScreenShot: Couldn't create a file\n"); - return; - } - - lastNumber++; - } - - R_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, qfalse ); - - if ( !silent ) { - ri.Printf (PRINT_ALL, "Wrote %s\n", checkname); - } -} - -void R_ScreenShotJPEG_f (void) { - char checkname[MAX_OSPATH]; - static int lastNumber = -1; - qboolean silent; - - if ( !strcmp( ri.Cmd_Argv(1), "levelshot" ) ) { - R_LevelShot(); - return; - } - - if ( !strcmp( ri.Cmd_Argv(1), "silent" ) ) { - silent = qtrue; - } else { - silent = qfalse; - } - - if ( ri.Cmd_Argc() == 2 && !silent ) { - // explicit filename - Com_sprintf( checkname, MAX_OSPATH, "screenshots/%s.jpg", ri.Cmd_Argv( 1 ) ); - } else { - // scan for a free filename - - // if we have saved a previous screenshot, don't scan - // again, because recording demo avis can involve - // thousands of shots - if ( lastNumber == -1 ) { - lastNumber = 0; - } - // scan for a free number - for ( ; lastNumber <= 9999 ; lastNumber++ ) { - R_ScreenshotFilenameJPEG( lastNumber, checkname ); - - if (!ri.FS_FileExists( checkname )) - { - break; // file doesn't exist - } - } - - if ( lastNumber == 10000 ) { - ri.Printf (PRINT_ALL, "ScreenShot: Couldn't create a file\n"); - return; - } - - lastNumber++; - } - - R_TakeScreenshot( 0, 0, glConfig.vidWidth, glConfig.vidHeight, checkname, qtrue ); - - if ( !silent ) { - ri.Printf (PRINT_ALL, "Wrote %s\n", checkname); - } -} - -//============================================================================ - -/* -================== -RB_TakeVideoFrameCmd -================== -*/ -const void *RB_TakeVideoFrameCmd( const void *data ) -{ - const videoFrameCommand_t *cmd; - byte *cBuf; - size_t memcount, linelen; - int padwidth, avipadwidth, padlen, avipadlen; - GLint packAlign; - - // finish any 2D drawing if needed - if(tess.numIndexes) - RB_EndSurface(); - - cmd = (const videoFrameCommand_t *)data; - - qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign); - - linelen = cmd->width * 3; - - // Alignment stuff for glReadPixels - padwidth = PAD(linelen, packAlign); - padlen = padwidth - linelen; - // AVI line padding - avipadwidth = PAD(linelen, AVI_LINE_PADDING); - avipadlen = avipadwidth - linelen; - - cBuf = PADP(cmd->captureBuffer, packAlign); - - qglReadPixels(0, 0, cmd->width, cmd->height, GL_RGB, - GL_UNSIGNED_BYTE, cBuf); - - memcount = padwidth * cmd->height; - - // gamma correct - if(glConfig.deviceSupportsGamma) - R_GammaCorrect(cBuf, memcount); - - if(cmd->motionJpeg) - { - memcount = RE_SaveJPGToBuffer(cmd->encodeBuffer, linelen * cmd->height, - r_aviMotionJpegQuality->integer, - cmd->width, cmd->height, cBuf, padlen); - ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, memcount); - } - else - { - byte *lineend, *memend; - byte *srcptr, *destptr; - - srcptr = cBuf; - destptr = cmd->encodeBuffer; - memend = srcptr + memcount; - - // swap R and B and remove line paddings - while(srcptr < memend) - { - lineend = srcptr + linelen; - while(srcptr < lineend) - { - *destptr++ = srcptr[2]; - *destptr++ = srcptr[1]; - *destptr++ = srcptr[0]; - srcptr += 3; - } - - Com_Memset(destptr, '\0', avipadlen); - destptr += avipadlen; - - srcptr += padlen; - } - - ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, avipadwidth * cmd->height); - } - - return (const void *)(cmd + 1); -} - -//============================================================================ - -/* -** GL_SetDefaultState -*/ -void GL_SetDefaultState( void ) -{ - qglClearDepth( 1.0f ); - - qglCullFace(GL_FRONT); - - qglColor4f (1,1,1,1); - - // initialize downstream texture unit if we're running - // in a multitexture environment - if ( qglActiveTextureARB ) { - GL_SelectTexture( 1 ); - GL_TextureMode( r_textureMode->string ); - GL_TexEnv( GL_MODULATE ); - qglDisable( GL_TEXTURE_2D ); - GL_SelectTexture( 0 ); - } - - qglEnable(GL_TEXTURE_2D); - GL_TextureMode( r_textureMode->string ); - GL_TexEnv( GL_MODULATE ); - - //qglShadeModel( GL_SMOOTH ); - qglDepthFunc( GL_LEQUAL ); - - // - // make sure our GL state vector is set correctly - // - glState.glStateBits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_TRUE; - - glState.vertexAttribsState = 0; - glState.vertexAttribPointersSet = 0; - glState.currentProgram = 0; - qglUseProgramObjectARB(0); - - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - glState.currentVBO = NULL; - glState.currentIBO = NULL; - - qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); - qglDepthMask( GL_TRUE ); - qglDisable( GL_DEPTH_TEST ); - qglEnable( GL_SCISSOR_TEST ); - qglDisable( GL_CULL_FACE ); - qglDisable( GL_BLEND ); - - if (glRefConfig.seamlessCubeMap) - qglEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); -} - -/* -================ -R_PrintLongString - -Workaround for ri.Printf's 1024 characters buffer limit. -================ -*/ -void R_PrintLongString(const char *string) { - char buffer[1024]; - const char *p; - int size = strlen(string); - - p = string; - while(size > 0) - { - Q_strncpyz(buffer, p, sizeof (buffer) ); - ri.Printf( PRINT_ALL, "%s", buffer ); - p += 1023; - size -= 1023; - } -} - -/* -================ -GfxInfo_f -================ -*/ -void GfxInfo_f( void ) -{ - const char *enablestrings[] = - { - "disabled", - "enabled" - }; - const char *fsstrings[] = - { - "windowed", - "fullscreen" - }; - - ri.Printf( PRINT_ALL, "\nGL_VENDOR: %s\n", glConfig.vendor_string ); - ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glConfig.renderer_string ); - ri.Printf( PRINT_ALL, "GL_VERSION: %s\n", glConfig.version_string ); - ri.Printf( PRINT_ALL, "GL_EXTENSIONS: " ); - R_PrintLongString( glConfig.extensions_string ); - ri.Printf( PRINT_ALL, "\n" ); - ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_SIZE: %d\n", glConfig.maxTextureSize ); - ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_UNITS_ARB: %d\n", glConfig.numTextureUnits ); - ri.Printf( PRINT_ALL, "\nPIXELFORMAT: color(%d-bits) Z(%d-bit) stencil(%d-bits)\n", glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits ); - ri.Printf( PRINT_ALL, "MODE: %d, %d x %d %s hz:", r_mode->integer, glConfig.vidWidth, glConfig.vidHeight, fsstrings[r_fullscreen->integer == 1] ); - if ( glConfig.displayFrequency ) - { - ri.Printf( PRINT_ALL, "%d\n", glConfig.displayFrequency ); - } - else - { - ri.Printf( PRINT_ALL, "N/A\n" ); - } - if ( glConfig.deviceSupportsGamma ) - { - ri.Printf( PRINT_ALL, "GAMMA: hardware w/ %d overbright bits\n", tr.overbrightBits ); - } - else - { - ri.Printf( PRINT_ALL, "GAMMA: software w/ %d overbright bits\n", tr.overbrightBits ); - } - - ri.Printf( PRINT_ALL, "texturemode: %s\n", r_textureMode->string ); - ri.Printf( PRINT_ALL, "picmip: %d\n", r_picmip->integer ); - ri.Printf( PRINT_ALL, "texture bits: %d\n", r_texturebits->integer ); - ri.Printf( PRINT_ALL, "multitexture: %s\n", enablestrings[qglActiveTextureARB != 0] ); - ri.Printf( PRINT_ALL, "compiled vertex arrays: %s\n", enablestrings[qglLockArraysEXT != 0 ] ); - ri.Printf( PRINT_ALL, "texenv add: %s\n", enablestrings[glConfig.textureEnvAddAvailable != 0] ); - ri.Printf( PRINT_ALL, "compressed textures: %s\n", enablestrings[glConfig.textureCompression!=TC_NONE] ); - if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) - { - ri.Printf( PRINT_ALL, "HACK: using vertex lightmap approximation\n" ); - } - if ( glConfig.hardwareType == GLHW_RAGEPRO ) - { - ri.Printf( PRINT_ALL, "HACK: ragePro approximations\n" ); - } - if ( glConfig.hardwareType == GLHW_RIVA128 ) - { - ri.Printf( PRINT_ALL, "HACK: riva128 approximations\n" ); - } - if ( r_finish->integer ) { - ri.Printf( PRINT_ALL, "Forcing glFinish\n" ); - } -} - -/* -================ -GfxMemInfo_f -================ -*/ -void GfxMemInfo_f( void ) -{ - switch (glRefConfig.memInfo) - { - case MI_NONE: - { - ri.Printf(PRINT_ALL, "No extension found for GPU memory info.\n"); - } - break; - case MI_NVX: - { - int value; - - qglGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &value); - ri.Printf(PRINT_ALL, "GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX: %ikb\n", value); - - qglGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &value); - ri.Printf(PRINT_ALL, "GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX: %ikb\n", value); - - qglGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &value); - ri.Printf(PRINT_ALL, "GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX: %ikb\n", value); - - qglGetIntegerv(GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX, &value); - ri.Printf(PRINT_ALL, "GPU_MEMORY_INFO_EVICTION_COUNT_NVX: %i\n", value); - - qglGetIntegerv(GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX, &value); - ri.Printf(PRINT_ALL, "GPU_MEMORY_INFO_EVICTED_MEMORY_NVX: %ikb\n", value); - } - break; - case MI_ATI: - { - // GL_ATI_meminfo - int value[4]; - - qglGetIntegerv(GL_VBO_FREE_MEMORY_ATI, &value[0]); - ri.Printf(PRINT_ALL, "VBO_FREE_MEMORY_ATI: %ikb total %ikb largest aux: %ikb total %ikb largest\n", value[0], value[1], value[2], value[3]); - - qglGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, &value[0]); - ri.Printf(PRINT_ALL, "TEXTURE_FREE_MEMORY_ATI: %ikb total %ikb largest aux: %ikb total %ikb largest\n", value[0], value[1], value[2], value[3]); - - qglGetIntegerv(GL_RENDERBUFFER_FREE_MEMORY_ATI, &value[0]); - ri.Printf(PRINT_ALL, "RENDERBUFFER_FREE_MEMORY_ATI: %ikb total %ikb largest aux: %ikb total %ikb largest\n", value[0], value[1], value[2], value[3]); - } - break; - } -} - -/* -=============== -R_Register -=============== -*/ -void R_Register( void ) -{ - #ifdef USE_RENDERER_DLOPEN - com_altivec = ri.Cvar_Get("com_altivec", "1", CVAR_ARCHIVE); - #endif - - // - // latched and archived variables - // - r_allowExtensions = ri.Cvar_Get( "r_allowExtensions", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_compressed_textures = ri.Cvar_Get( "r_ext_compressed_textures", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_multitexture = ri.Cvar_Get( "r_ext_multitexture", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_compiled_vertex_array = ri.Cvar_Get( "r_ext_compiled_vertex_array", "1", CVAR_ARCHIVE | CVAR_LATCH); - r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE | CVAR_LATCH); - - r_ext_draw_range_elements = ri.Cvar_Get( "r_ext_draw_range_elements", "1", CVAR_ARCHIVE | CVAR_LATCH); - r_ext_multi_draw_arrays = ri.Cvar_Get( "r_ext_multi_draw_arrays", "1", CVAR_ARCHIVE | CVAR_LATCH); - r_ext_framebuffer_object = ri.Cvar_Get( "r_ext_framebuffer_object", "1", CVAR_ARCHIVE | CVAR_LATCH); - r_ext_texture_float = ri.Cvar_Get( "r_ext_texture_float", "1", CVAR_ARCHIVE | CVAR_LATCH); - r_arb_half_float_pixel = ri.Cvar_Get( "r_arb_half_float_pixel", "1", CVAR_ARCHIVE | CVAR_LATCH); - r_ext_framebuffer_multisample = ri.Cvar_Get( "r_ext_framebuffer_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH); - r_arb_seamless_cube_map = ri.Cvar_Get( "r_arb_seamless_cube_map", "0", CVAR_ARCHIVE | CVAR_LATCH); - r_arb_vertex_type_2_10_10_10_rev = ri.Cvar_Get( "r_arb_vertex_type_2_10_10_10_rev", "1", CVAR_ARCHIVE | CVAR_LATCH); - - r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic", - "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_max_anisotropy = ri.Cvar_Get( "r_ext_max_anisotropy", "2", CVAR_ARCHIVE | CVAR_LATCH ); - - r_picmip = ri.Cvar_Get ("r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_roundImagesDown = ri.Cvar_Get ("r_roundImagesDown", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_colorMipLevels = ri.Cvar_Get ("r_colorMipLevels", "0", CVAR_LATCH ); - ri.Cvar_CheckRange( r_picmip, 0, 16, qtrue ); - r_detailTextures = ri.Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_texturebits = ri.Cvar_Get( "r_texturebits", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_colorbits = ri.Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_stencilbits = ri.Cvar_Get( "r_stencilbits", "8", CVAR_ARCHIVE | CVAR_LATCH ); - r_depthbits = ri.Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_ext_multisample = ri.Cvar_Get( "r_ext_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH ); - ri.Cvar_CheckRange( r_ext_multisample, 0, 4, qtrue ); - r_overBrightBits = ri.Cvar_Get ("r_overBrightBits", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_ignorehwgamma = ri.Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH); - r_mode = ri.Cvar_Get( "r_mode", "-2", CVAR_ARCHIVE | CVAR_LATCH ); - r_fullscreen = ri.Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE ); - r_noborder = ri.Cvar_Get("r_noborder", "0", CVAR_ARCHIVE | CVAR_LATCH); - r_customwidth = ri.Cvar_Get( "r_customwidth", "1600", CVAR_ARCHIVE | CVAR_LATCH ); - r_customheight = ri.Cvar_Get( "r_customheight", "1024", CVAR_ARCHIVE | CVAR_LATCH ); - r_customPixelAspect = ri.Cvar_Get( "r_customPixelAspect", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_simpleMipMaps = ri.Cvar_Get( "r_simpleMipMaps", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_vertexLight = ri.Cvar_Get( "r_vertexLight", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_uiFullScreen = ri.Cvar_Get( "r_uifullscreen", "0", 0); - r_subdivisions = ri.Cvar_Get ("r_subdivisions", "4", CVAR_ARCHIVE | CVAR_LATCH); - r_stereoEnabled = ri.Cvar_Get( "r_stereoEnabled", "0", CVAR_ARCHIVE | CVAR_LATCH); - r_greyscale = ri.Cvar_Get("r_greyscale", "0", CVAR_ARCHIVE | CVAR_LATCH); - ri.Cvar_CheckRange(r_greyscale, 0, 1, qfalse); - - r_softOverbright = ri.Cvar_Get( "r_softOverbright", "1", CVAR_ARCHIVE | CVAR_LATCH ); - - r_hdr = ri.Cvar_Get( "r_hdr", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_floatLightmap = ri.Cvar_Get( "r_floatLightmap", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_postProcess = ri.Cvar_Get( "r_postProcess", "1", CVAR_ARCHIVE ); - - r_toneMap = ri.Cvar_Get( "r_toneMap", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_forceToneMap = ri.Cvar_Get( "r_forceToneMap", "0", CVAR_CHEAT ); - r_forceToneMapMin = ri.Cvar_Get( "r_forceToneMapMin", "-8.0", CVAR_CHEAT ); - r_forceToneMapAvg = ri.Cvar_Get( "r_forceToneMapAvg", "-2.0", CVAR_CHEAT ); - r_forceToneMapMax = ri.Cvar_Get( "r_forceToneMapMax", "0.0", CVAR_CHEAT ); - - r_autoExposure = ri.Cvar_Get( "r_autoExposure", "1", CVAR_ARCHIVE ); - r_forceAutoExposure = ri.Cvar_Get( "r_forceAutoExposure", "0", CVAR_CHEAT ); - r_forceAutoExposureMin = ri.Cvar_Get( "r_forceAutoExposureMin", "-2.0", CVAR_CHEAT ); - r_forceAutoExposureMax = ri.Cvar_Get( "r_forceAutoExposureMax", "2.0", CVAR_CHEAT ); - - r_cameraExposure = ri.Cvar_Get( "r_cameraExposure", "0", CVAR_CHEAT ); - - r_srgb = ri.Cvar_Get( "r_srgb", "0", CVAR_ARCHIVE | CVAR_LATCH ); - - r_depthPrepass = ri.Cvar_Get( "r_depthPrepass", "1", CVAR_ARCHIVE ); - r_ssao = ri.Cvar_Get( "r_ssao", "0", CVAR_LATCH | CVAR_ARCHIVE ); - - r_normalMapping = ri.Cvar_Get( "r_normalMapping", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_specularMapping = ri.Cvar_Get( "r_specularMapping", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_deluxeMapping = ri.Cvar_Get( "r_deluxeMapping", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_parallaxMapping = ri.Cvar_Get( "r_parallaxMapping", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_cubeMapping = ri.Cvar_Get( "r_cubeMapping", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_deluxeSpecular = ri.Cvar_Get( "r_deluxeSpecular", "0.3", CVAR_ARCHIVE | CVAR_LATCH ); - r_specularIsMetallic = ri.Cvar_Get( "r_specularIsMetallic", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_baseSpecular = ri.Cvar_Get( "r_baseSpecular", "0.04", CVAR_ARCHIVE | CVAR_LATCH ); - r_baseGloss = ri.Cvar_Get( "r_baseGloss", "0.3", CVAR_ARCHIVE | CVAR_LATCH ); - r_dlightMode = ri.Cvar_Get( "r_dlightMode", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_pshadowDist = ri.Cvar_Get( "r_pshadowDist", "128", CVAR_ARCHIVE ); - r_recalcMD3Normals = ri.Cvar_Get( "r_recalcMD3Normals", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_mergeLightmaps = ri.Cvar_Get( "r_mergeLightmaps", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_imageUpsample = ri.Cvar_Get( "r_imageUpsample", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_imageUpsampleMaxSize = ri.Cvar_Get( "r_imageUpsampleMaxSize", "1024", CVAR_ARCHIVE | CVAR_LATCH ); - r_imageUpsampleType = ri.Cvar_Get( "r_imageUpsampleType", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_genNormalMaps = ri.Cvar_Get( "r_genNormalMaps", "0", CVAR_ARCHIVE | CVAR_LATCH ); - - r_forceSun = ri.Cvar_Get( "r_forceSun", "0", CVAR_CHEAT ); - r_forceSunMapLightScale = ri.Cvar_Get( "r_forceSunMapLightScale", "1.0", CVAR_CHEAT ); - r_forceSunLightScale = ri.Cvar_Get( "r_forceSunLightScale", "1.0", CVAR_CHEAT ); - r_forceSunAmbientScale = ri.Cvar_Get( "r_forceSunAmbientScale", "0.5", CVAR_CHEAT ); - r_drawSunRays = ri.Cvar_Get( "r_drawSunRays", "0", CVAR_ARCHIVE | CVAR_LATCH ); - r_sunlightMode = ri.Cvar_Get( "r_sunlightMode", "1", CVAR_ARCHIVE | CVAR_LATCH ); - - r_sunShadows = ri.Cvar_Get( "r_sunShadows", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_shadowFilter = ri.Cvar_Get( "r_shadowFilter", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_shadowMapSize = ri.Cvar_Get( "r_shadowMapSize", "1024", CVAR_ARCHIVE | CVAR_LATCH ); - r_shadowCascadeZNear = ri.Cvar_Get( "r_shadowCascadeZNear", "4", CVAR_ARCHIVE | CVAR_LATCH ); - r_shadowCascadeZFar = ri.Cvar_Get( "r_shadowCascadeZFar", "3072", CVAR_ARCHIVE | CVAR_LATCH ); - r_shadowCascadeZBias = ri.Cvar_Get( "r_shadowCascadeZBias", "-320", CVAR_ARCHIVE | CVAR_LATCH ); - r_ignoreDstAlpha = ri.Cvar_Get( "r_ignoreDstAlpha", "1", CVAR_ARCHIVE | CVAR_LATCH ); - - // - // temporary latched variables that can only change over a restart - // - r_fullbright = ri.Cvar_Get ("r_fullbright", "0", CVAR_LATCH|CVAR_CHEAT ); - r_mapOverBrightBits = ri.Cvar_Get ("r_mapOverBrightBits", "2", CVAR_LATCH ); - r_intensity = ri.Cvar_Get ("r_intensity", "1", CVAR_LATCH ); - r_singleShader = ri.Cvar_Get ("r_singleShader", "0", CVAR_CHEAT | CVAR_LATCH ); - - // - // archived variables that can change at any time - // - r_lodCurveError = ri.Cvar_Get( "r_lodCurveError", "250", CVAR_ARCHIVE|CVAR_CHEAT ); - r_lodbias = ri.Cvar_Get( "r_lodbias", "0", CVAR_ARCHIVE ); - r_flares = ri.Cvar_Get ("r_flares", "0", CVAR_ARCHIVE ); - r_znear = ri.Cvar_Get( "r_znear", "4", CVAR_CHEAT ); - ri.Cvar_CheckRange( r_znear, 0.001f, 200, qfalse ); - r_zproj = ri.Cvar_Get( "r_zproj", "64", CVAR_ARCHIVE ); - r_stereoSeparation = ri.Cvar_Get( "r_stereoSeparation", "64", CVAR_ARCHIVE ); - r_ignoreGLErrors = ri.Cvar_Get( "r_ignoreGLErrors", "1", CVAR_ARCHIVE ); - r_fastsky = ri.Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE ); - r_inGameVideo = ri.Cvar_Get( "r_inGameVideo", "1", CVAR_ARCHIVE ); - r_drawSun = ri.Cvar_Get( "r_drawSun", "0", CVAR_ARCHIVE ); - r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE ); - r_dlightBacks = ri.Cvar_Get( "r_dlightBacks", "1", CVAR_ARCHIVE ); - r_finish = ri.Cvar_Get ("r_finish", "0", CVAR_ARCHIVE); - r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE ); - r_swapInterval = ri.Cvar_Get( "r_swapInterval", "0", - CVAR_ARCHIVE | CVAR_LATCH ); - r_gamma = ri.Cvar_Get( "r_gamma", "1", CVAR_ARCHIVE ); - r_facePlaneCull = ri.Cvar_Get ("r_facePlaneCull", "1", CVAR_ARCHIVE ); - - r_railWidth = ri.Cvar_Get( "r_railWidth", "16", CVAR_ARCHIVE ); - r_railCoreWidth = ri.Cvar_Get( "r_railCoreWidth", "6", CVAR_ARCHIVE ); - r_railSegmentLength = ri.Cvar_Get( "r_railSegmentLength", "32", CVAR_ARCHIVE ); - - r_ambientScale = ri.Cvar_Get( "r_ambientScale", "0.6", CVAR_CHEAT ); - r_directedScale = ri.Cvar_Get( "r_directedScale", "1", CVAR_CHEAT ); - - r_anaglyphMode = ri.Cvar_Get("r_anaglyphMode", "0", CVAR_ARCHIVE); - r_mergeMultidraws = ri.Cvar_Get("r_mergeMultidraws", "1", CVAR_ARCHIVE); - r_mergeLeafSurfaces = ri.Cvar_Get("r_mergeLeafSurfaces", "1", CVAR_ARCHIVE); - - // - // temporary variables that can change at any time - // - r_showImages = ri.Cvar_Get( "r_showImages", "0", CVAR_TEMP ); - - r_debugLight = ri.Cvar_Get( "r_debuglight", "0", CVAR_TEMP ); - r_debugSort = ri.Cvar_Get( "r_debugSort", "0", CVAR_CHEAT ); - r_printShaders = ri.Cvar_Get( "r_printShaders", "0", 0 ); - r_saveFontData = ri.Cvar_Get( "r_saveFontData", "0", 0 ); - - r_nocurves = ri.Cvar_Get ("r_nocurves", "0", CVAR_CHEAT ); - r_drawworld = ri.Cvar_Get ("r_drawworld", "1", CVAR_CHEAT ); - r_lightmap = ri.Cvar_Get ("r_lightmap", "0", 0 ); - r_portalOnly = ri.Cvar_Get ("r_portalOnly", "0", CVAR_CHEAT ); - - r_flareSize = ri.Cvar_Get ("r_flareSize", "40", CVAR_CHEAT); - r_flareFade = ri.Cvar_Get ("r_flareFade", "7", CVAR_CHEAT); - r_flareCoeff = ri.Cvar_Get ("r_flareCoeff", FLARE_STDCOEFF, CVAR_CHEAT); - - r_skipBackEnd = ri.Cvar_Get ("r_skipBackEnd", "0", CVAR_CHEAT); - - r_measureOverdraw = ri.Cvar_Get( "r_measureOverdraw", "0", CVAR_CHEAT ); - r_lodscale = ri.Cvar_Get( "r_lodscale", "5", CVAR_CHEAT ); - r_norefresh = ri.Cvar_Get ("r_norefresh", "0", CVAR_CHEAT); - r_drawentities = ri.Cvar_Get ("r_drawentities", "1", CVAR_CHEAT ); - r_ignore = ri.Cvar_Get( "r_ignore", "1", CVAR_CHEAT ); - r_nocull = ri.Cvar_Get ("r_nocull", "0", CVAR_CHEAT); - r_novis = ri.Cvar_Get ("r_novis", "0", CVAR_CHEAT); - r_showcluster = ri.Cvar_Get ("r_showcluster", "0", CVAR_CHEAT); - r_speeds = ri.Cvar_Get ("r_speeds", "0", CVAR_CHEAT); - r_verbose = ri.Cvar_Get( "r_verbose", "0", CVAR_CHEAT ); - r_logFile = ri.Cvar_Get( "r_logFile", "0", CVAR_CHEAT ); - r_debugSurface = ri.Cvar_Get ("r_debugSurface", "0", CVAR_CHEAT); - r_nobind = ri.Cvar_Get ("r_nobind", "0", CVAR_CHEAT); - r_showtris = ri.Cvar_Get ("r_showtris", "0", CVAR_CHEAT); - r_showsky = ri.Cvar_Get ("r_showsky", "0", CVAR_CHEAT); - r_shownormals = ri.Cvar_Get ("r_shownormals", "0", CVAR_CHEAT); - r_clear = ri.Cvar_Get ("r_clear", "0", CVAR_CHEAT); - r_offsetFactor = ri.Cvar_Get( "r_offsetfactor", "-1", CVAR_CHEAT ); - r_offsetUnits = ri.Cvar_Get( "r_offsetunits", "-2", CVAR_CHEAT ); - r_drawBuffer = ri.Cvar_Get( "r_drawBuffer", "GL_BACK", CVAR_CHEAT ); - r_lockpvs = ri.Cvar_Get ("r_lockpvs", "0", CVAR_CHEAT); - r_noportals = ri.Cvar_Get ("r_noportals", "0", CVAR_CHEAT); - r_shadows = ri.Cvar_Get( "cg_shadows", "1", 0 ); - - r_marksOnTriangleMeshes = ri.Cvar_Get("r_marksOnTriangleMeshes", "0", CVAR_ARCHIVE); - - r_aviMotionJpegQuality = ri.Cvar_Get("r_aviMotionJpegQuality", "90", CVAR_ARCHIVE); - r_screenshotJpegQuality = ri.Cvar_Get("r_screenshotJpegQuality", "90", CVAR_ARCHIVE); - - r_maxpolys = ri.Cvar_Get( "r_maxpolys", va("%d", MAX_POLYS), 0); - r_maxpolyverts = ri.Cvar_Get( "r_maxpolyverts", va("%d", MAX_POLYVERTS), 0); - - // make sure all the commands added here are also - // removed in R_Shutdown - ri.Cmd_AddCommand( "imagelist", R_ImageList_f ); - ri.Cmd_AddCommand( "shaderlist", R_ShaderList_f ); - ri.Cmd_AddCommand( "skinlist", R_SkinList_f ); - ri.Cmd_AddCommand( "modellist", R_Modellist_f ); - ri.Cmd_AddCommand( "modelist", R_ModeList_f ); - ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f ); - ri.Cmd_AddCommand( "screenshotJPEG", R_ScreenShotJPEG_f ); - ri.Cmd_AddCommand( "gfxinfo", GfxInfo_f ); - ri.Cmd_AddCommand( "minimize", GLimp_Minimize ); - ri.Cmd_AddCommand( "gfxmeminfo", GfxMemInfo_f ); -} - -void R_InitQueries(void) -{ - if (!glRefConfig.occlusionQuery) - return; - - if (r_drawSunRays->integer) - qglGenQueriesARB(ARRAY_LEN(tr.sunFlareQuery), tr.sunFlareQuery); -} - -void R_ShutDownQueries(void) -{ - if (!glRefConfig.occlusionQuery) - return; - - if (r_drawSunRays->integer) - qglDeleteQueriesARB(ARRAY_LEN(tr.sunFlareQuery), tr.sunFlareQuery); -} - -/* -=============== -R_Init -=============== -*/ -void R_Init( void ) { - int err; - int i; - byte *ptr; - - ri.Printf( PRINT_ALL, "----- R_Init -----\n" ); - - // clear all our internal state - Com_Memset( &tr, 0, sizeof( tr ) ); - Com_Memset( &backEnd, 0, sizeof( backEnd ) ); - Com_Memset( &tess, 0, sizeof( tess ) ); - - if(sizeof(glconfig_t) != 11332) - ri.Error( ERR_FATAL, "Mod ABI incompatible: sizeof(glconfig_t) == %u != 11332", (unsigned int) sizeof(glconfig_t)); - -// Swap_Init(); - - if ( (intptr_t)tess.xyz & 15 ) { - ri.Printf( PRINT_WARNING, "tess.xyz not 16 byte aligned\n" ); - } - //Com_Memset( tess.constantColor255, 255, sizeof( tess.constantColor255 ) ); - - // - // init function tables - // - for ( i = 0; i < FUNCTABLE_SIZE; i++ ) - { - tr.sinTable[i] = sin( DEG2RAD( i * 360.0f / ( ( float ) ( FUNCTABLE_SIZE - 1 ) ) ) ); - tr.squareTable[i] = ( i < FUNCTABLE_SIZE/2 ) ? 1.0f : -1.0f; - tr.sawToothTable[i] = (float)i / FUNCTABLE_SIZE; - tr.inverseSawToothTable[i] = 1.0f - tr.sawToothTable[i]; - - if ( i < FUNCTABLE_SIZE / 2 ) - { - if ( i < FUNCTABLE_SIZE / 4 ) - { - tr.triangleTable[i] = ( float ) i / ( FUNCTABLE_SIZE / 4 ); - } - else - { - tr.triangleTable[i] = 1.0f - tr.triangleTable[i-FUNCTABLE_SIZE / 4]; - } - } - else - { - tr.triangleTable[i] = -tr.triangleTable[i-FUNCTABLE_SIZE/2]; - } - } - - R_InitFogTable(); - - R_NoiseInit(); - - R_Register(); - - max_polys = r_maxpolys->integer; - if (max_polys < MAX_POLYS) - max_polys = MAX_POLYS; - - max_polyverts = r_maxpolyverts->integer; - if (max_polyverts < MAX_POLYVERTS) - max_polyverts = MAX_POLYVERTS; - - ptr = ri.Hunk_Alloc( sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low); - backEndData = (backEndData_t *) ptr; - backEndData->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData )); - backEndData->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys); - R_InitNextFrame(); - - InitOpenGL(); - - R_InitImages(); - - if (glRefConfig.framebufferObject) - FBO_Init(); - - GLSL_InitGPUShaders(); - - R_InitVBOs(); - - R_InitShaders(); - - R_InitSkins(); - - R_ModelInit(); - - R_InitFreeType(); - - R_InitQueries(); - - - err = qglGetError(); - if ( err != GL_NO_ERROR ) - ri.Printf (PRINT_ALL, "glGetError() = 0x%x\n", err); - - // print info - GfxInfo_f(); - ri.Printf( PRINT_ALL, "----- finished R_Init -----\n" ); -} - -/* -=============== -RE_Shutdown -=============== -*/ -void RE_Shutdown( qboolean destroyWindow ) { - - ri.Printf( PRINT_ALL, "RE_Shutdown( %i )\n", destroyWindow ); - - ri.Cmd_RemoveCommand ("modellist"); - ri.Cmd_RemoveCommand ("screenshotJPEG"); - ri.Cmd_RemoveCommand ("screenshot"); - ri.Cmd_RemoveCommand ("imagelist"); - ri.Cmd_RemoveCommand ("shaderlist"); - ri.Cmd_RemoveCommand ("skinlist"); - ri.Cmd_RemoveCommand ("gfxinfo"); - ri.Cmd_RemoveCommand("minimize"); - ri.Cmd_RemoveCommand( "modelist" ); - ri.Cmd_RemoveCommand( "shaderstate" ); - ri.Cmd_RemoveCommand( "gfxmeminfo" ); - - - if ( tr.registered ) { - R_IssuePendingRenderCommands(); - R_ShutDownQueries(); - if (glRefConfig.framebufferObject) - FBO_Shutdown(); - R_DeleteTextures(); - R_ShutdownVBOs(); - GLSL_ShutdownGPUShaders(); - } - - R_DoneFreeType(); - - // shut down platform specific OpenGL stuff - if ( destroyWindow ) { - GLimp_Shutdown(); - - Com_Memset( &glConfig, 0, sizeof( glConfig ) ); - Com_Memset( &glState, 0, sizeof( glState ) ); - } - - tr.registered = qfalse; -} - - -/* -============= -RE_EndRegistration - -Touch all images to make sure they are resident -============= -*/ -void RE_EndRegistration( void ) { - R_IssuePendingRenderCommands(); - if (!ri.Sys_LowPhysicalMemory()) { - RB_ShowImages(); - } -} - - -/* -@@@@@@@@@@@@@@@@@@@@@ -GetRefAPI - -@@@@@@@@@@@@@@@@@@@@@ -*/ -#ifdef USE_RENDERER_DLOPEN -Q_EXPORT refexport_t* QDECL GetRefAPI ( int apiVersion, refimport_t *rimp ) { -#else -refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) { -#endif - - static refexport_t re; - - ri = *rimp; - - Com_Memset( &re, 0, sizeof( re ) ); - - if ( apiVersion != REF_API_VERSION ) { - ri.Printf(PRINT_ALL, "Mismatched REF_API_VERSION: expected %i, got %i\n", - REF_API_VERSION, apiVersion ); - return NULL; - } - - // the RE_ functions are Renderer Entry points - - re.Shutdown = RE_Shutdown; - - re.BeginRegistration = RE_BeginRegistration; - re.RegisterModel = RE_RegisterModel; - re.RegisterSkin = RE_RegisterSkin; - re.RegisterShader = RE_RegisterShader; - re.RegisterShaderNoMip = RE_RegisterShaderNoMip; - re.LoadWorld = RE_LoadWorldMap; - re.SetWorldVisData = RE_SetWorldVisData; - re.EndRegistration = RE_EndRegistration; - - re.BeginFrame = RE_BeginFrame; - re.EndFrame = RE_EndFrame; - - re.MarkFragments = R_MarkFragments; - re.LerpTag = R_LerpTag; - re.ModelBounds = R_ModelBounds; - - re.ClearScene = RE_ClearScene; - re.AddRefEntityToScene = RE_AddRefEntityToScene; - re.AddPolyToScene = RE_AddPolyToScene; - re.LFX_ParticleEffect = NULL; - re.LightForPoint = R_LightForPoint; - re.AddLightToScene = RE_AddLightToScene; - re.AddAdditiveLightToScene = RE_AddAdditiveLightToScene; - re.RenderScene = RE_RenderScene; - - re.SetColor = RE_SetColor; - re.DrawStretchPic = RE_StretchPic; - re.DrawStretchRaw = RE_StretchRaw; - re.UploadCinematic = RE_UploadCinematic; - - re.RegisterFont = RE_RegisterFont; - re.RemapShader = R_RemapShader; - re.GetEntityToken = R_GetEntityToken; - re.inPVS = R_inPVS; - - re.TakeVideoFrame = RE_TakeVideoFrame; - - return &re; -} diff --git a/code/renderergl2/tr_light.c b/code/renderergl2/tr_light.c deleted file mode 100644 index 3d1d1f241a..0000000000 --- a/code/renderergl2/tr_light.c +++ /dev/null @@ -1,488 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_light.c - -#include "tr_local.h" - -#define DLIGHT_AT_RADIUS 16 -// at the edge of a dlight's influence, this amount of light will be added - -#define DLIGHT_MINIMUM_RADIUS 16 -// never calculate a range less than this to prevent huge light numbers - - -/* -=============== -R_TransformDlights - -Transforms the origins of an array of dlights. -Used by both the front end (for DlightBmodel) and -the back end (before doing the lighting calculation) -=============== -*/ -void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or) { - int i; - vec3_t temp; - - for ( i = 0 ; i < count ; i++, dl++ ) { - VectorSubtract( dl->origin, or->origin, temp ); - dl->transformed[0] = DotProduct( temp, or->axis[0] ); - dl->transformed[1] = DotProduct( temp, or->axis[1] ); - dl->transformed[2] = DotProduct( temp, or->axis[2] ); - } -} - -/* -============= -R_DlightBmodel - -Determine which dynamic lights may effect this bmodel -============= -*/ -void R_DlightBmodel( bmodel_t *bmodel ) { - int i, j; - dlight_t *dl; - int mask; - msurface_t *surf; - - // transform all the lights - R_TransformDlights( tr.refdef.num_dlights, tr.refdef.dlights, &tr.or ); - - mask = 0; - for ( i=0 ; itransformed[j] - bmodel->bounds[1][j] > dl->radius ) { - break; - } - if ( bmodel->bounds[0][j] - dl->transformed[j] > dl->radius ) { - break; - } - } - if ( j < 3 ) { - continue; - } - - // we need to check this light - mask |= 1 << i; - } - - tr.currentEntity->needDlights = (mask != 0); - - // set the dlight bits in all the surfaces - for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) { - surf = tr.world->surfaces + bmodel->firstSurface + i; - - switch(*surf->data) - { - case SF_FACE: - case SF_GRID: - case SF_TRIANGLES: - case SF_VBO_MESH: - ((srfBspSurface_t *)surf->data)->dlightBits = mask; - break; - - default: - break; - } - } -} - - -/* -============================================================================= - -LIGHT SAMPLING - -============================================================================= -*/ - -extern cvar_t *r_ambientScale; -extern cvar_t *r_directedScale; -extern cvar_t *r_debugLight; - -/* -================= -R_SetupEntityLightingGrid - -================= -*/ -static void R_SetupEntityLightingGrid( trRefEntity_t *ent, world_t *world ) { - vec3_t lightOrigin; - int pos[3]; - int i, j; - byte *gridData; - float frac[3]; - int gridStep[3]; - vec3_t direction; - float totalFactor; - - if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { - // seperate lightOrigins are needed so an object that is - // sinking into the ground can still be lit, and so - // multi-part models can be lit identically - VectorCopy( ent->e.lightingOrigin, lightOrigin ); - } else { - VectorCopy( ent->e.origin, lightOrigin ); - } - - VectorSubtract( lightOrigin, world->lightGridOrigin, lightOrigin ); - for ( i = 0 ; i < 3 ; i++ ) { - float v; - - v = lightOrigin[i]*world->lightGridInverseSize[i]; - pos[i] = floor( v ); - frac[i] = v - pos[i]; - if ( pos[i] < 0 ) { - pos[i] = 0; - } else if ( pos[i] >= world->lightGridBounds[i] - 1 ) { - pos[i] = world->lightGridBounds[i] - 1; - } - } - - VectorClear( ent->ambientLight ); - VectorClear( ent->directedLight ); - VectorClear( direction ); - - assert( world->lightGridData ); // NULL with -nolight maps - - // trilerp the light value - gridStep[0] = 8; - gridStep[1] = 8 * world->lightGridBounds[0]; - gridStep[2] = 8 * world->lightGridBounds[0] * world->lightGridBounds[1]; - gridData = world->lightGridData + pos[0] * gridStep[0] - + pos[1] * gridStep[1] + pos[2] * gridStep[2]; - - totalFactor = 0; - for ( i = 0 ; i < 8 ; i++ ) { - float factor; - byte *data; - int lat, lng; - vec3_t normal; - qboolean ignore; - #if idppc - float d0, d1, d2, d3, d4, d5; - #endif - factor = 1.0; - data = gridData; - ignore = qfalse; - for ( j = 0 ; j < 3 ; j++ ) { - if ( i & (1<= world->lightGridBounds[j] - 1) - { - ignore = qtrue; // ignore values outside lightgrid - } - factor *= frac[j]; - data += gridStep[j]; - } else { - factor *= (1.0f - frac[j]); - } - } - - if ( ignore ) - continue; - - if (world->hdrLightGrid) - { - float *hdrData = world->hdrLightGrid + (int)(data - world->lightGridData) / 8 * 6; - if (!(hdrData[0]+hdrData[1]+hdrData[2]+hdrData[3]+hdrData[4]+hdrData[5]) ) { - continue; // ignore samples in walls - } - } - else - { - if (!(data[0]+data[1]+data[2]+data[3]+data[4]+data[5]) ) { - continue; // ignore samples in walls - } - } - totalFactor += factor; - #if idppc - d0 = data[0]; d1 = data[1]; d2 = data[2]; - d3 = data[3]; d4 = data[4]; d5 = data[5]; - - ent->ambientLight[0] += factor * d0; - ent->ambientLight[1] += factor * d1; - ent->ambientLight[2] += factor * d2; - - ent->directedLight[0] += factor * d3; - ent->directedLight[1] += factor * d4; - ent->directedLight[2] += factor * d5; - #else - if (world->hdrLightGrid) - { - // FIXME: this is hideous - float *hdrData = world->hdrLightGrid + (int)(data - world->lightGridData) / 8 * 6; - - ent->ambientLight[0] += factor * hdrData[0]; - ent->ambientLight[1] += factor * hdrData[1]; - ent->ambientLight[2] += factor * hdrData[2]; - - ent->directedLight[0] += factor * hdrData[3]; - ent->directedLight[1] += factor * hdrData[4]; - ent->directedLight[2] += factor * hdrData[5]; - } - else - { - ent->ambientLight[0] += factor * data[0]; - ent->ambientLight[1] += factor * data[1]; - ent->ambientLight[2] += factor * data[2]; - - ent->directedLight[0] += factor * data[3]; - ent->directedLight[1] += factor * data[4]; - ent->directedLight[2] += factor * data[5]; - } - #endif - lat = data[7]; - lng = data[6]; - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - normal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - VectorMA( direction, factor, normal, direction ); - } - - if ( totalFactor > 0 && totalFactor < 0.99 ) { - totalFactor = 1.0f / totalFactor; - VectorScale( ent->ambientLight, totalFactor, ent->ambientLight ); - VectorScale( ent->directedLight, totalFactor, ent->directedLight ); - } - - VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight ); - VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight ); - - VectorNormalize2( direction, ent->lightDir ); -} - - -/* -=============== -LogLight -=============== -*/ -static void LogLight( trRefEntity_t *ent ) { - int max1, max2; - - if ( !(ent->e.renderfx & RF_FIRST_PERSON ) ) { - return; - } - - max1 = ent->ambientLight[0]; - if ( ent->ambientLight[1] > max1 ) { - max1 = ent->ambientLight[1]; - } else if ( ent->ambientLight[2] > max1 ) { - max1 = ent->ambientLight[2]; - } - - max2 = ent->directedLight[0]; - if ( ent->directedLight[1] > max2 ) { - max2 = ent->directedLight[1]; - } else if ( ent->directedLight[2] > max2 ) { - max2 = ent->directedLight[2]; - } - - ri.Printf( PRINT_ALL, "amb:%i dir:%i\n", max1, max2 ); -} - -/* -================= -R_SetupEntityLighting - -Calculates all the lighting values that will be used -by the Calc_* functions -================= -*/ -void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) { - int i; - dlight_t *dl; - float power; - vec3_t dir; - float d; - vec3_t lightDir; - vec3_t lightOrigin; - - // lighting calculations - if ( ent->lightingCalculated ) { - return; - } - ent->lightingCalculated = qtrue; - - // - // trace a sample point down to find ambient light - // - if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { - // seperate lightOrigins are needed so an object that is - // sinking into the ground can still be lit, and so - // multi-part models can be lit identically - VectorCopy( ent->e.lightingOrigin, lightOrigin ); - } else { - VectorCopy( ent->e.origin, lightOrigin ); - } - - // if NOWORLDMODEL, only use dynamic lights (menu system, etc) - if ( !(refdef->rdflags & RDF_NOWORLDMODEL ) - && tr.world->lightGridData ) { - R_SetupEntityLightingGrid( ent, tr.world ); - } else { - ent->ambientLight[0] = ent->ambientLight[1] = - ent->ambientLight[2] = tr.identityLight * 150; - ent->directedLight[0] = ent->directedLight[1] = - ent->directedLight[2] = tr.identityLight * 150; - VectorCopy( tr.sunDirection, ent->lightDir ); - } - - // bonus items and view weapons have a fixed minimum add - if ( !r_hdr->integer /* ent->e.renderfx & RF_MINLIGHT */ ) { - // give everything a minimum light add - ent->ambientLight[0] += tr.identityLight * 32; - ent->ambientLight[1] += tr.identityLight * 32; - ent->ambientLight[2] += tr.identityLight * 32; - } - - // - // modify the light by dynamic lights - // - d = VectorLength( ent->directedLight ); - VectorScale( ent->lightDir, d, lightDir ); - - for ( i = 0 ; i < refdef->num_dlights ; i++ ) { - dl = &refdef->dlights[i]; - VectorSubtract( dl->origin, lightOrigin, dir ); - d = VectorNormalize( dir ); - - power = DLIGHT_AT_RADIUS * ( dl->radius * dl->radius ); - if ( d < DLIGHT_MINIMUM_RADIUS ) { - d = DLIGHT_MINIMUM_RADIUS; - } - d = power / ( d * d ); - - VectorMA( ent->directedLight, d, dl->color, ent->directedLight ); - VectorMA( lightDir, d, dir, lightDir ); - } - - // clamp ambient - if ( !r_hdr->integer ) - { - for ( i = 0 ; i < 3 ; i++ ) { - if ( ent->ambientLight[i] > tr.identityLightByte ) { - ent->ambientLight[i] = tr.identityLightByte; - } - } - } - - if ( r_debugLight->integer ) { - LogLight( ent ); - } - - // save out the byte packet version - ((byte *)&ent->ambientLightInt)[0] = ri.ftol(ent->ambientLight[0]); - ((byte *)&ent->ambientLightInt)[1] = ri.ftol(ent->ambientLight[1]); - ((byte *)&ent->ambientLightInt)[2] = ri.ftol(ent->ambientLight[2]); - ((byte *)&ent->ambientLightInt)[3] = 0xff; - - // transform the direction to local space - VectorNormalize( lightDir ); - ent->modelLightDir[0] = DotProduct( lightDir, ent->e.axis[0] ); - ent->modelLightDir[1] = DotProduct( lightDir, ent->e.axis[1] ); - ent->modelLightDir[2] = DotProduct( lightDir, ent->e.axis[2] ); - - VectorCopy(lightDir, ent->lightDir); -} - -/* -================= -R_LightForPoint -================= -*/ -int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ) -{ - trRefEntity_t ent; - - if ( tr.world->lightGridData == NULL ) - return qfalse; - - Com_Memset(&ent, 0, sizeof(ent)); - VectorCopy( point, ent.e.origin ); - R_SetupEntityLightingGrid( &ent, tr.world ); - VectorCopy(ent.ambientLight, ambientLight); - VectorCopy(ent.directedLight, directedLight); - VectorCopy(ent.lightDir, lightDir); - - return qtrue; -} - - -int R_LightDirForPoint( vec3_t point, vec3_t lightDir, vec3_t normal, world_t *world ) -{ - trRefEntity_t ent; - - if ( world->lightGridData == NULL ) - return qfalse; - - Com_Memset(&ent, 0, sizeof(ent)); - VectorCopy( point, ent.e.origin ); - R_SetupEntityLightingGrid( &ent, world ); - - if (DotProduct(ent.lightDir, normal) > 0.2f) - VectorCopy(ent.lightDir, lightDir); - else - VectorCopy(normal, lightDir); - - return qtrue; -} - - -int R_CubemapForPoint( vec3_t point ) -{ - int cubemapIndex = -1; - - if (r_cubeMapping->integer && tr.numCubemaps) - { - int i; - vec_t shortest = (float)WORLD_SIZE * (float)WORLD_SIZE; - - for (i = 0; i < tr.numCubemaps; i++) - { - vec3_t diff; - vec_t length; - - VectorSubtract(point, tr.cubemapOrigins[i], diff); - length = DotProduct(diff, diff); - - if (shortest > length) - { - shortest = length; - cubemapIndex = i; - } - } - } - - return cubemapIndex + 1; -} diff --git a/code/renderergl2/tr_local.h b/code/renderergl2/tr_local.h deleted file mode 100644 index 0fbabd20fc..0000000000 --- a/code/renderergl2/tr_local.h +++ /dev/null @@ -1,2499 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - - -#ifndef TR_LOCAL_H -#define TR_LOCAL_H - -#include "../qcommon/q_shared.h" -#include "../qcommon/qfiles.h" -#include "../qcommon/qcommon.h" -#include "../renderercommon/tr_public.h" -#include "../renderercommon/tr_common.h" -#include "tr_extratypes.h" -#include "tr_extramath.h" -#include "tr_fbo.h" -#include "tr_postprocess.h" -#include "../renderercommon/iqm.h" -#include "../renderercommon/qgl.h" - -#define GL_INDEX_TYPE GL_UNSIGNED_INT -typedef unsigned int glIndex_t; - -#define BUFFER_OFFSET(i) ((char *)NULL + (i)) - -// 14 bits -// can't be increased without changing bit packing for drawsurfs -// see QSORT_SHADERNUM_SHIFT -#define SHADERNUM_BITS 14 -#define MAX_SHADERS (1<or.origin in local coordinates - float modelMatrix[16]; - float transformMatrix[16]; -} orientationr_t; - -typedef enum -{ - VBO_USAGE_STATIC, - VBO_USAGE_DYNAMIC -} vboUsage_t; - -typedef struct VBO_s -{ - char name[MAX_QPATH]; - - uint32_t vertexesVBO; - int vertexesSize; // amount of memory data allocated for all vertices in bytes - uint32_t ofs_xyz; - uint32_t ofs_normal; - uint32_t ofs_st; - uint32_t ofs_lightmap; - uint32_t ofs_vertexcolor; - uint32_t ofs_lightdir; -#ifdef USE_VERT_TANGENT_SPACE - uint32_t ofs_tangent; -#endif - uint32_t stride_xyz; - uint32_t stride_normal; - uint32_t stride_st; - uint32_t stride_lightmap; - uint32_t stride_vertexcolor; - uint32_t stride_lightdir; -#ifdef USE_VERT_TANGENT_SPACE - uint32_t stride_tangent; -#endif - uint32_t size_xyz; - uint32_t size_normal; - - int attribs; -} VBO_t; - -typedef struct IBO_s -{ - char name[MAX_QPATH]; - - uint32_t indexesVBO; - int indexesSize; // amount of memory data allocated for all triangles in bytes -// uint32_t ofsIndexes; -} IBO_t; - -//=============================================================================== - -typedef enum { - SS_BAD, - SS_PORTAL, // mirrors, portals, viewscreens - SS_ENVIRONMENT, // sky box - SS_OPAQUE, // opaque - - SS_DECAL, // scorch marks, etc. - SS_SEE_THROUGH, // ladders, grates, grills that may have small blended edges - // in addition to alpha test - SS_BANNER, - - SS_FOG, - - SS_UNDERWATER, // for items that should be drawn in front of the water plane - - SS_BLEND0, // regular transparency and filters - SS_BLEND1, // generally only used for additive type effects - SS_BLEND2, - SS_BLEND3, - - SS_BLEND6, - SS_STENCIL_SHADOW, - SS_ALMOST_NEAREST, // gun smoke puffs - - SS_NEAREST // blood blobs -} shaderSort_t; - - -#define MAX_SHADER_STAGES 8 - -typedef enum { - GF_NONE, - - GF_SIN, - GF_SQUARE, - GF_TRIANGLE, - GF_SAWTOOTH, - GF_INVERSE_SAWTOOTH, - - GF_NOISE - -} genFunc_t; - - -typedef enum { - DEFORM_NONE, - DEFORM_WAVE, - DEFORM_NORMALS, - DEFORM_BULGE, - DEFORM_MOVE, - DEFORM_PROJECTION_SHADOW, - DEFORM_AUTOSPRITE, - DEFORM_AUTOSPRITE2, - DEFORM_TEXT0, - DEFORM_TEXT1, - DEFORM_TEXT2, - DEFORM_TEXT3, - DEFORM_TEXT4, - DEFORM_TEXT5, - DEFORM_TEXT6, - DEFORM_TEXT7 -} deform_t; - -// deformVertexes types that can be handled by the GPU -typedef enum -{ - // do not edit: same as genFunc_t - - DGEN_NONE, - DGEN_WAVE_SIN, - DGEN_WAVE_SQUARE, - DGEN_WAVE_TRIANGLE, - DGEN_WAVE_SAWTOOTH, - DGEN_WAVE_INVERSE_SAWTOOTH, - DGEN_WAVE_NOISE, - - // do not edit until this line - - DGEN_BULGE, - DGEN_MOVE -} deformGen_t; - -typedef enum { - AGEN_IDENTITY, - AGEN_SKIP, - AGEN_ENTITY, - AGEN_ONE_MINUS_ENTITY, - AGEN_VERTEX, - AGEN_ONE_MINUS_VERTEX, - AGEN_LIGHTING_SPECULAR, - AGEN_WAVEFORM, - AGEN_PORTAL, - AGEN_CONST, -} alphaGen_t; - -typedef enum { - CGEN_BAD, - CGEN_IDENTITY_LIGHTING, // tr.identityLight - CGEN_IDENTITY, // always (1,1,1,1) - CGEN_ENTITY, // grabbed from entity's modulate field - CGEN_ONE_MINUS_ENTITY, // grabbed from 1 - entity.modulate - CGEN_EXACT_VERTEX, // tess.vertexColors - CGEN_VERTEX, // tess.vertexColors * tr.identityLight - CGEN_EXACT_VERTEX_LIT, // like CGEN_EXACT_VERTEX but takes a light direction from the lightgrid - CGEN_VERTEX_LIT, // like CGEN_VERTEX but takes a light direction from the lightgrid - CGEN_ONE_MINUS_VERTEX, - CGEN_WAVEFORM, // programmatically generated - CGEN_LIGHTING_DIFFUSE, - CGEN_FOG, // standard fog - CGEN_CONST // fixed color -} colorGen_t; - -typedef enum { - TCGEN_BAD, - TCGEN_IDENTITY, // clear to 0,0 - TCGEN_LIGHTMAP, - TCGEN_TEXTURE, - TCGEN_ENVIRONMENT_MAPPED, - TCGEN_FOG, - TCGEN_VECTOR // S and T from world coordinates -} texCoordGen_t; - -typedef enum { - ACFF_NONE, - ACFF_MODULATE_RGB, - ACFF_MODULATE_RGBA, - ACFF_MODULATE_ALPHA -} acff_t; - -typedef struct { - genFunc_t func; - - float base; - float amplitude; - float phase; - float frequency; -} waveForm_t; - -#define TR_MAX_TEXMODS 4 - -typedef enum { - TMOD_NONE, - TMOD_TRANSFORM, - TMOD_TURBULENT, - TMOD_SCROLL, - TMOD_SCALE, - TMOD_STRETCH, - TMOD_ROTATE, - TMOD_ENTITY_TRANSLATE -} texMod_t; - -#define MAX_SHADER_DEFORMS 3 -typedef struct { - deform_t deformation; // vertex coordinate modification type - - vec3_t moveVector; - waveForm_t deformationWave; - float deformationSpread; - - float bulgeWidth; - float bulgeHeight; - float bulgeSpeed; -} deformStage_t; - - -typedef struct { - texMod_t type; - - // used for TMOD_TURBULENT and TMOD_STRETCH - waveForm_t wave; - - // used for TMOD_TRANSFORM - float matrix[2][2]; // s' = s * m[0][0] + t * m[1][0] + trans[0] - float translate[2]; // t' = s * m[0][1] + t * m[0][1] + trans[1] - - // used for TMOD_SCALE - float scale[2]; // s *= scale[0] - // t *= scale[1] - - // used for TMOD_SCROLL - float scroll[2]; // s' = s + scroll[0] * time - // t' = t + scroll[1] * time - - // + = clockwise - // - = counterclockwise - float rotateSpeed; - -} texModInfo_t; - - -#define MAX_IMAGE_ANIMATIONS 8 - -typedef struct { - image_t *image[MAX_IMAGE_ANIMATIONS]; - int numImageAnimations; - float imageAnimationSpeed; - - texCoordGen_t tcGen; - vec3_t tcGenVectors[2]; - - int numTexMods; - texModInfo_t *texMods; - - int videoMapHandle; - qboolean isLightmap; - qboolean isVideoMap; -} textureBundle_t; - -enum -{ - TB_COLORMAP = 0, - TB_DIFFUSEMAP = 0, - TB_LIGHTMAP = 1, - TB_LEVELSMAP = 1, - TB_SHADOWMAP3 = 1, - TB_NORMALMAP = 2, - TB_DELUXEMAP = 3, - TB_SHADOWMAP2 = 3, - TB_SPECULARMAP = 4, - TB_SHADOWMAP = 5, - TB_CUBEMAP = 6, - NUM_TEXTURE_BUNDLES = 7 -}; - -typedef enum -{ - // material shader stage types - ST_COLORMAP = 0, // vanilla Q3A style shader treatening - ST_DIFFUSEMAP = 0, // treat color and diffusemap the same - ST_NORMALMAP, - ST_NORMALPARALLAXMAP, - ST_SPECULARMAP, - ST_GLSL -} stageType_t; - -typedef struct { - qboolean active; - - textureBundle_t bundle[NUM_TEXTURE_BUNDLES]; - - waveForm_t rgbWave; - colorGen_t rgbGen; - - waveForm_t alphaWave; - alphaGen_t alphaGen; - - byte constantColor[4]; // for CGEN_CONST and AGEN_CONST - - unsigned stateBits; // GLS_xxxx mask - - acff_t adjustColorsForFog; - - qboolean isDetail; - - stageType_t type; - struct shaderProgram_s *glslShaderGroup; - int glslShaderIndex; - vec2_t materialInfo; -} shaderStage_t; - -struct shaderCommands_s; - -typedef enum { - CT_FRONT_SIDED, - CT_BACK_SIDED, - CT_TWO_SIDED -} cullType_t; - -typedef enum { - FP_NONE, // surface is translucent and will just be adjusted properly - FP_EQUAL, // surface is opaque but possibly alpha tested - FP_LE // surface is trnaslucent, but still needs a fog pass (fog surface) -} fogPass_t; - -typedef struct { - float cloudHeight; - image_t *outerbox[6], *innerbox[6]; -} skyParms_t; - -typedef struct { - vec3_t color; - float depthForOpaque; -} fogParms_t; - - -typedef struct shader_s { - char name[MAX_QPATH]; // game path, including extension - int lightmapIndex; // for a shader to match, both name and lightmapIndex must match - - int index; // this shader == tr.shaders[index] - int sortedIndex; // this shader == tr.sortedShaders[sortedIndex] - - float sort; // lower numbered shaders draw before higher numbered - - qboolean defaultShader; // we want to return index 0 if the shader failed to - // load for some reason, but R_FindShader should - // still keep a name allocated for it, so if - // something calls RE_RegisterShader again with - // the same name, we don't try looking for it again - - qboolean explicitlyDefined; // found in a .shader file - - int surfaceFlags; // if explicitlyDefined, this will have SURF_* flags - int contentFlags; - - qboolean entityMergable; // merge across entites optimizable (smoke, blood) - - qboolean isSky; - skyParms_t sky; - fogParms_t fogParms; - - float portalRange; // distance to fog out at - qboolean isPortal; - - int multitextureEnv; // 0, GL_MODULATE, GL_ADD (FIXME: put in stage) - - cullType_t cullType; // CT_FRONT_SIDED, CT_BACK_SIDED, or CT_TWO_SIDED - qboolean polygonOffset; // set for decals and other items that must be offset - qboolean noMipMaps; // for console fonts, 2D elements, etc. - qboolean noPicMip; // for images that must always be full resolution - - fogPass_t fogPass; // draw a blended pass, possibly with depth test equals - - int vertexAttribs; // not all shaders will need all data to be gathered - - int numDeforms; - deformStage_t deforms[MAX_SHADER_DEFORMS]; - - int numUnfoggedPasses; - shaderStage_t *stages[MAX_SHADER_STAGES]; - - void (*optimalStageIteratorFunc)( void ); - - float clampTime; // time this shader is clamped to - float timeOffset; // current time offset for this shader - - struct shader_s *remappedShader; // current shader this one is remapped too - - struct shader_s *next; -} shader_t; - -static ID_INLINE qboolean ShaderRequiresCPUDeforms(const shader_t * shader) -{ - if(shader->numDeforms) - { - const deformStage_t *ds = &shader->deforms[0]; - - if (shader->numDeforms > 1) - return qtrue; - - switch (ds->deformation) - { - case DEFORM_WAVE: - case DEFORM_BULGE: - return qfalse; - - default: - return qtrue; - } - } - - return qfalse; -} - -enum -{ - ATTR_INDEX_POSITION = 0, - ATTR_INDEX_TEXCOORD0 = 1, - ATTR_INDEX_TEXCOORD1 = 2, - ATTR_INDEX_TANGENT = 3, - ATTR_INDEX_NORMAL = 4, - ATTR_INDEX_COLOR = 5, - ATTR_INDEX_PAINTCOLOR = 6, - ATTR_INDEX_LIGHTDIRECTION = 7, - ATTR_INDEX_BONE_INDEXES = 8, - ATTR_INDEX_BONE_WEIGHTS = 9, - - // GPU vertex animations - ATTR_INDEX_POSITION2 = 10, - ATTR_INDEX_TANGENT2 = 11, - ATTR_INDEX_NORMAL2 = 12 -}; - -enum -{ - ATTR_POSITION = 0x0001, - ATTR_TEXCOORD = 0x0002, - ATTR_LIGHTCOORD = 0x0004, - ATTR_TANGENT = 0x0008, - ATTR_NORMAL = 0x0010, - ATTR_COLOR = 0x0020, - ATTR_PAINTCOLOR = 0x0040, - ATTR_LIGHTDIRECTION = 0x0080, - ATTR_BONE_INDEXES = 0x0100, - ATTR_BONE_WEIGHTS = 0x0200, - - // for .md3 interpolation - ATTR_POSITION2 = 0x0400, - ATTR_TANGENT2 = 0x0800, - ATTR_NORMAL2 = 0x1000, - - ATTR_DEFAULT = ATTR_POSITION, - ATTR_BITS = ATTR_POSITION | - ATTR_TEXCOORD | - ATTR_LIGHTCOORD | - ATTR_TANGENT | - ATTR_NORMAL | - ATTR_COLOR | - ATTR_PAINTCOLOR | - ATTR_LIGHTDIRECTION | - ATTR_BONE_INDEXES | - ATTR_BONE_WEIGHTS | - ATTR_POSITION2 | - ATTR_TANGENT2 | - ATTR_NORMAL2 -}; - -enum -{ - GENERICDEF_USE_DEFORM_VERTEXES = 0x0001, - GENERICDEF_USE_TCGEN_AND_TCMOD = 0x0002, - GENERICDEF_USE_VERTEX_ANIMATION = 0x0004, - GENERICDEF_USE_FOG = 0x0008, - GENERICDEF_USE_RGBAGEN = 0x0010, - GENERICDEF_USE_LIGHTMAP = 0x0020, - GENERICDEF_ALL = 0x003F, - GENERICDEF_COUNT = 0x0040, -}; - -enum -{ - FOGDEF_USE_DEFORM_VERTEXES = 0x0001, - FOGDEF_USE_VERTEX_ANIMATION = 0x0002, - FOGDEF_ALL = 0x0003, - FOGDEF_COUNT = 0x0004, -}; - -enum -{ - DLIGHTDEF_USE_DEFORM_VERTEXES = 0x0001, - DLIGHTDEF_ALL = 0x0001, - DLIGHTDEF_COUNT = 0x0002, -}; - -enum -{ - LIGHTDEF_USE_LIGHTMAP = 0x0001, - LIGHTDEF_USE_LIGHT_VECTOR = 0x0002, - LIGHTDEF_USE_LIGHT_VERTEX = 0x0003, - LIGHTDEF_LIGHTTYPE_MASK = 0x0003, - LIGHTDEF_ENTITY = 0x0004, - LIGHTDEF_USE_TCGEN_AND_TCMOD = 0x0008, - LIGHTDEF_USE_PARALLAXMAP = 0x0010, - LIGHTDEF_USE_SHADOWMAP = 0x0020, - LIGHTDEF_ALL = 0x003F, - LIGHTDEF_COUNT = 0x0040 -}; - -enum -{ - GLSL_INT, - GLSL_FLOAT, - GLSL_FLOAT5, - GLSL_VEC2, - GLSL_VEC3, - GLSL_VEC4, - GLSL_MAT16 -}; - -typedef enum -{ - UNIFORM_DIFFUSEMAP = 0, - UNIFORM_LIGHTMAP, - UNIFORM_NORMALMAP, - UNIFORM_DELUXEMAP, - UNIFORM_SPECULARMAP, - - UNIFORM_TEXTUREMAP, - UNIFORM_LEVELSMAP, - UNIFORM_CUBEMAP, - - UNIFORM_SCREENIMAGEMAP, - UNIFORM_SCREENDEPTHMAP, - - UNIFORM_SHADOWMAP, - UNIFORM_SHADOWMAP2, - UNIFORM_SHADOWMAP3, - - UNIFORM_SHADOWMVP, - UNIFORM_SHADOWMVP2, - UNIFORM_SHADOWMVP3, - - UNIFORM_ENABLETEXTURES, - - UNIFORM_DIFFUSETEXMATRIX, - UNIFORM_DIFFUSETEXOFFTURB, - UNIFORM_TEXTURE1ENV, - - UNIFORM_TCGEN0, - UNIFORM_TCGEN0VECTOR0, - UNIFORM_TCGEN0VECTOR1, - - UNIFORM_DEFORMGEN, - UNIFORM_DEFORMPARAMS, - - UNIFORM_COLORGEN, - UNIFORM_ALPHAGEN, - UNIFORM_COLOR, - UNIFORM_BASECOLOR, - UNIFORM_VERTCOLOR, - - UNIFORM_DLIGHTINFO, - UNIFORM_LIGHTFORWARD, - UNIFORM_LIGHTUP, - UNIFORM_LIGHTRIGHT, - UNIFORM_LIGHTORIGIN, - UNIFORM_MODELLIGHTDIR, - UNIFORM_LIGHTRADIUS, - UNIFORM_AMBIENTLIGHT, - UNIFORM_DIRECTEDLIGHT, - - UNIFORM_PORTALRANGE, - - UNIFORM_FOGDISTANCE, - UNIFORM_FOGDEPTH, - UNIFORM_FOGEYET, - UNIFORM_FOGCOLORMASK, - - UNIFORM_MODELMATRIX, - UNIFORM_MODELVIEWPROJECTIONMATRIX, - - UNIFORM_TIME, - UNIFORM_VERTEXLERP, - UNIFORM_MATERIALINFO, - - UNIFORM_VIEWINFO, // znear, zfar, width/2, height/2 - UNIFORM_VIEWORIGIN, - UNIFORM_LOCALVIEWORIGIN, - UNIFORM_VIEWFORWARD, - UNIFORM_VIEWLEFT, - UNIFORM_VIEWUP, - - UNIFORM_INVTEXRES, - UNIFORM_AUTOEXPOSUREMINMAX, - UNIFORM_TONEMINAVGMAXLINEAR, - - UNIFORM_PRIMARYLIGHTORIGIN, - UNIFORM_PRIMARYLIGHTCOLOR, - UNIFORM_PRIMARYLIGHTAMBIENT, - UNIFORM_PRIMARYLIGHTRADIUS, - - UNIFORM_COUNT -} uniform_t; - -// shaderProgram_t represents a pair of one -// GLSL vertex and one GLSL fragment shader -typedef struct shaderProgram_s -{ - char name[MAX_QPATH]; - - GLhandleARB program; - GLhandleARB vertexShader; - GLhandleARB fragmentShader; - uint32_t attribs; // vertex array attributes - - // uniform parameters - GLint uniforms[UNIFORM_COUNT]; - short uniformBufferOffsets[UNIFORM_COUNT]; // max 32767/64=511 uniforms - char *uniformBuffer; -} shaderProgram_t; - -// trRefdef_t holds everything that comes in refdef_t, -// as well as the locally generated scene information -typedef struct { - int x, y, width, height; - float fov_x, fov_y; - vec3_t vieworg; - vec3_t viewaxis[3]; // transformation matrix - - stereoFrame_t stereoFrame; - - int time; // time in milliseconds for shader effects and other time dependent rendering issues - int rdflags; // RDF_NOWORLDMODEL, etc - - // 1 bits will prevent the associated area from rendering at all - byte areamask[MAX_MAP_AREA_BYTES]; - qboolean areamaskModified; // qtrue if areamask changed since last scene - - float floatTime; // tr.refdef.time / 1000.0 - - float blurFactor; - - // text messages for deform text shaders - char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH]; - - int num_entities; - trRefEntity_t *entities; - - int num_dlights; - struct dlight_s *dlights; - - int numPolys; - struct srfPoly_s *polys; - - int numDrawSurfs; - struct drawSurf_s *drawSurfs; - - unsigned int dlightMask; - int num_pshadows; - struct pshadow_s *pshadows; - - float sunShadowMvp[3][16]; - float sunDir[4]; - float sunCol[4]; - float sunAmbCol[4]; - float colorScale; - - float autoExposureMinMax[2]; - float toneMinAvgMaxLinear[3]; -} trRefdef_t; - - -//================================================================================= - -// skins allow models to be retextured without modifying the model file -typedef struct { - char name[MAX_QPATH]; - shader_t *shader; -} skinSurface_t; - -typedef struct skin_s { - char name[MAX_QPATH]; // game path, including extension - int numSurfaces; - skinSurface_t *surfaces[MD3_MAX_SURFACES]; -} skin_t; - - -typedef struct { - int originalBrushNumber; - vec3_t bounds[2]; - - unsigned colorInt; // in packed byte format - float tcScale; // texture coordinate vector scales - fogParms_t parms; - - // for clipping distance in fog when outside - qboolean hasSurface; - float surface[4]; -} fog_t; - -typedef enum { - VPF_NONE = 0x00, - VPF_NOVIEWMODEL = 0x01, - VPF_SHADOWMAP = 0x02, - VPF_DEPTHSHADOW = 0x04, - VPF_DEPTHCLAMP = 0x08, - VPF_ORTHOGRAPHIC = 0x10, - VPF_USESUNLIGHT = 0x20, - VPF_FARPLANEFRUSTUM = 0x40, - VPF_NOCUBEMAPS = 0x80 -} viewParmFlags_t; - -typedef struct { - orientationr_t or; - orientationr_t world; - vec3_t pvsOrigin; // may be different than or.origin for portals - qboolean isPortal; // true if this view is through a portal - qboolean isMirror; // the portal is a mirror, invert the face culling - viewParmFlags_t flags; - int frameSceneNum; // copied from tr.frameSceneNum - int frameCount; // copied from tr.frameCount - cplane_t portalPlane; // clip anything behind this if mirroring - int viewportX, viewportY, viewportWidth, viewportHeight; - FBO_t *targetFbo; - int targetFboLayer; - int targetFboCubemapIndex; - float fovX, fovY; - float projectionMatrix[16]; - cplane_t frustum[5]; - vec3_t visBounds[2]; - float zFar; - float zNear; - stereoFrame_t stereoFrame; -} viewParms_t; - - -/* -============================================================================== - -SURFACES - -============================================================================== -*/ -typedef byte color4ub_t[4]; - -// any changes in surfaceType must be mirrored in rb_surfaceTable[] -typedef enum { - SF_BAD, - SF_SKIP, // ignore - SF_FACE, - SF_GRID, - SF_TRIANGLES, - SF_POLY, - SF_MDV, - SF_MDR, - SF_IQM, - SF_FLARE, - SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity - SF_DISPLAY_LIST, - SF_VBO_MESH, - SF_VBO_MDVMESH, - - SF_NUM_SURFACE_TYPES, - SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int ) -} surfaceType_t; - -typedef struct drawSurf_s { - unsigned int sort; // bit combination for fast compares - int cubemapIndex; - surfaceType_t *surface; // any of surface*_t -} drawSurf_t; - -#define MAX_FACE_POINTS 64 - -#define MAX_PATCH_SIZE 32 // max dimensions of a patch mesh in map file -#define MAX_GRID_SIZE 65 // max dimensions of a grid mesh in memory - -// when cgame directly specifies a polygon, it becomes a srfPoly_t -// as soon as it is called -typedef struct srfPoly_s { - surfaceType_t surfaceType; - qhandle_t hShader; - int fogIndex; - int numVerts; - polyVert_t *verts; -} srfPoly_t; - -typedef struct srfDisplayList_s { - surfaceType_t surfaceType; - int listNum; -} srfDisplayList_t; - - -typedef struct srfFlare_s { - surfaceType_t surfaceType; - vec3_t origin; - vec3_t normal; - vec3_t color; -} srfFlare_t; - -typedef struct -{ - vec3_t xyz; - vec2_t st; - vec2_t lightmap; - vec3_t normal; -#ifdef USE_VERT_TANGENT_SPACE - vec4_t tangent; -#endif - vec3_t lightdir; - vec4_t vertexColors; - -#if DEBUG_OPTIMIZEVERTICES - unsigned int id; -#endif -} srfVert_t; - -#ifdef USE_VERT_TANGENT_SPACE -#define srfVert_t_cleared(x) srfVert_t (x) = {{0, 0, 0}, {0, 0}, {0, 0}, {0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0}, {0, 0, 0, 0}} -#else -#define srfVert_t_cleared(x) srfVert_t (x) = {{0, 0, 0}, {0, 0}, {0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0, 0}} -#endif - -// srfBspSurface_t covers SF_GRID, SF_TRIANGLES, SF_POLY, and SF_VBO_MESH -typedef struct srfBspSurface_s -{ - surfaceType_t surfaceType; - - // dynamic lighting information - int dlightBits; - int pshadowBits; - - // culling information - vec3_t cullBounds[2]; - vec3_t cullOrigin; - float cullRadius; - cplane_t cullPlane; - - // indexes - int numIndexes; - glIndex_t *indexes; - - // vertexes - int numVerts; - srfVert_t *verts; - - // BSP VBO offsets - int firstVert; - int firstIndex; - glIndex_t minIndex; - glIndex_t maxIndex; - - // static render data - VBO_t *vbo; - IBO_t *ibo; - - // SF_GRID specific variables after here - - // lod information, which may be different - // than the culling information to allow for - // groups of curves that LOD as a unit - vec3_t lodOrigin; - float lodRadius; - int lodFixed; - int lodStitched; - - // vertexes - int width, height; - float *widthLodError; - float *heightLodError; -} srfBspSurface_t; - -// inter-quake-model -typedef struct { - int num_vertexes; - int num_triangles; - int num_frames; - int num_surfaces; - int num_joints; - int num_poses; - struct srfIQModel_s *surfaces; - - float *positions; - float *texcoords; - float *normals; - float *tangents; - byte *blendIndexes; - union { - float *f; - byte *b; - } blendWeights; - byte *colors; - int *triangles; - - // depending upon the exporter, blend indices and weights might be int/float - // as opposed to the recommended byte/byte, for example Noesis exports - // int/float whereas the official IQM tool exports byte/byte - byte blendWeightsType; // IQM_UBYTE or IQM_FLOAT - - int *jointParents; - float *jointMats; - float *poseMats; - float *bounds; - char *names; -} iqmData_t; - -// inter-quake-model surface -typedef struct srfIQModel_s { - surfaceType_t surfaceType; - char name[MAX_QPATH]; - shader_t *shader; - iqmData_t *data; - int first_vertex, num_vertexes; - int first_triangle, num_triangles; -} srfIQModel_t; - -typedef struct srfVBOMDVMesh_s -{ - surfaceType_t surfaceType; - - struct mdvModel_s *mdvModel; - struct mdvSurface_s *mdvSurface; - - // backEnd stats - int numIndexes; - int numVerts; - glIndex_t minIndex; - glIndex_t maxIndex; - - // static render data - VBO_t *vbo; - IBO_t *ibo; -} srfVBOMDVMesh_t; - -extern void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])(void *); - -/* -============================================================================== - -SHADOWS - -============================================================================== -*/ - -typedef struct pshadow_s -{ - float sort; - - int numEntities; - int entityNums[8]; - vec3_t entityOrigins[8]; - float entityRadiuses[8]; - - float viewRadius; - vec3_t viewOrigin; - - vec3_t lightViewAxis[3]; - vec3_t lightOrigin; - float lightRadius; - cplane_t cullPlane; -} pshadow_t; - - -/* -============================================================================== - -BRUSH MODELS - -============================================================================== -*/ - - -// -// in memory representation -// - -#define SIDE_FRONT 0 -#define SIDE_BACK 1 -#define SIDE_ON 2 - -#define CULLINFO_NONE 0 -#define CULLINFO_BOX 1 -#define CULLINFO_SPHERE 2 -#define CULLINFO_PLANE 4 - -typedef struct cullinfo_s { - int type; - vec3_t bounds[2]; - vec3_t localOrigin; - float radius; - cplane_t plane; -} cullinfo_t; - -typedef struct msurface_s { - //int viewCount; // if == tr.viewCount, already added - struct shader_s *shader; - int fogIndex; - int cubemapIndex; - cullinfo_t cullinfo; - - surfaceType_t *data; // any of srf*_t -} msurface_t; - - -#define CONTENTS_NODE -1 -typedef struct mnode_s { - // common with leaf and node - int contents; // -1 for nodes, to differentiate from leafs - int visCounts[MAX_VISCOUNTS]; // node needs to be traversed if current - vec3_t mins, maxs; // for bounding box culling - struct mnode_s *parent; - - // node specific - cplane_t *plane; - struct mnode_s *children[2]; - - // leaf specific - int cluster; - int area; - - int firstmarksurface; - int nummarksurfaces; -} mnode_t; - -typedef struct { - vec3_t bounds[2]; // for culling - int firstSurface; - int numSurfaces; -} bmodel_t; - -typedef struct { - char name[MAX_QPATH]; // ie: maps/tim_dm2.bsp - char baseName[MAX_QPATH]; // ie: tim_dm2 - - int dataSize; - - int numShaders; - dshader_t *shaders; - - int numBModels; - bmodel_t *bmodels; - - int numplanes; - cplane_t *planes; - - int numnodes; // includes leafs - int numDecisionNodes; - mnode_t *nodes; - - int numWorldSurfaces; - - int numsurfaces; - msurface_t *surfaces; - int *surfacesViewCount; - int *surfacesDlightBits; - int *surfacesPshadowBits; - - int numMergedSurfaces; - msurface_t *mergedSurfaces; - int *mergedSurfacesViewCount; - int *mergedSurfacesDlightBits; - int *mergedSurfacesPshadowBits; - - int nummarksurfaces; - int *marksurfaces; - int *viewSurfaces; - - int numfogs; - fog_t *fogs; - - vec3_t lightGridOrigin; - vec3_t lightGridSize; - vec3_t lightGridInverseSize; - int lightGridBounds[3]; - byte *lightGridData; - float *hdrLightGrid; - - - int numClusters; - int clusterBytes; - const byte *vis; // may be passed in by CM_LoadMap to save space - - byte *novis; // clusterBytes of 0xff - - char *entityString; - char *entityParsePoint; -} world_t; - - -/* -============================================================================== -MDV MODELS - meta format for vertex animation models like .md2, .md3, .mdc -============================================================================== -*/ -typedef struct -{ - float bounds[2][3]; - float localOrigin[3]; - float radius; -} mdvFrame_t; - -typedef struct -{ - float origin[3]; - float axis[3][3]; -} mdvTag_t; - -typedef struct -{ - char name[MAX_QPATH]; // tag name -} mdvTagName_t; - -typedef struct -{ - vec3_t xyz; - vec3_t normal; -#ifdef USE_VERT_TANGENT_SPACE - vec3_t tangent; - vec3_t bitangent; -#endif -} mdvVertex_t; - -typedef struct -{ - float st[2]; -} mdvSt_t; - -typedef struct mdvSurface_s -{ - surfaceType_t surfaceType; - - char name[MAX_QPATH]; // polyset name - - int numShaderIndexes; - int *shaderIndexes; - - int numVerts; - mdvVertex_t *verts; - mdvSt_t *st; - - int numIndexes; - glIndex_t *indexes; - - struct mdvModel_s *model; -} mdvSurface_t; - -typedef struct mdvModel_s -{ - int numFrames; - mdvFrame_t *frames; - - int numTags; - mdvTag_t *tags; - mdvTagName_t *tagNames; - - int numSurfaces; - mdvSurface_t *surfaces; - - int numVBOSurfaces; - srfVBOMDVMesh_t *vboSurfaces; - - int numSkins; -} mdvModel_t; - - -//====================================================================== - -typedef enum { - MOD_BAD, - MOD_BRUSH, - MOD_MESH, - MOD_MDR, - MOD_IQM -} modtype_t; - -typedef struct model_s { - char name[MAX_QPATH]; - modtype_t type; - int index; // model = tr.models[model->index] - - int dataSize; // just for listing purposes - bmodel_t *bmodel; // only if type == MOD_BRUSH - mdvModel_t *mdv[MD3_MAX_LODS]; // only if type == MOD_MESH - void *modelData; // only if type == (MOD_MDR | MOD_IQM) - - int numLods; -} model_t; - - -#define MAX_MOD_KNOWN 1024 - -void R_ModelInit (void); -model_t *R_GetModelByHandle( qhandle_t hModel ); -int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, - float frac, const char *tagName ); -void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ); - -void R_Modellist_f (void); - -//==================================================== - -#define MAX_DRAWIMAGES 2048 -#define MAX_SKINS 1024 - - -#define MAX_DRAWSURFS 0x10000 -#define DRAWSURF_MASK (MAX_DRAWSURFS-1) - -/* - -the drawsurf sort data is packed into a single 32 bit value so it can be -compared quickly during the qsorting process - -the bits are allocated as follows: - -0 - 1 : dlightmap index -//2 : used to be clipped flag REMOVED - 03.21.00 rad -2 - 6 : fog index -11 - 20 : entity index -21 - 31 : sorted shader index - - TTimo - 1.32 -0-1 : dlightmap index -2-6 : fog index -7-16 : entity index -17-30 : sorted shader index - - SmileTheory - for pshadows -17-31 : sorted shader index -7-16 : entity index -2-6 : fog index -1 : pshadow flag -0 : dlight flag -*/ -#define QSORT_FOGNUM_SHIFT 2 -#define QSORT_REFENTITYNUM_SHIFT 7 -#define QSORT_SHADERNUM_SHIFT (QSORT_REFENTITYNUM_SHIFT+REFENTITYNUM_BITS) -#if (QSORT_SHADERNUM_SHIFT+SHADERNUM_BITS) > 32 - #error "Need to update sorting, too many bits." -#endif -#define QSORT_PSHADOW_SHIFT 1 - -extern int gl_filter_min, gl_filter_max; - -/* -** performanceCounters_t -*/ -typedef struct { - int c_sphere_cull_patch_in, c_sphere_cull_patch_clip, c_sphere_cull_patch_out; - int c_box_cull_patch_in, c_box_cull_patch_clip, c_box_cull_patch_out; - int c_sphere_cull_md3_in, c_sphere_cull_md3_clip, c_sphere_cull_md3_out; - int c_box_cull_md3_in, c_box_cull_md3_clip, c_box_cull_md3_out; - - int c_leafs; - int c_dlightSurfaces; - int c_dlightSurfacesCulled; -} frontEndCounters_t; - -#define FOG_TABLE_SIZE 256 -#define FUNCTABLE_SIZE 1024 -#define FUNCTABLE_SIZE2 10 -#define FUNCTABLE_MASK (FUNCTABLE_SIZE-1) - - -// the renderer front end should never modify glstate_t -typedef struct { - int currenttextures[NUM_TEXTURE_BUNDLES]; - int currenttmu; - qboolean finishCalled; - int texEnv[2]; - int faceCulling; - unsigned long glStateBits; - uint32_t vertexAttribsState; - uint32_t vertexAttribPointersSet; - uint32_t vertexAttribsNewFrame; - uint32_t vertexAttribsOldFrame; - float vertexAttribsInterpolation; - qboolean vertexAnimation; - shaderProgram_t *currentProgram; - FBO_t *currentFBO; - VBO_t *currentVBO; - IBO_t *currentIBO; - mat4_t modelview; - mat4_t projection; - mat4_t modelviewProjection; -} glstate_t; - -typedef enum { - MI_NONE, - MI_NVX, - MI_ATI -} memInfo_t; - -typedef enum { - TCR_NONE = 0x0000, - TCR_LATC = 0x0001, - TCR_BPTC = 0x0002, -} textureCompressionRef_t; - -// We can't change glConfig_t without breaking DLL/vms compatibility, so -// store extensions we have here. -typedef struct { - qboolean drawRangeElements; - qboolean multiDrawArrays; - qboolean occlusionQuery; - - int glslMajorVersion; - int glslMinorVersion; - - memInfo_t memInfo; - - qboolean framebufferObject; - int maxRenderbufferSize; - int maxColorAttachments; - - qboolean textureNonPowerOfTwo; - qboolean textureFloat; - qboolean halfFloatPixel; - qboolean packedDepthStencil; - textureCompressionRef_t textureCompression; - - qboolean framebufferMultisample; - qboolean framebufferBlit; - - qboolean textureSrgb; - qboolean framebufferSrgb; - qboolean textureSrgbDecode; - - qboolean depthClamp; - qboolean seamlessCubeMap; - - GLenum packedNormalDataType; -} glRefConfig_t; - - -typedef struct { - int c_surfaces, c_shaders, c_vertexes, c_indexes, c_totalIndexes; - int c_surfBatches; - float c_overDraw; - - int c_vboVertexBuffers; - int c_vboIndexBuffers; - int c_vboVertexes; - int c_vboIndexes; - - int c_staticVboDraws; - int c_dynamicVboDraws; - - int c_multidraws; - int c_multidrawsMerged; - - int c_dlightVertexes; - int c_dlightIndexes; - - int c_flareAdds; - int c_flareTests; - int c_flareRenders; - - int c_glslShaderBinds; - int c_genericDraws; - int c_lightallDraws; - int c_fogDraws; - int c_dlightDraws; - - int msec; // total msec for backend run -} backEndCounters_t; - -// all state modified by the back end is seperated -// from the front end state -typedef struct { - trRefdef_t refdef; - viewParms_t viewParms; - orientationr_t or; - backEndCounters_t pc; - qboolean isHyperspace; - trRefEntity_t *currentEntity; - qboolean skyRenderedThisView; // flag for drawing sun - - qboolean projection2D; // if qtrue, drawstretchpic doesn't need to change modes - byte color2D[4]; - qboolean vertexes2D; // shader needs to be finished - trRefEntity_t entity2D; // currentEntity will point at this when doing 2D rendering - - FBO_t *last2DFBO; - qboolean colorMask[4]; - qboolean framePostProcessed; - qboolean depthFill; -} backEndState_t; - -/* -** trGlobals_t -** -** Most renderer globals are defined here. -** backend functions should never modify any of these fields, -** but may read fields that aren't dynamically modified -** by the frontend. -*/ -typedef struct { - qboolean registered; // cleared at shutdown, set at beginRegistration - - int visIndex; - int visClusters[MAX_VISCOUNTS]; - int visCounts[MAX_VISCOUNTS]; // incremented every time a new vis cluster is entered - - int frameCount; // incremented every frame - int sceneCount; // incremented every scene - int viewCount; // incremented every view (twice a scene if portaled) - // and every R_MarkFragments call - - int frameSceneNum; // zeroed at RE_BeginFrame - - qboolean worldMapLoaded; - qboolean worldDeluxeMapping; - vec2_t autoExposureMinMax; - vec3_t toneMinAvgMaxLevel; - world_t *world; - - const byte *externalVisData; // from RE_SetWorldVisData, shared with CM_Load - - image_t *defaultImage; - image_t *scratchImage[32]; - image_t *fogImage; - image_t *dlightImage; // inverse-quare highlight for projective adding - image_t *flareImage; - image_t *whiteImage; // full of 0xff - image_t *identityLightImage; // full of tr.identityLightByte - - image_t *shadowCubemaps[MAX_DLIGHTS]; - - - image_t *renderImage; - image_t *sunRaysImage; - image_t *renderDepthImage; - image_t *pshadowMaps[MAX_DRAWN_PSHADOWS]; - image_t *textureScratchImage[2]; - image_t *quarterImage[2]; - image_t *calcLevelsImage; - image_t *targetLevelsImage; - image_t *fixedLevelsImage; - image_t *sunShadowDepthImage[3]; - image_t *screenShadowImage; - image_t *screenSsaoImage; - image_t *hdrDepthImage; - image_t *renderCubeImage; - - image_t *textureDepthImage; - - FBO_t *renderFbo; - FBO_t *msaaResolveFbo; - FBO_t *sunRaysFbo; - FBO_t *depthFbo; - FBO_t *pshadowFbos[MAX_DRAWN_PSHADOWS]; - FBO_t *textureScratchFbo[2]; - FBO_t *quarterFbo[2]; - FBO_t *calcLevelsFbo; - FBO_t *targetLevelsFbo; - FBO_t *sunShadowFbo[3]; - FBO_t *screenShadowFbo; - FBO_t *screenSsaoFbo; - FBO_t *hdrDepthFbo; - FBO_t *renderCubeFbo; - - shader_t *defaultShader; - shader_t *shadowShader; - shader_t *projectionShadowShader; - - shader_t *flareShader; - shader_t *sunShader; - shader_t *sunFlareShader; - - int numLightmaps; - int lightmapSize; - image_t **lightmaps; - image_t **deluxemaps; - - int fatLightmapSize; - int fatLightmapStep; - - int numCubemaps; - vec3_t *cubemapOrigins; - image_t **cubemaps; - - trRefEntity_t *currentEntity; - trRefEntity_t worldEntity; // point currentEntity at this when rendering world - int currentEntityNum; - int shiftedEntityNum; // currentEntityNum << QSORT_REFENTITYNUM_SHIFT - model_t *currentModel; - - // - // GPU shader programs - // - shaderProgram_t genericShader[GENERICDEF_COUNT]; - shaderProgram_t textureColorShader; - shaderProgram_t fogShader[FOGDEF_COUNT]; - shaderProgram_t dlightShader[DLIGHTDEF_COUNT]; - shaderProgram_t lightallShader[LIGHTDEF_COUNT]; - shaderProgram_t shadowmapShader; - shaderProgram_t pshadowShader; - shaderProgram_t down4xShader; - shaderProgram_t bokehShader; - shaderProgram_t tonemapShader; - shaderProgram_t calclevels4xShader[2]; - shaderProgram_t shadowmaskShader; - shaderProgram_t ssaoShader; - shaderProgram_t depthBlurShader[2]; - shaderProgram_t testcubeShader; - - - // ----------------------------------------- - - viewParms_t viewParms; - - float identityLight; // 1.0 / ( 1 << overbrightBits ) - int identityLightByte; // identityLight * 255 - int overbrightBits; // r_overbrightBits->integer, but set to 0 if no hw gamma - - orientationr_t or; // for current entity - - trRefdef_t refdef; - - int viewCluster; - - float mapLightScale; - float sunShadowScale; - - qboolean sunShadows; - vec3_t sunLight; // from the sky shader for this level - vec3_t sunDirection; - - frontEndCounters_t pc; - int frontEndMsec; // not in pc due to clearing issue - - // - // put large tables at the end, so most elements will be - // within the +/32K indexed range on risc processors - // - model_t *models[MAX_MOD_KNOWN]; - int numModels; - - int numImages; - image_t *images[MAX_DRAWIMAGES]; - - int numFBOs; - FBO_t *fbos[MAX_FBOS]; - - int numVBOs; - VBO_t *vbos[MAX_VBOS]; - - int numIBOs; - IBO_t *ibos[MAX_IBOS]; - - // shader indexes from other modules will be looked up in tr.shaders[] - // shader indexes from drawsurfs will be looked up in sortedShaders[] - // lower indexed sortedShaders must be rendered first (opaque surfaces before translucent) - int numShaders; - shader_t *shaders[MAX_SHADERS]; - shader_t *sortedShaders[MAX_SHADERS]; - - int numSkins; - skin_t *skins[MAX_SKINS]; - - GLuint sunFlareQuery[2]; - int sunFlareQueryIndex; - qboolean sunFlareQueryActive[2]; - - float sinTable[FUNCTABLE_SIZE]; - float squareTable[FUNCTABLE_SIZE]; - float triangleTable[FUNCTABLE_SIZE]; - float sawToothTable[FUNCTABLE_SIZE]; - float inverseSawToothTable[FUNCTABLE_SIZE]; - float fogTable[FOG_TABLE_SIZE]; -} trGlobals_t; - -extern backEndState_t backEnd; -extern trGlobals_t tr; -extern glstate_t glState; // outside of TR since it shouldn't be cleared during ref re-init -extern glRefConfig_t glRefConfig; - -// -// cvars -// -extern cvar_t *r_flareSize; -extern cvar_t *r_flareFade; -// coefficient for the flare intensity falloff function. -#define FLARE_STDCOEFF "150" -extern cvar_t *r_flareCoeff; - -extern cvar_t *r_railWidth; -extern cvar_t *r_railCoreWidth; -extern cvar_t *r_railSegmentLength; - -extern cvar_t *r_ignore; // used for debugging anything -extern cvar_t *r_verbose; // used for verbose debug spew - -extern cvar_t *r_znear; // near Z clip plane -extern cvar_t *r_zproj; // z distance of projection plane -extern cvar_t *r_stereoSeparation; // separation of cameras for stereo rendering - -extern cvar_t *r_measureOverdraw; // enables stencil buffer overdraw measurement - -extern cvar_t *r_lodbias; // push/pull LOD transitions -extern cvar_t *r_lodscale; - -extern cvar_t *r_inGameVideo; // controls whether in game video should be draw -extern cvar_t *r_fastsky; // controls whether sky should be cleared or drawn -extern cvar_t *r_drawSun; // controls drawing of sun quad -extern cvar_t *r_dynamiclight; // dynamic lights enabled/disabled -extern cvar_t *r_dlightBacks; // dlight non-facing surfaces for continuity - -extern cvar_t *r_norefresh; // bypasses the ref rendering -extern cvar_t *r_drawentities; // disable/enable entity rendering -extern cvar_t *r_drawworld; // disable/enable world rendering -extern cvar_t *r_speeds; // various levels of information display -extern cvar_t *r_detailTextures; // enables/disables detail texturing stages -extern cvar_t *r_novis; // disable/enable usage of PVS -extern cvar_t *r_nocull; -extern cvar_t *r_facePlaneCull; // enables culling of planar surfaces with back side test -extern cvar_t *r_nocurves; -extern cvar_t *r_showcluster; - -extern cvar_t *r_gamma; - -extern cvar_t *r_ext_draw_range_elements; -extern cvar_t *r_ext_multi_draw_arrays; -extern cvar_t *r_ext_framebuffer_object; -extern cvar_t *r_ext_texture_float; -extern cvar_t *r_arb_half_float_pixel; -extern cvar_t *r_ext_framebuffer_multisample; -extern cvar_t *r_arb_seamless_cube_map; -extern cvar_t *r_arb_vertex_type_2_10_10_10_rev; - -extern cvar_t *r_nobind; // turns off binding to appropriate textures -extern cvar_t *r_singleShader; // make most world faces use default shader -extern cvar_t *r_roundImagesDown; -extern cvar_t *r_colorMipLevels; // development aid to see texture mip usage -extern cvar_t *r_picmip; // controls picmip values -extern cvar_t *r_finish; -extern cvar_t *r_textureMode; -extern cvar_t *r_offsetFactor; -extern cvar_t *r_offsetUnits; - -extern cvar_t *r_fullbright; // avoid lightmap pass -extern cvar_t *r_lightmap; // render lightmaps only -extern cvar_t *r_vertexLight; // vertex lighting mode for better performance -extern cvar_t *r_uiFullScreen; // ui is running fullscreen - -extern cvar_t *r_logFile; // number of frames to emit GL logs -extern cvar_t *r_showtris; // enables wireframe rendering of the world -extern cvar_t *r_showsky; // forces sky in front of all surfaces -extern cvar_t *r_shownormals; // draws wireframe normals -extern cvar_t *r_clear; // force screen clear every frame - -extern cvar_t *r_shadows; // controls shadows: 0 = none, 1 = blur, 2 = stencil, 3 = black planar projection -extern cvar_t *r_flares; // light flares - -extern cvar_t *r_intensity; - -extern cvar_t *r_lockpvs; -extern cvar_t *r_noportals; -extern cvar_t *r_portalOnly; - -extern cvar_t *r_subdivisions; -extern cvar_t *r_lodCurveError; -extern cvar_t *r_skipBackEnd; - -extern cvar_t *r_anaglyphMode; - -extern cvar_t *r_mergeMultidraws; -extern cvar_t *r_mergeLeafSurfaces; - -extern cvar_t *r_softOverbright; - -extern cvar_t *r_hdr; -extern cvar_t *r_floatLightmap; -extern cvar_t *r_postProcess; - -extern cvar_t *r_toneMap; -extern cvar_t *r_forceToneMap; -extern cvar_t *r_forceToneMapMin; -extern cvar_t *r_forceToneMapAvg; -extern cvar_t *r_forceToneMapMax; - -extern cvar_t *r_autoExposure; -extern cvar_t *r_forceAutoExposure; -extern cvar_t *r_forceAutoExposureMin; -extern cvar_t *r_forceAutoExposureMax; - -extern cvar_t *r_cameraExposure; - -extern cvar_t *r_srgb; - -extern cvar_t *r_depthPrepass; -extern cvar_t *r_ssao; - -extern cvar_t *r_normalMapping; -extern cvar_t *r_specularMapping; -extern cvar_t *r_deluxeMapping; -extern cvar_t *r_parallaxMapping; -extern cvar_t *r_cubeMapping; -extern cvar_t *r_deluxeSpecular; -extern cvar_t *r_specularIsMetallic; -extern cvar_t *r_baseSpecular; -extern cvar_t *r_baseGloss; -extern cvar_t *r_dlightMode; -extern cvar_t *r_pshadowDist; -extern cvar_t *r_recalcMD3Normals; -extern cvar_t *r_mergeLightmaps; -extern cvar_t *r_imageUpsample; -extern cvar_t *r_imageUpsampleMaxSize; -extern cvar_t *r_imageUpsampleType; -extern cvar_t *r_genNormalMaps; -extern cvar_t *r_forceSun; -extern cvar_t *r_forceSunMapLightScale; -extern cvar_t *r_forceSunLightScale; -extern cvar_t *r_forceSunAmbientScale; -extern cvar_t *r_sunlightMode; -extern cvar_t *r_drawSunRays; -extern cvar_t *r_sunShadows; -extern cvar_t *r_shadowFilter; -extern cvar_t *r_shadowMapSize; -extern cvar_t *r_shadowCascadeZNear; -extern cvar_t *r_shadowCascadeZFar; -extern cvar_t *r_shadowCascadeZBias; -extern cvar_t *r_ignoreDstAlpha; - -extern cvar_t *r_greyscale; - -extern cvar_t *r_ignoreGLErrors; - -extern cvar_t *r_overBrightBits; -extern cvar_t *r_mapOverBrightBits; - -extern cvar_t *r_debugSurface; -extern cvar_t *r_simpleMipMaps; - -extern cvar_t *r_showImages; -extern cvar_t *r_debugSort; - -extern cvar_t *r_printShaders; - -extern cvar_t *r_marksOnTriangleMeshes; - -//==================================================================== - -void R_SwapBuffers( int ); - -void R_RenderView( viewParms_t *parms ); -void R_RenderDlightCubemaps(const refdef_t *fd); -void R_RenderPshadowMaps(const refdef_t *fd); -void R_RenderSunShadowMaps(const refdef_t *fd, int level); -void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene ); - -void R_AddMD3Surfaces( trRefEntity_t *e ); -void R_AddNullModelSurfaces( trRefEntity_t *e ); -void R_AddBeamSurfaces( trRefEntity_t *e ); -void R_AddRailSurfaces( trRefEntity_t *e, qboolean isUnderwater ); -void R_AddLightningBoltSurfaces( trRefEntity_t *e ); - -void R_AddPolygonSurfaces( void ); - -void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader, - int *fogNum, int *dlightMap, int *pshadowMap ); - -void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, - int fogIndex, int dlightMap, int pshadowMap, int cubemap ); - -void R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, vec3_t normal, - const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t t0, const vec2_t t1, const vec2_t t2); -qboolean R_CalcTangentVectors(srfVert_t * dv[3]); - -#define CULL_IN 0 // completely unclipped -#define CULL_CLIP 1 // clipped by one or more planes -#define CULL_OUT 2 // completely outside the clipping planes -void R_LocalNormalToWorld (const vec3_t local, vec3_t world); -void R_LocalPointToWorld (const vec3_t local, vec3_t world); -int R_CullBox (vec3_t bounds[2]); -int R_CullLocalBox (vec3_t bounds[2]); -int R_CullPointAndRadiusEx( const vec3_t origin, float radius, const cplane_t* frustum, int numPlanes ); -int R_CullPointAndRadius( const vec3_t origin, float radius ); -int R_CullLocalPointAndRadius( const vec3_t origin, float radius ); - -void R_SetupProjection(viewParms_t *dest, float zProj, float zFar, qboolean computeFrustum); -void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, orientationr_t *or ); - -/* -** GL wrapper/helper functions -*/ -void GL_Bind( image_t *image ); -void GL_BindToTMU( image_t *image, int tmu ); -void GL_SetDefaultState (void); -void GL_SelectTexture( int unit ); -void GL_TextureMode( const char *string ); -void GL_CheckErrs( char *file, int line ); -#define GL_CheckErrors(...) GL_CheckErrs(__FILE__, __LINE__) -void GL_State( unsigned long stateVector ); -void GL_SetProjectionMatrix(mat4_t matrix); -void GL_SetModelviewMatrix(mat4_t matrix); -void GL_TexEnv( int env ); -void GL_Cull( int cullType ); - -#define GLS_SRCBLEND_ZERO 0x00000001 -#define GLS_SRCBLEND_ONE 0x00000002 -#define GLS_SRCBLEND_DST_COLOR 0x00000003 -#define GLS_SRCBLEND_ONE_MINUS_DST_COLOR 0x00000004 -#define GLS_SRCBLEND_SRC_ALPHA 0x00000005 -#define GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA 0x00000006 -#define GLS_SRCBLEND_DST_ALPHA 0x00000007 -#define GLS_SRCBLEND_ONE_MINUS_DST_ALPHA 0x00000008 -#define GLS_SRCBLEND_ALPHA_SATURATE 0x00000009 -#define GLS_SRCBLEND_BITS 0x0000000f - -#define GLS_DSTBLEND_ZERO 0x00000010 -#define GLS_DSTBLEND_ONE 0x00000020 -#define GLS_DSTBLEND_SRC_COLOR 0x00000030 -#define GLS_DSTBLEND_ONE_MINUS_SRC_COLOR 0x00000040 -#define GLS_DSTBLEND_SRC_ALPHA 0x00000050 -#define GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA 0x00000060 -#define GLS_DSTBLEND_DST_ALPHA 0x00000070 -#define GLS_DSTBLEND_ONE_MINUS_DST_ALPHA 0x00000080 -#define GLS_DSTBLEND_BITS 0x000000f0 - -#define GLS_DEPTHMASK_TRUE 0x00000100 - -#define GLS_POLYMODE_LINE 0x00001000 - -#define GLS_DEPTHTEST_DISABLE 0x00010000 -#define GLS_DEPTHFUNC_EQUAL 0x00020000 -#define GLS_DEPTHFUNC_GREATER 0x00040000 -#define GLS_DEPTHFUNC_BITS 0x00060000 - -#define GLS_ATEST_GT_0 0x10000000 -#define GLS_ATEST_LT_80 0x20000000 -#define GLS_ATEST_GE_80 0x40000000 -#define GLS_ATEST_BITS 0x70000000 - -#define GLS_DEFAULT GLS_DEPTHMASK_TRUE - -void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty); -void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty); - -void RE_BeginFrame( stereoFrame_t stereoFrame ); -void RE_BeginRegistration( glconfig_t *glconfig ); -void RE_LoadWorldMap( const char *mapname ); -void RE_SetWorldVisData( const byte *vis ); -qhandle_t RE_RegisterModel( const char *name ); -qhandle_t RE_RegisterSkin( const char *name ); -void RE_Shutdown( qboolean destroyWindow ); - -qboolean R_GetEntityToken( char *buffer, int size ); - -model_t *R_AllocModel( void ); - -void R_Init( void ); -void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height ); - -void R_SetColorMappings( void ); -void R_GammaCorrect( byte *buffer, int bufSize ); - -void R_ImageList_f( void ); -void R_SkinList_f( void ); -// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=516 -const void *RB_TakeScreenshotCmd( const void *data ); -void R_ScreenShot_f( void ); - -void R_InitFogTable( void ); -float R_FogFactor( float s, float t ); -void R_InitImages( void ); -void R_DeleteTextures( void ); -int R_SumOfUsedImages( void ); -void R_InitSkins( void ); -skin_t *R_GetSkinByHandle( qhandle_t hSkin ); - -int R_ComputeLOD( trRefEntity_t *ent ); - -const void *RB_TakeVideoFrameCmd( const void *data ); - -// -// tr_shader.c -// -shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ); -shader_t *R_GetShaderByHandle( qhandle_t hShader ); -shader_t *R_GetShaderByState( int index, long *cycleTime ); -shader_t *R_FindShaderByName( const char *name ); -void R_InitShaders( void ); -void R_ShaderList_f( void ); -void R_RemapShader(const char *oldShader, const char *newShader, const char *timeOffset); - -/* -==================================================================== - -IMPLEMENTATION SPECIFIC FUNCTIONS - -==================================================================== -*/ - -void GLimp_InitExtraExtensions( void ); - -/* -==================================================================== - -TESSELATOR/SHADER DECLARATIONS - -==================================================================== -*/ - -typedef struct stageVars -{ - color4ub_t colors[SHADER_MAX_VERTEXES]; - vec2_t texcoords[NUM_TEXTURE_BUNDLES][SHADER_MAX_VERTEXES]; -} stageVars_t; - -#define MAX_MULTIDRAW_PRIMITIVES 16384 - -typedef struct shaderCommands_s -{ - glIndex_t indexes[SHADER_MAX_INDEXES] QALIGN(16); - vec4_t xyz[SHADER_MAX_VERTEXES] QALIGN(16); - uint32_t normal[SHADER_MAX_VERTEXES] QALIGN(16); -#ifdef USE_VERT_TANGENT_SPACE - uint32_t tangent[SHADER_MAX_VERTEXES] QALIGN(16); -#endif - vec2_t texCoords[SHADER_MAX_VERTEXES][2] QALIGN(16); - vec4_t vertexColors[SHADER_MAX_VERTEXES] QALIGN(16); - uint32_t lightdir[SHADER_MAX_VERTEXES] QALIGN(16); - //int vertexDlightBits[SHADER_MAX_VERTEXES] QALIGN(16); - - VBO_t *vbo; - IBO_t *ibo; - qboolean useInternalVBO; - - stageVars_t svars QALIGN(16); - - //color4ub_t constantColor255[SHADER_MAX_VERTEXES] QALIGN(16); - - shader_t *shader; - float shaderTime; - int fogNum; - int cubemapIndex; - - int dlightBits; // or together of all vertexDlightBits - int pshadowBits; - - int firstIndex; - int numIndexes; - int numVertexes; - glIndex_t minIndex; - glIndex_t maxIndex; - - int multiDrawPrimitives; - GLsizei multiDrawNumIndexes[MAX_MULTIDRAW_PRIMITIVES]; - glIndex_t *multiDrawFirstIndex[MAX_MULTIDRAW_PRIMITIVES]; - glIndex_t *multiDrawLastIndex[MAX_MULTIDRAW_PRIMITIVES]; - glIndex_t multiDrawMinIndex[MAX_MULTIDRAW_PRIMITIVES]; - glIndex_t multiDrawMaxIndex[MAX_MULTIDRAW_PRIMITIVES]; - - // info extracted from current shader - int numPasses; - void (*currentStageIteratorFunc)( void ); - shaderStage_t **xstages; -} shaderCommands_t; - -extern shaderCommands_t tess; - -void RB_BeginSurface(shader_t *shader, int fogNum, int cubemapIndex ); -void RB_EndSurface(void); -void RB_CheckOverflow( int verts, int indexes ); -#define RB_CHECKOVERFLOW(v,i) if (tess.numVertexes + (v) >= SHADER_MAX_VERTEXES || tess.numIndexes + (i) >= SHADER_MAX_INDEXES ) {RB_CheckOverflow(v,i);} - -void R_DrawElementsVBO( int numIndexes, glIndex_t firstIndex, glIndex_t minIndex, glIndex_t maxIndex ); -void RB_StageIteratorGeneric( void ); -void RB_StageIteratorSky( void ); -void RB_StageIteratorVertexLitTexture( void ); -void RB_StageIteratorLightmappedMultitexture( void ); - -void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, float color[4] ); -void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, float color[4], float s1, float t1, float s2, float t2 ); -void RB_InstantQuad( vec4_t quadVerts[4] ); -//void RB_InstantQuad2(vec4_t quadVerts[4], vec2_t texCoords[4], vec4_t color, shaderProgram_t *sp, vec2_t invTexRes); -void RB_InstantQuad2(vec4_t quadVerts[4], vec2_t texCoords[4]); - -void RB_ShowImages( void ); - - -/* -============================================================ - -WORLD MAP - -============================================================ -*/ - -void R_AddBrushModelSurfaces( trRefEntity_t *e ); -void R_AddWorldSurfaces( void ); -qboolean R_inPVS( const vec3_t p1, const vec3_t p2 ); - - -/* -============================================================ - -FLARES - -============================================================ -*/ - -void R_ClearFlares( void ); - -void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ); -void RB_AddDlightFlares( void ); -void RB_RenderFlares (void); - -/* -============================================================ - -LIGHTS - -============================================================ -*/ - -void R_DlightBmodel( bmodel_t *bmodel ); -void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ); -void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or ); -int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ); -int R_LightDirForPoint( vec3_t point, vec3_t lightDir, vec3_t normal, world_t *world ); -int R_CubemapForPoint( vec3_t point ); - - -/* -============================================================ - -SHADOWS - -============================================================ -*/ - -void RB_ShadowTessEnd( void ); -void RB_ShadowFinish( void ); -void RB_ProjectionShadowDeform( void ); - -/* -============================================================ - -SKIES - -============================================================ -*/ - -void R_BuildCloudData( shaderCommands_t *shader ); -void R_InitSkyTexCoords( float cloudLayerHeight ); -void R_DrawSkyBox( shaderCommands_t *shader ); -void RB_DrawSun( float scale, shader_t *shader ); -void RB_ClipSkyPolygons( shaderCommands_t *shader ); - -/* -============================================================ - -CURVE TESSELATION - -============================================================ -*/ - -#define PATCH_STITCHING - -srfBspSurface_t *R_SubdividePatchToGrid( int width, int height, - srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ); -srfBspSurface_t *R_GridInsertColumn( srfBspSurface_t *grid, int column, int row, vec3_t point, float loderror ); -srfBspSurface_t *R_GridInsertRow( srfBspSurface_t *grid, int row, int column, vec3_t point, float loderror ); -void R_FreeSurfaceGridMesh( srfBspSurface_t *grid ); - -/* -============================================================ - -MARKERS, POLYGON PROJECTION ON WORLD POLYGONS - -============================================================ -*/ - -int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, - int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ); - - -/* -============================================================ - -VERTEX BUFFER OBJECTS - -============================================================ -*/ - -uint32_t R_VboPackTangent(vec4_t v); -uint32_t R_VboPackNormal(vec3_t v); -void R_VboUnpackTangent(vec4_t v, uint32_t b); -void R_VboUnpackNormal(vec3_t v, uint32_t b); - -VBO_t *R_CreateVBO(const char *name, byte * vertexes, int vertexesSize, vboUsage_t usage); -VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * vertexes, uint32_t stateBits, vboUsage_t usage); - -IBO_t *R_CreateIBO(const char *name, byte * indexes, int indexesSize, vboUsage_t usage); -IBO_t *R_CreateIBO2(const char *name, int numIndexes, glIndex_t * inIndexes, vboUsage_t usage); - -void R_BindVBO(VBO_t * vbo); -void R_BindNullVBO(void); - -void R_BindIBO(IBO_t * ibo); -void R_BindNullIBO(void); - -void R_InitVBOs(void); -void R_ShutdownVBOs(void); -void R_VBOList_f(void); - -void RB_UpdateVBOs(unsigned int attribBits); - - -/* -============================================================ - -GLSL - -============================================================ -*/ - -void GLSL_InitGPUShaders(void); -void GLSL_ShutdownGPUShaders(void); -void GLSL_VertexAttribsState(uint32_t stateBits); -void GLSL_VertexAttribPointers(uint32_t attribBits); -void GLSL_BindProgram(shaderProgram_t * program); -void GLSL_BindNullProgram(void); - -void GLSL_SetUniformInt(shaderProgram_t *program, int uniformNum, GLint value); -void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat value); -void GLSL_SetUniformFloat5(shaderProgram_t *program, int uniformNum, const vec5_t v); -void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t v); -void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t v); -void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t v); -void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t matrix); - -shaderProgram_t *GLSL_GetGenericShaderProgram(int stage); - -/* -============================================================ - -SCENE GENERATION - -============================================================ -*/ - -void R_InitNextFrame( void ); - -void RE_ClearScene( void ); -void RE_AddRefEntityToScene( const refEntity_t *ent ); -void RE_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num ); -void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ); -void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ); -void RE_BeginScene( const refdef_t *fd ); -void RE_RenderScene( const refdef_t *fd ); -void RE_EndScene( void ); - -/* -============================================================= - -UNCOMPRESSING BONES - -============================================================= -*/ - -#define MC_BITS_X (16) -#define MC_BITS_Y (16) -#define MC_BITS_Z (16) -#define MC_BITS_VECT (16) - -#define MC_SCALE_X (1.0f/64) -#define MC_SCALE_Y (1.0f/64) -#define MC_SCALE_Z (1.0f/64) - -void MC_UnCompress(float mat[3][4],const unsigned char * comp); - -/* -============================================================= - -ANIMATED MODELS - -============================================================= -*/ - -void R_MDRAddAnimSurfaces( trRefEntity_t *ent ); -void RB_MDRSurfaceAnim( mdrSurface_t *surface ); -qboolean R_LoadIQM (model_t *mod, void *buffer, int filesize, const char *name ); -void R_AddIQMSurfaces( trRefEntity_t *ent ); -void RB_IQMSurfaceAnim( surfaceType_t *surface ); -int R_IQMLerpTag( orientation_t *tag, iqmData_t *data, - int startFrame, int endFrame, - float frac, const char *tagName ); - -/* -============================================================= - -IMAGE LOADERS - -============================================================= -*/ - -void R_LoadBMP( const char *name, byte **pic, int *width, int *height ); -void R_LoadJPG( const char *name, byte **pic, int *width, int *height ); -void R_LoadPCX( const char *name, byte **pic, int *width, int *height ); -void R_LoadPNG( const char *name, byte **pic, int *width, int *height ); -void R_LoadTGA( const char *name, byte **pic, int *width, int *height ); - -/* -============================================================= -============================================================= -*/ -void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix, - vec4_t eye, vec4_t dst ); -void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ); - -void RB_DeformTessGeometry( void ); - -void RB_CalcFogTexCoords( float *dstTexCoords ); - -void RB_CalcScaleTexMatrix( const float scale[2], float *matrix ); -void RB_CalcScrollTexMatrix( const float scrollSpeed[2], float *matrix ); -void RB_CalcRotateTexMatrix( float degsPerSecond, float *matrix ); -void RB_CalcTurbulentFactors( const waveForm_t *wf, float *amplitude, float *now ); -void RB_CalcTransformTexMatrix( const texModInfo_t *tmi, float *matrix ); -void RB_CalcStretchTexMatrix( const waveForm_t *wf, float *matrix ); - -void RB_CalcModulateColorsByFog( unsigned char *dstColors ); -float RB_CalcWaveAlphaSingle( const waveForm_t *wf ); -float RB_CalcWaveColorSingle( const waveForm_t *wf ); - -/* -============================================================= - -RENDERER BACK END FUNCTIONS - -============================================================= -*/ - -void RB_ExecuteRenderCommands( const void *data ); - -/* -============================================================= - -RENDERER BACK END COMMAND QUEUE - -============================================================= -*/ - -#define MAX_RENDER_COMMANDS 0x40000 - -typedef struct { - byte cmds[MAX_RENDER_COMMANDS]; - int used; -} renderCommandList_t; - -typedef struct { - int commandId; - float color[4]; -} setColorCommand_t; - -typedef struct { - int commandId; - int buffer; -} drawBufferCommand_t; - -typedef struct { - int commandId; - image_t *image; - int width; - int height; - void *data; -} subImageCommand_t; - -typedef struct { - int commandId; -} swapBuffersCommand_t; - -typedef struct { - int commandId; - int buffer; -} endFrameCommand_t; - -typedef struct { - int commandId; - shader_t *shader; - float x, y; - float w, h; - float s1, t1; - float s2, t2; -} stretchPicCommand_t; - -typedef struct { - int commandId; - trRefdef_t refdef; - viewParms_t viewParms; - drawSurf_t *drawSurfs; - int numDrawSurfs; -} drawSurfsCommand_t; - -typedef struct { - int commandId; - int x; - int y; - int width; - int height; - char *fileName; - qboolean jpeg; -} screenshotCommand_t; - -typedef struct { - int commandId; - int width; - int height; - byte *captureBuffer; - byte *encodeBuffer; - qboolean motionJpeg; -} videoFrameCommand_t; - -typedef struct -{ - int commandId; - - GLboolean rgba[4]; -} colorMaskCommand_t; - -typedef struct -{ - int commandId; -} clearDepthCommand_t; - -typedef struct { - int commandId; - int map; - int cubeSide; -} capShadowmapCommand_t; - -typedef struct { - int commandId; - trRefdef_t refdef; - viewParms_t viewParms; -} postProcessCommand_t; - -typedef enum { - RC_END_OF_LIST, - RC_SET_COLOR, - RC_STRETCH_PIC, - RC_DRAW_SURFS, - RC_DRAW_BUFFER, - RC_SWAP_BUFFERS, - RC_SCREENSHOT, - RC_VIDEOFRAME, - RC_COLORMASK, - RC_CLEARDEPTH, - RC_CAPSHADOWMAP, - RC_POSTPROCESS -} renderCommand_t; - - -// these are sort of arbitrary limits. -// the limits apply to the sum of all scenes in a frame -- -// the main view, all the 3D icons, etc -#define MAX_POLYS 600 -#define MAX_POLYVERTS 3000 - -// all of the information needed by the back end must be -// contained in a backEndData_t -typedef struct { - drawSurf_t drawSurfs[MAX_DRAWSURFS]; - dlight_t dlights[MAX_DLIGHTS]; - trRefEntity_t entities[MAX_REFENTITIES]; - srfPoly_t *polys;//[MAX_POLYS]; - polyVert_t *polyVerts;//[MAX_POLYVERTS]; - pshadow_t pshadows[MAX_CALC_PSHADOWS]; - renderCommandList_t commands; -} backEndData_t; - -extern int max_polys; -extern int max_polyverts; - -extern backEndData_t *backEndData; // the second one may not be allocated - - -void *R_GetCommandBuffer( int bytes ); -void RB_ExecuteRenderCommands( const void *data ); - -void R_IssuePendingRenderCommands( void ); - -void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ); -void R_AddCapShadowmapCmd( int dlight, int cubeSide ); -void R_AddPostProcessCmd (void); - -void RE_SetColor( const float *rgba ); -void RE_StretchPic ( float x, float y, float w, float h, - float s1, float t1, float s2, float t2, qhandle_t hShader ); -void RE_BeginFrame( stereoFrame_t stereoFrame ); -void RE_EndFrame( int *frontEndMsec, int *backEndMsec ); -void RE_SaveJPG(char * filename, int quality, int image_width, int image_height, - unsigned char *image_buffer, int padding); -size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality, - int image_width, int image_height, byte *image_buffer, int padding); -void RE_TakeVideoFrame( int width, int height, - byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg ); - - -#endif //TR_LOCAL_H diff --git a/code/renderergl2/tr_main.c b/code/renderergl2/tr_main.c deleted file mode 100644 index df1f8e60c9..0000000000 --- a/code/renderergl2/tr_main.c +++ /dev/null @@ -1,2913 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_main.c -- main control flow for each frame - -#include "tr_local.h" - -#include // memcpy - -trGlobals_t tr; - -static float s_flipMatrix[16] = { - // convert from our coordinate system (looking down X) - // to OpenGL's coordinate system (looking down -Z) - 0, 0, -1, 0, - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1 -}; - - -refimport_t ri; - -// entities that will have procedurally generated surfaces will just -// point at this for their sorting surface -surfaceType_t entitySurface = SF_ENTITY; - -/* -================ -R_CompareVert -================ -*/ -qboolean R_CompareVert(srfVert_t * v1, srfVert_t * v2, qboolean checkST) -{ - int i; - - for(i = 0; i < 3; i++) - { - if(floor(v1->xyz[i] + 0.1) != floor(v2->xyz[i] + 0.1)) - { - return qfalse; - } - - if(checkST && ((v1->st[0] != v2->st[0]) || (v1->st[1] != v2->st[1]))) - { - return qfalse; - } - } - - return qtrue; -} - -/* -============= -R_CalcNormalForTriangle -============= -*/ -void R_CalcNormalForTriangle(vec3_t normal, const vec3_t v0, const vec3_t v1, const vec3_t v2) -{ - vec3_t udir, vdir; - - // compute the face normal based on vertex points - VectorSubtract(v2, v0, udir); - VectorSubtract(v1, v0, vdir); - CrossProduct(udir, vdir, normal); - - VectorNormalize(normal); -} - -/* -============= -R_CalcTangentsForTriangle -http://members.rogers.com/deseric/tangentspace.htm -============= -*/ -void R_CalcTangentsForTriangle(vec3_t tangent, vec3_t bitangent, - const vec3_t v0, const vec3_t v1, const vec3_t v2, - const vec2_t t0, const vec2_t t1, const vec2_t t2) -{ - int i; - vec3_t planes[3]; - vec3_t u, v; - - for(i = 0; i < 3; i++) - { - VectorSet(u, v1[i] - v0[i], t1[0] - t0[0], t1[1] - t0[1]); - VectorSet(v, v2[i] - v0[i], t2[0] - t0[0], t2[1] - t0[1]); - - VectorNormalize(u); - VectorNormalize(v); - - CrossProduct(u, v, planes[i]); - } - - //So your tangent space will be defined by this : - //Normal = Normal of the triangle or Tangent X Bitangent (careful with the cross product, - // you have to make sure the normal points in the right direction) - //Tangent = ( dp(Fx(s,t)) / ds, dp(Fy(s,t)) / ds, dp(Fz(s,t)) / ds ) or ( -Bx/Ax, -By/Ay, - Bz/Az ) - //Bitangent = ( dp(Fx(s,t)) / dt, dp(Fy(s,t)) / dt, dp(Fz(s,t)) / dt ) or ( -Cx/Ax, -Cy/Ay, -Cz/Az ) - - // tangent... - tangent[0] = -planes[0][1] / planes[0][0]; - tangent[1] = -planes[1][1] / planes[1][0]; - tangent[2] = -planes[2][1] / planes[2][0]; - VectorNormalize(tangent); - - // bitangent... - bitangent[0] = -planes[0][2] / planes[0][0]; - bitangent[1] = -planes[1][2] / planes[1][0]; - bitangent[2] = -planes[2][2] / planes[2][0]; - VectorNormalize(bitangent); -} - - - - -/* -============= -R_CalcTangentSpace -============= -*/ -void R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, vec3_t normal, - const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t t0, const vec2_t t1, const vec2_t t2) -{ - vec3_t cp, u, v; - vec3_t faceNormal; - - VectorSet(u, v1[0] - v0[0], t1[0] - t0[0], t1[1] - t0[1]); - VectorSet(v, v2[0] - v0[0], t2[0] - t0[0], t2[1] - t0[1]); - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[0] = -cp[1] / cp[0]; - bitangent[0] = -cp[2] / cp[0]; - } - - u[0] = v1[1] - v0[1]; - v[0] = v2[1] - v0[1]; - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[1] = -cp[1] / cp[0]; - bitangent[1] = -cp[2] / cp[0]; - } - - u[0] = v1[2] - v0[2]; - v[0] = v2[2] - v0[2]; - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[2] = -cp[1] / cp[0]; - bitangent[2] = -cp[2] / cp[0]; - } - - VectorNormalize(tangent); - VectorNormalize(bitangent); - - // compute the face normal based on vertex points - if ( normal[0] == 0.0f && normal[1] == 0.0f && normal[2] == 0.0f ) - { - VectorSubtract(v2, v0, u); - VectorSubtract(v1, v0, v); - CrossProduct(u, v, faceNormal); - } - else - { - VectorCopy(normal, faceNormal); - } - - VectorNormalize(faceNormal); - -#if 1 - // Gram-Schmidt orthogonalize - //tangent[a] = (t - n * Dot(n, t)).Normalize(); - VectorMA(tangent, -DotProduct(faceNormal, tangent), faceNormal, tangent); - VectorNormalize(tangent); - - // compute the cross product B=NxT - //CrossProduct(normal, tangent, bitangent); -#else - // normal, compute the cross product N=TxB - CrossProduct(tangent, bitangent, normal); - VectorNormalize(normal); - - if(DotProduct(normal, faceNormal) < 0) - { - //VectorInverse(normal); - //VectorInverse(tangent); - //VectorInverse(bitangent); - - // compute the cross product T=BxN - CrossProduct(bitangent, faceNormal, tangent); - - // compute the cross product B=NxT - //CrossProduct(normal, tangent, bitangent); - } -#endif - - VectorCopy(faceNormal, normal); -} - -void R_CalcTangentSpaceFast(vec3_t tangent, vec3_t bitangent, vec3_t normal, - const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t t0, const vec2_t t1, const vec2_t t2) -{ - vec3_t cp, u, v; - vec3_t faceNormal; - - VectorSet(u, v1[0] - v0[0], t1[0] - t0[0], t1[1] - t0[1]); - VectorSet(v, v2[0] - v0[0], t2[0] - t0[0], t2[1] - t0[1]); - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[0] = -cp[1] / cp[0]; - bitangent[0] = -cp[2] / cp[0]; - } - - u[0] = v1[1] - v0[1]; - v[0] = v2[1] - v0[1]; - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[1] = -cp[1] / cp[0]; - bitangent[1] = -cp[2] / cp[0]; - } - - u[0] = v1[2] - v0[2]; - v[0] = v2[2] - v0[2]; - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[2] = -cp[1] / cp[0]; - bitangent[2] = -cp[2] / cp[0]; - } - - VectorNormalizeFast(tangent); - VectorNormalizeFast(bitangent); - - // compute the face normal based on vertex points - VectorSubtract(v2, v0, u); - VectorSubtract(v1, v0, v); - CrossProduct(u, v, faceNormal); - - VectorNormalizeFast(faceNormal); - -#if 0 - // normal, compute the cross product N=TxB - CrossProduct(tangent, bitangent, normal); - VectorNormalizeFast(normal); - - if(DotProduct(normal, faceNormal) < 0) - { - VectorInverse(normal); - //VectorInverse(tangent); - //VectorInverse(bitangent); - - CrossProduct(normal, tangent, bitangent); - } - - VectorCopy(faceNormal, normal); -#else - // Gram-Schmidt orthogonalize - //tangent[a] = (t - n * Dot(n, t)).Normalize(); - VectorMA(tangent, -DotProduct(faceNormal, tangent), faceNormal, tangent); - VectorNormalizeFast(tangent); -#endif - - VectorCopy(faceNormal, normal); -} - -/* -http://www.terathon.com/code/tangent.html -*/ -void R_CalcTBN(vec3_t tangent, vec3_t bitangent, vec3_t normal, - const vec3_t v1, const vec3_t v2, const vec3_t v3, const vec2_t w1, const vec2_t w2, const vec2_t w3) -{ - vec3_t u, v; - float x1, x2, y1, y2, z1, z2; - float s1, s2, t1, t2; - float r, dot; - - x1 = v2[0] - v1[0]; - x2 = v3[0] - v1[0]; - y1 = v2[1] - v1[1]; - y2 = v3[1] - v1[1]; - z1 = v2[2] - v1[2]; - z2 = v3[2] - v1[2]; - - s1 = w2[0] - w1[0]; - s2 = w3[0] - w1[0]; - t1 = w2[1] - w1[1]; - t2 = w3[1] - w1[1]; - - r = 1.0f / (s1 * t2 - s2 * t1); - - VectorSet(tangent, (t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r); - VectorSet(bitangent, (s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r); - - // compute the face normal based on vertex points - VectorSubtract(v3, v1, u); - VectorSubtract(v2, v1, v); - CrossProduct(u, v, normal); - - VectorNormalize(normal); - - // Gram-Schmidt orthogonalize - //tangent[a] = (t - n * Dot(n, t)).Normalize(); - dot = DotProduct(normal, tangent); - VectorMA(tangent, -dot, normal, tangent); - VectorNormalize(tangent); - - // B=NxT - //CrossProduct(normal, tangent, bitangent); -} - -void R_CalcTBN2(vec3_t tangent, vec3_t bitangent, vec3_t normal, - const vec3_t v1, const vec3_t v2, const vec3_t v3, const vec2_t t1, const vec2_t t2, const vec2_t t3) -{ - vec3_t v2v1; - vec3_t v3v1; - - float c2c1_T; - float c2c1_B; - - float c3c1_T; - float c3c1_B; - - float denominator; - float scale1, scale2; - - vec3_t T, B, N, C; - - - // Calculate the tangent basis for each vertex of the triangle - // UPDATE: In the 3rd edition of the accompanying article, the for-loop located here has - // been removed as it was redundant (the entire TBN matrix was calculated three times - // instead of just one). - // - // Please note, that this function relies on the fact that the input geometry are triangles - // and the tangent basis for each vertex thus is identical! - // - - // Calculate the vectors from the current vertex to the two other vertices in the triangle - VectorSubtract(v2, v1, v2v1); - VectorSubtract(v3, v1, v3v1); - - // The equation presented in the article states that: - // c2c1_T = V2.texcoord.x - V1.texcoord.x - // c2c1_B = V2.texcoord.y - V1.texcoord.y - // c3c1_T = V3.texcoord.x - V1.texcoord.x - // c3c1_B = V3.texcoord.y - V1.texcoord.y - - // Calculate c2c1_T and c2c1_B - c2c1_T = t2[0] - t1[0]; - c2c1_B = t2[1] - t2[1]; - - // Calculate c3c1_T and c3c1_B - c3c1_T = t3[0] - t1[0]; - c3c1_B = t3[1] - t1[1]; - - denominator = c2c1_T * c3c1_B - c3c1_T * c2c1_B; - //if(ROUNDOFF(fDenominator) == 0.0f) - if(denominator == 0.0f) - { - // We won't risk a divide by zero, so set the tangent matrix to the identity matrix - VectorSet(tangent, 1, 0, 0); - VectorSet(bitangent, 0, 1, 0); - VectorSet(normal, 0, 0, 1); - } - else - { - // Calculate the reciprocal value once and for all (to achieve speed) - scale1 = 1.0f / denominator; - - // T and B are calculated just as the equation in the article states - VectorSet(T, (c3c1_B * v2v1[0] - c2c1_B * v3v1[0]) * scale1, - (c3c1_B * v2v1[1] - c2c1_B * v3v1[1]) * scale1, - (c3c1_B * v2v1[2] - c2c1_B * v3v1[2]) * scale1); - - VectorSet(B, (-c3c1_T * v2v1[0] + c2c1_T * v3v1[0]) * scale1, - (-c3c1_T * v2v1[1] + c2c1_T * v3v1[1]) * scale1, - (-c3c1_T * v2v1[2] + c2c1_T * v3v1[2]) * scale1); - - // The normal N is calculated as the cross product between T and B - CrossProduct(T, B, N); - -#if 0 - VectorCopy(T, tangent); - VectorCopy(B, bitangent); - VectorCopy(N, normal); -#else - // Calculate the reciprocal value once and for all (to achieve speed) - scale2 = 1.0f / ((T[0] * B[1] * N[2] - T[2] * B[1] * N[0]) + - (B[0] * N[1] * T[2] - B[2] * N[1] * T[0]) + - (N[0] * T[1] * B[2] - N[2] * T[1] * B[0])); - - // Calculate the inverse if the TBN matrix using the formula described in the article. - // We store the basis vectors directly in the provided TBN matrix: pvTBNMatrix - CrossProduct(B, N, C); tangent[0] = C[0] * scale2; - CrossProduct(N, T, C); tangent[1] = -C[0] * scale2; - CrossProduct(T, B, C); tangent[2] = C[0] * scale2; - VectorNormalize(tangent); - - CrossProduct(B, N, C); bitangent[0] = -C[1] * scale2; - CrossProduct(N, T, C); bitangent[1] = C[1] * scale2; - CrossProduct(T, B, C); bitangent[2] = -C[1] * scale2; - VectorNormalize(bitangent); - - CrossProduct(B, N, C); normal[0] = C[2] * scale2; - CrossProduct(N, T, C); normal[1] = -C[2] * scale2; - CrossProduct(T, B, C); normal[2] = C[2] * scale2; - VectorNormalize(normal); -#endif - } -} - - -#ifdef USE_VERT_TANGENT_SPACE -qboolean R_CalcTangentVectors(srfVert_t * dv[3]) -{ - int i; - float bb, s, t; - vec3_t bary; - - - /* calculate barycentric basis for the triangle */ - bb = (dv[1]->st[0] - dv[0]->st[0]) * (dv[2]->st[1] - dv[0]->st[1]) - (dv[2]->st[0] - dv[0]->st[0]) * (dv[1]->st[1] - dv[0]->st[1]); - if(fabs(bb) < 0.00000001f) - return qfalse; - - /* do each vertex */ - for(i = 0; i < 3; i++) - { - vec3_t bitangent, nxt; - - // calculate s tangent vector - s = dv[i]->st[0] + 10.0f; - t = dv[i]->st[1]; - bary[0] = ((dv[1]->st[0] - s) * (dv[2]->st[1] - t) - (dv[2]->st[0] - s) * (dv[1]->st[1] - t)) / bb; - bary[1] = ((dv[2]->st[0] - s) * (dv[0]->st[1] - t) - (dv[0]->st[0] - s) * (dv[2]->st[1] - t)) / bb; - bary[2] = ((dv[0]->st[0] - s) * (dv[1]->st[1] - t) - (dv[1]->st[0] - s) * (dv[0]->st[1] - t)) / bb; - - dv[i]->tangent[0] = bary[0] * dv[0]->xyz[0] + bary[1] * dv[1]->xyz[0] + bary[2] * dv[2]->xyz[0]; - dv[i]->tangent[1] = bary[0] * dv[0]->xyz[1] + bary[1] * dv[1]->xyz[1] + bary[2] * dv[2]->xyz[1]; - dv[i]->tangent[2] = bary[0] * dv[0]->xyz[2] + bary[1] * dv[1]->xyz[2] + bary[2] * dv[2]->xyz[2]; - - VectorSubtract(dv[i]->tangent, dv[i]->xyz, dv[i]->tangent); - VectorNormalize(dv[i]->tangent); - - // calculate t tangent vector - s = dv[i]->st[0]; - t = dv[i]->st[1] + 10.0f; - bary[0] = ((dv[1]->st[0] - s) * (dv[2]->st[1] - t) - (dv[2]->st[0] - s) * (dv[1]->st[1] - t)) / bb; - bary[1] = ((dv[2]->st[0] - s) * (dv[0]->st[1] - t) - (dv[0]->st[0] - s) * (dv[2]->st[1] - t)) / bb; - bary[2] = ((dv[0]->st[0] - s) * (dv[1]->st[1] - t) - (dv[1]->st[0] - s) * (dv[0]->st[1] - t)) / bb; - - bitangent[0] = bary[0] * dv[0]->xyz[0] + bary[1] * dv[1]->xyz[0] + bary[2] * dv[2]->xyz[0]; - bitangent[1] = bary[0] * dv[0]->xyz[1] + bary[1] * dv[1]->xyz[1] + bary[2] * dv[2]->xyz[1]; - bitangent[2] = bary[0] * dv[0]->xyz[2] + bary[1] * dv[1]->xyz[2] + bary[2] * dv[2]->xyz[2]; - - VectorSubtract(bitangent, dv[i]->xyz, bitangent); - VectorNormalize(bitangent); - - // store bitangent handedness - CrossProduct(dv[i]->normal, dv[i]->tangent, nxt); - dv[i]->tangent[3] = (DotProduct(nxt, bitangent) < 0.0f) ? -1.0f : 1.0f; - - // debug code - //% Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i, - //% stv[ i ][ 0 ], stv[ i ][ 1 ], stv[ i ][ 2 ], ttv[ i ][ 0 ], ttv[ i ][ 1 ], ttv[ i ][ 2 ] ); - } - - return qtrue; -} -#endif - - -/* -================= -R_CullLocalBox - -Returns CULL_IN, CULL_CLIP, or CULL_OUT -================= -*/ -int R_CullLocalBox(vec3_t localBounds[2]) { -#if 0 - int i, j; - vec3_t transformed[8]; - float dists[8]; - vec3_t v; - cplane_t *frust; - int anyBack; - int front, back; - - if ( r_nocull->integer ) { - return CULL_CLIP; - } - - // transform into world space - for (i = 0 ; i < 8 ; i++) { - v[0] = bounds[i&1][0]; - v[1] = bounds[(i>>1)&1][1]; - v[2] = bounds[(i>>2)&1][2]; - - VectorCopy( tr.or.origin, transformed[i] ); - VectorMA( transformed[i], v[0], tr.or.axis[0], transformed[i] ); - VectorMA( transformed[i], v[1], tr.or.axis[1], transformed[i] ); - VectorMA( transformed[i], v[2], tr.or.axis[2], transformed[i] ); - } - - // check against frustum planes - anyBack = 0; - for (i = 0 ; i < 4 ; i++) { - frust = &tr.viewParms.frustum[i]; - - front = back = 0; - for (j = 0 ; j < 8 ; j++) { - dists[j] = DotProduct(transformed[j], frust->normal); - if ( dists[j] > frust->dist ) { - front = 1; - if ( back ) { - break; // a point is in front - } - } else { - back = 1; - } - } - if ( !front ) { - // all points were behind one of the planes - return CULL_OUT; - } - anyBack |= back; - } - - if ( !anyBack ) { - return CULL_IN; // completely inside frustum - } - - return CULL_CLIP; // partially clipped -#else - int j; - vec3_t transformed; - vec3_t v; - vec3_t worldBounds[2]; - - if(r_nocull->integer) - { - return CULL_CLIP; - } - - // transform into world space - ClearBounds(worldBounds[0], worldBounds[1]); - - for(j = 0; j < 8; j++) - { - v[0] = localBounds[j & 1][0]; - v[1] = localBounds[(j >> 1) & 1][1]; - v[2] = localBounds[(j >> 2) & 1][2]; - - R_LocalPointToWorld(v, transformed); - - AddPointToBounds(transformed, worldBounds[0], worldBounds[1]); - } - - return R_CullBox(worldBounds); -#endif -} - -/* -================= -R_CullBox - -Returns CULL_IN, CULL_CLIP, or CULL_OUT -================= -*/ -int R_CullBox(vec3_t worldBounds[2]) { - int i; - cplane_t *frust; - qboolean anyClip; - int r, numPlanes; - - numPlanes = (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 5 : 4; - - // check against frustum planes - anyClip = qfalse; - for(i = 0; i < numPlanes; i++) - { - frust = &tr.viewParms.frustum[i]; - - r = BoxOnPlaneSide(worldBounds[0], worldBounds[1], frust); - - if(r == 2) - { - // completely outside frustum - return CULL_OUT; - } - if(r == 3) - { - anyClip = qtrue; - } - } - - if(!anyClip) - { - // completely inside frustum - return CULL_IN; - } - - // partially clipped - return CULL_CLIP; -} - -/* -** R_CullLocalPointAndRadius -*/ -int R_CullLocalPointAndRadius( const vec3_t pt, float radius ) -{ - vec3_t transformed; - - R_LocalPointToWorld( pt, transformed ); - - return R_CullPointAndRadius( transformed, radius ); -} - -/* -** R_CullPointAndRadius -*/ -int R_CullPointAndRadiusEx( const vec3_t pt, float radius, const cplane_t* frustum, int numPlanes ) -{ - int i; - float dist; - const cplane_t *frust; - qboolean mightBeClipped = qfalse; - - if ( r_nocull->integer ) { - return CULL_CLIP; - } - - // check against frustum planes - for (i = 0 ; i < numPlanes ; i++) - { - frust = &frustum[i]; - - dist = DotProduct( pt, frust->normal) - frust->dist; - if ( dist < -radius ) - { - return CULL_OUT; - } - else if ( dist <= radius ) - { - mightBeClipped = qtrue; - } - } - - if ( mightBeClipped ) - { - return CULL_CLIP; - } - - return CULL_IN; // completely inside frustum -} - -/* -** R_CullPointAndRadius -*/ -int R_CullPointAndRadius( const vec3_t pt, float radius ) -{ - return R_CullPointAndRadiusEx(pt, radius, tr.viewParms.frustum, (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 5 : 4); -} - -/* -================= -R_LocalNormalToWorld - -================= -*/ -void R_LocalNormalToWorld (const vec3_t local, vec3_t world) { - world[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0]; - world[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1]; - world[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2]; -} - -/* -================= -R_LocalPointToWorld - -================= -*/ -void R_LocalPointToWorld (const vec3_t local, vec3_t world) { - world[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0] + tr.or.origin[0]; - world[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1] + tr.or.origin[1]; - world[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2] + tr.or.origin[2]; -} - -/* -================= -R_WorldToLocal - -================= -*/ -void R_WorldToLocal (const vec3_t world, vec3_t local) { - local[0] = DotProduct(world, tr.or.axis[0]); - local[1] = DotProduct(world, tr.or.axis[1]); - local[2] = DotProduct(world, tr.or.axis[2]); -} - -/* -========================== -R_TransformModelToClip - -========================== -*/ -void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix, - vec4_t eye, vec4_t dst ) { - int i; - - for ( i = 0 ; i < 4 ; i++ ) { - eye[i] = - src[0] * modelMatrix[ i + 0 * 4 ] + - src[1] * modelMatrix[ i + 1 * 4 ] + - src[2] * modelMatrix[ i + 2 * 4 ] + - 1 * modelMatrix[ i + 3 * 4 ]; - } - - for ( i = 0 ; i < 4 ; i++ ) { - dst[i] = - eye[0] * projectionMatrix[ i + 0 * 4 ] + - eye[1] * projectionMatrix[ i + 1 * 4 ] + - eye[2] * projectionMatrix[ i + 2 * 4 ] + - eye[3] * projectionMatrix[ i + 3 * 4 ]; - } -} - -/* -========================== -R_TransformClipToWindow - -========================== -*/ -void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ) { - normalized[0] = clip[0] / clip[3]; - normalized[1] = clip[1] / clip[3]; - normalized[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] ); - - window[0] = 0.5f * ( 1.0f + normalized[0] ) * view->viewportWidth; - window[1] = 0.5f * ( 1.0f + normalized[1] ) * view->viewportHeight; - window[2] = normalized[2]; - - window[0] = (int) ( window[0] + 0.5 ); - window[1] = (int) ( window[1] + 0.5 ); -} - - -/* -========================== -myGlMultMatrix - -========================== -*/ -void myGlMultMatrix( const float *a, const float *b, float *out ) { - int i, j; - - for ( i = 0 ; i < 4 ; i++ ) { - for ( j = 0 ; j < 4 ; j++ ) { - out[ i * 4 + j ] = - a [ i * 4 + 0 ] * b [ 0 * 4 + j ] - + a [ i * 4 + 1 ] * b [ 1 * 4 + j ] - + a [ i * 4 + 2 ] * b [ 2 * 4 + j ] - + a [ i * 4 + 3 ] * b [ 3 * 4 + j ]; - } - } -} - -/* -================= -R_RotateForEntity - -Generates an orientation for an entity and viewParms -Does NOT produce any GL calls -Called by both the front end and the back end -================= -*/ -void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, - orientationr_t *or ) { - float glMatrix[16]; - vec3_t delta; - float axisLength; - - if ( ent->e.reType != RT_MODEL ) { - *or = viewParms->world; - return; - } - - VectorCopy( ent->e.origin, or->origin ); - - VectorCopy( ent->e.axis[0], or->axis[0] ); - VectorCopy( ent->e.axis[1], or->axis[1] ); - VectorCopy( ent->e.axis[2], or->axis[2] ); - - glMatrix[0] = or->axis[0][0]; - glMatrix[4] = or->axis[1][0]; - glMatrix[8] = or->axis[2][0]; - glMatrix[12] = or->origin[0]; - - glMatrix[1] = or->axis[0][1]; - glMatrix[5] = or->axis[1][1]; - glMatrix[9] = or->axis[2][1]; - glMatrix[13] = or->origin[1]; - - glMatrix[2] = or->axis[0][2]; - glMatrix[6] = or->axis[1][2]; - glMatrix[10] = or->axis[2][2]; - glMatrix[14] = or->origin[2]; - - glMatrix[3] = 0; - glMatrix[7] = 0; - glMatrix[11] = 0; - glMatrix[15] = 1; - - Mat4Copy(glMatrix, or->transformMatrix); - myGlMultMatrix( glMatrix, viewParms->world.modelMatrix, or->modelMatrix ); - - // calculate the viewer origin in the model's space - // needed for fog, specular, and environment mapping - VectorSubtract( viewParms->or.origin, or->origin, delta ); - - // compensate for scale in the axes if necessary - if ( ent->e.nonNormalizedAxes ) { - axisLength = VectorLength( ent->e.axis[0] ); - if ( !axisLength ) { - axisLength = 0; - } else { - axisLength = 1.0f / axisLength; - } - } else { - axisLength = 1.0f; - } - - or->viewOrigin[0] = DotProduct( delta, or->axis[0] ) * axisLength; - or->viewOrigin[1] = DotProduct( delta, or->axis[1] ) * axisLength; - or->viewOrigin[2] = DotProduct( delta, or->axis[2] ) * axisLength; -} - -/* -================= -R_RotateForViewer - -Sets up the modelview matrix for a given viewParm -================= -*/ -void R_RotateForViewer (void) -{ - float viewerMatrix[16]; - vec3_t origin; - - Com_Memset (&tr.or, 0, sizeof(tr.or)); - tr.or.axis[0][0] = 1; - tr.or.axis[1][1] = 1; - tr.or.axis[2][2] = 1; - VectorCopy (tr.viewParms.or.origin, tr.or.viewOrigin); - - // transform by the camera placement - VectorCopy( tr.viewParms.or.origin, origin ); - - viewerMatrix[0] = tr.viewParms.or.axis[0][0]; - viewerMatrix[4] = tr.viewParms.or.axis[0][1]; - viewerMatrix[8] = tr.viewParms.or.axis[0][2]; - viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8]; - - viewerMatrix[1] = tr.viewParms.or.axis[1][0]; - viewerMatrix[5] = tr.viewParms.or.axis[1][1]; - viewerMatrix[9] = tr.viewParms.or.axis[1][2]; - viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9]; - - viewerMatrix[2] = tr.viewParms.or.axis[2][0]; - viewerMatrix[6] = tr.viewParms.or.axis[2][1]; - viewerMatrix[10] = tr.viewParms.or.axis[2][2]; - viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10]; - - viewerMatrix[3] = 0; - viewerMatrix[7] = 0; - viewerMatrix[11] = 0; - viewerMatrix[15] = 1; - - // convert from our coordinate system (looking down X) - // to OpenGL's coordinate system (looking down -Z) - myGlMultMatrix( viewerMatrix, s_flipMatrix, tr.or.modelMatrix ); - - tr.viewParms.world = tr.or; - -} - -/* -** SetFarClip -*/ -static void R_SetFarClip( void ) -{ - float farthestCornerDistance = 0; - int i; - - // if not rendering the world (icons, menus, etc) - // set a 2k far clip plane - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - tr.viewParms.zFar = 2048; - return; - } - - // - // set far clipping planes dynamically - // - farthestCornerDistance = 0; - for ( i = 0; i < 8; i++ ) - { - vec3_t v; - vec3_t vecTo; - float distance; - - if ( i & 1 ) - { - v[0] = tr.viewParms.visBounds[0][0]; - } - else - { - v[0] = tr.viewParms.visBounds[1][0]; - } - - if ( i & 2 ) - { - v[1] = tr.viewParms.visBounds[0][1]; - } - else - { - v[1] = tr.viewParms.visBounds[1][1]; - } - - if ( i & 4 ) - { - v[2] = tr.viewParms.visBounds[0][2]; - } - else - { - v[2] = tr.viewParms.visBounds[1][2]; - } - - VectorSubtract( v, tr.viewParms.or.origin, vecTo ); - - distance = vecTo[0] * vecTo[0] + vecTo[1] * vecTo[1] + vecTo[2] * vecTo[2]; - - if ( distance > farthestCornerDistance ) - { - farthestCornerDistance = distance; - } - } - tr.viewParms.zFar = sqrt( farthestCornerDistance ); -} - -/* -================= -R_SetupFrustum - -Set up the culling frustum planes for the current view using the results we got from computing the first two rows of -the projection matrix. -================= -*/ -void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, float zProj, float zFar, float stereoSep) -{ - vec3_t ofsorigin; - float oppleg, adjleg, length; - int i; - - if(stereoSep == 0 && xmin == -xmax) - { - // symmetric case can be simplified - VectorCopy(dest->or.origin, ofsorigin); - - length = sqrt(xmax * xmax + zProj * zProj); - oppleg = xmax / length; - adjleg = zProj / length; - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[0].normal); - VectorMA(dest->frustum[0].normal, adjleg, dest->or.axis[1], dest->frustum[0].normal); - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[1].normal); - VectorMA(dest->frustum[1].normal, -adjleg, dest->or.axis[1], dest->frustum[1].normal); - } - else - { - // In stereo rendering, due to the modification of the projection matrix, dest->or.origin is not the - // actual origin that we're rendering so offset the tip of the view pyramid. - VectorMA(dest->or.origin, stereoSep, dest->or.axis[1], ofsorigin); - - oppleg = xmax + stereoSep; - length = sqrt(oppleg * oppleg + zProj * zProj); - VectorScale(dest->or.axis[0], oppleg / length, dest->frustum[0].normal); - VectorMA(dest->frustum[0].normal, zProj / length, dest->or.axis[1], dest->frustum[0].normal); - - oppleg = xmin + stereoSep; - length = sqrt(oppleg * oppleg + zProj * zProj); - VectorScale(dest->or.axis[0], -oppleg / length, dest->frustum[1].normal); - VectorMA(dest->frustum[1].normal, -zProj / length, dest->or.axis[1], dest->frustum[1].normal); - } - - length = sqrt(ymax * ymax + zProj * zProj); - oppleg = ymax / length; - adjleg = zProj / length; - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[2].normal); - VectorMA(dest->frustum[2].normal, adjleg, dest->or.axis[2], dest->frustum[2].normal); - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[3].normal); - VectorMA(dest->frustum[3].normal, -adjleg, dest->or.axis[2], dest->frustum[3].normal); - - for (i=0 ; i<4 ; i++) { - dest->frustum[i].type = PLANE_NON_AXIAL; - dest->frustum[i].dist = DotProduct (ofsorigin, dest->frustum[i].normal); - SetPlaneSignbits( &dest->frustum[i] ); - } - - if (zFar != 0.0f) - { - vec3_t farpoint; - - VectorMA(ofsorigin, zFar, dest->or.axis[0], farpoint); - VectorScale(dest->or.axis[0], -1.0f, dest->frustum[4].normal); - - dest->frustum[4].type = PLANE_NON_AXIAL; - dest->frustum[4].dist = DotProduct (farpoint, dest->frustum[4].normal); - SetPlaneSignbits( &dest->frustum[4] ); - dest->flags |= VPF_FARPLANEFRUSTUM; - } -} - -/* -=============== -R_SetupProjection -=============== -*/ -void R_SetupProjection(viewParms_t *dest, float zProj, float zFar, qboolean computeFrustum) -{ - float xmin, xmax, ymin, ymax; - float width, height, stereoSep = r_stereoSeparation->value; - - /* - * offset the view origin of the viewer for stereo rendering - * by setting the projection matrix appropriately. - */ - - if(stereoSep != 0) - { - if(dest->stereoFrame == STEREO_LEFT) - stereoSep = zProj / stereoSep; - else if(dest->stereoFrame == STEREO_RIGHT) - stereoSep = zProj / -stereoSep; - else - stereoSep = 0; - } - - ymax = zProj * tan(dest->fovY * M_PI / 360.0f); - ymin = -ymax; - - xmax = zProj * tan(dest->fovX * M_PI / 360.0f); - xmin = -xmax; - - width = xmax - xmin; - height = ymax - ymin; - - dest->projectionMatrix[0] = 2 * zProj / width; - dest->projectionMatrix[4] = 0; - dest->projectionMatrix[8] = (xmax + xmin + 2 * stereoSep) / width; - dest->projectionMatrix[12] = 2 * zProj * stereoSep / width; - - dest->projectionMatrix[1] = 0; - dest->projectionMatrix[5] = 2 * zProj / height; - dest->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0 - dest->projectionMatrix[13] = 0; - - dest->projectionMatrix[3] = 0; - dest->projectionMatrix[7] = 0; - dest->projectionMatrix[11] = -1; - dest->projectionMatrix[15] = 0; - - // Now that we have all the data for the projection matrix we can also setup the view frustum. - if(computeFrustum) - R_SetupFrustum(dest, xmin, xmax, ymax, zProj, zFar, stereoSep); -} - -/* -=============== -R_SetupProjectionZ - -Sets the z-component transformation part in the projection matrix -=============== -*/ -void R_SetupProjectionZ(viewParms_t *dest) -{ - float zNear, zFar, depth; - - zNear = r_znear->value; - zFar = dest->zFar; - - depth = zFar - zNear; - - dest->projectionMatrix[2] = 0; - dest->projectionMatrix[6] = 0; - dest->projectionMatrix[10] = -( zFar + zNear ) / depth; - dest->projectionMatrix[14] = -2 * zFar * zNear / depth; - - if (dest->isPortal) - { - float plane[4]; - float plane2[4]; - vec4_t q, c; - - // transform portal plane into camera space - plane[0] = dest->portalPlane.normal[0]; - plane[1] = dest->portalPlane.normal[1]; - plane[2] = dest->portalPlane.normal[2]; - plane[3] = dest->portalPlane.dist; - - plane2[0] = -DotProduct (dest->or.axis[1], plane); - plane2[1] = DotProduct (dest->or.axis[2], plane); - plane2[2] = -DotProduct (dest->or.axis[0], plane); - plane2[3] = DotProduct (plane, dest->or.origin) - plane[3]; - - // Lengyel, Eric. "Modifying the Projection Matrix to Perform Oblique Near-plane Clipping". - // Terathon Software 3D Graphics Library, 2004. http://www.terathon.com/code/oblique.html - q[0] = (SGN(plane2[0]) + dest->projectionMatrix[8]) / dest->projectionMatrix[0]; - q[1] = (SGN(plane2[1]) + dest->projectionMatrix[9]) / dest->projectionMatrix[5]; - q[2] = -1.0f; - q[3] = (1.0f + dest->projectionMatrix[10]) / dest->projectionMatrix[14]; - - VectorScale4(plane2, 2.0f / DotProduct4(plane2, q), c); - - dest->projectionMatrix[2] = c[0]; - dest->projectionMatrix[6] = c[1]; - dest->projectionMatrix[10] = c[2] + 1.0f; - dest->projectionMatrix[14] = c[3]; - - } - -} - -/* -=============== -R_SetupProjectionOrtho -=============== -*/ -void R_SetupProjectionOrtho(viewParms_t *dest, vec3_t viewBounds[2]) -{ - float xmin, xmax, ymin, ymax, znear, zfar; - //viewParms_t *dest = &tr.viewParms; - int i; - vec3_t pop; - - // Quake3: Projection: - // - // Z X Y Z - // | / | / - // |/ |/ - // Y--+ +--X - - xmin = viewBounds[0][1]; - xmax = viewBounds[1][1]; - ymin = -viewBounds[1][2]; - ymax = -viewBounds[0][2]; - znear = viewBounds[0][0]; - zfar = viewBounds[1][0]; - - dest->projectionMatrix[0] = 2 / (xmax - xmin); - dest->projectionMatrix[4] = 0; - dest->projectionMatrix[8] = 0; - dest->projectionMatrix[12] = (xmax + xmin) / (xmax - xmin); - - dest->projectionMatrix[1] = 0; - dest->projectionMatrix[5] = 2 / (ymax - ymin); - dest->projectionMatrix[9] = 0; - dest->projectionMatrix[13] = (ymax + ymin) / (ymax - ymin); - - dest->projectionMatrix[2] = 0; - dest->projectionMatrix[6] = 0; - dest->projectionMatrix[10] = -2 / (zfar - znear); - dest->projectionMatrix[14] = -(zfar + znear) / (zfar - znear); - - dest->projectionMatrix[3] = 0; - dest->projectionMatrix[7] = 0; - dest->projectionMatrix[11] = 0; - dest->projectionMatrix[15] = 1; - - VectorScale(dest->or.axis[1], 1.0f, dest->frustum[0].normal); - VectorMA(dest->or.origin, viewBounds[0][1], dest->frustum[0].normal, pop); - dest->frustum[0].dist = DotProduct(pop, dest->frustum[0].normal); - - VectorScale(dest->or.axis[1], -1.0f, dest->frustum[1].normal); - VectorMA(dest->or.origin, -viewBounds[1][1], dest->frustum[1].normal, pop); - dest->frustum[1].dist = DotProduct(pop, dest->frustum[1].normal); - - VectorScale(dest->or.axis[2], 1.0f, dest->frustum[2].normal); - VectorMA(dest->or.origin, viewBounds[0][2], dest->frustum[2].normal, pop); - dest->frustum[2].dist = DotProduct(pop, dest->frustum[2].normal); - - VectorScale(dest->or.axis[2], -1.0f, dest->frustum[3].normal); - VectorMA(dest->or.origin, -viewBounds[1][2], dest->frustum[3].normal, pop); - dest->frustum[3].dist = DotProduct(pop, dest->frustum[3].normal); - - VectorScale(dest->or.axis[0], -1.0f, dest->frustum[4].normal); - VectorMA(dest->or.origin, -viewBounds[1][0], dest->frustum[4].normal, pop); - dest->frustum[4].dist = DotProduct(pop, dest->frustum[4].normal); - - for (i = 0; i < 5; i++) - { - dest->frustum[i].type = PLANE_NON_AXIAL; - SetPlaneSignbits (&dest->frustum[i]); - } - - dest->flags |= VPF_FARPLANEFRUSTUM; -} - -/* -================= -R_MirrorPoint -================= -*/ -void R_MirrorPoint (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) { - int i; - vec3_t local; - vec3_t transformed; - float d; - - VectorSubtract( in, surface->origin, local ); - - VectorClear( transformed ); - for ( i = 0 ; i < 3 ; i++ ) { - d = DotProduct(local, surface->axis[i]); - VectorMA( transformed, d, camera->axis[i], transformed ); - } - - VectorAdd( transformed, camera->origin, out ); -} - -void R_MirrorVector (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) { - int i; - float d; - - VectorClear( out ); - for ( i = 0 ; i < 3 ; i++ ) { - d = DotProduct(in, surface->axis[i]); - VectorMA( out, d, camera->axis[i], out ); - } -} - - -/* -============= -R_PlaneForSurface -============= -*/ -void R_PlaneForSurface (surfaceType_t *surfType, cplane_t *plane) { - srfBspSurface_t *tri; - srfPoly_t *poly; - srfVert_t *v1, *v2, *v3; - vec4_t plane4; - - if (!surfType) { - Com_Memset (plane, 0, sizeof(*plane)); - plane->normal[0] = 1; - return; - } - switch (*surfType) { - case SF_FACE: - *plane = ((srfBspSurface_t *)surfType)->cullPlane; - return; - case SF_TRIANGLES: - tri = (srfBspSurface_t *)surfType; - v1 = tri->verts + tri->indexes[0]; - v2 = tri->verts + tri->indexes[1]; - v3 = tri->verts + tri->indexes[2]; - PlaneFromPoints( plane4, v1->xyz, v2->xyz, v3->xyz ); - VectorCopy( plane4, plane->normal ); - plane->dist = plane4[3]; - return; - case SF_POLY: - poly = (srfPoly_t *)surfType; - PlaneFromPoints( plane4, poly->verts[0].xyz, poly->verts[1].xyz, poly->verts[2].xyz ); - VectorCopy( plane4, plane->normal ); - plane->dist = plane4[3]; - return; - default: - Com_Memset (plane, 0, sizeof(*plane)); - plane->normal[0] = 1; - return; - } -} - -/* -================= -R_GetPortalOrientation - -entityNum is the entity that the portal surface is a part of, which may -be moving and rotating. - -Returns qtrue if it should be mirrored -================= -*/ -qboolean R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum, - orientation_t *surface, orientation_t *camera, - vec3_t pvsOrigin, qboolean *mirror ) { - int i; - cplane_t originalPlane, plane; - trRefEntity_t *e; - float d; - vec3_t transformed; - - // create plane axis for the portal we are seeing - R_PlaneForSurface( drawSurf->surface, &originalPlane ); - - // rotate the plane if necessary - if ( entityNum != REFENTITYNUM_WORLD ) { - tr.currentEntityNum = entityNum; - tr.currentEntity = &tr.refdef.entities[entityNum]; - - // get the orientation of the entity - R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or ); - - // rotate the plane, but keep the non-rotated version for matching - // against the portalSurface entities - R_LocalNormalToWorld( originalPlane.normal, plane.normal ); - plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin ); - - // translate the original plane - originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin ); - } else { - plane = originalPlane; - } - - VectorCopy( plane.normal, surface->axis[0] ); - PerpendicularVector( surface->axis[1], surface->axis[0] ); - CrossProduct( surface->axis[0], surface->axis[1], surface->axis[2] ); - - // locate the portal entity closest to this plane. - // origin will be the origin of the portal, origin2 will be - // the origin of the camera - for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) { - e = &tr.refdef.entities[i]; - if ( e->e.reType != RT_PORTALSURFACE ) { - continue; - } - - d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist; - if ( d > 64 || d < -64) { - continue; - } - - // get the pvsOrigin from the entity - VectorCopy( e->e.oldorigin, pvsOrigin ); - - // if the entity is just a mirror, don't use as a camera point - if ( e->e.oldorigin[0] == e->e.origin[0] && - e->e.oldorigin[1] == e->e.origin[1] && - e->e.oldorigin[2] == e->e.origin[2] ) { - VectorScale( plane.normal, plane.dist, surface->origin ); - VectorCopy( surface->origin, camera->origin ); - VectorSubtract( vec3_origin, surface->axis[0], camera->axis[0] ); - VectorCopy( surface->axis[1], camera->axis[1] ); - VectorCopy( surface->axis[2], camera->axis[2] ); - - *mirror = qtrue; - return qtrue; - } - - // project the origin onto the surface plane to get - // an origin point we can rotate around - d = DotProduct( e->e.origin, plane.normal ) - plane.dist; - VectorMA( e->e.origin, -d, surface->axis[0], surface->origin ); - - // now get the camera origin and orientation - VectorCopy( e->e.oldorigin, camera->origin ); - AxisCopy( e->e.axis, camera->axis ); - VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] ); - VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] ); - - // optionally rotate - if ( e->e.oldframe ) { - // if a speed is specified - if ( e->e.frame ) { - // continuous rotate - d = (tr.refdef.time/1000.0f) * e->e.frame; - VectorCopy( camera->axis[1], transformed ); - RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); - CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); - } else { - // bobbing rotate, with skinNum being the rotation offset - d = sin( tr.refdef.time * 0.003f ); - d = e->e.skinNum + d * 4; - VectorCopy( camera->axis[1], transformed ); - RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); - CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); - } - } - else if ( e->e.skinNum ) { - d = e->e.skinNum; - VectorCopy( camera->axis[1], transformed ); - RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); - CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); - } - *mirror = qfalse; - return qtrue; - } - - // if we didn't locate a portal entity, don't render anything. - // We don't want to just treat it as a mirror, because without a - // portal entity the server won't have communicated a proper entity set - // in the snapshot - - // unfortunately, with local movement prediction it is easily possible - // to see a surface before the server has communicated the matching - // portal surface entity, so we don't want to print anything here... - - //ri.Printf( PRINT_ALL, "Portal surface without a portal entity\n" ); - - return qfalse; -} - -static qboolean IsMirror( const drawSurf_t *drawSurf, int entityNum ) -{ - int i; - cplane_t originalPlane, plane; - trRefEntity_t *e; - float d; - - // create plane axis for the portal we are seeing - R_PlaneForSurface( drawSurf->surface, &originalPlane ); - - // rotate the plane if necessary - if ( entityNum != REFENTITYNUM_WORLD ) - { - tr.currentEntityNum = entityNum; - tr.currentEntity = &tr.refdef.entities[entityNum]; - - // get the orientation of the entity - R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or ); - - // rotate the plane, but keep the non-rotated version for matching - // against the portalSurface entities - R_LocalNormalToWorld( originalPlane.normal, plane.normal ); - plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin ); - - // translate the original plane - originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin ); - } - - // locate the portal entity closest to this plane. - // origin will be the origin of the portal, origin2 will be - // the origin of the camera - for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) - { - e = &tr.refdef.entities[i]; - if ( e->e.reType != RT_PORTALSURFACE ) { - continue; - } - - d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist; - if ( d > 64 || d < -64) { - continue; - } - - // if the entity is just a mirror, don't use as a camera point - if ( e->e.oldorigin[0] == e->e.origin[0] && - e->e.oldorigin[1] == e->e.origin[1] && - e->e.oldorigin[2] == e->e.origin[2] ) - { - return qtrue; - } - - return qfalse; - } - return qfalse; -} - -/* -** SurfIsOffscreen -** -** Determines if a surface is completely offscreen. -*/ -static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) { - float shortest = 100000000; - int entityNum; - int numTriangles; - shader_t *shader; - int fogNum; - int dlighted; - int pshadowed; - vec4_t clip, eye; - int i; - unsigned int pointOr = 0; - unsigned int pointAnd = (unsigned int)~0; - - R_RotateForViewer(); - - R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed ); - RB_BeginSurface( shader, fogNum, drawSurf->cubemapIndex); - rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); - - assert( tess.numVertexes < 128 ); - - for ( i = 0; i < tess.numVertexes; i++ ) - { - int j; - unsigned int pointFlags = 0; - - R_TransformModelToClip( tess.xyz[i], tr.or.modelMatrix, tr.viewParms.projectionMatrix, eye, clip ); - - for ( j = 0; j < 3; j++ ) - { - if ( clip[j] >= clip[3] ) - { - pointFlags |= (1 << (j*2)); - } - else if ( clip[j] <= -clip[3] ) - { - pointFlags |= ( 1 << (j*2+1)); - } - } - pointAnd &= pointFlags; - pointOr |= pointFlags; - } - - // trivially reject - if ( pointAnd ) - { - return qtrue; - } - - // determine if this surface is backfaced and also determine the distance - // to the nearest vertex so we can cull based on portal range. Culling - // based on vertex distance isn't 100% correct (we should be checking for - // range to the surface), but it's good enough for the types of portals - // we have in the game right now. - numTriangles = tess.numIndexes / 3; - - for ( i = 0; i < tess.numIndexes; i += 3 ) - { - vec3_t normal, tNormal; - - float len; - - VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.or.origin, normal ); - - len = VectorLengthSquared( normal ); // lose the sqrt - if ( len < shortest ) - { - shortest = len; - } - - R_VboUnpackNormal(tNormal, tess.normal[tess.indexes[i]]); - - if ( DotProduct( normal, tNormal ) >= 0 ) - { - numTriangles--; - } - } - if ( !numTriangles ) - { - return qtrue; - } - - // mirrors can early out at this point, since we don't do a fade over distance - // with them (although we could) - if ( IsMirror( drawSurf, entityNum ) ) - { - return qfalse; - } - - if ( shortest > (tess.shader->portalRange*tess.shader->portalRange) ) - { - return qtrue; - } - - return qfalse; -} - -/* -======================== -R_MirrorViewBySurface - -Returns qtrue if another view has been rendered -======================== -*/ -qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) { - vec4_t clipDest[128]; - viewParms_t newParms; - viewParms_t oldParms; - orientation_t surface, camera; - - // don't recursively mirror - if (tr.viewParms.isPortal) { - ri.Printf( PRINT_DEVELOPER, "WARNING: recursive mirror/portal found\n" ); - return qfalse; - } - - if ( r_noportals->integer || (r_fastsky->integer == 1) ) { - return qfalse; - } - - // trivially reject portal/mirror - if ( SurfIsOffscreen( drawSurf, clipDest ) ) { - return qfalse; - } - - // save old viewParms so we can return to it after the mirror view - oldParms = tr.viewParms; - - newParms = tr.viewParms; - newParms.isPortal = qtrue; - newParms.zFar = 0.0f; - newParms.flags &= ~VPF_FARPLANEFRUSTUM; - if ( !R_GetPortalOrientations( drawSurf, entityNum, &surface, &camera, - newParms.pvsOrigin, &newParms.isMirror ) ) { - return qfalse; // bad portal, no portalentity - } - - if (newParms.isMirror) - newParms.flags |= VPF_NOVIEWMODEL; - - R_MirrorPoint (oldParms.or.origin, &surface, &camera, newParms.or.origin ); - - VectorSubtract( vec3_origin, camera.axis[0], newParms.portalPlane.normal ); - newParms.portalPlane.dist = DotProduct( camera.origin, newParms.portalPlane.normal ); - - R_MirrorVector (oldParms.or.axis[0], &surface, &camera, newParms.or.axis[0]); - R_MirrorVector (oldParms.or.axis[1], &surface, &camera, newParms.or.axis[1]); - R_MirrorVector (oldParms.or.axis[2], &surface, &camera, newParms.or.axis[2]); - - // OPTIMIZE: restrict the viewport on the mirrored view - - // render the mirror view - R_RenderView (&newParms); - - tr.viewParms = oldParms; - - return qtrue; -} - -/* -================= -R_SpriteFogNum - -See if a sprite is inside a fog volume -================= -*/ -int R_SpriteFogNum( trRefEntity_t *ent ) { - int i, j; - fog_t *fog; - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return 0; - } - - for ( i = 1 ; i < tr.world->numfogs ; i++ ) { - fog = &tr.world->fogs[i]; - for ( j = 0 ; j < 3 ; j++ ) { - if ( ent->e.origin[j] - ent->e.radius >= fog->bounds[1][j] ) { - break; - } - if ( ent->e.origin[j] + ent->e.radius <= fog->bounds[0][j] ) { - break; - } - } - if ( j == 3 ) { - return i; - } - } - - return 0; -} - -/* -========================================================================================== - -DRAWSURF SORTING - -========================================================================================== -*/ - -/* -=============== -R_Radix -=============== -*/ -static ID_INLINE void R_Radix( int byte, int size, drawSurf_t *source, drawSurf_t *dest ) -{ - int count[ 256 ] = { 0 }; - int index[ 256 ]; - int i; - unsigned char *sortKey = NULL; - unsigned char *end = NULL; - - sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte; - end = sortKey + ( size * sizeof( drawSurf_t ) ); - for( ; sortKey < end; sortKey += sizeof( drawSurf_t ) ) - ++count[ *sortKey ]; - - index[ 0 ] = 0; - - for( i = 1; i < 256; ++i ) - index[ i ] = index[ i - 1 ] + count[ i - 1 ]; - - sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte; - for( i = 0; i < size; ++i, sortKey += sizeof( drawSurf_t ) ) - dest[ index[ *sortKey ]++ ] = source[ i ]; -} - -/* -=============== -R_RadixSort - -Radix sort with 4 byte size buckets -=============== -*/ -static void R_RadixSort( drawSurf_t *source, int size ) -{ - static drawSurf_t scratch[ MAX_DRAWSURFS ]; -#ifdef Q3_LITTLE_ENDIAN - R_Radix( 0, size, source, scratch ); - R_Radix( 1, size, scratch, source ); - R_Radix( 2, size, source, scratch ); - R_Radix( 3, size, scratch, source ); -#else - R_Radix( 3, size, source, scratch ); - R_Radix( 2, size, scratch, source ); - R_Radix( 1, size, source, scratch ); - R_Radix( 0, size, scratch, source ); -#endif //Q3_LITTLE_ENDIAN -} - -//========================================================================================== - -/* -================= -R_AddDrawSurf -================= -*/ -void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, - int fogIndex, int dlightMap, int pshadowMap, int cubemap ) { - int index; - - // instead of checking for overflow, we just mask the index - // so it wraps around - index = tr.refdef.numDrawSurfs & DRAWSURF_MASK; - // the sort data is packed into a single 32 bit value so it can be - // compared quickly during the qsorting process - tr.refdef.drawSurfs[index].sort = (shader->sortedIndex << QSORT_SHADERNUM_SHIFT) - | tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT ) - | ((int)pshadowMap << QSORT_PSHADOW_SHIFT) | (int)dlightMap; - tr.refdef.drawSurfs[index].cubemapIndex = cubemap; - tr.refdef.drawSurfs[index].surface = surface; - tr.refdef.numDrawSurfs++; -} - -/* -================= -R_DecomposeSort -================= -*/ -void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader, - int *fogNum, int *dlightMap, int *pshadowMap ) { - *fogNum = ( sort >> QSORT_FOGNUM_SHIFT ) & 31; - *shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1) ]; - *entityNum = ( sort >> QSORT_REFENTITYNUM_SHIFT ) & REFENTITYNUM_MASK; - *pshadowMap = (sort >> QSORT_PSHADOW_SHIFT ) & 1; - *dlightMap = sort & 1; -} - -/* -================= -R_SortDrawSurfs -================= -*/ -void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) { - shader_t *shader; - int fogNum; - int entityNum; - int dlighted; - int pshadowed; - int i; - - //ri.Printf(PRINT_ALL, "firstDrawSurf %d numDrawSurfs %d\n", (int)(drawSurfs - tr.refdef.drawSurfs), numDrawSurfs); - - // it is possible for some views to not have any surfaces - if ( numDrawSurfs < 1 ) { - // we still need to add it for hyperspace cases - R_AddDrawSurfCmd( drawSurfs, numDrawSurfs ); - return; - } - - // if we overflowed MAX_DRAWSURFS, the drawsurfs - // wrapped around in the buffer and we will be missing - // the first surfaces, not the last ones - if ( numDrawSurfs > MAX_DRAWSURFS ) { - numDrawSurfs = MAX_DRAWSURFS; - } - - // sort the drawsurfs by sort type, then orientation, then shader - R_RadixSort( drawSurfs, numDrawSurfs ); - - // skip pass through drawing if rendering a shadow map - if (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW)) - { - R_AddDrawSurfCmd( drawSurfs, numDrawSurfs ); - return; - } - - // check for any pass through drawing, which - // may cause another view to be rendered first - for ( i = 0 ; i < numDrawSurfs ; i++ ) { - R_DecomposeSort( (drawSurfs+i)->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed ); - - if ( shader->sort > SS_PORTAL ) { - break; - } - - // no shader should ever have this sort type - if ( shader->sort == SS_BAD ) { - ri.Error (ERR_DROP, "Shader '%s'with sort == SS_BAD", shader->name ); - } - - // if the mirror was completely clipped away, we may need to check another surface - if ( R_MirrorViewBySurface( (drawSurfs+i), entityNum) ) { - // this is a debug option to see exactly what is being mirrored - if ( r_portalOnly->integer ) { - return; - } - break; // only one mirror view at a time - } - } - - R_AddDrawSurfCmd( drawSurfs, numDrawSurfs ); -} - -static void R_AddEntitySurface (int entityNum) -{ - trRefEntity_t *ent; - shader_t *shader; - - tr.currentEntityNum = entityNum; - - ent = tr.currentEntity = &tr.refdef.entities[tr.currentEntityNum]; - - ent->needDlights = qfalse; - - // preshift the value we are going to OR into the drawsurf sort - tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT; - - // - // the weapon model must be handled special -- - // we don't want the hacked weapon position showing in - // mirrors, because the true body position will already be drawn - // - if ( (ent->e.renderfx & RF_FIRST_PERSON) && (tr.viewParms.flags & VPF_NOVIEWMODEL)) { - return; - } - - // simple generated models, like sprites and beams, are not culled - switch ( ent->e.reType ) { - case RT_PORTALSURFACE: - break; // don't draw anything - case RT_SPRITE: - case RT_BEAM: - case RT_LIGHTNING: - case RT_RAIL_CORE: - case RT_RAIL_RINGS: - // self blood sprites, talk balloons, etc should not be drawn in the primary - // view. We can't just do this check for all entities, because md3 - // entities may still want to cast shadows from them - if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) { - return; - } - shader = R_GetShaderByHandle( ent->e.customShader ); - R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0, 0, 0 /*cubeMap*/ ); - break; - - case RT_MODEL: - // we must set up parts of tr.or for model culling - R_RotateForEntity( ent, &tr.viewParms, &tr.or ); - - tr.currentModel = R_GetModelByHandle( ent->e.hModel ); - if (!tr.currentModel) { - R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0, 0 /*cubeMap*/ ); - } else { - switch ( tr.currentModel->type ) { - case MOD_MESH: - R_AddMD3Surfaces( ent ); - break; - case MOD_MDR: - R_MDRAddAnimSurfaces( ent ); - break; - case MOD_IQM: - R_AddIQMSurfaces( ent ); - break; - case MOD_BRUSH: - R_AddBrushModelSurfaces( ent ); - break; - case MOD_BAD: // null model axis - if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) { - break; - } - R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0, 0 ); - break; - default: - ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" ); - break; - } - } - break; - default: - ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad reType" ); - } -} - -/* -============= -R_AddEntitySurfaces -============= -*/ -void R_AddEntitySurfaces (void) { - int i; - - if ( !r_drawentities->integer ) { - return; - } - - for ( i = 0; i < tr.refdef.num_entities; i++) - R_AddEntitySurface(i); -} - - -/* -==================== -R_GenerateDrawSurfs -==================== -*/ -void R_GenerateDrawSurfs( void ) { - R_AddWorldSurfaces (); - - R_AddPolygonSurfaces(); - - // set the projection matrix with the minimum zfar - // now that we have the world bounded - // this needs to be done before entities are - // added, because they use the projection - // matrix for lod calculation - - // dynamically compute far clip plane distance - if (!(tr.viewParms.flags & VPF_SHADOWMAP)) - { - R_SetFarClip(); - } - - // we know the size of the clipping volume. Now set the rest of the projection matrix. - R_SetupProjectionZ (&tr.viewParms); - - R_AddEntitySurfaces (); -} - -/* -================ -R_DebugPolygon -================ -*/ -void R_DebugPolygon( int color, int numPoints, float *points ) { - // FIXME: implement this -#if 0 - int i; - - GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - - // draw solid shade - - qglColor3f( color&1, (color>>1)&1, (color>>2)&1 ); - qglBegin( GL_POLYGON ); - for ( i = 0 ; i < numPoints ; i++ ) { - qglVertex3fv( points + i * 3 ); - } - qglEnd(); - - // draw wireframe outline - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - qglDepthRange( 0, 0 ); - qglColor3f( 1, 1, 1 ); - qglBegin( GL_POLYGON ); - for ( i = 0 ; i < numPoints ; i++ ) { - qglVertex3fv( points + i * 3 ); - } - qglEnd(); - qglDepthRange( 0, 1 ); -#endif -} - -/* -==================== -R_DebugGraphics - -Visualization aid for movement clipping debugging -==================== -*/ -void R_DebugGraphics( void ) { - if ( !r_debugSurface->integer ) { - return; - } - - R_IssuePendingRenderCommands(); - - GL_Bind( tr.whiteImage); - GL_Cull( CT_FRONT_SIDED ); - ri.CM_DrawDebugSurface( R_DebugPolygon ); -} - - -/* -================ -R_RenderView - -A view may be either the actual camera view, -or a mirror / remote location -================ -*/ -void R_RenderView (viewParms_t *parms) { - int firstDrawSurf; - - if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) { - return; - } - - tr.viewCount++; - - tr.viewParms = *parms; - tr.viewParms.frameSceneNum = tr.frameSceneNum; - tr.viewParms.frameCount = tr.frameCount; - - firstDrawSurf = tr.refdef.numDrawSurfs; - - tr.viewCount++; - - // set viewParms.world - R_RotateForViewer (); - - R_SetupProjection(&tr.viewParms, r_zproj->value, tr.viewParms.zFar, qtrue); - - R_GenerateDrawSurfs(); - - R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf ); - - // draw main system development information (surface outlines, etc) - R_DebugGraphics(); -} - - -void R_RenderDlightCubemaps(const refdef_t *fd) -{ - int i; - - for (i = 0; i < tr.refdef.num_dlights; i++) - { - viewParms_t shadowParms; - int j; - - // use previous frame to determine visible dlights - if ((1 << i) & tr.refdef.dlightMask) - continue; - - Com_Memset( &shadowParms, 0, sizeof( shadowParms ) ); - - shadowParms.viewportX = tr.refdef.x; - shadowParms.viewportY = glConfig.vidHeight - ( tr.refdef.y + PSHADOW_MAP_SIZE ); - shadowParms.viewportWidth = PSHADOW_MAP_SIZE; - shadowParms.viewportHeight = PSHADOW_MAP_SIZE; - shadowParms.isPortal = qfalse; - shadowParms.isMirror = qtrue; // because it is - - shadowParms.fovX = 90; - shadowParms.fovY = 90; - - shadowParms.flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW | VPF_NOVIEWMODEL; - shadowParms.zFar = tr.refdef.dlights[i].radius; - - VectorCopy( tr.refdef.dlights[i].origin, shadowParms.or.origin ); - - for (j = 0; j < 6; j++) - { - switch(j) - { - case 0: - // -X - VectorSet( shadowParms.or.axis[0], -1, 0, 0); - VectorSet( shadowParms.or.axis[1], 0, 0, -1); - VectorSet( shadowParms.or.axis[2], 0, 1, 0); - break; - case 1: - // +X - VectorSet( shadowParms.or.axis[0], 1, 0, 0); - VectorSet( shadowParms.or.axis[1], 0, 0, 1); - VectorSet( shadowParms.or.axis[2], 0, 1, 0); - break; - case 2: - // -Y - VectorSet( shadowParms.or.axis[0], 0, -1, 0); - VectorSet( shadowParms.or.axis[1], 1, 0, 0); - VectorSet( shadowParms.or.axis[2], 0, 0, -1); - break; - case 3: - // +Y - VectorSet( shadowParms.or.axis[0], 0, 1, 0); - VectorSet( shadowParms.or.axis[1], 1, 0, 0); - VectorSet( shadowParms.or.axis[2], 0, 0, 1); - break; - case 4: - // -Z - VectorSet( shadowParms.or.axis[0], 0, 0, -1); - VectorSet( shadowParms.or.axis[1], 1, 0, 0); - VectorSet( shadowParms.or.axis[2], 0, 1, 0); - break; - case 5: - // +Z - VectorSet( shadowParms.or.axis[0], 0, 0, 1); - VectorSet( shadowParms.or.axis[1], -1, 0, 0); - VectorSet( shadowParms.or.axis[2], 0, 1, 0); - break; - } - - R_RenderView(&shadowParms); - R_AddCapShadowmapCmd( i, j ); - } - } -} - - -void R_RenderPshadowMaps(const refdef_t *fd) -{ - viewParms_t shadowParms; - int i; - - // first, make a list of shadows - for ( i = 0; i < tr.refdef.num_entities; i++) - { - trRefEntity_t *ent = &tr.refdef.entities[i]; - - if((ent->e.renderfx & (RF_FIRST_PERSON | RF_NOSHADOW))) - continue; - - //if((ent->e.renderfx & RF_THIRD_PERSON)) - //continue; - - if (ent->e.reType == RT_MODEL) - { - model_t *model = R_GetModelByHandle( ent->e.hModel ); - pshadow_t shadow; - float radius = 0.0f; - float scale = 1.0f; - vec3_t diff; - int j; - - if (!model) - continue; - - if (ent->e.nonNormalizedAxes) - { - scale = VectorLength( ent->e.axis[0] ); - } - - switch (model->type) - { - case MOD_MESH: - { - mdvFrame_t *frame = &model->mdv[0]->frames[ent->e.frame]; - - radius = frame->radius * scale; - } - break; - - case MOD_MDR: - { - // FIXME: never actually tested this - mdrHeader_t *header = model->modelData; - int frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); - mdrFrame_t *frame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame); - - radius = frame->radius; - } - break; - case MOD_IQM: - { - // FIXME: never actually tested this - iqmData_t *data = model->modelData; - vec3_t diag; - float *framebounds; - - framebounds = data->bounds + 6*ent->e.frame; - VectorSubtract( framebounds+3, framebounds, diag ); - radius = 0.5f * VectorLength( diag ); - } - break; - - default: - break; - } - - if (!radius) - continue; - - // Cull entities that are behind the viewer by more than lightRadius - VectorSubtract(ent->e.origin, fd->vieworg, diff); - if (DotProduct(diff, fd->viewaxis[0]) < -r_pshadowDist->value) - continue; - - memset(&shadow, 0, sizeof(shadow)); - - shadow.numEntities = 1; - shadow.entityNums[0] = i; - shadow.viewRadius = radius; - shadow.lightRadius = r_pshadowDist->value; - VectorCopy(ent->e.origin, shadow.viewOrigin); - shadow.sort = DotProduct(diff, diff) / (radius * radius); - VectorCopy(ent->e.origin, shadow.entityOrigins[0]); - shadow.entityRadiuses[0] = radius; - - for (j = 0; j < MAX_CALC_PSHADOWS; j++) - { - pshadow_t swap; - - if (j + 1 > tr.refdef.num_pshadows) - { - tr.refdef.num_pshadows = j + 1; - tr.refdef.pshadows[j] = shadow; - break; - } - - // sort shadows by distance from camera divided by radius - // FIXME: sort better - if (tr.refdef.pshadows[j].sort <= shadow.sort) - continue; - - swap = tr.refdef.pshadows[j]; - tr.refdef.pshadows[j] = shadow; - shadow = swap; - } - } - } - - // next, merge touching pshadows - for ( i = 0; i < tr.refdef.num_pshadows; i++) - { - pshadow_t *ps1 = &tr.refdef.pshadows[i]; - int j; - - for (j = i + 1; j < tr.refdef.num_pshadows; j++) - { - pshadow_t *ps2 = &tr.refdef.pshadows[j]; - int k; - qboolean touch; - - if (ps1->numEntities == 8) - break; - - touch = qfalse; - if (SpheresIntersect(ps1->viewOrigin, ps1->viewRadius, ps2->viewOrigin, ps2->viewRadius)) - { - for (k = 0; k < ps1->numEntities; k++) - { - if (SpheresIntersect(ps1->entityOrigins[k], ps1->entityRadiuses[k], ps2->viewOrigin, ps2->viewRadius)) - { - touch = qtrue; - break; - } - } - } - - if (touch) - { - vec3_t newOrigin; - float newRadius; - - BoundingSphereOfSpheres(ps1->viewOrigin, ps1->viewRadius, ps2->viewOrigin, ps2->viewRadius, newOrigin, &newRadius); - VectorCopy(newOrigin, ps1->viewOrigin); - ps1->viewRadius = newRadius; - - ps1->entityNums[ps1->numEntities] = ps2->entityNums[0]; - VectorCopy(ps2->viewOrigin, ps1->entityOrigins[ps1->numEntities]); - ps1->entityRadiuses[ps1->numEntities] = ps2->viewRadius; - - ps1->numEntities++; - - for (k = j; k < tr.refdef.num_pshadows - 1; k++) - { - tr.refdef.pshadows[k] = tr.refdef.pshadows[k + 1]; - } - - j--; - tr.refdef.num_pshadows--; - } - } - } - - // cap number of drawn pshadows - if (tr.refdef.num_pshadows > MAX_DRAWN_PSHADOWS) - { - tr.refdef.num_pshadows = MAX_DRAWN_PSHADOWS; - } - - // next, fill up the rest of the shadow info - for ( i = 0; i < tr.refdef.num_pshadows; i++) - { - pshadow_t *shadow = &tr.refdef.pshadows[i]; - vec3_t up; - vec3_t ambientLight, directedLight, lightDir; - - VectorSet(lightDir, 0.57735f, 0.57735f, 0.57735f); -#if 1 - R_LightForPoint(shadow->viewOrigin, ambientLight, directedLight, lightDir); - - // sometimes there's no light - if (DotProduct(lightDir, lightDir) < 0.9f) - VectorSet(lightDir, 0.0f, 0.0f, 1.0f); -#endif - - if (shadow->viewRadius * 3.0f > shadow->lightRadius) - { - shadow->lightRadius = shadow->viewRadius * 3.0f; - } - - VectorMA(shadow->viewOrigin, shadow->viewRadius, lightDir, shadow->lightOrigin); - - // make up a projection, up doesn't matter - VectorScale(lightDir, -1.0f, shadow->lightViewAxis[0]); - VectorSet(up, 0, 0, -1); - - if ( abs(DotProduct(up, shadow->lightViewAxis[0])) > 0.9f ) - { - VectorSet(up, -1, 0, 0); - } - - CrossProduct(shadow->lightViewAxis[0], up, shadow->lightViewAxis[1]); - VectorNormalize(shadow->lightViewAxis[1]); - CrossProduct(shadow->lightViewAxis[0], shadow->lightViewAxis[1], shadow->lightViewAxis[2]); - - VectorCopy(shadow->lightViewAxis[0], shadow->cullPlane.normal); - shadow->cullPlane.dist = DotProduct(shadow->cullPlane.normal, shadow->lightOrigin); - shadow->cullPlane.type = PLANE_NON_AXIAL; - SetPlaneSignbits(&shadow->cullPlane); - } - - // next, render shadowmaps - for ( i = 0; i < tr.refdef.num_pshadows; i++) - { - int firstDrawSurf; - pshadow_t *shadow = &tr.refdef.pshadows[i]; - int j; - - Com_Memset( &shadowParms, 0, sizeof( shadowParms ) ); - - if (glRefConfig.framebufferObject) - { - shadowParms.viewportX = 0; - shadowParms.viewportY = 0; - } - else - { - shadowParms.viewportX = tr.refdef.x; - shadowParms.viewportY = glConfig.vidHeight - ( tr.refdef.y + PSHADOW_MAP_SIZE ); - } - shadowParms.viewportWidth = PSHADOW_MAP_SIZE; - shadowParms.viewportHeight = PSHADOW_MAP_SIZE; - shadowParms.isPortal = qfalse; - shadowParms.isMirror = qfalse; - - shadowParms.fovX = 90; - shadowParms.fovY = 90; - - if (glRefConfig.framebufferObject) - shadowParms.targetFbo = tr.pshadowFbos[i]; - - shadowParms.flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW | VPF_NOVIEWMODEL; - shadowParms.zFar = shadow->lightRadius; - - VectorCopy(shadow->lightOrigin, shadowParms.or.origin); - - VectorCopy(shadow->lightViewAxis[0], shadowParms.or.axis[0]); - VectorCopy(shadow->lightViewAxis[1], shadowParms.or.axis[1]); - VectorCopy(shadow->lightViewAxis[2], shadowParms.or.axis[2]); - - { - tr.viewCount++; - - tr.viewParms = shadowParms; - tr.viewParms.frameSceneNum = tr.frameSceneNum; - tr.viewParms.frameCount = tr.frameCount; - - firstDrawSurf = tr.refdef.numDrawSurfs; - - tr.viewCount++; - - // set viewParms.world - R_RotateForViewer (); - - { - float xmin, xmax, ymin, ymax, znear, zfar; - viewParms_t *dest = &tr.viewParms; - vec3_t pop; - - xmin = ymin = -shadow->viewRadius; - xmax = ymax = shadow->viewRadius; - znear = 0; - zfar = shadow->lightRadius; - - dest->projectionMatrix[0] = 2 / (xmax - xmin); - dest->projectionMatrix[4] = 0; - dest->projectionMatrix[8] = (xmax + xmin) / (xmax - xmin); - dest->projectionMatrix[12] =0; - - dest->projectionMatrix[1] = 0; - dest->projectionMatrix[5] = 2 / (ymax - ymin); - dest->projectionMatrix[9] = ( ymax + ymin ) / (ymax - ymin); // normally 0 - dest->projectionMatrix[13] = 0; - - dest->projectionMatrix[2] = 0; - dest->projectionMatrix[6] = 0; - dest->projectionMatrix[10] = 2 / (zfar - znear); - dest->projectionMatrix[14] = 0; - - dest->projectionMatrix[3] = 0; - dest->projectionMatrix[7] = 0; - dest->projectionMatrix[11] = 0; - dest->projectionMatrix[15] = 1; - - VectorScale(dest->or.axis[1], 1.0f, dest->frustum[0].normal); - VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[0].normal, pop); - dest->frustum[0].dist = DotProduct(pop, dest->frustum[0].normal); - - VectorScale(dest->or.axis[1], -1.0f, dest->frustum[1].normal); - VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[1].normal, pop); - dest->frustum[1].dist = DotProduct(pop, dest->frustum[1].normal); - - VectorScale(dest->or.axis[2], 1.0f, dest->frustum[2].normal); - VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[2].normal, pop); - dest->frustum[2].dist = DotProduct(pop, dest->frustum[2].normal); - - VectorScale(dest->or.axis[2], -1.0f, dest->frustum[3].normal); - VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[3].normal, pop); - dest->frustum[3].dist = DotProduct(pop, dest->frustum[3].normal); - - VectorScale(dest->or.axis[0], -1.0f, dest->frustum[4].normal); - VectorMA(dest->or.origin, -shadow->lightRadius, dest->frustum[4].normal, pop); - dest->frustum[4].dist = DotProduct(pop, dest->frustum[4].normal); - - for (j = 0; j < 5; j++) - { - dest->frustum[j].type = PLANE_NON_AXIAL; - SetPlaneSignbits (&dest->frustum[j]); - } - - dest->flags |= VPF_FARPLANEFRUSTUM; - } - - for (j = 0; j < shadow->numEntities; j++) - { - R_AddEntitySurface(shadow->entityNums[j]); - } - - R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf ); - - if (!glRefConfig.framebufferObject) - R_AddCapShadowmapCmd( i, -1 ); - } - } -} - -static float CalcSplit(float n, float f, float i, float m) -{ - return (n * pow(f / n, i / m) + (f - n) * i / m) / 2.0f; -} - - -void R_RenderSunShadowMaps(const refdef_t *fd, int level) -{ - viewParms_t shadowParms; - vec4_t lightDir, lightCol; - vec3_t lightViewAxis[3]; - vec3_t lightOrigin; - float splitZNear, splitZFar, splitBias; - float viewZNear, viewZFar; - vec3_t lightviewBounds[2]; - qboolean lightViewIndependentOfCameraView = qfalse; - - if (r_forceSun->integer == 2) - { - int scale = 32768; - float angle = (fd->time % scale) / (float)scale * M_PI; - lightDir[0] = cos(angle); - lightDir[1] = sin(35.0f * M_PI / 180.0f); - lightDir[2] = sin(angle) * cos(35.0f * M_PI / 180.0f); - lightDir[3] = 0.0f; - - if (1) //((fd->time % (scale * 2)) < scale) - { - lightCol[0] = - lightCol[1] = - lightCol[2] = CLAMP(sin(angle) * 2.0f, 0.0f, 1.0f) * 2.0f; - lightCol[3] = 1.0f; - } - else - { - lightCol[0] = - lightCol[1] = - lightCol[2] = CLAMP(sin(angle) * 2.0f * 0.1f, 0.0f, 0.1f); - lightCol[3] = 1.0f; - } - - VectorCopy4(lightDir, tr.refdef.sunDir); - VectorCopy4(lightCol, tr.refdef.sunCol); - VectorScale4(lightCol, 0.2f, tr.refdef.sunAmbCol); - } - else - { - VectorCopy4(tr.refdef.sunDir, lightDir); - } - - viewZNear = r_shadowCascadeZNear->value; - viewZFar = r_shadowCascadeZFar->value; - splitBias = r_shadowCascadeZBias->value; - - switch(level) - { - case 0: - default: - //splitZNear = r_znear->value; - //splitZFar = 256; - splitZNear = viewZNear; - splitZFar = CalcSplit(viewZNear, viewZFar, 1, 3) + splitBias; - break; - case 1: - splitZNear = CalcSplit(viewZNear, viewZFar, 1, 3) + splitBias; - splitZFar = CalcSplit(viewZNear, viewZFar, 2, 3) + splitBias; - //splitZNear = 256; - //splitZFar = 896; - break; - case 2: - splitZNear = CalcSplit(viewZNear, viewZFar, 2, 3) + splitBias; - splitZFar = viewZFar; - //splitZNear = 896; - //splitZFar = 3072; - break; - } - - VectorCopy(fd->vieworg, lightOrigin); - - - // Make up a projection - VectorScale(lightDir, -1.0f, lightViewAxis[0]); - - if (lightViewIndependentOfCameraView) - { - // Use world up as light view up - VectorSet(lightViewAxis[2], 0, 0, 1); - } - else if (level == 0) - { - // Level 0 tries to use a diamond texture orientation relative to camera view - // Use halfway between camera view forward and left for light view up - VectorAdd(fd->viewaxis[0], fd->viewaxis[1], lightViewAxis[2]); - } - else - { - // Use camera view up as light view up - VectorCopy(fd->viewaxis[2], lightViewAxis[2]); - } - - // Check if too close to parallel to light direction - if (abs(DotProduct(lightViewAxis[2], lightViewAxis[0])) > 0.9f) - { - if (lightViewIndependentOfCameraView) - { - // Use world left as light view up - VectorSet(lightViewAxis[2], 0, 1, 0); - } - else if (level == 0) - { - // Level 0 tries to use a diamond texture orientation relative to camera view - // Use halfway between camera view forward and up for light view up - VectorAdd(fd->viewaxis[0], fd->viewaxis[2], lightViewAxis[2]); - } - else - { - // Use camera view left as light view up - VectorCopy(fd->viewaxis[1], lightViewAxis[2]); - } - } - - // clean axes - CrossProduct(lightViewAxis[2], lightViewAxis[0], lightViewAxis[1]); - VectorNormalize(lightViewAxis[1]); - CrossProduct(lightViewAxis[0], lightViewAxis[1], lightViewAxis[2]); - - // Create bounds for light projection using slice of view projection - { - mat4_t lightViewMatrix; - vec4_t point, base, lightViewPoint; - float lx, ly; - - base[3] = 1; - point[3] = 1; - lightViewPoint[3] = 1; - - Mat4View(lightViewAxis, lightOrigin, lightViewMatrix); - - ClearBounds(lightviewBounds[0], lightviewBounds[1]); - - // add view near plane - lx = splitZNear * tan(fd->fov_x * M_PI / 360.0f); - ly = splitZNear * tan(fd->fov_y * M_PI / 360.0f); - VectorMA(fd->vieworg, splitZNear, fd->viewaxis[0], base); - - VectorMA(base, lx, fd->viewaxis[1], point); - VectorMA(point, ly, fd->viewaxis[2], point); - Mat4Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - VectorMA(base, -lx, fd->viewaxis[1], point); - VectorMA(point, ly, fd->viewaxis[2], point); - Mat4Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - VectorMA(base, lx, fd->viewaxis[1], point); - VectorMA(point, -ly, fd->viewaxis[2], point); - Mat4Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - VectorMA(base, -lx, fd->viewaxis[1], point); - VectorMA(point, -ly, fd->viewaxis[2], point); - Mat4Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - - // add view far plane - lx = splitZFar * tan(fd->fov_x * M_PI / 360.0f); - ly = splitZFar * tan(fd->fov_y * M_PI / 360.0f); - VectorMA(fd->vieworg, splitZFar, fd->viewaxis[0], base); - - VectorMA(base, lx, fd->viewaxis[1], point); - VectorMA(point, ly, fd->viewaxis[2], point); - Mat4Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - VectorMA(base, -lx, fd->viewaxis[1], point); - VectorMA(point, ly, fd->viewaxis[2], point); - Mat4Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - VectorMA(base, lx, fd->viewaxis[1], point); - VectorMA(point, -ly, fd->viewaxis[2], point); - Mat4Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - VectorMA(base, -lx, fd->viewaxis[1], point); - VectorMA(point, -ly, fd->viewaxis[2], point); - Mat4Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - if (!glRefConfig.depthClamp) - lightviewBounds[0][0] = lightviewBounds[1][0] - 8192; - - // Moving the Light in Texel-Sized Increments - // from http://msdn.microsoft.com/en-us/library/windows/desktop/ee416324%28v=vs.85%29.aspx - // - if (lightViewIndependentOfCameraView) - { - float cascadeBound, worldUnitsPerTexel, invWorldUnitsPerTexel; - - cascadeBound = MAX(lightviewBounds[1][0] - lightviewBounds[0][0], lightviewBounds[1][1] - lightviewBounds[0][1]); - cascadeBound = MAX(cascadeBound, lightviewBounds[1][2] - lightviewBounds[0][2]); - worldUnitsPerTexel = cascadeBound / tr.sunShadowFbo[level]->width; - invWorldUnitsPerTexel = 1.0f / worldUnitsPerTexel; - - VectorScale(lightviewBounds[0], invWorldUnitsPerTexel, lightviewBounds[0]); - lightviewBounds[0][0] = floor(lightviewBounds[0][0]); - lightviewBounds[0][1] = floor(lightviewBounds[0][1]); - lightviewBounds[0][2] = floor(lightviewBounds[0][2]); - VectorScale(lightviewBounds[0], worldUnitsPerTexel, lightviewBounds[0]); - - VectorScale(lightviewBounds[1], invWorldUnitsPerTexel, lightviewBounds[1]); - lightviewBounds[1][0] = floor(lightviewBounds[1][0]); - lightviewBounds[1][1] = floor(lightviewBounds[1][1]); - lightviewBounds[1][2] = floor(lightviewBounds[1][2]); - VectorScale(lightviewBounds[1], worldUnitsPerTexel, lightviewBounds[1]); - } - - //ri.Printf(PRINT_ALL, "znear %f zfar %f\n", lightviewBounds[0][0], lightviewBounds[1][0]); - //ri.Printf(PRINT_ALL, "fovx %f fovy %f xmin %f xmax %f ymin %f ymax %f\n", fd->fov_x, fd->fov_y, xmin, xmax, ymin, ymax); - } - - - { - int firstDrawSurf; - - Com_Memset( &shadowParms, 0, sizeof( shadowParms ) ); - - if (glRefConfig.framebufferObject) - { - shadowParms.viewportX = 0; - shadowParms.viewportY = 0; - } - else - { - shadowParms.viewportX = tr.refdef.x; - shadowParms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.sunShadowFbo[level]->height ); - } - shadowParms.viewportWidth = tr.sunShadowFbo[level]->width; - shadowParms.viewportHeight = tr.sunShadowFbo[level]->height; - shadowParms.isPortal = qfalse; - shadowParms.isMirror = qfalse; - - shadowParms.fovX = 90; - shadowParms.fovY = 90; - - if (glRefConfig.framebufferObject) - shadowParms.targetFbo = tr.sunShadowFbo[level]; - - shadowParms.flags = VPF_DEPTHSHADOW | VPF_DEPTHCLAMP | VPF_ORTHOGRAPHIC | VPF_NOVIEWMODEL; - shadowParms.zFar = lightviewBounds[1][0]; - - VectorCopy(lightOrigin, shadowParms.or.origin); - - VectorCopy(lightViewAxis[0], shadowParms.or.axis[0]); - VectorCopy(lightViewAxis[1], shadowParms.or.axis[1]); - VectorCopy(lightViewAxis[2], shadowParms.or.axis[2]); - - VectorCopy(lightOrigin, shadowParms.pvsOrigin ); - - { - tr.viewCount++; - - tr.viewParms = shadowParms; - tr.viewParms.frameSceneNum = tr.frameSceneNum; - tr.viewParms.frameCount = tr.frameCount; - - firstDrawSurf = tr.refdef.numDrawSurfs; - - tr.viewCount++; - - // set viewParms.world - R_RotateForViewer (); - - R_SetupProjectionOrtho(&tr.viewParms, lightviewBounds); - - R_AddWorldSurfaces (); - - R_AddPolygonSurfaces(); - - R_AddEntitySurfaces (); - - R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf ); - } - - Mat4Multiply(tr.viewParms.projectionMatrix, tr.viewParms.world.modelMatrix, tr.refdef.sunShadowMvp[level]); - } -} - -void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene ) -{ - refdef_t refdef; - viewParms_t parms; - float oldColorScale = tr.refdef.colorScale; - - memset( &refdef, 0, sizeof( refdef ) ); - refdef.rdflags = 0; - VectorCopy(tr.cubemapOrigins[cubemapIndex], refdef.vieworg); - - switch(cubemapSide) - { - case 0: - // -X - VectorSet( refdef.viewaxis[0], -1, 0, 0); - VectorSet( refdef.viewaxis[1], 0, 0, -1); - VectorSet( refdef.viewaxis[2], 0, 1, 0); - break; - case 1: - // +X - VectorSet( refdef.viewaxis[0], 1, 0, 0); - VectorSet( refdef.viewaxis[1], 0, 0, 1); - VectorSet( refdef.viewaxis[2], 0, 1, 0); - break; - case 2: - // -Y - VectorSet( refdef.viewaxis[0], 0, -1, 0); - VectorSet( refdef.viewaxis[1], 1, 0, 0); - VectorSet( refdef.viewaxis[2], 0, 0, -1); - break; - case 3: - // +Y - VectorSet( refdef.viewaxis[0], 0, 1, 0); - VectorSet( refdef.viewaxis[1], 1, 0, 0); - VectorSet( refdef.viewaxis[2], 0, 0, 1); - break; - case 4: - // -Z - VectorSet( refdef.viewaxis[0], 0, 0, -1); - VectorSet( refdef.viewaxis[1], 1, 0, 0); - VectorSet( refdef.viewaxis[2], 0, 1, 0); - break; - case 5: - // +Z - VectorSet( refdef.viewaxis[0], 0, 0, 1); - VectorSet( refdef.viewaxis[1], -1, 0, 0); - VectorSet( refdef.viewaxis[2], 0, 1, 0); - break; - } - - refdef.fov_x = 90; - refdef.fov_y = 90; - - refdef.x = 0; - refdef.y = 0; - refdef.width = tr.renderCubeFbo->width; - refdef.height = tr.renderCubeFbo->height; - - refdef.time = 0; - - if (!subscene) - { - RE_BeginScene(&refdef); - - // FIXME: sun shadows aren't rendered correctly in cubemaps - // fix involves changing r_FBufScale to fit smaller cubemap image size, or rendering cubemap to framebuffer first - if(0) //(glRefConfig.framebufferObject && r_sunlightMode->integer && (r_forceSun->integer || tr.sunShadows)) - { - R_RenderSunShadowMaps(&refdef, 0); - R_RenderSunShadowMaps(&refdef, 1); - R_RenderSunShadowMaps(&refdef, 2); - } - } - - { - vec3_t ambient, directed, lightDir; - R_LightForPoint(tr.refdef.vieworg, ambient, directed, lightDir); - tr.refdef.colorScale = 766.0f / (directed[0] + directed[1] + directed[2] + 1.0f); - if (directed[0] + directed[1] + directed[2] == 0) - { - ri.Printf(PRINT_ALL, "cubemap %d (%f, %f, %f) is outside the lightgrid!\n", cubemapIndex, tr.refdef.vieworg[0], tr.refdef.vieworg[1], tr.refdef.vieworg[2]); - } - } - - Com_Memset( &parms, 0, sizeof( parms ) ); - - parms.viewportX = 0; - parms.viewportY = 0; - parms.viewportWidth = tr.renderCubeFbo->width; - parms.viewportHeight = tr.renderCubeFbo->height; - parms.isPortal = qfalse; - parms.isMirror = qtrue; - parms.flags = VPF_NOVIEWMODEL | VPF_NOCUBEMAPS; - - parms.fovX = 90; - parms.fovY = 90; - - VectorCopy( refdef.vieworg, parms.or.origin ); - VectorCopy( refdef.viewaxis[0], parms.or.axis[0] ); - VectorCopy( refdef.viewaxis[1], parms.or.axis[1] ); - VectorCopy( refdef.viewaxis[2], parms.or.axis[2] ); - - VectorCopy( refdef.vieworg, parms.pvsOrigin ); - - // FIXME: sun shadows aren't rendered correctly in cubemaps - // fix involves changing r_FBufScale to fit smaller cubemap image size, or rendering cubemap to framebuffer first - if (0) //(r_depthPrepass->value && ((r_forceSun->integer) || tr.sunShadows)) - { - parms.flags = VPF_USESUNLIGHT; - } - - parms.targetFbo = tr.renderCubeFbo; - parms.targetFboLayer = cubemapSide; - parms.targetFboCubemapIndex = cubemapIndex; - - R_RenderView(&parms); - - if (subscene) - { - tr.refdef.colorScale = oldColorScale; - } - else - { - RE_EndScene(); - } -} \ No newline at end of file diff --git a/code/renderergl2/tr_marks.c b/code/renderergl2/tr_marks.c deleted file mode 100644 index 830d4d2918..0000000000 --- a/code/renderergl2/tr_marks.c +++ /dev/null @@ -1,466 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_marks.c -- polygon projection on the world polygons - -#include "tr_local.h" -//#include "assert.h" - -#define MAX_VERTS_ON_POLY 64 - -#define MARKER_OFFSET 0 // 1 - -/* -============= -R_ChopPolyBehindPlane - -Out must have space for two more vertexes than in -============= -*/ -#define SIDE_FRONT 0 -#define SIDE_BACK 1 -#define SIDE_ON 2 -static void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY], - int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY], - vec3_t normal, vec_t dist, vec_t epsilon) { - float dists[MAX_VERTS_ON_POLY+4] = { 0 }; - int sides[MAX_VERTS_ON_POLY+4] = { 0 }; - int counts[3]; - float dot; - int i, j; - float *p1, *p2, *clip; - float d; - - // don't clip if it might overflow - if ( numInPoints >= MAX_VERTS_ON_POLY - 2 ) { - *numOutPoints = 0; - return; - } - - counts[0] = counts[1] = counts[2] = 0; - - // determine sides for each point - for ( i = 0 ; i < numInPoints ; i++ ) { - dot = DotProduct( inPoints[i], normal ); - dot -= dist; - dists[i] = dot; - if ( dot > epsilon ) { - sides[i] = SIDE_FRONT; - } else if ( dot < -epsilon ) { - sides[i] = SIDE_BACK; - } else { - sides[i] = SIDE_ON; - } - counts[sides[i]]++; - } - sides[i] = sides[0]; - dists[i] = dists[0]; - - *numOutPoints = 0; - - if ( !counts[0] ) { - return; - } - if ( !counts[1] ) { - *numOutPoints = numInPoints; - Com_Memcpy( outPoints, inPoints, numInPoints * sizeof(vec3_t) ); - return; - } - - for ( i = 0 ; i < numInPoints ; i++ ) { - p1 = inPoints[i]; - clip = outPoints[ *numOutPoints ]; - - if ( sides[i] == SIDE_ON ) { - VectorCopy( p1, clip ); - (*numOutPoints)++; - continue; - } - - if ( sides[i] == SIDE_FRONT ) { - VectorCopy( p1, clip ); - (*numOutPoints)++; - clip = outPoints[ *numOutPoints ]; - } - - if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) { - continue; - } - - // generate a split point - p2 = inPoints[ (i+1) % numInPoints ]; - - d = dists[i] - dists[i+1]; - if ( d == 0 ) { - dot = 0; - } else { - dot = dists[i] / d; - } - - // clip xyz - - for (j=0 ; j<3 ; j++) { - clip[j] = p1[j] + dot * ( p2[j] - p1[j] ); - } - - (*numOutPoints)++; - } -} - -/* -================= -R_BoxSurfaces_r - -================= -*/ -void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir) { - - int s, c; - msurface_t *surf; - int *mark; - - // do the tail recursion in a loop - while ( node->contents == -1 ) { - s = BoxOnPlaneSide( mins, maxs, node->plane ); - if (s == 1) { - node = node->children[0]; - } else if (s == 2) { - node = node->children[1]; - } else { - R_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir); - node = node->children[1]; - } - } - - // add the individual surfaces - mark = tr.world->marksurfaces + node->firstmarksurface; - c = node->nummarksurfaces; - while (c--) { - int *surfViewCount; - // - if (*listlength >= listsize) break; - // - surfViewCount = &tr.world->surfacesViewCount[*mark]; - surf = tr.world->surfaces + *mark; - // check if the surface has NOIMPACT or NOMARKS set - if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) ) - || ( surf->shader->contentFlags & CONTENTS_FOG ) ) { - *surfViewCount = tr.viewCount; - } - // extra check for surfaces to avoid list overflows - else if (*(surf->data) == SF_FACE) { - // the face plane should go through the box - s = BoxOnPlaneSide( mins, maxs, &surf->cullinfo.plane ); - if (s == 1 || s == 2) { - *surfViewCount = tr.viewCount; - } else if (DotProduct(surf->cullinfo.plane.normal, dir) > -0.5) { - // don't add faces that make sharp angles with the projection direction - *surfViewCount = tr.viewCount; - } - } - else if (*(surf->data) != SF_GRID && - *(surf->data) != SF_TRIANGLES) - *surfViewCount = tr.viewCount; - // check the viewCount because the surface may have - // already been added if it spans multiple leafs - if (*surfViewCount != tr.viewCount) { - *surfViewCount = tr.viewCount; - list[*listlength] = surf->data; - (*listlength)++; - } - mark++; - } -} - -/* -================= -R_AddMarkFragments - -================= -*/ -void R_AddMarkFragments(int numClipPoints, vec3_t clipPoints[2][MAX_VERTS_ON_POLY], - int numPlanes, vec3_t *normals, float *dists, - int maxPoints, vec3_t pointBuffer, - int maxFragments, markFragment_t *fragmentBuffer, - int *returnedPoints, int *returnedFragments, - vec3_t mins, vec3_t maxs) { - int pingPong, i; - markFragment_t *mf; - - // chop the surface by all the bounding planes of the to be projected polygon - pingPong = 0; - - for ( i = 0 ; i < numPlanes ; i++ ) { - - R_ChopPolyBehindPlane( numClipPoints, clipPoints[pingPong], - &numClipPoints, clipPoints[!pingPong], - normals[i], dists[i], 0.5 ); - pingPong ^= 1; - if ( numClipPoints == 0 ) { - break; - } - } - // completely clipped away? - if ( numClipPoints == 0 ) { - return; - } - - // add this fragment to the returned list - if ( numClipPoints + (*returnedPoints) > maxPoints ) { - return; // not enough space for this polygon - } - /* - // all the clip points should be within the bounding box - for ( i = 0 ; i < numClipPoints ; i++ ) { - int j; - for ( j = 0 ; j < 3 ; j++ ) { - if (clipPoints[pingPong][i][j] < mins[j] - 0.5) break; - if (clipPoints[pingPong][i][j] > maxs[j] + 0.5) break; - } - if (j < 3) break; - } - if (i < numClipPoints) return; - */ - - mf = fragmentBuffer + (*returnedFragments); - mf->firstPoint = (*returnedPoints); - mf->numPoints = numClipPoints; - Com_Memcpy( pointBuffer + (*returnedPoints) * 3, clipPoints[pingPong], numClipPoints * sizeof(vec3_t) ); - - (*returnedPoints) += numClipPoints; - (*returnedFragments)++; -} - -/* -================= -R_MarkFragments - -================= -*/ -int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, - int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) { - int numsurfaces, numPlanes; - int i, j, k, m, n; - surfaceType_t *surfaces[64]; - vec3_t mins, maxs; - int returnedFragments; - int returnedPoints; - vec3_t normals[MAX_VERTS_ON_POLY+2]; - float dists[MAX_VERTS_ON_POLY+2]; - vec3_t clipPoints[2][MAX_VERTS_ON_POLY]; - int numClipPoints; - float *v; - srfBspSurface_t *cv; - glIndex_t *tri; - srfVert_t *dv; - vec3_t normal; - vec3_t projectionDir; - vec3_t v1, v2; - - if (numPoints <= 0) { - return 0; - } - - //increment view count for double check prevention - tr.viewCount++; - - // - VectorNormalize2( projection, projectionDir ); - // find all the brushes that are to be considered - ClearBounds( mins, maxs ); - for ( i = 0 ; i < numPoints ; i++ ) { - vec3_t temp; - - AddPointToBounds( points[i], mins, maxs ); - VectorAdd( points[i], projection, temp ); - AddPointToBounds( temp, mins, maxs ); - // make sure we get all the leafs (also the one(s) in front of the hit surface) - VectorMA( points[i], -20, projectionDir, temp ); - AddPointToBounds( temp, mins, maxs ); - } - - if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY; - // create the bounding planes for the to be projected polygon - for ( i = 0 ; i < numPoints ; i++ ) { - VectorSubtract(points[(i+1)%numPoints], points[i], v1); - VectorAdd(points[i], projection, v2); - VectorSubtract(points[i], v2, v2); - CrossProduct(v1, v2, normals[i]); - VectorNormalizeFast(normals[i]); - dists[i] = DotProduct(normals[i], points[i]); - } - // add near and far clipping planes for projection - VectorCopy(projectionDir, normals[numPoints]); - dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32; - VectorCopy(projectionDir, normals[numPoints+1]); - VectorInverse(normals[numPoints+1]); - dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20; - numPlanes = numPoints + 2; - - numsurfaces = 0; - R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir); - //assert(numsurfaces <= 64); - //assert(numsurfaces != 64); - - returnedPoints = 0; - returnedFragments = 0; - - for ( i = 0 ; i < numsurfaces ; i++ ) { - - if (*surfaces[i] == SF_GRID) { - - cv = (srfBspSurface_t *) surfaces[i]; - for ( m = 0 ; m < cv->height - 1 ; m++ ) { - for ( n = 0 ; n < cv->width - 1 ; n++ ) { - // We triangulate the grid and chop all triangles within - // the bounding planes of the to be projected polygon. - // LOD is not taken into account, not such a big deal though. - // - // It's probably much nicer to chop the grid itself and deal - // with this grid as a normal SF_GRID surface so LOD will - // be applied. However the LOD of that chopped grid must - // be synced with the LOD of the original curve. - // One way to do this; the chopped grid shares vertices with - // the original curve. When LOD is applied to the original - // curve the unused vertices are flagged. Now the chopped curve - // should skip the flagged vertices. This still leaves the - // problems with the vertices at the chopped grid edges. - // - // To avoid issues when LOD applied to "hollow curves" (like - // the ones around many jump pads) we now just add a 2 unit - // offset to the triangle vertices. - // The offset is added in the vertex normal vector direction - // so all triangles will still fit together. - // The 2 unit offset should avoid pretty much all LOD problems. - - numClipPoints = 3; - - dv = cv->verts + m * cv->width + n; - - VectorCopy(dv[0].xyz, clipPoints[0][0]); - VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]); - VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); - VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); - VectorCopy(dv[1].xyz, clipPoints[0][2]); - VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]); - // check the normal of this triangle - VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); - VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); - CrossProduct(v1, v2, normal); - VectorNormalizeFast(normal); - if (DotProduct(normal, projectionDir) < -0.1) { - // add the fragments of this triangle - R_AddMarkFragments(numClipPoints, clipPoints, - numPlanes, normals, dists, - maxPoints, pointBuffer, - maxFragments, fragmentBuffer, - &returnedPoints, &returnedFragments, mins, maxs); - - if ( returnedFragments == maxFragments ) { - return returnedFragments; // not enough space for more fragments - } - } - - VectorCopy(dv[1].xyz, clipPoints[0][0]); - VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]); - VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); - VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); - VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]); - VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]); - // check the normal of this triangle - VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); - VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); - CrossProduct(v1, v2, normal); - VectorNormalizeFast(normal); - if (DotProduct(normal, projectionDir) < -0.05) { - // add the fragments of this triangle - R_AddMarkFragments(numClipPoints, clipPoints, - numPlanes, normals, dists, - maxPoints, pointBuffer, - maxFragments, fragmentBuffer, - &returnedPoints, &returnedFragments, mins, maxs); - - if ( returnedFragments == maxFragments ) { - return returnedFragments; // not enough space for more fragments - } - } - } - } - } - else if (*surfaces[i] == SF_FACE) { - - srfBspSurface_t *surf = ( srfBspSurface_t * ) surfaces[i]; - - // check the normal of this face - if (DotProduct(surf->cullPlane.normal, projectionDir) > -0.5) { - continue; - } - - for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3) - { - for(j = 0; j < 3; j++) - { - v = surf->verts[tri[j]].xyz; - VectorMA(v, MARKER_OFFSET, surf->cullPlane.normal, clipPoints[0][j]); - } - - // add the fragments of this face - R_AddMarkFragments( 3 , clipPoints, - numPlanes, normals, dists, - maxPoints, pointBuffer, - maxFragments, fragmentBuffer, - &returnedPoints, &returnedFragments, mins, maxs); - if ( returnedFragments == maxFragments ) { - return returnedFragments; // not enough space for more fragments - } - } - } - else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) { - - srfBspSurface_t *surf = (srfBspSurface_t *) surfaces[i]; - - for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3) - { - for(j = 0; j < 3; j++) - { - v = surf->verts[tri[j]].xyz; - VectorMA(v, MARKER_OFFSET, surf->verts[tri[j]].normal, clipPoints[0][j]); - } - - // add the fragments of this face - R_AddMarkFragments(3, clipPoints, - numPlanes, normals, dists, - maxPoints, pointBuffer, - maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs); - if(returnedFragments == maxFragments) - { - return returnedFragments; // not enough space for more fragments - } - } - } - } - return returnedFragments; -} - - - - - diff --git a/code/renderergl2/tr_mesh.c b/code/renderergl2/tr_mesh.c deleted file mode 100644 index 618958be50..0000000000 --- a/code/renderergl2/tr_mesh.c +++ /dev/null @@ -1,404 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_mesh.c: triangle model functions - -#include "tr_local.h" - -static float ProjectRadius( float r, vec3_t location ) -{ - float pr; - float dist; - float c; - vec3_t p; - float projected[4]; - - c = DotProduct( tr.viewParms.or.axis[0], tr.viewParms.or.origin ); - dist = DotProduct( tr.viewParms.or.axis[0], location ) - c; - - if ( dist <= 0 ) - return 0; - - p[0] = 0; - p[1] = fabs( r ); - p[2] = -dist; - - projected[0] = p[0] * tr.viewParms.projectionMatrix[0] + - p[1] * tr.viewParms.projectionMatrix[4] + - p[2] * tr.viewParms.projectionMatrix[8] + - tr.viewParms.projectionMatrix[12]; - - projected[1] = p[0] * tr.viewParms.projectionMatrix[1] + - p[1] * tr.viewParms.projectionMatrix[5] + - p[2] * tr.viewParms.projectionMatrix[9] + - tr.viewParms.projectionMatrix[13]; - - projected[2] = p[0] * tr.viewParms.projectionMatrix[2] + - p[1] * tr.viewParms.projectionMatrix[6] + - p[2] * tr.viewParms.projectionMatrix[10] + - tr.viewParms.projectionMatrix[14]; - - projected[3] = p[0] * tr.viewParms.projectionMatrix[3] + - p[1] * tr.viewParms.projectionMatrix[7] + - p[2] * tr.viewParms.projectionMatrix[11] + - tr.viewParms.projectionMatrix[15]; - - - pr = projected[1] / projected[3]; - - if ( pr > 1.0f ) - pr = 1.0f; - - return pr; -} - -/* -============= -R_CullModel -============= -*/ -static int R_CullModel( mdvModel_t *model, trRefEntity_t *ent ) { - vec3_t bounds[2]; - mdvFrame_t *oldFrame, *newFrame; - int i; - - // compute frame pointers - newFrame = model->frames + ent->e.frame; - oldFrame = model->frames + ent->e.oldframe; - - // cull bounding sphere ONLY if this is not an upscaled entity - if ( !ent->e.nonNormalizedAxes ) - { - if ( ent->e.frame == ent->e.oldframe ) - { - switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) ) - { - case CULL_OUT: - tr.pc.c_sphere_cull_md3_out++; - return CULL_OUT; - - case CULL_IN: - tr.pc.c_sphere_cull_md3_in++; - return CULL_IN; - - case CULL_CLIP: - tr.pc.c_sphere_cull_md3_clip++; - break; - } - } - else - { - int sphereCull, sphereCullB; - - sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ); - if ( newFrame == oldFrame ) { - sphereCullB = sphereCull; - } else { - sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius ); - } - - if ( sphereCull == sphereCullB ) - { - if ( sphereCull == CULL_OUT ) - { - tr.pc.c_sphere_cull_md3_out++; - return CULL_OUT; - } - else if ( sphereCull == CULL_IN ) - { - tr.pc.c_sphere_cull_md3_in++; - return CULL_IN; - } - else - { - tr.pc.c_sphere_cull_md3_clip++; - } - } - } - } - - // calculate a bounding box in the current coordinate system - for (i = 0 ; i < 3 ; i++) { - bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; - bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; - } - - switch ( R_CullLocalBox( bounds ) ) - { - case CULL_IN: - tr.pc.c_box_cull_md3_in++; - return CULL_IN; - case CULL_CLIP: - tr.pc.c_box_cull_md3_clip++; - return CULL_CLIP; - case CULL_OUT: - default: - tr.pc.c_box_cull_md3_out++; - return CULL_OUT; - } -} - - -/* -================= -R_ComputeLOD - -================= -*/ -int R_ComputeLOD( trRefEntity_t *ent ) { - float radius; - float flod, lodscale; - float projectedRadius; - mdvFrame_t *frame; - mdrHeader_t *mdr; - mdrFrame_t *mdrframe; - int lod; - - if ( tr.currentModel->numLods < 2 ) - { - // model has only 1 LOD level, skip computations and bias - lod = 0; - } - else - { - // multiple LODs exist, so compute projected bounding sphere - // and use that as a criteria for selecting LOD - - if(tr.currentModel->type == MOD_MDR) - { - int frameSize; - mdr = (mdrHeader_t *) tr.currentModel->modelData; - frameSize = (size_t) (&((mdrFrame_t *)0)->bones[mdr->numBones]); - - mdrframe = (mdrFrame_t *) ((byte *) mdr + mdr->ofsFrames + frameSize * ent->e.frame); - - radius = RadiusFromBounds(mdrframe->bounds[0], mdrframe->bounds[1]); - } - else - { - //frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames ); - frame = tr.currentModel->mdv[0]->frames; - - frame += ent->e.frame; - - radius = RadiusFromBounds( frame->bounds[0], frame->bounds[1] ); - } - - if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 ) - { - lodscale = r_lodscale->value; - if (lodscale > 20) lodscale = 20; - flod = 1.0f - projectedRadius * lodscale; - } - else - { - // object intersects near view plane, e.g. view weapon - flod = 0; - } - - flod *= tr.currentModel->numLods; - lod = ri.ftol(flod); - - if ( lod < 0 ) - { - lod = 0; - } - else if ( lod >= tr.currentModel->numLods ) - { - lod = tr.currentModel->numLods - 1; - } - } - - lod += r_lodbias->integer; - - if ( lod >= tr.currentModel->numLods ) - lod = tr.currentModel->numLods - 1; - if ( lod < 0 ) - lod = 0; - - return lod; -} - -/* -================= -R_ComputeFogNum - -================= -*/ -int R_ComputeFogNum( mdvModel_t *model, trRefEntity_t *ent ) { - int i, j; - fog_t *fog; - mdvFrame_t *mdvFrame; - vec3_t localOrigin; - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return 0; - } - - // FIXME: non-normalized axis issues - mdvFrame = model->frames + ent->e.frame; - VectorAdd( ent->e.origin, mdvFrame->localOrigin, localOrigin ); - for ( i = 1 ; i < tr.world->numfogs ; i++ ) { - fog = &tr.world->fogs[i]; - for ( j = 0 ; j < 3 ; j++ ) { - if ( localOrigin[j] - mdvFrame->radius >= fog->bounds[1][j] ) { - break; - } - if ( localOrigin[j] + mdvFrame->radius <= fog->bounds[0][j] ) { - break; - } - } - if ( j == 3 ) { - return i; - } - } - - return 0; -} - -/* -================= -R_AddMD3Surfaces - -================= -*/ -void R_AddMD3Surfaces( trRefEntity_t *ent ) { - int i; - mdvModel_t *model = NULL; - mdvSurface_t *surface = NULL; - shader_t *shader = NULL; - int cull; - int lod; - int fogNum; - int cubemapIndex; - qboolean personalModel; - - // don't add third_person objects if not in a portal - personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !(tr.viewParms.isPortal - || (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW))); - - if ( ent->e.renderfx & RF_WRAP_FRAMES ) { - ent->e.frame %= tr.currentModel->mdv[0]->numFrames; - ent->e.oldframe %= tr.currentModel->mdv[0]->numFrames; - } - - // - // Validate the frames so there is no chance of a crash. - // This will write directly into the entity structure, so - // when the surfaces are rendered, they don't need to be - // range checked again. - // - if ( (ent->e.frame >= tr.currentModel->mdv[0]->numFrames) - || (ent->e.frame < 0) - || (ent->e.oldframe >= tr.currentModel->mdv[0]->numFrames) - || (ent->e.oldframe < 0) ) { - ri.Printf( PRINT_DEVELOPER, "R_AddMD3Surfaces: no such frame %d to %d for '%s'\n", - ent->e.oldframe, ent->e.frame, - tr.currentModel->name ); - ent->e.frame = 0; - ent->e.oldframe = 0; - } - - // - // compute LOD - // - lod = R_ComputeLOD( ent ); - - model = tr.currentModel->mdv[lod]; - - // - // cull the entire model if merged bounding box of both frames - // is outside the view frustum. - // - cull = R_CullModel ( model, ent ); - if ( cull == CULL_OUT ) { - return; - } - - // - // set up lighting now that we know we aren't culled - // - if ( !personalModel || r_shadows->integer > 1 ) { - R_SetupEntityLighting( &tr.refdef, ent ); - } - - // - // see if we are in a fog volume - // - fogNum = R_ComputeFogNum( model, ent ); - - cubemapIndex = R_CubemapForPoint(ent->e.origin); - - // - // draw all surfaces - // - surface = model->surfaces; - for ( i = 0 ; i < model->numSurfaces ; i++ ) { - - if ( ent->e.customShader ) { - shader = R_GetShaderByHandle( ent->e.customShader ); - } else if ( ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins ) { - skin_t *skin; - int j; - - skin = R_GetSkinByHandle( ent->e.customSkin ); - - // match the surface name to something in the skin file - shader = tr.defaultShader; - for ( j = 0 ; j < skin->numSurfaces ; j++ ) { - // the names have both been lowercased - if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) { - shader = skin->surfaces[j]->shader; - break; - } - } - if (shader == tr.defaultShader) { - ri.Printf( PRINT_DEVELOPER, "WARNING: no shader for surface %s in skin %s\n", surface->name, skin->name); - } - else if (shader->defaultShader) { - ri.Printf( PRINT_DEVELOPER, "WARNING: shader %s in skin %s not found\n", shader->name, skin->name); - } - //} else if ( surface->numShaders <= 0 ) { - //shader = tr.defaultShader; - } else { - //md3Shader = (md3Shader_t *) ( (byte *)surface + surface->ofsShaders ); - //md3Shader += ent->e.skinNum % surface->numShaders; - //shader = tr.shaders[ md3Shader->shaderIndex ]; - shader = tr.shaders[ surface->shaderIndexes[ ent->e.skinNum % surface->numShaderIndexes ] ]; - } - - // don't add third_person objects if not viewing through a portal - if(!personalModel) - { - srfVBOMDVMesh_t *vboSurface = &model->vboSurfaces[i]; - - R_AddDrawSurf((void *)vboSurface, shader, fogNum, qfalse, qfalse, cubemapIndex ); - } - - surface++; - } - -} - - - - - diff --git a/code/renderergl2/tr_model.c b/code/renderergl2/tr_model.c deleted file mode 100644 index c0dbeaa228..0000000000 --- a/code/renderergl2/tr_model.c +++ /dev/null @@ -1,1388 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_models.c -- model loading and caching - -#include "tr_local.h" - -#define LL(x) x=LittleLong(x) - -static qboolean R_LoadMD3(model_t *mod, int lod, void *buffer, int bufferSize, const char *modName); -static qboolean R_LoadMDR(model_t *mod, void *buffer, int filesize, const char *name ); - -/* -==================== -R_RegisterMD3 -==================== -*/ -qhandle_t R_RegisterMD3(const char *name, model_t *mod) -{ - union { - unsigned *u; - void *v; - } buf; - int size; - int lod; - int ident; - qboolean loaded = qfalse; - int numLoaded; - char filename[MAX_QPATH], namebuf[MAX_QPATH+20]; - char *fext, defex[] = "md3"; - - numLoaded = 0; - - strcpy(filename, name); - - fext = strchr(filename, '.'); - if(!fext) - fext = defex; - else - { - *fext = '\0'; - fext++; - } - - for (lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod--) - { - if(lod) - Com_sprintf(namebuf, sizeof(namebuf), "%s_%d.%s", filename, lod, fext); - else - Com_sprintf(namebuf, sizeof(namebuf), "%s.%s", filename, fext); - - size = ri.FS_ReadFile( namebuf, &buf.v ); - if(!buf.u) - continue; - - ident = LittleLong(* (unsigned *) buf.u); - if (ident == MD3_IDENT) - loaded = R_LoadMD3(mod, lod, buf.u, size, name); - else - ri.Printf(PRINT_WARNING,"R_RegisterMD3: unknown fileid for %s\n", name); - - ri.FS_FreeFile(buf.v); - - if(loaded) - { - mod->numLods++; - numLoaded++; - } - else - break; - } - - if(numLoaded) - { - // duplicate into higher lod spots that weren't - // loaded, in case the user changes r_lodbias on the fly - for(lod--; lod >= 0; lod--) - { - mod->numLods++; - mod->mdv[lod] = mod->mdv[lod + 1]; - } - - return mod->index; - } - -#ifdef _DEBUG - ri.Printf(PRINT_WARNING,"R_RegisterMD3: couldn't load %s\n", name); -#endif - - mod->type = MOD_BAD; - return 0; -} - -/* -==================== -R_RegisterMDR -==================== -*/ -qhandle_t R_RegisterMDR(const char *name, model_t *mod) -{ - union { - unsigned *u; - void *v; - } buf; - int ident; - qboolean loaded = qfalse; - int filesize; - - filesize = ri.FS_ReadFile(name, (void **) &buf.v); - if(!buf.u) - { - mod->type = MOD_BAD; - return 0; - } - - ident = LittleLong(*(unsigned *)buf.u); - if(ident == MDR_IDENT) - loaded = R_LoadMDR(mod, buf.u, filesize, name); - - ri.FS_FreeFile (buf.v); - - if(!loaded) - { - ri.Printf(PRINT_WARNING,"R_RegisterMDR: couldn't load mdr file %s\n", name); - mod->type = MOD_BAD; - return 0; - } - - return mod->index; -} - -/* -==================== -R_RegisterIQM -==================== -*/ -qhandle_t R_RegisterIQM(const char *name, model_t *mod) -{ - union { - unsigned *u; - void *v; - } buf; - qboolean loaded = qfalse; - int filesize; - - filesize = ri.FS_ReadFile(name, (void **) &buf.v); - if(!buf.u) - { - mod->type = MOD_BAD; - return 0; - } - - loaded = R_LoadIQM(mod, buf.u, filesize, name); - - ri.FS_FreeFile (buf.v); - - if(!loaded) - { - ri.Printf(PRINT_WARNING,"R_RegisterIQM: couldn't load iqm file %s\n", name); - mod->type = MOD_BAD; - return 0; - } - - return mod->index; -} - - -typedef struct -{ - char *ext; - qhandle_t (*ModelLoader)( const char *, model_t * ); -} modelExtToLoaderMap_t; - -// Note that the ordering indicates the order of preference used -// when there are multiple models of different formats available -static modelExtToLoaderMap_t modelLoaders[ ] = -{ - { "iqm", R_RegisterIQM }, - { "mdr", R_RegisterMDR }, - { "md3", R_RegisterMD3 } -}; - -static int numModelLoaders = ARRAY_LEN(modelLoaders); - -//=============================================================================== - -/* -** R_GetModelByHandle -*/ -model_t *R_GetModelByHandle( qhandle_t index ) { - model_t *mod; - - // out of range gets the defualt model - if ( index < 1 || index >= tr.numModels ) { - return tr.models[0]; - } - - mod = tr.models[index]; - - return mod; -} - -//=============================================================================== - -/* -** R_AllocModel -*/ -model_t *R_AllocModel( void ) { - model_t *mod; - - if ( tr.numModels == MAX_MOD_KNOWN ) { - return NULL; - } - - mod = ri.Hunk_Alloc( sizeof( *tr.models[tr.numModels] ), h_low ); - mod->index = tr.numModels; - tr.models[tr.numModels] = mod; - tr.numModels++; - - return mod; -} - -/* -==================== -RE_RegisterModel - -Loads in a model for the given name - -Zero will be returned if the model fails to load. -An entry will be retained for failed models as an -optimization to prevent disk rescanning if they are -asked for again. -==================== -*/ -qhandle_t RE_RegisterModel( const char *name ) { - model_t *mod; - qhandle_t hModel; - qboolean orgNameFailed = qfalse; - int orgLoader = -1; - int i; - char localName[ MAX_QPATH ]; - const char *ext; - char altName[ MAX_QPATH ]; - - if ( !name || !name[0] ) { - ri.Printf( PRINT_ALL, "RE_RegisterModel: NULL name\n" ); - return 0; - } - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_ALL, "Model name exceeds MAX_QPATH\n" ); - return 0; - } - - // - // search the currently loaded models - // - for ( hModel = 1 ; hModel < tr.numModels; hModel++ ) { - mod = tr.models[hModel]; - if ( !strcmp( mod->name, name ) ) { - if( mod->type == MOD_BAD ) { - return 0; - } - return hModel; - } - } - - // allocate a new model_t - - if ( ( mod = R_AllocModel() ) == NULL ) { - ri.Printf( PRINT_WARNING, "RE_RegisterModel: R_AllocModel() failed for '%s'\n", name); - return 0; - } - - // only set the name after the model has been successfully loaded - Q_strncpyz( mod->name, name, sizeof( mod->name ) ); - - - R_IssuePendingRenderCommands(); - - mod->type = MOD_BAD; - mod->numLods = 0; - - // - // load the files - // - Q_strncpyz( localName, name, MAX_QPATH ); - - ext = COM_GetExtension( localName ); - - if( *ext ) - { - // Look for the correct loader and use it - for( i = 0; i < numModelLoaders; i++ ) - { - if( !Q_stricmp( ext, modelLoaders[ i ].ext ) ) - { - // Load - hModel = modelLoaders[ i ].ModelLoader( localName, mod ); - break; - } - } - - // A loader was found - if( i < numModelLoaders ) - { - if( !hModel ) - { - // Loader failed, most likely because the file isn't there; - // try again without the extension - orgNameFailed = qtrue; - orgLoader = i; - COM_StripExtension( name, localName, MAX_QPATH ); - } - else - { - // Something loaded - return mod->index; - } - } - } - - // Try and find a suitable match using all - // the model formats supported - for( i = 0; i < numModelLoaders; i++ ) - { - if (i == orgLoader) - continue; - - Com_sprintf( altName, sizeof (altName), "%s.%s", localName, modelLoaders[ i ].ext ); - - // Load - hModel = modelLoaders[ i ].ModelLoader( altName, mod ); - - if( hModel ) - { - if( orgNameFailed ) - { - ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n", - name, altName ); - } - - break; - } - } - - return hModel; -} - -/* -================= -R_LoadMD3 -================= -*/ -static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, const char *modName) -{ - int f, i, j, k; - - md3Header_t *md3Model; - md3Frame_t *md3Frame; - md3Surface_t *md3Surf; - md3Shader_t *md3Shader; - md3Triangle_t *md3Tri; - md3St_t *md3st; - md3XyzNormal_t *md3xyz; - md3Tag_t *md3Tag; - - mdvModel_t *mdvModel; - mdvFrame_t *frame; - mdvSurface_t *surf;//, *surface; - int *shaderIndex; - glIndex_t *tri; - mdvVertex_t *v; - mdvSt_t *st; - mdvTag_t *tag; - mdvTagName_t *tagName; - - int version; - int size; - - md3Model = (md3Header_t *) buffer; - - version = LittleLong(md3Model->version); - if(version != MD3_VERSION) - { - ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n", modName, version, MD3_VERSION); - return qfalse; - } - - mod->type = MOD_MESH; - size = LittleLong(md3Model->ofsEnd); - mod->dataSize += size; - mdvModel = mod->mdv[lod] = ri.Hunk_Alloc(sizeof(mdvModel_t), h_low); - -// Com_Memcpy(mod->md3[lod], buffer, LittleLong(md3Model->ofsEnd)); - - LL(md3Model->ident); - LL(md3Model->version); - LL(md3Model->numFrames); - LL(md3Model->numTags); - LL(md3Model->numSurfaces); - LL(md3Model->ofsFrames); - LL(md3Model->ofsTags); - LL(md3Model->ofsSurfaces); - LL(md3Model->ofsEnd); - - if(md3Model->numFrames < 1) - { - ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has no frames\n", modName); - return qfalse; - } - - // swap all the frames - mdvModel->numFrames = md3Model->numFrames; - mdvModel->frames = frame = ri.Hunk_Alloc(sizeof(*frame) * md3Model->numFrames, h_low); - - md3Frame = (md3Frame_t *) ((byte *) md3Model + md3Model->ofsFrames); - for(i = 0; i < md3Model->numFrames; i++, frame++, md3Frame++) - { - frame->radius = LittleFloat(md3Frame->radius); - for(j = 0; j < 3; j++) - { - frame->bounds[0][j] = LittleFloat(md3Frame->bounds[0][j]); - frame->bounds[1][j] = LittleFloat(md3Frame->bounds[1][j]); - frame->localOrigin[j] = LittleFloat(md3Frame->localOrigin[j]); - } - } - - // swap all the tags - mdvModel->numTags = md3Model->numTags; - mdvModel->tags = tag = ri.Hunk_Alloc(sizeof(*tag) * (md3Model->numTags * md3Model->numFrames), h_low); - - md3Tag = (md3Tag_t *) ((byte *) md3Model + md3Model->ofsTags); - for(i = 0; i < md3Model->numTags * md3Model->numFrames; i++, tag++, md3Tag++) - { - for(j = 0; j < 3; j++) - { - tag->origin[j] = LittleFloat(md3Tag->origin[j]); - tag->axis[0][j] = LittleFloat(md3Tag->axis[0][j]); - tag->axis[1][j] = LittleFloat(md3Tag->axis[1][j]); - tag->axis[2][j] = LittleFloat(md3Tag->axis[2][j]); - } - } - - - mdvModel->tagNames = tagName = ri.Hunk_Alloc(sizeof(*tagName) * (md3Model->numTags), h_low); - - md3Tag = (md3Tag_t *) ((byte *) md3Model + md3Model->ofsTags); - for(i = 0; i < md3Model->numTags; i++, tagName++, md3Tag++) - { - Q_strncpyz(tagName->name, md3Tag->name, sizeof(tagName->name)); - } - - // swap all the surfaces - mdvModel->numSurfaces = md3Model->numSurfaces; - mdvModel->surfaces = surf = ri.Hunk_Alloc(sizeof(*surf) * md3Model->numSurfaces, h_low); - - md3Surf = (md3Surface_t *) ((byte *) md3Model + md3Model->ofsSurfaces); - for(i = 0; i < md3Model->numSurfaces; i++) - { - LL(md3Surf->ident); - LL(md3Surf->flags); - LL(md3Surf->numFrames); - LL(md3Surf->numShaders); - LL(md3Surf->numTriangles); - LL(md3Surf->ofsTriangles); - LL(md3Surf->numVerts); - LL(md3Surf->ofsShaders); - LL(md3Surf->ofsSt); - LL(md3Surf->ofsXyzNormals); - LL(md3Surf->ofsEnd); - - if(md3Surf->numVerts >= SHADER_MAX_VERTEXES) - { - ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i verts on %s (%i).\n", - modName, SHADER_MAX_VERTEXES - 1, md3Surf->name[0] ? md3Surf->name : "a surface", - md3Surf->numVerts ); - return qfalse; - } - if(md3Surf->numTriangles * 3 >= SHADER_MAX_INDEXES) - { - ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i triangles on %s (%i).\n", - modName, ( SHADER_MAX_INDEXES / 3 ) - 1, md3Surf->name[0] ? md3Surf->name : "a surface", - md3Surf->numTriangles ); - return qfalse; - } - - // change to surface identifier - surf->surfaceType = SF_MDV; - - // give pointer to model for Tess_SurfaceMDX - surf->model = mdvModel; - - // copy surface name - Q_strncpyz(surf->name, md3Surf->name, sizeof(surf->name)); - - // lowercase the surface name so skin compares are faster - Q_strlwr(surf->name); - - // strip off a trailing _1 or _2 - // this is a crutch for q3data being a mess - j = strlen(surf->name); - if(j > 2 && surf->name[j - 2] == '_') - { - surf->name[j - 2] = 0; - } - - // register the shaders - surf->numShaderIndexes = md3Surf->numShaders; - surf->shaderIndexes = shaderIndex = ri.Hunk_Alloc(sizeof(*shaderIndex) * md3Surf->numShaders, h_low); - - md3Shader = (md3Shader_t *) ((byte *) md3Surf + md3Surf->ofsShaders); - for(j = 0; j < md3Surf->numShaders; j++, shaderIndex++, md3Shader++) - { - shader_t *sh; - - sh = R_FindShader(md3Shader->name, LIGHTMAP_NONE, qtrue); - if(sh->defaultShader) - { - *shaderIndex = 0; - } - else - { - *shaderIndex = sh->index; - } - } - - // swap all the triangles - surf->numIndexes = md3Surf->numTriangles * 3; - surf->indexes = tri = ri.Hunk_Alloc(sizeof(*tri) * 3 * md3Surf->numTriangles, h_low); - - md3Tri = (md3Triangle_t *) ((byte *) md3Surf + md3Surf->ofsTriangles); - for(j = 0; j < md3Surf->numTriangles; j++, tri += 3, md3Tri++) - { - tri[0] = LittleLong(md3Tri->indexes[0]); - tri[1] = LittleLong(md3Tri->indexes[1]); - tri[2] = LittleLong(md3Tri->indexes[2]); - } - - // swap all the XyzNormals - surf->numVerts = md3Surf->numVerts; - surf->verts = v = ri.Hunk_Alloc(sizeof(*v) * (md3Surf->numVerts * md3Surf->numFrames), h_low); - - md3xyz = (md3XyzNormal_t *) ((byte *) md3Surf + md3Surf->ofsXyzNormals); - for(j = 0; j < md3Surf->numVerts * md3Surf->numFrames; j++, md3xyz++, v++) - { - unsigned lat, lng; - unsigned short normal; - - v->xyz[0] = LittleShort(md3xyz->xyz[0]) * MD3_XYZ_SCALE; - v->xyz[1] = LittleShort(md3xyz->xyz[1]) * MD3_XYZ_SCALE; - v->xyz[2] = LittleShort(md3xyz->xyz[2]) * MD3_XYZ_SCALE; - - normal = LittleShort(md3xyz->normal); - - lat = ( normal >> 8 ) & 0xff; - lng = ( normal & 0xff ); - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - v->normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - v->normal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - v->normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - } - - // swap all the ST - surf->st = st = ri.Hunk_Alloc(sizeof(*st) * md3Surf->numVerts, h_low); - - md3st = (md3St_t *) ((byte *) md3Surf + md3Surf->ofsSt); - for(j = 0; j < md3Surf->numVerts; j++, md3st++, st++) - { - st->st[0] = LittleFloat(md3st->st[0]); - st->st[1] = LittleFloat(md3st->st[1]); - } - -#ifdef USE_VERT_TANGENT_SPACE - // calc tangent spaces - { - // Valgrind complaints: Conditional jump or move depends on uninitialised value(s) - // So lets Initialize them. - const float *v0 = NULL, *v1 = NULL, *v2 = NULL; - const float *t0 = NULL, *t1 = NULL, *t2 = NULL; - vec3_t tangent = { 0, 0, 0 }; - vec3_t bitangent = { 0, 0, 0 }; - vec3_t normal = { 0, 0, 0 }; - - for(j = 0, v = surf->verts; j < (surf->numVerts * mdvModel->numFrames); j++, v++) - { - VectorClear(v->tangent); - VectorClear(v->bitangent); - if (r_recalcMD3Normals->integer) - VectorClear(v->normal); - } - - for(f = 0; f < mdvModel->numFrames; f++) - { - for(j = 0, tri = surf->indexes; j < surf->numIndexes; j += 3, tri += 3) - { - v0 = surf->verts[surf->numVerts * f + tri[0]].xyz; - v1 = surf->verts[surf->numVerts * f + tri[1]].xyz; - v2 = surf->verts[surf->numVerts * f + tri[2]].xyz; - - t0 = surf->st[tri[0]].st; - t1 = surf->st[tri[1]].st; - t2 = surf->st[tri[2]].st; - - if (!r_recalcMD3Normals->integer) - VectorCopy(v->normal, normal); - else - VectorClear(normal); - - #if 1 - R_CalcTangentSpace(tangent, bitangent, normal, v0, v1, v2, t0, t1, t2); - #else - R_CalcNormalForTriangle(normal, v0, v1, v2); - R_CalcTangentsForTriangle(tangent, bitangent, v0, v1, v2, t0, t1, t2); - #endif - - for(k = 0; k < 3; k++) - { - float *v; - - v = surf->verts[surf->numVerts * f + tri[k]].tangent; - VectorAdd(v, tangent, v); - - v = surf->verts[surf->numVerts * f + tri[k]].bitangent; - VectorAdd(v, bitangent, v); - - if (r_recalcMD3Normals->integer) - { - v = surf->verts[surf->numVerts * f + tri[k]].normal; - VectorAdd(v, normal, v); - } - } - } - } - - for(j = 0, v = surf->verts; j < (surf->numVerts * mdvModel->numFrames); j++, v++) - { - VectorNormalize(v->tangent); - VectorNormalize(v->bitangent); - VectorNormalize(v->normal); - } - } -#endif - - // find the next surface - md3Surf = (md3Surface_t *) ((byte *) md3Surf + md3Surf->ofsEnd); - surf++; - } - - { - srfVBOMDVMesh_t *vboSurf; - - mdvModel->numVBOSurfaces = mdvModel->numSurfaces; - mdvModel->vboSurfaces = ri.Hunk_Alloc(sizeof(*mdvModel->vboSurfaces) * mdvModel->numSurfaces, h_low); - - vboSurf = mdvModel->vboSurfaces; - surf = mdvModel->surfaces; - for (i = 0; i < mdvModel->numSurfaces; i++, vboSurf++, surf++) - { - vec3_t *verts; - vec2_t *texcoords; - uint32_t *normals; -#ifdef USE_VERT_TANGENT_SPACE - uint32_t *tangents; -#endif - - byte *data; - int dataSize; - - int ofs_xyz, ofs_normal, ofs_st; -#ifdef USE_VERT_TANGENT_SPACE - int ofs_tangent; -#endif - - dataSize = 0; - - ofs_xyz = dataSize; - dataSize += surf->numVerts * mdvModel->numFrames * sizeof(*verts); - - ofs_normal = dataSize; - dataSize += surf->numVerts * mdvModel->numFrames * sizeof(*normals); - -#ifdef USE_VERT_TANGENT_SPACE - ofs_tangent = dataSize; - dataSize += surf->numVerts * mdvModel->numFrames * sizeof(*tangents); -#endif - - ofs_st = dataSize; - dataSize += surf->numVerts * sizeof(*texcoords); - - data = ri.Malloc(dataSize); - - verts = (void *)(data + ofs_xyz); - normals = (void *)(data + ofs_normal); -#ifdef USE_VERT_TANGENT_SPACE - tangents = (void *)(data + ofs_tangent); -#endif - texcoords = (void *)(data + ofs_st); - - v = surf->verts; - for ( j = 0; j < surf->numVerts * mdvModel->numFrames ; j++, v++ ) - { - vec3_t nxt; - vec4_t tangent; - - VectorCopy(v->xyz, verts[j]); - - normals[j] = R_VboPackNormal(v->normal); -#ifdef USE_VERT_TANGENT_SPACE - CrossProduct(v->normal, v->tangent, nxt); - VectorCopy(v->tangent, tangent); - tangent[3] = (DotProduct(nxt, v->bitangent) < 0.0f) ? -1.0f : 1.0f; - - tangents[j] = R_VboPackTangent(tangent); -#endif - } - - st = surf->st; - for ( j = 0 ; j < surf->numVerts ; j++, st++ ) { - texcoords[j][0] = st->st[0]; - texcoords[j][1] = st->st[1]; - } - - vboSurf->surfaceType = SF_VBO_MDVMESH; - vboSurf->mdvModel = mdvModel; - vboSurf->mdvSurface = surf; - vboSurf->numIndexes = surf->numIndexes; - vboSurf->numVerts = surf->numVerts; - - vboSurf->minIndex = 0; - vboSurf->maxIndex = surf->numVerts; - - vboSurf->vbo = R_CreateVBO(va("staticMD3Mesh_VBO '%s'", surf->name), data, dataSize, VBO_USAGE_STATIC); - - vboSurf->vbo->ofs_xyz = ofs_xyz; - vboSurf->vbo->ofs_normal = ofs_normal; -#ifdef USE_VERT_TANGENT_SPACE - vboSurf->vbo->ofs_tangent = ofs_tangent; -#endif - vboSurf->vbo->ofs_st = ofs_st; - - vboSurf->vbo->stride_xyz = sizeof(*verts); - vboSurf->vbo->stride_normal = sizeof(*normals); -#ifdef USE_VERT_TANGENT_SPACE - vboSurf->vbo->stride_tangent = sizeof(*tangents); -#endif - vboSurf->vbo->stride_st = sizeof(*st); - - vboSurf->vbo->size_xyz = sizeof(*verts) * surf->numVerts; - vboSurf->vbo->size_normal = sizeof(*normals) * surf->numVerts; - - ri.Free(data); - - vboSurf->ibo = R_CreateIBO2(va("staticMD3Mesh_IBO %s", surf->name), surf->numIndexes, surf->indexes, VBO_USAGE_STATIC); - } - } - - return qtrue; -} - - - -/* -================= -R_LoadMDR -================= -*/ -static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char *mod_name ) -{ - int i, j, k, l; - mdrHeader_t *pinmodel, *mdr; - mdrFrame_t *frame; - mdrLOD_t *lod, *curlod; - mdrSurface_t *surf, *cursurf; - mdrTriangle_t *tri, *curtri; - mdrVertex_t *v, *curv; - mdrWeight_t *weight, *curweight; - mdrTag_t *tag, *curtag; - int size; - shader_t *sh; - - pinmodel = (mdrHeader_t *)buffer; - - pinmodel->version = LittleLong(pinmodel->version); - if (pinmodel->version != MDR_VERSION) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has wrong version (%i should be %i)\n", mod_name, pinmodel->version, MDR_VERSION); - return qfalse; - } - - size = LittleLong(pinmodel->ofsEnd); - - if(size > filesize) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: Header of %s is broken. Wrong filesize declared!\n", mod_name); - return qfalse; - } - - mod->type = MOD_MDR; - - LL(pinmodel->numFrames); - LL(pinmodel->numBones); - LL(pinmodel->ofsFrames); - - // This is a model that uses some type of compressed Bones. We don't want to uncompress every bone for each rendered frame - // over and over again, we'll uncompress it in this function already, so we must adjust the size of the target mdr. - if(pinmodel->ofsFrames < 0) - { - // mdrFrame_t is larger than mdrCompFrame_t: - size += pinmodel->numFrames * sizeof(frame->name); - // now add enough space for the uncompressed bones. - size += pinmodel->numFrames * pinmodel->numBones * ((sizeof(mdrBone_t) - sizeof(mdrCompBone_t))); - } - - // simple bounds check - if(pinmodel->numBones < 0 || - sizeof(*mdr) + pinmodel->numFrames * (sizeof(*frame) + (pinmodel->numBones - 1) * sizeof(*frame->bones)) > size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - mod->dataSize += size; - mod->modelData = mdr = ri.Hunk_Alloc( size, h_low ); - - // Copy all the values over from the file and fix endian issues in the process, if necessary. - - mdr->ident = LittleLong(pinmodel->ident); - mdr->version = pinmodel->version; // Don't need to swap byte order on this one, we already did above. - Q_strncpyz(mdr->name, pinmodel->name, sizeof(mdr->name)); - mdr->numFrames = pinmodel->numFrames; - mdr->numBones = pinmodel->numBones; - mdr->numLODs = LittleLong(pinmodel->numLODs); - mdr->numTags = LittleLong(pinmodel->numTags); - // We don't care about the other offset values, we'll generate them ourselves while loading. - - mod->numLods = mdr->numLODs; - - if ( mdr->numFrames < 1 ) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has no frames\n", mod_name); - return qfalse; - } - - /* The first frame will be put into the first free space after the header */ - frame = (mdrFrame_t *)(mdr + 1); - mdr->ofsFrames = (int)((byte *) frame - (byte *) mdr); - - if (pinmodel->ofsFrames < 0) - { - mdrCompFrame_t *cframe; - - // compressed model... - cframe = (mdrCompFrame_t *)((byte *) pinmodel - pinmodel->ofsFrames); - - for(i = 0; i < mdr->numFrames; i++) - { - for(j = 0; j < 3; j++) - { - frame->bounds[0][j] = LittleFloat(cframe->bounds[0][j]); - frame->bounds[1][j] = LittleFloat(cframe->bounds[1][j]); - frame->localOrigin[j] = LittleFloat(cframe->localOrigin[j]); - } - - frame->radius = LittleFloat(cframe->radius); - frame->name[0] = '\0'; // No name supplied in the compressed version. - - for(j = 0; j < mdr->numBones; j++) - { - for(k = 0; k < (sizeof(cframe->bones[j].Comp) / 2); k++) - { - // Do swapping for the uncompressing functions. They seem to use shorts - // values only, so I assume this will work. Never tested it on other - // platforms, though. - - ((unsigned short *)(cframe->bones[j].Comp))[k] = - LittleShort( ((unsigned short *)(cframe->bones[j].Comp))[k] ); - } - - /* Now do the actual uncompressing */ - MC_UnCompress(frame->bones[j].matrix, cframe->bones[j].Comp); - } - - // Next Frame... - cframe = (mdrCompFrame_t *) &cframe->bones[j]; - frame = (mdrFrame_t *) &frame->bones[j]; - } - } - else - { - mdrFrame_t *curframe; - - // uncompressed model... - // - - curframe = (mdrFrame_t *)((byte *) pinmodel + pinmodel->ofsFrames); - - // swap all the frames - for ( i = 0 ; i < mdr->numFrames ; i++) - { - for(j = 0; j < 3; j++) - { - frame->bounds[0][j] = LittleFloat(curframe->bounds[0][j]); - frame->bounds[1][j] = LittleFloat(curframe->bounds[1][j]); - frame->localOrigin[j] = LittleFloat(curframe->localOrigin[j]); - } - - frame->radius = LittleFloat(curframe->radius); - Q_strncpyz(frame->name, curframe->name, sizeof(frame->name)); - - for (j = 0; j < (int) (mdr->numBones * sizeof(mdrBone_t) / 4); j++) - { - ((float *)frame->bones)[j] = LittleFloat( ((float *)curframe->bones)[j] ); - } - - curframe = (mdrFrame_t *) &curframe->bones[mdr->numBones]; - frame = (mdrFrame_t *) &frame->bones[mdr->numBones]; - } - } - - // frame should now point to the first free address after all frames. - lod = (mdrLOD_t *) frame; - mdr->ofsLODs = (int) ((byte *) lod - (byte *)mdr); - - curlod = (mdrLOD_t *)((byte *) pinmodel + LittleLong(pinmodel->ofsLODs)); - - // swap all the LOD's - for ( l = 0 ; l < mdr->numLODs ; l++) - { - // simple bounds check - if((byte *) (lod + 1) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - lod->numSurfaces = LittleLong(curlod->numSurfaces); - - // swap all the surfaces - surf = (mdrSurface_t *) (lod + 1); - lod->ofsSurfaces = (int)((byte *) surf - (byte *) lod); - cursurf = (mdrSurface_t *) ((byte *)curlod + LittleLong(curlod->ofsSurfaces)); - - for ( i = 0 ; i < lod->numSurfaces ; i++) - { - // simple bounds check - if((byte *) (surf + 1) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - // first do some copying stuff - - surf->ident = SF_MDR; - Q_strncpyz(surf->name, cursurf->name, sizeof(surf->name)); - Q_strncpyz(surf->shader, cursurf->shader, sizeof(surf->shader)); - - surf->ofsHeader = (byte *) mdr - (byte *) surf; - - surf->numVerts = LittleLong(cursurf->numVerts); - surf->numTriangles = LittleLong(cursurf->numTriangles); - // numBoneReferences and BoneReferences generally seem to be unused - - // now do the checks that may fail. - if ( surf->numVerts >= SHADER_MAX_VERTEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on %s (%i).\n", - mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface", - surf->numVerts ); - return qfalse; - } - if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on %s (%i).\n", - mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface", - surf->numTriangles ); - return qfalse; - } - // lowercase the surface name so skin compares are faster - Q_strlwr( surf->name ); - - // register the shaders - sh = R_FindShader(surf->shader, LIGHTMAP_NONE, qtrue); - if ( sh->defaultShader ) { - surf->shaderIndex = 0; - } else { - surf->shaderIndex = sh->index; - } - - // now copy the vertexes. - v = (mdrVertex_t *) (surf + 1); - surf->ofsVerts = (int)((byte *) v - (byte *) surf); - curv = (mdrVertex_t *) ((byte *)cursurf + LittleLong(cursurf->ofsVerts)); - - for(j = 0; j < surf->numVerts; j++) - { - LL(curv->numWeights); - - // simple bounds check - if(curv->numWeights < 0 || (byte *) (v + 1) + (curv->numWeights - 1) * sizeof(*weight) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - v->normal[0] = LittleFloat(curv->normal[0]); - v->normal[1] = LittleFloat(curv->normal[1]); - v->normal[2] = LittleFloat(curv->normal[2]); - - v->texCoords[0] = LittleFloat(curv->texCoords[0]); - v->texCoords[1] = LittleFloat(curv->texCoords[1]); - - v->numWeights = curv->numWeights; - weight = &v->weights[0]; - curweight = &curv->weights[0]; - - // Now copy all the weights - for(k = 0; k < v->numWeights; k++) - { - weight->boneIndex = LittleLong(curweight->boneIndex); - weight->boneWeight = LittleFloat(curweight->boneWeight); - - weight->offset[0] = LittleFloat(curweight->offset[0]); - weight->offset[1] = LittleFloat(curweight->offset[1]); - weight->offset[2] = LittleFloat(curweight->offset[2]); - - weight++; - curweight++; - } - - v = (mdrVertex_t *) weight; - curv = (mdrVertex_t *) curweight; - } - - // we know the offset to the triangles now: - tri = (mdrTriangle_t *) v; - surf->ofsTriangles = (int)((byte *) tri - (byte *) surf); - curtri = (mdrTriangle_t *)((byte *) cursurf + LittleLong(cursurf->ofsTriangles)); - - // simple bounds check - if(surf->numTriangles < 0 || (byte *) (tri + surf->numTriangles) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - for(j = 0; j < surf->numTriangles; j++) - { - tri->indexes[0] = LittleLong(curtri->indexes[0]); - tri->indexes[1] = LittleLong(curtri->indexes[1]); - tri->indexes[2] = LittleLong(curtri->indexes[2]); - - tri++; - curtri++; - } - - // tri now points to the end of the surface. - surf->ofsEnd = (byte *) tri - (byte *) surf; - surf = (mdrSurface_t *) tri; - - // find the next surface. - cursurf = (mdrSurface_t *) ((byte *) cursurf + LittleLong(cursurf->ofsEnd)); - } - - // surf points to the next lod now. - lod->ofsEnd = (int)((byte *) surf - (byte *) lod); - lod = (mdrLOD_t *) surf; - - // find the next LOD. - curlod = (mdrLOD_t *)((byte *) curlod + LittleLong(curlod->ofsEnd)); - } - - // lod points to the first tag now, so update the offset too. - tag = (mdrTag_t *) lod; - mdr->ofsTags = (int)((byte *) tag - (byte *) mdr); - curtag = (mdrTag_t *) ((byte *)pinmodel + LittleLong(pinmodel->ofsTags)); - - // simple bounds check - if(mdr->numTags < 0 || (byte *) (tag + mdr->numTags) > (byte *) mdr + size) - { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name); - return qfalse; - } - - for (i = 0 ; i < mdr->numTags ; i++) - { - tag->boneIndex = LittleLong(curtag->boneIndex); - Q_strncpyz(tag->name, curtag->name, sizeof(tag->name)); - - tag++; - curtag++; - } - - // And finally we know the real offset to the end. - mdr->ofsEnd = (int)((byte *) tag - (byte *) mdr); - - // phew! we're done. - - return qtrue; -} - - - -//============================================================================= - -/* -** RE_BeginRegistration -*/ -void RE_BeginRegistration( glconfig_t *glconfigOut ) { - - R_Init(); - - *glconfigOut = glConfig; - - R_IssuePendingRenderCommands(); - - tr.visIndex = 0; - memset(tr.visClusters, -2, sizeof(tr.visClusters)); // force markleafs to regenerate - - R_ClearFlares(); - RE_ClearScene(); - - tr.registered = qtrue; -} - -//============================================================================= - -/* -=============== -R_ModelInit -=============== -*/ -void R_ModelInit( void ) { - model_t *mod; - - // leave a space for NULL model - tr.numModels = 0; - - mod = R_AllocModel(); - mod->type = MOD_BAD; -} - - -/* -================ -R_Modellist_f -================ -*/ -void R_Modellist_f( void ) { - int i, j; - model_t *mod; - int total; - int lods; - - total = 0; - for ( i = 1 ; i < tr.numModels; i++ ) { - mod = tr.models[i]; - lods = 1; - for ( j = 1 ; j < MD3_MAX_LODS ; j++ ) { - if ( mod->mdv[j] && mod->mdv[j] != mod->mdv[j-1] ) { - lods++; - } - } - ri.Printf( PRINT_ALL, "%8i : (%i) %s\n",mod->dataSize, lods, mod->name ); - total += mod->dataSize; - } - ri.Printf( PRINT_ALL, "%8i : Total models\n", total ); - -#if 0 // not working right with new hunk - if ( tr.world ) { - ri.Printf( PRINT_ALL, "\n%8i : %s\n", tr.world->dataSize, tr.world->name ); - } -#endif -} - - -//============================================================================= - - -/* -================ -R_GetTag -================ -*/ -static mdvTag_t *R_GetTag( mdvModel_t *mod, int frame, const char *_tagName ) { - int i; - mdvTag_t *tag; - mdvTagName_t *tagName; - - if ( frame >= mod->numFrames ) { - // it is possible to have a bad frame while changing models, so don't error - frame = mod->numFrames - 1; - } - - tag = mod->tags + frame * mod->numTags; - tagName = mod->tagNames; - for(i = 0; i < mod->numTags; i++, tag++, tagName++) - { - if(!strcmp(tagName->name, _tagName)) - { - return tag; - } - } - - return NULL; -} - -void R_GetAnimTag( mdrHeader_t *mod, int framenum, const char *tagName, mdvTag_t * dest) -{ - int i, j, k; - int frameSize; - mdrFrame_t *frame; - mdrTag_t *tag; - - if ( framenum >= mod->numFrames ) - { - // it is possible to have a bad frame while changing models, so don't error - framenum = mod->numFrames - 1; - } - - tag = (mdrTag_t *)((byte *)mod + mod->ofsTags); - for ( i = 0 ; i < mod->numTags ; i++, tag++ ) - { - if ( !strcmp( tag->name, tagName ) ) - { - // uncompressed model... - // - frameSize = (intptr_t)( &((mdrFrame_t *)0)->bones[ mod->numBones ] ); - frame = (mdrFrame_t *)((byte *)mod + mod->ofsFrames + framenum * frameSize ); - - for (j = 0; j < 3; j++) - { - for (k = 0; k < 3; k++) - dest->axis[j][k]=frame->bones[tag->boneIndex].matrix[k][j]; - } - - dest->origin[0]=frame->bones[tag->boneIndex].matrix[0][3]; - dest->origin[1]=frame->bones[tag->boneIndex].matrix[1][3]; - dest->origin[2]=frame->bones[tag->boneIndex].matrix[2][3]; - - return; - } - } - - AxisClear( dest->axis ); - VectorClear( dest->origin ); -} - -/* -================ -R_LerpTag -================ -*/ -int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, - float frac, const char *tagName ) { - mdvTag_t *start, *end; - mdvTag_t start_space, end_space; - int i; - float frontLerp, backLerp; - model_t *model; - - model = R_GetModelByHandle( handle ); - if ( !model->mdv[0] ) - { - if(model->type == MOD_MDR) - { - start = &start_space; - end = &end_space; - R_GetAnimTag((mdrHeader_t *) model->modelData, startFrame, tagName, start); - R_GetAnimTag((mdrHeader_t *) model->modelData, endFrame, tagName, end); - } - else if( model->type == MOD_IQM ) { - return R_IQMLerpTag( tag, model->modelData, - startFrame, endFrame, - frac, tagName ); - } else { - - AxisClear( tag->axis ); - VectorClear( tag->origin ); - return qfalse; - - } - } - else - { - start = R_GetTag( model->mdv[0], startFrame, tagName ); - end = R_GetTag( model->mdv[0], endFrame, tagName ); - if ( !start || !end ) { - AxisClear( tag->axis ); - VectorClear( tag->origin ); - return qfalse; - } - } - - frontLerp = frac; - backLerp = 1.0f - frac; - - for ( i = 0 ; i < 3 ; i++ ) { - tag->origin[i] = start->origin[i] * backLerp + end->origin[i] * frontLerp; - tag->axis[0][i] = start->axis[0][i] * backLerp + end->axis[0][i] * frontLerp; - tag->axis[1][i] = start->axis[1][i] * backLerp + end->axis[1][i] * frontLerp; - tag->axis[2][i] = start->axis[2][i] * backLerp + end->axis[2][i] * frontLerp; - } - VectorNormalize( tag->axis[0] ); - VectorNormalize( tag->axis[1] ); - VectorNormalize( tag->axis[2] ); - return qtrue; -} - - -/* -==================== -R_ModelBounds -==================== -*/ -void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) { - model_t *model; - - model = R_GetModelByHandle( handle ); - - if(model->type == MOD_BRUSH) { - VectorCopy( model->bmodel->bounds[0], mins ); - VectorCopy( model->bmodel->bounds[1], maxs ); - - return; - } else if (model->type == MOD_MESH) { - mdvModel_t *header; - mdvFrame_t *frame; - - header = model->mdv[0]; - frame = header->frames; - - VectorCopy( frame->bounds[0], mins ); - VectorCopy( frame->bounds[1], maxs ); - - return; - } else if (model->type == MOD_MDR) { - mdrHeader_t *header; - mdrFrame_t *frame; - - header = (mdrHeader_t *)model->modelData; - frame = (mdrFrame_t *) ((byte *)header + header->ofsFrames); - - VectorCopy( frame->bounds[0], mins ); - VectorCopy( frame->bounds[1], maxs ); - - return; - } else if(model->type == MOD_IQM) { - iqmData_t *iqmData; - - iqmData = model->modelData; - - if(iqmData->bounds) - { - VectorCopy(iqmData->bounds, mins); - VectorCopy(iqmData->bounds + 3, maxs); - return; - } - } - - VectorClear( mins ); - VectorClear( maxs ); -} diff --git a/code/renderergl2/tr_model_iqm.c b/code/renderergl2/tr_model_iqm.c deleted file mode 100644 index b3843c5d8b..0000000000 --- a/code/renderergl2/tr_model_iqm.c +++ /dev/null @@ -1,1200 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2011 Thilo Schulz -Copyright (C) 2011 Matthias Bentrup - -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "tr_local.h" - -#define LL(x) x=LittleLong(x) - -// 3x4 identity matrix -static float identityMatrix[12] = { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0 -}; - -static qboolean IQM_CheckRange( iqmHeader_t *header, int offset, - int count,int size ) { - // return true if the range specified by offset, count and size - // doesn't fit into the file - return ( count <= 0 || - offset < 0 || - offset > header->filesize || - offset + count * size < 0 || - offset + count * size > header->filesize ); -} -// "multiply" 3x4 matrices, these are assumed to be the top 3 rows -// of a 4x4 matrix with the last row = (0 0 0 1) -static void Matrix34Multiply( float *a, float *b, float *out ) { - out[ 0] = a[0] * b[0] + a[1] * b[4] + a[ 2] * b[ 8]; - out[ 1] = a[0] * b[1] + a[1] * b[5] + a[ 2] * b[ 9]; - out[ 2] = a[0] * b[2] + a[1] * b[6] + a[ 2] * b[10]; - out[ 3] = a[0] * b[3] + a[1] * b[7] + a[ 2] * b[11] + a[ 3]; - out[ 4] = a[4] * b[0] + a[5] * b[4] + a[ 6] * b[ 8]; - out[ 5] = a[4] * b[1] + a[5] * b[5] + a[ 6] * b[ 9]; - out[ 6] = a[4] * b[2] + a[5] * b[6] + a[ 6] * b[10]; - out[ 7] = a[4] * b[3] + a[5] * b[7] + a[ 6] * b[11] + a[ 7]; - out[ 8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[ 8]; - out[ 9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[ 9]; - out[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10]; - out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11]; -} -static void Matrix34Multiply_OnlySetOrigin( float *a, float *b, float *out ) { - out[ 3] = a[0] * b[3] + a[1] * b[7] + a[ 2] * b[11] + a[ 3]; - out[ 7] = a[4] * b[3] + a[5] * b[7] + a[ 6] * b[11] + a[ 7]; - out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11]; -} -static void InterpolateMatrix( float *a, float *b, float lerp, float *mat ) { - float unLerp = 1.0f - lerp; - - mat[ 0] = a[ 0] * unLerp + b[ 0] * lerp; - mat[ 1] = a[ 1] * unLerp + b[ 1] * lerp; - mat[ 2] = a[ 2] * unLerp + b[ 2] * lerp; - mat[ 3] = a[ 3] * unLerp + b[ 3] * lerp; - mat[ 4] = a[ 4] * unLerp + b[ 4] * lerp; - mat[ 5] = a[ 5] * unLerp + b[ 5] * lerp; - mat[ 6] = a[ 6] * unLerp + b[ 6] * lerp; - mat[ 7] = a[ 7] * unLerp + b[ 7] * lerp; - mat[ 8] = a[ 8] * unLerp + b[ 8] * lerp; - mat[ 9] = a[ 9] * unLerp + b[ 9] * lerp; - mat[10] = a[10] * unLerp + b[10] * lerp; - mat[11] = a[11] * unLerp + b[11] * lerp; -} -static void JointToMatrix( vec4_t rot, vec3_t scale, vec3_t trans, - float *mat ) { - float xx = 2.0f * rot[0] * rot[0]; - float yy = 2.0f * rot[1] * rot[1]; - float zz = 2.0f * rot[2] * rot[2]; - float xy = 2.0f * rot[0] * rot[1]; - float xz = 2.0f * rot[0] * rot[2]; - float yz = 2.0f * rot[1] * rot[2]; - float wx = 2.0f * rot[3] * rot[0]; - float wy = 2.0f * rot[3] * rot[1]; - float wz = 2.0f * rot[3] * rot[2]; - - mat[ 0] = scale[0] * (1.0f - (yy + zz)); - mat[ 1] = scale[0] * (xy - wz); - mat[ 2] = scale[0] * (xz + wy); - mat[ 3] = trans[0]; - mat[ 4] = scale[1] * (xy + wz); - mat[ 5] = scale[1] * (1.0f - (xx + zz)); - mat[ 6] = scale[1] * (yz - wx); - mat[ 7] = trans[1]; - mat[ 8] = scale[2] * (xz - wy); - mat[ 9] = scale[2] * (yz + wx); - mat[10] = scale[2] * (1.0f - (xx + yy)); - mat[11] = trans[2]; -} -static void Matrix34Invert( float *inMat, float *outMat ) -{ - vec3_t trans; - float invSqrLen, *v; - - outMat[ 0] = inMat[ 0]; outMat[ 1] = inMat[ 4]; outMat[ 2] = inMat[ 8]; - outMat[ 4] = inMat[ 1]; outMat[ 5] = inMat[ 5]; outMat[ 6] = inMat[ 9]; - outMat[ 8] = inMat[ 2]; outMat[ 9] = inMat[ 6]; outMat[10] = inMat[10]; - - v = outMat + 0; invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v); - v = outMat + 4; invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v); - v = outMat + 8; invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v); - - trans[0] = inMat[ 3]; - trans[1] = inMat[ 7]; - trans[2] = inMat[11]; - - outMat[ 3] = -DotProduct(outMat + 0, trans); - outMat[ 7] = -DotProduct(outMat + 4, trans); - outMat[11] = -DotProduct(outMat + 8, trans); -} - -/* -================= -R_LoadIQM - -Load an IQM model and compute the joint matrices for every frame. -================= -*/ -qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_name ) { - iqmHeader_t *header; - iqmVertexArray_t *vertexarray; - iqmTriangle_t *triangle; - iqmMesh_t *mesh; - iqmJoint_t *joint; - iqmPose_t *pose; - iqmBounds_t *bounds; - unsigned short *framedata; - char *str; - int i, j; - float jointInvMats[IQM_MAX_JOINTS * 12]; - float *mat, *matInv; - size_t size, joint_names; - iqmData_t *iqmData; - srfIQModel_t *surface; - char meshName[MAX_QPATH]; - byte blendIndexesType, blendWeightsType; - - if( filesize < sizeof(iqmHeader_t) ) { - return qfalse; - } - - header = (iqmHeader_t *)buffer; - if( Q_strncmp( header->magic, IQM_MAGIC, sizeof(header->magic) ) ) { - return qfalse; - } - - LL( header->version ); - if( header->version != IQM_VERSION ) { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s is a unsupported IQM version (%d), only version %d is supported.\n", - mod_name, header->version, IQM_VERSION); - return qfalse; - } - - LL( header->filesize ); - if( header->filesize > filesize || header->filesize > 16<<20 ) { - return qfalse; - } - - LL( header->flags ); - LL( header->num_text ); - LL( header->ofs_text ); - LL( header->num_meshes ); - LL( header->ofs_meshes ); - LL( header->num_vertexarrays ); - LL( header->num_vertexes ); - LL( header->ofs_vertexarrays ); - LL( header->num_triangles ); - LL( header->ofs_triangles ); - LL( header->ofs_adjacency ); - LL( header->num_joints ); - LL( header->ofs_joints ); - LL( header->num_poses ); - LL( header->ofs_poses ); - LL( header->num_anims ); - LL( header->ofs_anims ); - LL( header->num_frames ); - LL( header->num_framechannels ); - LL( header->ofs_frames ); - LL( header->ofs_bounds ); - LL( header->num_comment ); - LL( header->ofs_comment ); - LL( header->num_extensions ); - LL( header->ofs_extensions ); - - // check ioq3 joint limit - if ( header->num_joints > IQM_MAX_JOINTS ) { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %d joints (%d).\n", - mod_name, IQM_MAX_JOINTS, header->num_joints); - return qfalse; - } - - blendIndexesType = blendWeightsType = IQM_UBYTE; - - // check and swap vertex arrays - if( IQM_CheckRange( header, header->ofs_vertexarrays, - header->num_vertexarrays, - sizeof(iqmVertexArray_t) ) ) { - return qfalse; - } - vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays); - for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) { - int n, *intPtr; - - if( vertexarray->size <= 0 || vertexarray->size > 4 ) { - return qfalse; - } - - // total number of values - n = header->num_vertexes * vertexarray->size; - - switch( vertexarray->format ) { - case IQM_BYTE: - case IQM_UBYTE: - // 1 byte, no swapping necessary - if( IQM_CheckRange( header, vertexarray->offset, - n, sizeof(byte) ) ) { - return qfalse; - } - break; - case IQM_INT: - case IQM_UINT: - case IQM_FLOAT: - // 4-byte swap - if( IQM_CheckRange( header, vertexarray->offset, - n, sizeof(float) ) ) { - return qfalse; - } - intPtr = (int *)((byte *)header + vertexarray->offset); - for( j = 0; j < n; j++, intPtr++ ) { - LL( *intPtr ); - } - break; - default: - // not supported - return qfalse; - break; - } - - switch( vertexarray->type ) { - case IQM_POSITION: - case IQM_NORMAL: - if( vertexarray->format != IQM_FLOAT || - vertexarray->size != 3 ) { - return qfalse; - } - break; - case IQM_TANGENT: - if( vertexarray->format != IQM_FLOAT || - vertexarray->size != 4 ) { - return qfalse; - } - break; - case IQM_TEXCOORD: - if( vertexarray->format != IQM_FLOAT || - vertexarray->size != 2 ) { - return qfalse; - } - break; - case IQM_BLENDINDEXES: - if( (vertexarray->format != IQM_INT && - vertexarray->format != IQM_UBYTE) || - vertexarray->size != 4 ) { - return qfalse; - } - blendIndexesType = vertexarray->format; - break; - case IQM_BLENDWEIGHTS: - if( (vertexarray->format != IQM_FLOAT && - vertexarray->format != IQM_UBYTE) || - vertexarray->size != 4 ) { - return qfalse; - } - blendWeightsType = vertexarray->format; - break; - case IQM_COLOR: - if( vertexarray->format != IQM_UBYTE || - vertexarray->size != 4 ) { - return qfalse; - } - break; - } - } - - // check and swap triangles - if( IQM_CheckRange( header, header->ofs_triangles, - header->num_triangles, sizeof(iqmTriangle_t) ) ) { - return qfalse; - } - triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles); - for( i = 0; i < header->num_triangles; i++, triangle++ ) { - LL( triangle->vertex[0] ); - LL( triangle->vertex[1] ); - LL( triangle->vertex[2] ); - - if( triangle->vertex[0] > header->num_vertexes || - triangle->vertex[1] > header->num_vertexes || - triangle->vertex[2] > header->num_vertexes ) { - return qfalse; - } - } - - // check and swap meshes - if( IQM_CheckRange( header, header->ofs_meshes, - header->num_meshes, sizeof(iqmMesh_t) ) ) { - return qfalse; - } - mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes); - for( i = 0; i < header->num_meshes; i++, mesh++) { - LL( mesh->name ); - LL( mesh->material ); - LL( mesh->first_vertex ); - LL( mesh->num_vertexes ); - LL( mesh->first_triangle ); - LL( mesh->num_triangles ); - - if ( mesh->name < header->num_text ) { - Q_strncpyz( meshName, (char*)header + header->ofs_text + mesh->name, sizeof (meshName) ); - } else { - meshName[0] = '\0'; - } - - // check ioq3 limits - if ( mesh->num_vertexes >= SHADER_MAX_VERTEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on %s (%i).\n", - mod_name, SHADER_MAX_VERTEXES - 1, meshName[0] ? meshName : "a surface", - mesh->num_vertexes ); - return qfalse; - } - if ( mesh->num_triangles*3 >= SHADER_MAX_INDEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on %s (%i).\n", - mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, meshName[0] ? meshName : "a surface", - mesh->num_triangles ); - return qfalse; - } - - if( mesh->first_vertex >= header->num_vertexes || - mesh->first_vertex + mesh->num_vertexes > header->num_vertexes || - mesh->first_triangle >= header->num_triangles || - mesh->first_triangle + mesh->num_triangles > header->num_triangles || - mesh->name >= header->num_text || - mesh->material >= header->num_text ) { - return qfalse; - } - } - - if( header->num_poses != header->num_joints && header->num_poses != 0 ) { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has %d poses and %d joints, must have the same number or 0 poses\n", - mod_name, header->num_poses, header->num_joints ); - return qfalse; - } - - joint_names = 0; - - if ( header->num_joints ) - { - // check and swap joints - if( IQM_CheckRange( header, header->ofs_joints, - header->num_joints, sizeof(iqmJoint_t) ) ) { - return qfalse; - } - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - LL( joint->name ); - LL( joint->parent ); - LL( joint->translate[0] ); - LL( joint->translate[1] ); - LL( joint->translate[2] ); - LL( joint->rotate[0] ); - LL( joint->rotate[1] ); - LL( joint->rotate[2] ); - LL( joint->rotate[3] ); - LL( joint->scale[0] ); - LL( joint->scale[1] ); - LL( joint->scale[2] ); - - if( joint->parent < -1 || - joint->parent >= (int)header->num_joints || - joint->name >= (int)header->num_text ) { - return qfalse; - } - joint_names += strlen( (char *)header + header->ofs_text + - joint->name ) + 1; - } - } - - if ( header->num_poses ) - { - // check and swap poses - if( IQM_CheckRange( header, header->ofs_poses, - header->num_poses, sizeof(iqmPose_t) ) ) { - return qfalse; - } - pose = (iqmPose_t *)((byte *)header + header->ofs_poses); - for( i = 0; i < header->num_poses; i++, pose++ ) { - LL( pose->parent ); - LL( pose->mask ); - LL( pose->channeloffset[0] ); - LL( pose->channeloffset[1] ); - LL( pose->channeloffset[2] ); - LL( pose->channeloffset[3] ); - LL( pose->channeloffset[4] ); - LL( pose->channeloffset[5] ); - LL( pose->channeloffset[6] ); - LL( pose->channeloffset[7] ); - LL( pose->channeloffset[8] ); - LL( pose->channeloffset[9] ); - LL( pose->channelscale[0] ); - LL( pose->channelscale[1] ); - LL( pose->channelscale[2] ); - LL( pose->channelscale[3] ); - LL( pose->channelscale[4] ); - LL( pose->channelscale[5] ); - LL( pose->channelscale[6] ); - LL( pose->channelscale[7] ); - LL( pose->channelscale[8] ); - LL( pose->channelscale[9] ); - } - } - - if (header->ofs_bounds) - { - // check and swap model bounds - if(IQM_CheckRange(header, header->ofs_bounds, - header->num_frames, sizeof(*bounds))) - { - return qfalse; - } - bounds = (iqmBounds_t *) ((byte *) header + header->ofs_bounds); - for(i = 0; i < header->num_frames; i++) - { - LL(bounds->bbmin[0]); - LL(bounds->bbmin[1]); - LL(bounds->bbmin[2]); - LL(bounds->bbmax[0]); - LL(bounds->bbmax[1]); - LL(bounds->bbmax[2]); - - bounds++; - } - } - - // allocate the model and copy the data - size = sizeof(iqmData_t); - size += header->num_meshes * sizeof( srfIQModel_t ); - size += header->num_joints * 12 * sizeof( float ); // joint mats - size += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats - if(header->ofs_bounds) - size += header->num_frames * 6 * sizeof(float); // model bounds - size += header->num_vertexes * 3 * sizeof(float); // positions - size += header->num_vertexes * 2 * sizeof(float); // texcoords - size += header->num_vertexes * 3 * sizeof(float); // normals - size += header->num_vertexes * 4 * sizeof(float); // tangents - size += header->num_vertexes * 4 * sizeof(byte); // blendIndexes - size += header->num_vertexes * 4 * sizeof(byte); // colors - size += header->num_joints * sizeof(int); // parents - size += header->num_triangles * 3 * sizeof(int); // triangles - size += joint_names; // joint names - - // blendWeights - if (blendWeightsType == IQM_FLOAT) { - size += header->num_vertexes * 4 * sizeof(float); - } else { - size += header->num_vertexes * 4 * sizeof(byte); - } - - mod->type = MOD_IQM; - iqmData = (iqmData_t *)ri.Hunk_Alloc( size, h_low ); - mod->modelData = iqmData; - - // fill header - iqmData->num_vertexes = header->num_vertexes; - iqmData->num_triangles = header->num_triangles; - iqmData->num_frames = header->num_frames; - iqmData->num_surfaces = header->num_meshes; - iqmData->num_joints = header->num_joints; - iqmData->num_poses = header->num_poses; - iqmData->blendWeightsType = blendWeightsType; - iqmData->surfaces = (srfIQModel_t *)(iqmData + 1); - iqmData->jointMats = (float *) (iqmData->surfaces + iqmData->num_surfaces); - iqmData->poseMats = iqmData->jointMats + 12 * header->num_joints; - if(header->ofs_bounds) - { - iqmData->bounds = iqmData->poseMats + 12 * header->num_poses * header->num_frames; - iqmData->positions = iqmData->bounds + 6 * header->num_frames; - } - else - iqmData->positions = iqmData->poseMats + 12 * header->num_poses * header->num_frames; - iqmData->texcoords = iqmData->positions + 3 * header->num_vertexes; - iqmData->normals = iqmData->texcoords + 2 * header->num_vertexes; - iqmData->tangents = iqmData->normals + 3 * header->num_vertexes; - iqmData->blendIndexes = (byte *)(iqmData->tangents + 4 * header->num_vertexes); - - if(blendWeightsType == IQM_FLOAT) { - iqmData->blendWeights.f = (float *)(iqmData->blendIndexes + 4 * header->num_vertexes); - iqmData->colors = (byte *)(iqmData->blendWeights.f + 4 * header->num_vertexes); - } else { - iqmData->blendWeights.b = iqmData->blendIndexes + 4 * header->num_vertexes; - iqmData->colors = iqmData->blendWeights.b + 4 * header->num_vertexes; - } - - iqmData->jointParents = (int *)(iqmData->colors + 4 * header->num_vertexes); - iqmData->triangles = iqmData->jointParents + header->num_joints; - iqmData->names = (char *)(iqmData->triangles + 3 * header->num_triangles); - - if ( header->num_joints == 0 ) - iqmData->jointMats = NULL; - - if ( header->num_poses == 0 ) - iqmData->poseMats = NULL; - - // calculate joint matrices and their inverses - // joint inverses are needed only until the pose matrices are calculated - mat = iqmData->jointMats; - matInv = jointInvMats; - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - float baseFrame[12], invBaseFrame[12]; - - JointToMatrix( joint->rotate, joint->scale, joint->translate, baseFrame ); - Matrix34Invert( baseFrame, invBaseFrame ); - - if ( joint->parent >= 0 ) - { - Matrix34Multiply( iqmData->jointMats + 12 * joint->parent, baseFrame, mat ); - mat += 12; - Matrix34Multiply( invBaseFrame, jointInvMats + 12 * joint->parent, matInv ); - matInv += 12; - } - else - { - Com_Memcpy( mat, baseFrame, sizeof(baseFrame) ); - mat += 12; - Com_Memcpy( matInv, invBaseFrame, sizeof(invBaseFrame) ); - matInv += 12; - } - } - - // calculate pose matrices - framedata = (unsigned short *)((byte *)header + header->ofs_frames); - mat = iqmData->poseMats; - for( i = 0; i < header->num_frames; i++ ) { - pose = (iqmPose_t *)((byte *)header + header->ofs_poses); - for( j = 0; j < header->num_poses; j++, pose++ ) { - vec3_t translate; - vec4_t rotate; - vec3_t scale; - float mat1[12], mat2[12]; - - translate[0] = pose->channeloffset[0]; - if( pose->mask & 0x001) - translate[0] += *framedata++ * pose->channelscale[0]; - translate[1] = pose->channeloffset[1]; - if( pose->mask & 0x002) - translate[1] += *framedata++ * pose->channelscale[1]; - translate[2] = pose->channeloffset[2]; - if( pose->mask & 0x004) - translate[2] += *framedata++ * pose->channelscale[2]; - - rotate[0] = pose->channeloffset[3]; - if( pose->mask & 0x008) - rotate[0] += *framedata++ * pose->channelscale[3]; - rotate[1] = pose->channeloffset[4]; - if( pose->mask & 0x010) - rotate[1] += *framedata++ * pose->channelscale[4]; - rotate[2] = pose->channeloffset[5]; - if( pose->mask & 0x020) - rotate[2] += *framedata++ * pose->channelscale[5]; - rotate[3] = pose->channeloffset[6]; - if( pose->mask & 0x040) - rotate[3] += *framedata++ * pose->channelscale[6]; - - scale[0] = pose->channeloffset[7]; - if( pose->mask & 0x080) - scale[0] += *framedata++ * pose->channelscale[7]; - scale[1] = pose->channeloffset[8]; - if( pose->mask & 0x100) - scale[1] += *framedata++ * pose->channelscale[8]; - scale[2] = pose->channeloffset[9]; - if( pose->mask & 0x200) - scale[2] += *framedata++ * pose->channelscale[9]; - - // construct transformation matrix - JointToMatrix( rotate, scale, translate, mat1 ); - - if( pose->parent >= 0 ) { - Matrix34Multiply( iqmData->jointMats + 12 * pose->parent, - mat1, mat2 ); - } else { - Com_Memcpy( mat2, mat1, sizeof(mat1) ); - } - - Matrix34Multiply( mat2, jointInvMats + 12 * j, mat ); - mat += 12; - } - } - - // register shaders - // overwrite the material offset with the shader index - mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes); - surface = iqmData->surfaces; - str = (char *)header + header->ofs_text; - for( i = 0; i < header->num_meshes; i++, mesh++, surface++ ) { - surface->surfaceType = SF_IQM; - Q_strncpyz(surface->name, str + mesh->name, sizeof (surface->name)); - Q_strlwr(surface->name); // lowercase the surface name so skin compares are faster - surface->shader = R_FindShader( str + mesh->material, LIGHTMAP_NONE, qtrue ); - if( surface->shader->defaultShader ) - surface->shader = tr.defaultShader; - surface->data = iqmData; - surface->first_vertex = mesh->first_vertex; - surface->num_vertexes = mesh->num_vertexes; - surface->first_triangle = mesh->first_triangle; - surface->num_triangles = mesh->num_triangles; - } - - // copy vertexarrays and indexes - vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays); - for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) { - int n; - - // total number of values - n = header->num_vertexes * vertexarray->size; - - switch( vertexarray->type ) { - case IQM_POSITION: - Com_Memcpy( iqmData->positions, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_NORMAL: - Com_Memcpy( iqmData->normals, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_TANGENT: - Com_Memcpy( iqmData->tangents, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_TEXCOORD: - Com_Memcpy( iqmData->texcoords, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_BLENDINDEXES: - if( blendIndexesType == IQM_INT ) { - int *data = (int*)((byte*)header + vertexarray->offset); - for ( j = 0; j < n; j++ ) { - iqmData->blendIndexes[j] = (byte)data[j]; - } - } else { - Com_Memcpy( iqmData->blendIndexes, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); - } - break; - case IQM_BLENDWEIGHTS: - if( blendWeightsType == IQM_FLOAT ) { - Com_Memcpy( iqmData->blendWeights.f, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - } else { - Com_Memcpy( iqmData->blendWeights.b, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); - } - break; - case IQM_COLOR: - Com_Memcpy( iqmData->colors, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); - break; - } - } - - // copy joint parents - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - iqmData->jointParents[i] = joint->parent; - } - - // copy triangles - triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles); - for( i = 0; i < header->num_triangles; i++, triangle++ ) { - iqmData->triangles[3*i+0] = triangle->vertex[0]; - iqmData->triangles[3*i+1] = triangle->vertex[1]; - iqmData->triangles[3*i+2] = triangle->vertex[2]; - } - - // copy joint names - str = iqmData->names; - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - char *name = (char *)header + header->ofs_text + - joint->name; - int len = strlen( name ) + 1; - Com_Memcpy( str, name, len ); - str += len; - } - - // copy model bounds - if(header->ofs_bounds) - { - mat = iqmData->bounds; - bounds = (iqmBounds_t *) ((byte *) header + header->ofs_bounds); - for(i = 0; i < header->num_frames; i++) - { - mat[0] = bounds->bbmin[0]; - mat[1] = bounds->bbmin[1]; - mat[2] = bounds->bbmin[2]; - mat[3] = bounds->bbmax[0]; - mat[4] = bounds->bbmax[1]; - mat[5] = bounds->bbmax[2]; - - mat += 6; - bounds++; - } - } - - return qtrue; -} - -/* -============= -R_CullIQM -============= -*/ -static int R_CullIQM( iqmData_t *data, trRefEntity_t *ent ) { - vec3_t bounds[2]; - vec_t *oldBounds, *newBounds; - int i; - - if (!data->bounds) { - tr.pc.c_box_cull_md3_clip++; - return CULL_CLIP; - } - - // compute bounds pointers - oldBounds = data->bounds + 6*ent->e.oldframe; - newBounds = data->bounds + 6*ent->e.frame; - - // calculate a bounding box in the current coordinate system - for (i = 0 ; i < 3 ; i++) { - bounds[0][i] = oldBounds[i] < newBounds[i] ? oldBounds[i] : newBounds[i]; - bounds[1][i] = oldBounds[i+3] > newBounds[i+3] ? oldBounds[i+3] : newBounds[i+3]; - } - - switch ( R_CullLocalBox( bounds ) ) - { - case CULL_IN: - tr.pc.c_box_cull_md3_in++; - return CULL_IN; - case CULL_CLIP: - tr.pc.c_box_cull_md3_clip++; - return CULL_CLIP; - case CULL_OUT: - default: - tr.pc.c_box_cull_md3_out++; - return CULL_OUT; - } -} - -/* -================= -R_ComputeIQMFogNum - -================= -*/ -int R_ComputeIQMFogNum( iqmData_t *data, trRefEntity_t *ent ) { - int i, j; - fog_t *fog; - const vec_t *bounds; - const vec_t defaultBounds[6] = { -8, -8, -8, 8, 8, 8 }; - vec3_t diag, center; - vec3_t localOrigin; - vec_t radius; - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return 0; - } - - // FIXME: non-normalized axis issues - if (data->bounds) { - bounds = data->bounds + 6*ent->e.frame; - } else { - bounds = defaultBounds; - } - VectorSubtract( bounds+3, bounds, diag ); - VectorMA( bounds, 0.5f, diag, center ); - VectorAdd( ent->e.origin, center, localOrigin ); - radius = 0.5f * VectorLength( diag ); - - for ( i = 1 ; i < tr.world->numfogs ; i++ ) { - fog = &tr.world->fogs[i]; - for ( j = 0 ; j < 3 ; j++ ) { - if ( localOrigin[j] - radius >= fog->bounds[1][j] ) { - break; - } - if ( localOrigin[j] + radius <= fog->bounds[0][j] ) { - break; - } - } - if ( j == 3 ) { - return i; - } - } - - return 0; -} - -/* -================= -R_AddIQMSurfaces - -Add all surfaces of this model -================= -*/ -void R_AddIQMSurfaces( trRefEntity_t *ent ) { - iqmData_t *data; - srfIQModel_t *surface; - int i, j; - qboolean personalModel; - int cull; - int fogNum; - int cubemapIndex; - shader_t *shader; - skin_t *skin; - - data = tr.currentModel->modelData; - surface = data->surfaces; - - // don't add third_person objects if not in a portal - personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; - - if ( ent->e.renderfx & RF_WRAP_FRAMES ) { - ent->e.frame %= data->num_frames; - ent->e.oldframe %= data->num_frames; - } - - // - // Validate the frames so there is no chance of a crash. - // This will write directly into the entity structure, so - // when the surfaces are rendered, they don't need to be - // range checked again. - // - if ( (ent->e.frame >= data->num_frames) - || (ent->e.frame < 0) - || (ent->e.oldframe >= data->num_frames) - || (ent->e.oldframe < 0) ) { - ri.Printf( PRINT_DEVELOPER, "R_AddIQMSurfaces: no such frame %d to %d for '%s'\n", - ent->e.oldframe, ent->e.frame, - tr.currentModel->name ); - ent->e.frame = 0; - ent->e.oldframe = 0; - } - - // - // cull the entire model if merged bounding box of both frames - // is outside the view frustum. - // - cull = R_CullIQM ( data, ent ); - if ( cull == CULL_OUT ) { - return; - } - - // - // set up lighting now that we know we aren't culled - // - if ( !personalModel || r_shadows->integer > 1 ) { - R_SetupEntityLighting( &tr.refdef, ent ); - } - - // - // see if we are in a fog volume - // - fogNum = R_ComputeIQMFogNum( data, ent ); - - cubemapIndex = R_CubemapForPoint(ent->e.origin); - - for ( i = 0 ; i < data->num_surfaces ; i++ ) { - if(ent->e.customShader) - shader = R_GetShaderByHandle( ent->e.customShader ); - else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins) - { - skin = R_GetSkinByHandle(ent->e.customSkin); - shader = tr.defaultShader; - - for(j = 0; j < skin->numSurfaces; j++) - { - if (!strcmp(skin->surfaces[j]->name, surface->name)) - { - shader = skin->surfaces[j]->shader; - break; - } - } - } else { - shader = surface->shader; - } - - // we will add shadows even if the main object isn't visible in the view - - // stencil shadows can't do personal models unless I polyhedron clip - if ( !personalModel - && r_shadows->integer == 2 - && fogNum == 0 - && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) - && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, 0, 0, 0 ); - } - - // projection shadows work fine with personal models - if ( r_shadows->integer == 3 - && fogNum == 0 - && (ent->e.renderfx & RF_SHADOW_PLANE ) - && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, 0, 0, 0 ); - } - - if( !personalModel ) { - R_AddDrawSurf( (void *)surface, shader, fogNum, 0, 0, cubemapIndex ); - } - - surface++; - } -} - - -static void ComputePoseMats( iqmData_t *data, int frame, int oldframe, - float backlerp, float *mat ) { - float *mat1, *mat2; - int *joint = data->jointParents; - int i; - - if ( data->num_poses == 0 ) { - for( i = 0; i < data->num_joints; i++, joint++ ) { - if( *joint >= 0 ) { - Matrix34Multiply( mat + 12 * *joint, - identityMatrix, mat + 12*i ); - } else { - Com_Memcpy( mat + 12*i, identityMatrix, 12 * sizeof(float) ); - } - } - return; - } - - if ( oldframe == frame ) { - mat1 = data->poseMats + 12 * data->num_poses * frame; - for( i = 0; i < data->num_poses; i++, joint++ ) { - if( *joint >= 0 ) { - Matrix34Multiply( mat + 12 * *joint, - mat1 + 12*i, mat + 12*i ); - } else { - Com_Memcpy( mat + 12*i, mat1 + 12*i, 12 * sizeof(float) ); - } - } - } else { - mat1 = data->poseMats + 12 * data->num_poses * frame; - mat2 = data->poseMats + 12 * data->num_poses * oldframe; - - for( i = 0; i < data->num_poses; i++, joint++ ) { - if( *joint >= 0 ) { - float tmpMat[12]; - InterpolateMatrix( mat1 + 12*i, mat2 + 12*i, - backlerp, tmpMat ); - Matrix34Multiply( mat + 12 * *joint, - tmpMat, mat + 12*i ); - - } else { - InterpolateMatrix( mat1 + 12*i, mat2 + 12*i, - backlerp, mat ); - } - } - } -} - -static void ComputeJointMats( iqmData_t *data, int frame, int oldframe, - float backlerp, float *mat ) { - float *mat1; - int i; - - ComputePoseMats( data, frame, oldframe, backlerp, mat ); - - for( i = 0; i < data->num_joints; i++ ) { - float outmat[12]; - mat1 = mat + 12 * i; - - Com_Memcpy(outmat, mat1, sizeof(outmat)); - - Matrix34Multiply_OnlySetOrigin( outmat, data->jointMats + 12 * i, mat1 ); - } -} - - -/* -================= -RB_AddIQMSurfaces - -Compute vertices for this model surface -================= -*/ -void RB_IQMSurfaceAnim( surfaceType_t *surface ) { - srfIQModel_t *surf = (srfIQModel_t *)surface; - iqmData_t *data = surf->data; - float jointMats[IQM_MAX_JOINTS * 12]; - int i; - - vec4_t *outXYZ; - uint32_t *outNormal; -#ifdef USE_VERT_TANGENT_SPACE - uint32_t *outTangent; -#endif - vec2_t (*outTexCoord)[2]; - vec4_t *outColor; - - int frame = data->num_frames ? backEnd.currentEntity->e.frame % data->num_frames : 0; - int oldframe = data->num_frames ? backEnd.currentEntity->e.oldframe % data->num_frames : 0; - float backlerp = backEnd.currentEntity->e.backlerp; - - int *tri; - glIndex_t *ptr; - glIndex_t base; - - RB_CHECKOVERFLOW( surf->num_vertexes, surf->num_triangles * 3 ); - - outXYZ = &tess.xyz[tess.numVertexes]; - outNormal = &tess.normal[tess.numVertexes]; -#ifdef USE_VERT_TANGENT_SPACE - outTangent = &tess.tangent[tess.numVertexes]; -#endif - outTexCoord = &tess.texCoords[tess.numVertexes]; - outColor = &tess.vertexColors[tess.numVertexes]; - - // compute interpolated joint matrices - if ( data->num_poses > 0 ) { - ComputePoseMats( data, frame, oldframe, backlerp, jointMats ); - } - - // transform vertexes and fill other data - for( i = 0; i < surf->num_vertexes; - i++, outXYZ++, outNormal++, outTexCoord++, outColor++ ) { - int j, k; - float vtxMat[12]; - float nrmMat[9]; - int vtx = i + surf->first_vertex; - float blendWeights[4]; - int numWeights; - - for ( numWeights = 0; numWeights < 4; numWeights++ ) { - if ( data->blendWeightsType == IQM_FLOAT ) - blendWeights[numWeights] = data->blendWeights.f[4*vtx + numWeights]; - else - blendWeights[numWeights] = (float)data->blendWeights.b[4*vtx + numWeights] / 255.0f; - - if ( blendWeights[numWeights] <= 0 ) - break; - } - - if ( data->num_poses == 0 || numWeights == 0 ) { - // no blend joint, use identity matrix. - Com_Memcpy( vtxMat, identityMatrix, 12 * sizeof (float) ); - } else { - // compute the vertex matrix by blending the up to - // four blend weights - Com_Memset( vtxMat, 0, 12 * sizeof (float) ); - for( j = 0; j < numWeights; j++ ) { - for( k = 0; k < 12; k++ ) { - vtxMat[k] += blendWeights[j] * jointMats[12*data->blendIndexes[4*vtx + j] + k]; - } - } - } - - // compute the normal matrix as transpose of the adjoint - // of the vertex matrix - nrmMat[ 0] = vtxMat[ 5]*vtxMat[10] - vtxMat[ 6]*vtxMat[ 9]; - nrmMat[ 1] = vtxMat[ 6]*vtxMat[ 8] - vtxMat[ 4]*vtxMat[10]; - nrmMat[ 2] = vtxMat[ 4]*vtxMat[ 9] - vtxMat[ 5]*vtxMat[ 8]; - nrmMat[ 3] = vtxMat[ 2]*vtxMat[ 9] - vtxMat[ 1]*vtxMat[10]; - nrmMat[ 4] = vtxMat[ 0]*vtxMat[10] - vtxMat[ 2]*vtxMat[ 8]; - nrmMat[ 5] = vtxMat[ 1]*vtxMat[ 8] - vtxMat[ 0]*vtxMat[ 9]; - nrmMat[ 6] = vtxMat[ 1]*vtxMat[ 6] - vtxMat[ 2]*vtxMat[ 5]; - nrmMat[ 7] = vtxMat[ 2]*vtxMat[ 4] - vtxMat[ 0]*vtxMat[ 6]; - nrmMat[ 8] = vtxMat[ 0]*vtxMat[ 5] - vtxMat[ 1]*vtxMat[ 4]; - - (*outTexCoord)[0][0] = data->texcoords[2*vtx + 0]; - (*outTexCoord)[0][1] = data->texcoords[2*vtx + 1]; - (*outTexCoord)[1][0] = (*outTexCoord)[0][0]; - (*outTexCoord)[1][1] = (*outTexCoord)[0][1]; - - (*outXYZ)[0] = - vtxMat[ 0] * data->positions[3*vtx+0] + - vtxMat[ 1] * data->positions[3*vtx+1] + - vtxMat[ 2] * data->positions[3*vtx+2] + - vtxMat[ 3]; - (*outXYZ)[1] = - vtxMat[ 4] * data->positions[3*vtx+0] + - vtxMat[ 5] * data->positions[3*vtx+1] + - vtxMat[ 6] * data->positions[3*vtx+2] + - vtxMat[ 7]; - (*outXYZ)[2] = - vtxMat[ 8] * data->positions[3*vtx+0] + - vtxMat[ 9] * data->positions[3*vtx+1] + - vtxMat[10] * data->positions[3*vtx+2] + - vtxMat[11]; - (*outXYZ)[3] = 1.0f; - - { - vec3_t normal; - vec4_t tangent; - - normal[0] = DotProduct(&nrmMat[0], &data->normals[3*vtx]); - normal[1] = DotProduct(&nrmMat[3], &data->normals[3*vtx]); - normal[2] = DotProduct(&nrmMat[6], &data->normals[3*vtx]); - - *outNormal = R_VboPackNormal(normal); - -#ifdef USE_VERT_TANGENT_SPACE - tangent[0] = DotProduct(&nrmMat[0], &data->tangents[4*vtx]); - tangent[1] = DotProduct(&nrmMat[3], &data->tangents[4*vtx]); - tangent[2] = DotProduct(&nrmMat[6], &data->tangents[4*vtx]); - tangent[3] = data->tangents[4*vtx+3]; - - *outTangent++ = R_VboPackTangent(tangent); -#endif - } - - (*outColor)[0] = data->colors[4*vtx+0] / 255.0f; - (*outColor)[1] = data->colors[4*vtx+1] / 255.0f; - (*outColor)[2] = data->colors[4*vtx+2] / 255.0f; - (*outColor)[3] = data->colors[4*vtx+3] / 255.0f; - } - - tri = data->triangles + 3 * surf->first_triangle; - ptr = &tess.indexes[tess.numIndexes]; - base = tess.numVertexes; - - for( i = 0; i < surf->num_triangles; i++ ) { - *ptr++ = base + (*tri++ - surf->first_vertex); - *ptr++ = base + (*tri++ - surf->first_vertex); - *ptr++ = base + (*tri++ - surf->first_vertex); - } - - tess.numIndexes += 3 * surf->num_triangles; - tess.numVertexes += surf->num_vertexes; -} - -int R_IQMLerpTag( orientation_t *tag, iqmData_t *data, - int startFrame, int endFrame, - float frac, const char *tagName ) { - float jointMats[IQM_MAX_JOINTS * 12]; - int joint; - char *names = data->names; - - // get joint number by reading the joint names - for( joint = 0; joint < data->num_joints; joint++ ) { - if( !strcmp( tagName, names ) ) - break; - names += strlen( names ) + 1; - } - if( joint >= data->num_joints ) { - AxisClear( tag->axis ); - VectorClear( tag->origin ); - return qfalse; - } - - ComputeJointMats( data, startFrame, endFrame, frac, jointMats ); - - tag->axis[0][0] = jointMats[12 * joint + 0]; - tag->axis[1][0] = jointMats[12 * joint + 1]; - tag->axis[2][0] = jointMats[12 * joint + 2]; - tag->origin[0] = jointMats[12 * joint + 3]; - tag->axis[0][1] = jointMats[12 * joint + 4]; - tag->axis[1][1] = jointMats[12 * joint + 5]; - tag->axis[2][1] = jointMats[12 * joint + 6]; - tag->origin[1] = jointMats[12 * joint + 7]; - tag->axis[0][2] = jointMats[12 * joint + 8]; - tag->axis[1][2] = jointMats[12 * joint + 9]; - tag->axis[2][2] = jointMats[12 * joint + 10]; - tag->origin[2] = jointMats[12 * joint + 11]; - - return qtrue; -} diff --git a/code/renderergl2/tr_postprocess.c b/code/renderergl2/tr_postprocess.c deleted file mode 100644 index 35982fcec9..0000000000 --- a/code/renderergl2/tr_postprocess.c +++ /dev/null @@ -1,523 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2011 Andrei Drexler, Richard Allen, James Canete - -This file is part of Reaction source code. - -Reaction 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. - -Reaction 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 Reaction source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "tr_local.h" - -void RB_ToneMap(FBO_t *hdrFbo, ivec4_t hdrBox, FBO_t *ldrFbo, ivec4_t ldrBox, int autoExposure) -{ - ivec4_t srcBox, dstBox; - vec4_t color; - static int lastFrameCount = 0; - - if (autoExposure) - { - if (lastFrameCount == 0 || tr.frameCount < lastFrameCount || tr.frameCount - lastFrameCount > 5) - { - // determine average log luminance - FBO_t *srcFbo, *dstFbo, *tmp; - int size = 256; - - lastFrameCount = tr.frameCount; - - VectorSet4(dstBox, 0, 0, size, size); - - FBO_Blit(hdrFbo, hdrBox, NULL, tr.textureScratchFbo[0], dstBox, &tr.calclevels4xShader[0], NULL, 0); - - srcFbo = tr.textureScratchFbo[0]; - dstFbo = tr.textureScratchFbo[1]; - - // downscale to 1x1 texture - while (size > 1) - { - VectorSet4(srcBox, 0, 0, size, size); - //size >>= 2; - size >>= 1; - VectorSet4(dstBox, 0, 0, size, size); - - if (size == 1) - dstFbo = tr.targetLevelsFbo; - - //FBO_Blit(targetFbo, srcBox, NULL, tr.textureScratchFbo[nextScratch], dstBox, &tr.calclevels4xShader[1], NULL, 0); - FBO_FastBlit(srcFbo, srcBox, dstFbo, dstBox, GL_COLOR_BUFFER_BIT, GL_LINEAR); - - tmp = srcFbo; - srcFbo = dstFbo; - dstFbo = tmp; - } - } - - // blend with old log luminance for gradual change - VectorSet4(srcBox, 0, 0, 0, 0); - - color[0] = - color[1] = - color[2] = 1.0f; - if (glRefConfig.textureFloat) - color[3] = 0.03f; - else - color[3] = 0.1f; - - FBO_Blit(tr.targetLevelsFbo, srcBox, NULL, tr.calcLevelsFbo, NULL, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); - } - - // tonemap - color[0] = - color[1] = - color[2] = pow(2, r_cameraExposure->value); //exp2(r_cameraExposure->value); - color[3] = 1.0f; - - if (autoExposure) - GL_BindToTMU(tr.calcLevelsImage, TB_LEVELSMAP); - else - GL_BindToTMU(tr.fixedLevelsImage, TB_LEVELSMAP); - - FBO_Blit(hdrFbo, hdrBox, NULL, ldrFbo, ldrBox, &tr.tonemapShader, color, 0); -} - -/* -============= -RB_BokehBlur - - -Blurs a part of one framebuffer to another. - -Framebuffers can be identical. -============= -*/ -void RB_BokehBlur(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, float blur) -{ -// ivec4_t srcBox, dstBox; - vec4_t color; - - blur *= 10.0f; - - if (blur < 0.004f) - return; - - if (glRefConfig.framebufferObject) - { - // bokeh blur - if (blur > 0.0f) - { - ivec4_t quarterBox; - - quarterBox[0] = 0; - quarterBox[1] = tr.quarterFbo[0]->height; - quarterBox[2] = tr.quarterFbo[0]->width; - quarterBox[3] = -tr.quarterFbo[0]->height; - - // create a quarter texture - //FBO_Blit(NULL, NULL, NULL, tr.quarterFbo[0], NULL, NULL, NULL, 0); - FBO_FastBlit(src, srcBox, tr.quarterFbo[0], quarterBox, GL_COLOR_BUFFER_BIT, GL_LINEAR); - } - -#ifndef HQ_BLUR - if (blur > 1.0f) - { - // create a 1/16th texture - //FBO_Blit(tr.quarterFbo[0], NULL, NULL, tr.textureScratchFbo[0], NULL, NULL, NULL, 0); - FBO_FastBlit(tr.quarterFbo[0], NULL, tr.textureScratchFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR); - } -#endif - - if (blur > 0.0f && blur <= 1.0f) - { - // Crossfade original with quarter texture - VectorSet4(color, 1, 1, 1, blur); - - FBO_Blit(tr.quarterFbo[0], NULL, NULL, dst, dstBox, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); - } -#ifndef HQ_BLUR - // ok blur, but can see some pixelization - else if (blur > 1.0f && blur <= 2.0f) - { - // crossfade quarter texture with 1/16th texture - FBO_Blit(tr.quarterFbo[0], NULL, NULL, dst, dstBox, NULL, NULL, 0); - - VectorSet4(color, 1, 1, 1, blur - 1.0f); - - FBO_Blit(tr.textureScratchFbo[0], NULL, NULL, dst, dstBox, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); - } - else if (blur > 2.0f) - { - // blur 1/16th texture then replace - int i; - - for (i = 0; i < 2; i++) - { - vec2_t blurTexScale; - float subblur; - - subblur = ((blur - 2.0f) / 2.0f) / 3.0f * (float)(i + 1); - - blurTexScale[0] = - blurTexScale[1] = subblur; - - color[0] = - color[1] = - color[2] = 0.5f; - color[3] = 1.0f; - - if (i != 0) - FBO_Blit(tr.textureScratchFbo[0], NULL, blurTexScale, tr.textureScratchFbo[1], NULL, &tr.bokehShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE); - else - FBO_Blit(tr.textureScratchFbo[0], NULL, blurTexScale, tr.textureScratchFbo[1], NULL, &tr.bokehShader, color, 0); - } - - FBO_Blit(tr.textureScratchFbo[1], NULL, NULL, dst, dstBox, &tr.textureColorShader, NULL, 0); - } -#else // higher quality blur, but slower - else if (blur > 1.0f) - { - // blur quarter texture then replace - int i; - - src = tr.quarterFbo[0]; - dst = tr.quarterFbo[1]; - - VectorSet4(color, 0.5f, 0.5f, 0.5f, 1); - - for (i = 0; i < 2; i++) - { - vec2_t blurTexScale; - float subblur; - - subblur = (blur - 1.0f) / 2.0f * (float)(i + 1); - - blurTexScale[0] = - blurTexScale[1] = subblur; - - color[0] = - color[1] = - color[2] = 1.0f; - if (i != 0) - color[3] = 1.0f; - else - color[3] = 0.5f; - - FBO_Blit(tr.quarterFbo[0], NULL, blurTexScale, tr.quarterFbo[1], NULL, &tr.bokehShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); - } - - FBO_Blit(tr.quarterFbo[1], NULL, NULL, dst, dstBox, &tr.textureColorShader, NULL, 0); - } -#endif - } -} - - -static void RB_RadialBlur(FBO_t *srcFbo, FBO_t *dstFbo, int passes, float stretch, float x, float y, float w, float h, float xcenter, float ycenter, float alpha) -{ - ivec4_t srcBox, dstBox; - vec4_t color; - const float inc = 1.f / passes; - const float mul = powf(stretch, inc); - float scale; - - { - vec2_t texScale; - - texScale[0] = - texScale[1] = 1.0f; - - alpha *= inc; - VectorSet4(color, alpha, alpha, alpha, 1.0f); - - VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height); - VectorSet4(dstBox, x, y, w, h); - FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, 0); - - --passes; - scale = mul; - while (passes > 0) - { - float iscale = 1.f / scale; - float s0 = xcenter * (1.f - iscale); - float t0 = (1.0f - ycenter) * (1.f - iscale); - float s1 = iscale + s0; - float t1 = iscale + t0; - - if (srcFbo) - { - srcBox[0] = s0 * srcFbo->width; - srcBox[1] = t0 * srcFbo->height; - srcBox[2] = (s1 - s0) * srcFbo->width; - srcBox[3] = (t1 - t0) * srcFbo->height; - } - else - { - srcBox[0] = s0 * glConfig.vidWidth; - srcBox[1] = t0 * glConfig.vidHeight; - srcBox[2] = (s1 - s0) * glConfig.vidWidth; - srcBox[3] = (t1 - t0) * glConfig.vidHeight; - } - - FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - - scale *= mul; - --passes; - } - } -} - - -static qboolean RB_UpdateSunFlareVis(void) -{ - GLuint sampleCount = 0; - if (!glRefConfig.occlusionQuery) - return qtrue; - - tr.sunFlareQueryIndex ^= 1; - if (!tr.sunFlareQueryActive[tr.sunFlareQueryIndex]) - return qtrue; - - /* debug code */ - if (0) - { - int iter; - for (iter=0 ; ; ++iter) - { - GLint available = 0; - qglGetQueryObjectivARB(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_AVAILABLE_ARB, &available); - if (available) - break; - } - - ri.Printf(PRINT_DEVELOPER, "Waited %d iterations\n", iter); - } - - qglGetQueryObjectuivARB(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_ARB, &sampleCount); - return sampleCount > 0; -} - -void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox) -{ - vec4_t color; - float dot; - const float cutoff = 0.25f; - qboolean colorize = qtrue; - -// float w, h, w2, h2; - mat4_t mvp; - vec4_t pos, hpos; - - dot = DotProduct(tr.sunDirection, backEnd.viewParms.or.axis[0]); - if (dot < cutoff) - return; - - if (!RB_UpdateSunFlareVis()) - return; - - // From RB_DrawSun() - { - float dist; - mat4_t trans, model, mvp; - - Mat4Translation( backEnd.viewParms.or.origin, trans ); - Mat4Multiply( backEnd.viewParms.world.modelMatrix, trans, model ); - Mat4Multiply(backEnd.viewParms.projectionMatrix, model, mvp); - - dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) - - VectorScale( tr.sunDirection, dist, pos ); - } - - // project sun point - //Mat4Multiply(backEnd.viewParms.projectionMatrix, backEnd.viewParms.world.modelMatrix, mvp); - Mat4Transform(mvp, pos, hpos); - - // transform to UV coords - hpos[3] = 0.5f / hpos[3]; - - pos[0] = 0.5f + hpos[0] * hpos[3]; - pos[1] = 0.5f + hpos[1] * hpos[3]; - - // initialize quarter buffers - { - float mul = 1.f; - vec2_t texScale; - ivec4_t rayBox, quarterBox; - - texScale[0] = - texScale[1] = 1.0f; - - VectorSet4(color, mul, mul, mul, 1); - - if (srcFbo) - { - rayBox[0] = srcBox[0] * tr.sunRaysFbo->width / srcFbo->width; - rayBox[1] = srcBox[1] * tr.sunRaysFbo->height / srcFbo->height; - rayBox[2] = srcBox[2] * tr.sunRaysFbo->width / srcFbo->width; - rayBox[3] = srcBox[3] * tr.sunRaysFbo->height / srcFbo->height; - } - else - { - rayBox[0] = srcBox[0] * tr.sunRaysFbo->width / glConfig.vidWidth; - rayBox[1] = srcBox[1] * tr.sunRaysFbo->height / glConfig.vidHeight; - rayBox[2] = srcBox[2] * tr.sunRaysFbo->width / glConfig.vidWidth; - rayBox[3] = srcBox[3] * tr.sunRaysFbo->height / glConfig.vidHeight; - } - - quarterBox[0] = 0; - quarterBox[1] = tr.quarterFbo[0]->height; - quarterBox[2] = tr.quarterFbo[0]->width; - quarterBox[3] = -tr.quarterFbo[0]->height; - - // first, downsample the framebuffer - if (colorize) - { - FBO_FastBlit(srcFbo, srcBox, tr.quarterFbo[0], quarterBox, GL_COLOR_BUFFER_BIT, GL_LINEAR); - FBO_Blit(tr.sunRaysFbo, rayBox, NULL, tr.quarterFbo[0], quarterBox, NULL, color, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO); - } - else - { - FBO_FastBlit(tr.sunRaysFbo, rayBox, tr.quarterFbo[0], quarterBox, GL_COLOR_BUFFER_BIT, GL_LINEAR); - } - } - - // radial blur passes, ping-ponging between the two quarter-size buffers - { - const float stretch_add = 2.f/3.f; - float stretch = 1.f + stretch_add; - int i; - for (i=0; i<2; ++i) - { - RB_RadialBlur(tr.quarterFbo[i&1], tr.quarterFbo[(~i) & 1], 5, stretch, 0.f, 0.f, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height, pos[0], pos[1], 1.125f); - stretch += stretch_add; - } - } - - // add result back on top of the main buffer - { - float mul = 1.f; - vec2_t texScale; - - texScale[0] = - texScale[1] = 1.0f; - - VectorSet4(color, mul, mul, mul, 1); - - FBO_Blit(tr.quarterFbo[0], NULL, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE); - } -} - -static void RB_BlurAxis(FBO_t *srcFbo, FBO_t *dstFbo, float strength, qboolean horizontal) -{ - float dx, dy; - float xmul, ymul; - float weights[3] = { - 0.227027027f, - 0.316216216f, - 0.070270270f, - }; - float offsets[3] = { - 0.f, - 1.3846153846f, - 3.2307692308f, - }; - - xmul = horizontal; - ymul = 1.f - xmul; - - xmul *= strength; - ymul *= strength; - - { - ivec4_t srcBox, dstBox; - vec4_t color; - vec2_t texScale; - - texScale[0] = - texScale[1] = 1.0f; - - VectorSet4(color, weights[0], weights[0], weights[0], 1.0f); - VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height); - VectorSet4(dstBox, 0, 0, dstFbo->width, dstFbo->height); - FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, 0 ); - - VectorSet4(color, weights[1], weights[1], weights[1], 1.0f); - dx = offsets[1] * xmul; - dy = offsets[1] * ymul; - VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height); - FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - VectorSet4(srcBox, -dx, -dy, srcFbo->width, srcFbo->height); - FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - - VectorSet4(color, weights[2], weights[2], weights[2], 1.0f); - dx = offsets[2] * xmul; - dy = offsets[2] * ymul; - VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height); - FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - VectorSet4(srcBox, -dx, -dy, srcFbo->width, srcFbo->height); - FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - } -} - -static void RB_HBlur(FBO_t *srcFbo, FBO_t *dstFbo, float strength) -{ - RB_BlurAxis(srcFbo, dstFbo, strength, qtrue); -} - -static void RB_VBlur(FBO_t *srcFbo, FBO_t *dstFbo, float strength) -{ - RB_BlurAxis(srcFbo, dstFbo, strength, qfalse); -} - -void RB_GaussianBlur(float blur) -{ - //float mul = 1.f; - float factor = Com_Clamp(0.f, 1.f, blur); - - if (factor <= 0.f) - return; - - { - ivec4_t srcBox, dstBox; - vec4_t color; - vec2_t texScale; - - texScale[0] = - texScale[1] = 1.0f; - - VectorSet4(color, 1, 1, 1, 1); - - // first, downsample the framebuffer - FBO_FastBlit(NULL, NULL, tr.quarterFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR); - FBO_FastBlit(tr.quarterFbo[0], NULL, tr.textureScratchFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR); - - // set the alpha channel - VectorSet4(srcBox, 0, 0, tr.whiteImage->width, tr.whiteImage->height); - VectorSet4(dstBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height); - qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); - FBO_BlitFromTexture(tr.whiteImage, srcBox, texScale, tr.textureScratchFbo[0], dstBox, &tr.textureColorShader, color, GLS_DEPTHTEST_DISABLE); - qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - - // blur the tiny buffer horizontally and vertically - RB_HBlur(tr.textureScratchFbo[0], tr.textureScratchFbo[1], factor); - RB_VBlur(tr.textureScratchFbo[1], tr.textureScratchFbo[0], factor); - - // finally, merge back to framebuffer - VectorSet4(srcBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height); - VectorSet4(dstBox, 0, 0, glConfig.vidWidth, glConfig.vidHeight); - color[3] = factor; - FBO_Blit(tr.textureScratchFbo[0], srcBox, texScale, NULL, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); - } -} diff --git a/code/renderergl2/tr_postprocess.h b/code/renderergl2/tr_postprocess.h deleted file mode 100644 index 09daf13465..0000000000 --- a/code/renderergl2/tr_postprocess.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2011 Andrei Drexler, Richard Allen, James Canete - -This file is part of Reaction source code. - -Reaction 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. - -Reaction 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 Reaction source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#ifndef TR_POSTPROCESS_H -#define TR_POSTPROCESS_H - -#include "tr_fbo.h" - -void RB_ToneMap(FBO_t *hdrFbo, ivec4_t hdrBox, FBO_t *ldrFbo, ivec4_t ldrBox, int autoExposure); -void RB_BokehBlur(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, float blur); -void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox); -void RB_GaussianBlur(float blur); - -#endif diff --git a/code/renderergl2/tr_scene.c b/code/renderergl2/tr_scene.c deleted file mode 100644 index db2d138670..0000000000 --- a/code/renderergl2/tr_scene.c +++ /dev/null @@ -1,559 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "tr_local.h" - -int r_firstSceneDrawSurf; - -int r_numdlights; -int r_firstSceneDlight; - -int r_numentities; -int r_firstSceneEntity; - -int r_numpolys; -int r_firstScenePoly; - -int r_numpolyverts; - - -/* -==================== -R_InitNextFrame - -==================== -*/ -void R_InitNextFrame( void ) { - backEndData->commands.used = 0; - - r_firstSceneDrawSurf = 0; - - r_numdlights = 0; - r_firstSceneDlight = 0; - - r_numentities = 0; - r_firstSceneEntity = 0; - - r_numpolys = 0; - r_firstScenePoly = 0; - - r_numpolyverts = 0; -} - - -/* -==================== -RE_ClearScene - -==================== -*/ -void RE_ClearScene( void ) { - r_firstSceneDlight = r_numdlights; - r_firstSceneEntity = r_numentities; - r_firstScenePoly = r_numpolys; -} - -/* -=========================================================================== - -DISCRETE POLYS - -=========================================================================== -*/ - -/* -===================== -R_AddPolygonSurfaces - -Adds all the scene's polys into this view's drawsurf list -===================== -*/ -void R_AddPolygonSurfaces( void ) { - int i; - shader_t *sh; - srfPoly_t *poly; - int fogMask; - - tr.currentEntityNum = REFENTITYNUM_WORLD; - tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT; - fogMask = -((tr.refdef.rdflags & RDF_NOFOG) == 0); - - for ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) { - sh = R_GetShaderByHandle( poly->hShader ); - R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex & fogMask, qfalse, qfalse, 0 /*cubeMap*/ ); - } -} - -/* -===================== -RE_AddPolyToScene - -===================== -*/ -void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ) { - srfPoly_t *poly; - int i, j; - int fogIndex; - fog_t *fog; - vec3_t bounds[2]; - - if ( !tr.registered ) { - return; - } - - if ( !hShader ) { - // This isn't a useful warning, and an hShader of zero isn't a null shader, it's - // the default shader. - //ri.Printf( PRINT_WARNING, "WARNING: RE_AddPolyToScene: NULL poly shader\n"); - //return; - } - - for ( j = 0; j < numPolys; j++ ) { - if ( r_numpolyverts + numVerts > max_polyverts || r_numpolys >= max_polys ) { - /* - NOTE TTimo this was initially a PRINT_WARNING - but it happens a lot with high fighting scenes and particles - since we don't plan on changing the const and making for room for those effects - simply cut this message to developer only - */ - ri.Printf( PRINT_DEVELOPER, "WARNING: RE_AddPolyToScene: r_max_polys or r_max_polyverts reached\n"); - return; - } - - poly = &backEndData->polys[r_numpolys]; - poly->surfaceType = SF_POLY; - poly->hShader = hShader; - poly->numVerts = numVerts; - poly->verts = &backEndData->polyVerts[r_numpolyverts]; - - Com_Memcpy( poly->verts, &verts[numVerts*j], numVerts * sizeof( *verts ) ); - - if ( glConfig.hardwareType == GLHW_RAGEPRO ) { - poly->verts->modulate[0] = 255; - poly->verts->modulate[1] = 255; - poly->verts->modulate[2] = 255; - poly->verts->modulate[3] = 255; - } - // done. - r_numpolys++; - r_numpolyverts += numVerts; - - // if no world is loaded - if ( tr.world == NULL ) { - fogIndex = 0; - } - // see if it is in a fog volume - else if ( tr.world->numfogs == 1 ) { - fogIndex = 0; - } else { - // find which fog volume the poly is in - VectorCopy( poly->verts[0].xyz, bounds[0] ); - VectorCopy( poly->verts[0].xyz, bounds[1] ); - for ( i = 1 ; i < poly->numVerts ; i++ ) { - AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] ); - } - for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) { - fog = &tr.world->fogs[fogIndex]; - if ( bounds[1][0] >= fog->bounds[0][0] - && bounds[1][1] >= fog->bounds[0][1] - && bounds[1][2] >= fog->bounds[0][2] - && bounds[0][0] <= fog->bounds[1][0] - && bounds[0][1] <= fog->bounds[1][1] - && bounds[0][2] <= fog->bounds[1][2] ) { - break; - } - } - if ( fogIndex == tr.world->numfogs ) { - fogIndex = 0; - } - } - poly->fogIndex = fogIndex; - } -} - - -//================================================================================= - - -/* -===================== -RE_AddRefEntityToScene - -===================== -*/ -void RE_AddRefEntityToScene( const refEntity_t *ent ) { - vec3_t cross; - - if ( !tr.registered ) { - return; - } - if ( r_numentities >= MAX_REFENTITIES ) { - ri.Printf(PRINT_DEVELOPER, "RE_AddRefEntityToScene: Dropping refEntity, reached MAX_REFENTITIES\n"); - return; - } - if ( Q_isnan(ent->origin[0]) || Q_isnan(ent->origin[1]) || Q_isnan(ent->origin[2]) ) { - static qboolean firstTime = qtrue; - if (firstTime) { - firstTime = qfalse; - ri.Printf( PRINT_WARNING, "RE_AddRefEntityToScene passed a refEntity which has an origin with a NaN component\n"); - } - return; - } - if ( (int)ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) { - ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType ); - } - - backEndData->entities[r_numentities].e = *ent; - backEndData->entities[r_numentities].lightingCalculated = qfalse; - - CrossProduct(ent->axis[0], ent->axis[1], cross); - backEndData->entities[r_numentities].mirrored = (DotProduct(ent->axis[2], cross) < 0.f); - - r_numentities++; -} - - -/* -===================== -RE_AddDynamicLightToScene - -===================== -*/ -void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, float g, float b, int additive ) { - dlight_t *dl; - - if ( !tr.registered ) { - return; - } - if ( r_numdlights >= MAX_DLIGHTS ) { - return; - } - if ( intensity <= 0 ) { - return; - } - // these cards don't have the correct blend mode - if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) { - return; - } - dl = &backEndData->dlights[r_numdlights++]; - VectorCopy (org, dl->origin); - dl->radius = intensity; - dl->color[0] = r; - dl->color[1] = g; - dl->color[2] = b; - dl->additive = additive; -} - -/* -===================== -RE_AddLightToScene - -===================== -*/ -void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) { - RE_AddDynamicLightToScene( org, intensity, r, g, b, qfalse ); -} - -/* -===================== -RE_AddAdditiveLightToScene - -===================== -*/ -void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) { - RE_AddDynamicLightToScene( org, intensity, r, g, b, qtrue ); -} - - -void RE_BeginScene(const refdef_t *fd) -{ - Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) ); - - tr.refdef.x = fd->x; - tr.refdef.y = fd->y; - tr.refdef.width = fd->width; - tr.refdef.height = fd->height; - tr.refdef.fov_x = fd->fov_x; - tr.refdef.fov_y = fd->fov_y; - - VectorCopy( fd->vieworg, tr.refdef.vieworg ); - VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] ); - VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] ); - VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] ); - - tr.refdef.time = fd->time; - tr.refdef.rdflags = fd->rdflags; - - // copy the areamask data over and note if it has changed, which - // will force a reset of the visible leafs even if the view hasn't moved - tr.refdef.areamaskModified = qfalse; - if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) { - int areaDiff; - int i; - - // compare the area bits - areaDiff = 0; - for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) { - areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i]; - ((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i]; - } - - if ( areaDiff ) { - // a door just opened or something - tr.refdef.areamaskModified = qtrue; - } - } - - tr.refdef.sunDir[3] = 0.0f; - tr.refdef.sunCol[3] = 1.0f; - tr.refdef.sunAmbCol[3] = 1.0f; - - VectorCopy(tr.sunDirection, tr.refdef.sunDir); - if ( (tr.refdef.rdflags & RDF_NOWORLDMODEL) || !(r_depthPrepass->value) ){ - tr.refdef.colorScale = 1.0f; - VectorSet(tr.refdef.sunCol, 0, 0, 0); - VectorSet(tr.refdef.sunAmbCol, 0, 0, 0); - } - else - { - tr.refdef.colorScale = r_forceSun->integer ? r_forceSunMapLightScale->value : tr.mapLightScale; - - if (r_sunlightMode->integer == 1) - { - tr.refdef.sunCol[0] = - tr.refdef.sunCol[1] = - tr.refdef.sunCol[2] = 1.0f; - - tr.refdef.sunAmbCol[0] = - tr.refdef.sunAmbCol[1] = - tr.refdef.sunAmbCol[2] = r_forceSun->integer ? r_forceSunAmbientScale->value : tr.sunShadowScale; - } - else - { - float scale = pow(2, r_mapOverBrightBits->integer - tr.overbrightBits - 8); - if (r_forceSun->integer) - { - VectorScale(tr.sunLight, scale * r_forceSunLightScale->value, tr.refdef.sunCol); - VectorScale(tr.sunLight, scale * r_forceSunAmbientScale->value, tr.refdef.sunAmbCol); - } - else - { - VectorScale(tr.sunLight, scale, tr.refdef.sunCol); - VectorScale(tr.sunLight, scale * tr.sunShadowScale, tr.refdef.sunAmbCol); - } - } - } - - if (r_forceAutoExposure->integer) - { - tr.refdef.autoExposureMinMax[0] = r_forceAutoExposureMin->value; - tr.refdef.autoExposureMinMax[1] = r_forceAutoExposureMax->value; - } - else - { - tr.refdef.autoExposureMinMax[0] = tr.autoExposureMinMax[0]; - tr.refdef.autoExposureMinMax[1] = tr.autoExposureMinMax[1]; - } - - if (r_forceToneMap->integer) - { - tr.refdef.toneMinAvgMaxLinear[0] = pow(2, r_forceToneMapMin->value); - tr.refdef.toneMinAvgMaxLinear[1] = pow(2, r_forceToneMapAvg->value); - tr.refdef.toneMinAvgMaxLinear[2] = pow(2, r_forceToneMapMax->value); - } - else - { - tr.refdef.toneMinAvgMaxLinear[0] = pow(2, tr.toneMinAvgMaxLevel[0]); - tr.refdef.toneMinAvgMaxLinear[1] = pow(2, tr.toneMinAvgMaxLevel[1]); - tr.refdef.toneMinAvgMaxLinear[2] = pow(2, tr.toneMinAvgMaxLevel[2]); - } - - // Makro - copy exta info if present - if (fd->rdflags & RDF_EXTRA) { - const refdefex_t* extra = (const refdefex_t*) (fd+1); - - tr.refdef.blurFactor = extra->blurFactor; - - if (fd->rdflags & RDF_SUNLIGHT) - { - VectorCopy(extra->sunDir, tr.refdef.sunDir); - VectorCopy(extra->sunCol, tr.refdef.sunCol); - VectorCopy(extra->sunAmbCol, tr.refdef.sunAmbCol); - } - } - else - { - tr.refdef.blurFactor = 0.0f; - } - - // derived info - - tr.refdef.floatTime = tr.refdef.time * 0.001f; - - tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; - tr.refdef.drawSurfs = backEndData->drawSurfs; - - tr.refdef.num_entities = r_numentities - r_firstSceneEntity; - tr.refdef.entities = &backEndData->entities[r_firstSceneEntity]; - - tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight; - tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight]; - - tr.refdef.numPolys = r_numpolys - r_firstScenePoly; - tr.refdef.polys = &backEndData->polys[r_firstScenePoly]; - - tr.refdef.num_pshadows = 0; - tr.refdef.pshadows = &backEndData->pshadows[0]; - - // turn off dynamic lighting globally by clearing all the - // dlights if it needs to be disabled or if vertex lighting is enabled - if ( r_dynamiclight->integer == 0 || - r_vertexLight->integer == 1 || - glConfig.hardwareType == GLHW_PERMEDIA2 ) { - tr.refdef.num_dlights = 0; - } - - // a single frame may have multiple scenes draw inside it -- - // a 3D game view, 3D status bar renderings, 3D menus, etc. - // They need to be distinguished by the light flare code, because - // the visibility state for a given surface may be different in - // each scene / view. - tr.frameSceneNum++; - tr.sceneCount++; -} - - -void RE_EndScene() -{ - // the next scene rendered in this frame will tack on after this one - r_firstSceneDrawSurf = tr.refdef.numDrawSurfs; - r_firstSceneEntity = r_numentities; - r_firstSceneDlight = r_numdlights; - r_firstScenePoly = r_numpolys; -} - -/* -@@@@@@@@@@@@@@@@@@@@@ -RE_RenderScene - -Draw a 3D view into a part of the window, then return -to 2D drawing. - -Rendering a scene may require multiple views to be rendered -to handle mirrors, -@@@@@@@@@@@@@@@@@@@@@ -*/ -void RE_RenderScene( const refdef_t *fd ) { - viewParms_t parms; - int startTime; - - if ( !tr.registered ) { - return; - } - GLimp_LogComment( "====== RE_RenderScene =====\n" ); - - if ( r_norefresh->integer ) { - return; - } - - startTime = ri.Milliseconds(); - - if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) { - ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel"); - } - - RE_BeginScene(fd); - - // SmileTheory: playing with shadow mapping - if (!( fd->rdflags & RDF_NOWORLDMODEL ) && tr.refdef.num_dlights && r_dlightMode->integer >= 2) - { - R_RenderDlightCubemaps(fd); - } - - /* playing with more shadows */ - if(glRefConfig.framebufferObject && !( fd->rdflags & RDF_NOWORLDMODEL ) && r_shadows->integer == 4) - { - R_RenderPshadowMaps(fd); - } - - // playing with even more shadows - if(glRefConfig.framebufferObject && r_sunlightMode->integer && !( fd->rdflags & RDF_NOWORLDMODEL ) && (r_forceSun->integer || tr.sunShadows)) - { - R_RenderSunShadowMaps(fd, 0); - R_RenderSunShadowMaps(fd, 1); - R_RenderSunShadowMaps(fd, 2); - } - - // playing with cube maps - // this is where dynamic cubemaps would be rendered - if (0) //(glRefConfig.framebufferObject && !( fd->rdflags & RDF_NOWORLDMODEL )) - { - int i, j; - - for (i = 0; i < tr.numCubemaps; i++) - { - for (j = 0; j < 6; j++) - { - R_RenderCubemapSide(i, j, qtrue); - } - } - } - - // setup view parms for the initial view - // - // set up viewport - // The refdef takes 0-at-the-top y coordinates, so - // convert to GL's 0-at-the-bottom space - // - Com_Memset( &parms, 0, sizeof( parms ) ); - parms.viewportX = tr.refdef.x; - parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height ); - parms.viewportWidth = tr.refdef.width; - parms.viewportHeight = tr.refdef.height; - parms.isPortal = qfalse; - - parms.fovX = tr.refdef.fov_x; - parms.fovY = tr.refdef.fov_y; - - parms.stereoFrame = tr.refdef.stereoFrame; - - VectorCopy( fd->vieworg, parms.or.origin ); - VectorCopy( fd->viewaxis[0], parms.or.axis[0] ); - VectorCopy( fd->viewaxis[1], parms.or.axis[1] ); - VectorCopy( fd->viewaxis[2], parms.or.axis[2] ); - - VectorCopy( fd->vieworg, parms.pvsOrigin ); - - if(!( fd->rdflags & RDF_NOWORLDMODEL ) && r_depthPrepass->value && ((r_forceSun->integer) || tr.sunShadows)) - { - parms.flags = VPF_USESUNLIGHT; - } - - R_RenderView( &parms ); - - if(!( fd->rdflags & RDF_NOWORLDMODEL )) - R_AddPostProcessCmd(); - - RE_EndScene(); - - tr.frontEndMsec += ri.Milliseconds() - startTime; -} diff --git a/code/renderergl2/tr_shade.c b/code/renderergl2/tr_shade.c deleted file mode 100644 index 856b87483b..0000000000 --- a/code/renderergl2/tr_shade.c +++ /dev/null @@ -1,1652 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_shade.c - -#include "tr_local.h" -#if idppc_altivec && !defined(MACOS_X) -#include -#endif - -/* - - THIS ENTIRE FILE IS BACK END - - This file deals with applying shaders to surface data in the tess struct. -*/ - - -/* -================== -R_DrawElements - -================== -*/ - -void R_DrawElementsVBO( int numIndexes, glIndex_t firstIndex, glIndex_t minIndex, glIndex_t maxIndex ) -{ - if (glRefConfig.drawRangeElements) - qglDrawRangeElementsEXT(GL_TRIANGLES, minIndex, maxIndex, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(glIndex_t))); - else - qglDrawElements(GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(glIndex_t))); - -} - - -static void R_DrawMultiElementsVBO( int multiDrawPrimitives, glIndex_t *multiDrawMinIndex, glIndex_t *multiDrawMaxIndex, - GLsizei *multiDrawNumIndexes, glIndex_t **multiDrawFirstIndex) -{ - if (glRefConfig.multiDrawArrays) - { - qglMultiDrawElementsEXT(GL_TRIANGLES, multiDrawNumIndexes, GL_INDEX_TYPE, (const GLvoid **)multiDrawFirstIndex, multiDrawPrimitives); - } - else - { - int i; - - if (glRefConfig.drawRangeElements) - { - for (i = 0; i < multiDrawPrimitives; i++) - { - qglDrawRangeElementsEXT(GL_TRIANGLES, multiDrawMinIndex[i], multiDrawMaxIndex[i], multiDrawNumIndexes[i], GL_INDEX_TYPE, multiDrawFirstIndex[i]); - } - } - else - { - for (i = 0; i < multiDrawPrimitives; i++) - { - qglDrawElements(GL_TRIANGLES, multiDrawNumIndexes[i], GL_INDEX_TYPE, multiDrawFirstIndex[i]); - } - } - } -} - - -/* -============================================================= - -SURFACE SHADERS - -============================================================= -*/ - -shaderCommands_t tess; - - -/* -================= -R_BindAnimatedImageToTMU - -================= -*/ -static void R_BindAnimatedImageToTMU( textureBundle_t *bundle, int tmu ) { - int index; - - if ( bundle->isVideoMap ) { - int oldtmu = glState.currenttmu; - GL_SelectTexture(tmu); - ri.CIN_RunCinematic(bundle->videoMapHandle); - ri.CIN_UploadCinematic(bundle->videoMapHandle); - GL_SelectTexture(oldtmu); - return; - } - - if ( bundle->numImageAnimations <= 1 ) { - GL_BindToTMU( bundle->image[0], tmu); - return; - } - - // it is necessary to do this messy calc to make sure animations line up - // exactly with waveforms of the same frequency - index = ri.ftol(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE); - index >>= FUNCTABLE_SIZE2; - - if ( index < 0 ) { - index = 0; // may happen with shader time offsets - } - index %= bundle->numImageAnimations; - - GL_BindToTMU( bundle->image[ index ], tmu ); -} - - -/* -================ -DrawTris - -Draws triangle outlines for debugging -================ -*/ -static void DrawTris (shaderCommands_t *input) { - GL_Bind( tr.whiteImage ); - - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ); - qglDepthRange( 0, 0 ); - - { - shaderProgram_t *sp = &tr.textureColorShader; - vec4_t color; - - GLSL_VertexAttribsState(ATTR_POSITION); - GLSL_BindProgram(sp); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - VectorSet4(color, 1, 1, 1, 1); - GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color); - - if (input->multiDrawPrimitives) - { - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); - } - } - - qglDepthRange( 0, 1 ); -} - - -/* -================ -DrawNormals - -Draws vertex normals for debugging -================ -*/ -static void DrawNormals (shaderCommands_t *input) { - //FIXME: implement this -} - -/* -============== -RB_BeginSurface - -We must set some things up before beginning any tesselation, -because a surface may be forced to perform a RB_End due -to overflow. -============== -*/ -void RB_BeginSurface( shader_t *shader, int fogNum, int cubemapIndex ) { - - shader_t *state = (shader->remappedShader) ? shader->remappedShader : shader; - - tess.numIndexes = 0; - tess.firstIndex = 0; - tess.numVertexes = 0; - tess.multiDrawPrimitives = 0; - tess.shader = state; - tess.fogNum = fogNum; - tess.cubemapIndex = cubemapIndex; - tess.dlightBits = 0; // will be OR'd in by surface functions - tess.pshadowBits = 0; // will be OR'd in by surface functions - tess.xstages = state->stages; - tess.numPasses = state->numUnfoggedPasses; - tess.currentStageIteratorFunc = state->optimalStageIteratorFunc; - tess.useInternalVBO = qtrue; - - tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; - if (tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime) { - tess.shaderTime = tess.shader->clampTime; - } - - if (backEnd.viewParms.flags & VPF_SHADOWMAP) - { - tess.currentStageIteratorFunc = RB_StageIteratorGeneric; - } -} - - - -extern float EvalWaveForm( const waveForm_t *wf ); -extern float EvalWaveFormClamped( const waveForm_t *wf ); - - -static void ComputeTexMods( shaderStage_t *pStage, int bundleNum, float *outMatrix, float *outOffTurb) -{ - int tm; - float matrix[6], currentmatrix[6]; - textureBundle_t *bundle = &pStage->bundle[bundleNum]; - - matrix[0] = 1.0f; matrix[2] = 0.0f; matrix[4] = 0.0f; - matrix[1] = 0.0f; matrix[3] = 1.0f; matrix[5] = 0.0f; - - currentmatrix[0] = 1.0f; currentmatrix[2] = 0.0f; currentmatrix[4] = 0.0f; - currentmatrix[1] = 0.0f; currentmatrix[3] = 1.0f; currentmatrix[5] = 0.0f; - - outMatrix[0] = 1.0f; outMatrix[2] = 0.0f; - outMatrix[1] = 0.0f; outMatrix[3] = 1.0f; - - outOffTurb[0] = 0.0f; outOffTurb[1] = 0.0f; outOffTurb[2] = 0.0f; outOffTurb[3] = 0.0f; - - for ( tm = 0; tm < bundle->numTexMods ; tm++ ) { - switch ( bundle->texMods[tm].type ) - { - - case TMOD_NONE: - tm = TR_MAX_TEXMODS; // break out of for loop - break; - - case TMOD_TURBULENT: - RB_CalcTurbulentFactors(&bundle->texMods[tm].wave, &outOffTurb[2], &outOffTurb[3]); - break; - - case TMOD_ENTITY_TRANSLATE: - RB_CalcScrollTexMatrix( backEnd.currentEntity->e.shaderTexCoord, matrix ); - break; - - case TMOD_SCROLL: - RB_CalcScrollTexMatrix( bundle->texMods[tm].scroll, - matrix ); - break; - - case TMOD_SCALE: - RB_CalcScaleTexMatrix( bundle->texMods[tm].scale, - matrix ); - break; - - case TMOD_STRETCH: - RB_CalcStretchTexMatrix( &bundle->texMods[tm].wave, - matrix ); - break; - - case TMOD_TRANSFORM: - RB_CalcTransformTexMatrix( &bundle->texMods[tm], - matrix ); - break; - - case TMOD_ROTATE: - RB_CalcRotateTexMatrix( bundle->texMods[tm].rotateSpeed, - matrix ); - break; - - default: - ri.Error( ERR_DROP, "ERROR: unknown texmod '%d' in shader '%s'", bundle->texMods[tm].type, tess.shader->name ); - break; - } - - switch ( bundle->texMods[tm].type ) - { - case TMOD_NONE: - case TMOD_TURBULENT: - default: - break; - - case TMOD_ENTITY_TRANSLATE: - case TMOD_SCROLL: - case TMOD_SCALE: - case TMOD_STRETCH: - case TMOD_TRANSFORM: - case TMOD_ROTATE: - outMatrix[0] = matrix[0] * currentmatrix[0] + matrix[2] * currentmatrix[1]; - outMatrix[1] = matrix[1] * currentmatrix[0] + matrix[3] * currentmatrix[1]; - - outMatrix[2] = matrix[0] * currentmatrix[2] + matrix[2] * currentmatrix[3]; - outMatrix[3] = matrix[1] * currentmatrix[2] + matrix[3] * currentmatrix[3]; - - outOffTurb[0] = matrix[0] * currentmatrix[4] + matrix[2] * currentmatrix[5] + matrix[4]; - outOffTurb[1] = matrix[1] * currentmatrix[4] + matrix[3] * currentmatrix[5] + matrix[5]; - - currentmatrix[0] = outMatrix[0]; - currentmatrix[1] = outMatrix[1]; - currentmatrix[2] = outMatrix[2]; - currentmatrix[3] = outMatrix[3]; - currentmatrix[4] = outOffTurb[0]; - currentmatrix[5] = outOffTurb[1]; - break; - } - } -} - - -static void ComputeDeformValues(int *deformGen, vec5_t deformParams) -{ - // u_DeformGen - *deformGen = DGEN_NONE; - if(!ShaderRequiresCPUDeforms(tess.shader)) - { - deformStage_t *ds; - - // only support the first one - ds = &tess.shader->deforms[0]; - - switch (ds->deformation) - { - case DEFORM_WAVE: - *deformGen = ds->deformationWave.func; - - deformParams[0] = ds->deformationWave.base; - deformParams[1] = ds->deformationWave.amplitude; - deformParams[2] = ds->deformationWave.phase; - deformParams[3] = ds->deformationWave.frequency; - deformParams[4] = ds->deformationSpread; - break; - - case DEFORM_BULGE: - *deformGen = DGEN_BULGE; - - deformParams[0] = 0; - deformParams[1] = ds->bulgeHeight; // amplitude - deformParams[2] = ds->bulgeWidth; // phase - deformParams[3] = ds->bulgeSpeed; // frequency - deformParams[4] = 0; - break; - - default: - break; - } - } -} - - -static void ProjectDlightTexture( void ) { - int l; - vec3_t origin; - float scale; - float radius; - int deformGen; - vec5_t deformParams; - - if ( !backEnd.refdef.num_dlights ) { - return; - } - - ComputeDeformValues(&deformGen, deformParams); - - for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { - dlight_t *dl; - shaderProgram_t *sp; - vec4_t vector; - - if ( !( tess.dlightBits & ( 1 << l ) ) ) { - continue; // this surface definately doesn't have any of this light - } - - dl = &backEnd.refdef.dlights[l]; - VectorCopy( dl->transformed, origin ); - radius = dl->radius; - scale = 1.0f / radius; - - sp = &tr.dlightShader[deformGen == DGEN_NONE ? 0 : 1]; - - backEnd.pc.c_dlightDraws++; - - GLSL_BindProgram(sp); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - - GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - - GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); - if (deformGen != DGEN_NONE) - { - GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); - GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); - } - - vector[0] = dl->color[0]; - vector[1] = dl->color[1]; - vector[2] = dl->color[2]; - vector[3] = 1.0f; - GLSL_SetUniformVec4(sp, UNIFORM_COLOR, vector); - - vector[0] = origin[0]; - vector[1] = origin[1]; - vector[2] = origin[2]; - vector[3] = scale; - GLSL_SetUniformVec4(sp, UNIFORM_DLIGHTINFO, vector); - - GL_Bind( tr.dlightImage ); - - // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light - // where they aren't rendered - if ( dl->additive ) { - GL_State( GLS_ATEST_GT_0 | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); - } - else { - GL_State( GLS_ATEST_GT_0 | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); - } - - if (tess.multiDrawPrimitives) - { - shaderCommands_t *input = &tess; - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVBO(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); - } - - backEnd.pc.c_totalIndexes += tess.numIndexes; - backEnd.pc.c_dlightIndexes += tess.numIndexes; - backEnd.pc.c_dlightVertexes += tess.numVertexes; - } -} - - -static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t vertColor, int blend ) -{ - baseColor[0] = - baseColor[1] = - baseColor[2] = - baseColor[3] = 1.0f; - - vertColor[0] = - vertColor[1] = - vertColor[2] = - vertColor[3] = 0.0f; - - // - // rgbGen - // - switch ( pStage->rgbGen ) - { - case CGEN_IDENTITY_LIGHTING: - baseColor[0] = - baseColor[1] = - baseColor[2] = tr.identityLight; - break; - case CGEN_EXACT_VERTEX: - case CGEN_EXACT_VERTEX_LIT: - baseColor[0] = - baseColor[1] = - baseColor[2] = - baseColor[3] = 0.0f; - - vertColor[0] = - vertColor[1] = - vertColor[2] = - vertColor[3] = 1.0f; - break; - case CGEN_CONST: - baseColor[0] = pStage->constantColor[0] / 255.0f; - baseColor[1] = pStage->constantColor[1] / 255.0f; - baseColor[2] = pStage->constantColor[2] / 255.0f; - baseColor[3] = pStage->constantColor[3] / 255.0f; - break; - case CGEN_VERTEX: - baseColor[0] = - baseColor[1] = - baseColor[2] = - baseColor[3] = 0.0f; - - vertColor[0] = - vertColor[1] = - vertColor[2] = tr.identityLight; - vertColor[3] = 1.0f; - break; - case CGEN_VERTEX_LIT: - baseColor[0] = - baseColor[1] = - baseColor[2] = - baseColor[3] = 0.0f; - - vertColor[0] = - vertColor[1] = - vertColor[2] = - vertColor[3] = tr.identityLight; - break; - case CGEN_ONE_MINUS_VERTEX: - baseColor[0] = - baseColor[1] = - baseColor[2] = tr.identityLight; - - vertColor[0] = - vertColor[1] = - vertColor[2] = -tr.identityLight; - break; - case CGEN_FOG: - { - fog_t *fog; - - fog = tr.world->fogs + tess.fogNum; - - baseColor[0] = ((unsigned char *)(&fog->colorInt))[0] / 255.0f; - baseColor[1] = ((unsigned char *)(&fog->colorInt))[1] / 255.0f; - baseColor[2] = ((unsigned char *)(&fog->colorInt))[2] / 255.0f; - baseColor[3] = ((unsigned char *)(&fog->colorInt))[3] / 255.0f; - } - break; - case CGEN_WAVEFORM: - baseColor[0] = - baseColor[1] = - baseColor[2] = RB_CalcWaveColorSingle( &pStage->rgbWave ); - break; - case CGEN_ENTITY: - if (backEnd.currentEntity) - { - baseColor[0] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[0] / 255.0f; - baseColor[1] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[1] / 255.0f; - baseColor[2] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[2] / 255.0f; - baseColor[3] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f; - } - break; - case CGEN_ONE_MINUS_ENTITY: - if (backEnd.currentEntity) - { - baseColor[0] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[0] / 255.0f; - baseColor[1] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[1] / 255.0f; - baseColor[2] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[2] / 255.0f; - baseColor[3] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f; - } - break; - case CGEN_IDENTITY: - case CGEN_LIGHTING_DIFFUSE: - case CGEN_BAD: - break; - } - - // - // alphaGen - // - switch ( pStage->alphaGen ) - { - case AGEN_SKIP: - break; - case AGEN_CONST: - baseColor[3] = pStage->constantColor[3] / 255.0f; - vertColor[3] = 0.0f; - break; - case AGEN_WAVEFORM: - baseColor[3] = RB_CalcWaveAlphaSingle( &pStage->alphaWave ); - vertColor[3] = 0.0f; - break; - case AGEN_ENTITY: - if (backEnd.currentEntity) - { - baseColor[3] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f; - } - vertColor[3] = 0.0f; - break; - case AGEN_ONE_MINUS_ENTITY: - if (backEnd.currentEntity) - { - baseColor[3] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f; - } - vertColor[3] = 0.0f; - break; - case AGEN_VERTEX: - baseColor[3] = 0.0f; - vertColor[3] = 1.0f; - break; - case AGEN_ONE_MINUS_VERTEX: - baseColor[3] = 1.0f; - vertColor[3] = -1.0f; - break; - case AGEN_IDENTITY: - case AGEN_LIGHTING_SPECULAR: - case AGEN_PORTAL: - // Done entirely in vertex program - baseColor[3] = 1.0f; - vertColor[3] = 0.0f; - break; - } - - // multiply color by overbrightbits if this isn't a blend - if (r_softOverbright->integer && tr.overbrightBits - && !((blend & GLS_SRCBLEND_BITS) == GLS_SRCBLEND_DST_COLOR) - && !((blend & GLS_SRCBLEND_BITS) == GLS_SRCBLEND_ONE_MINUS_DST_COLOR) - && !((blend & GLS_DSTBLEND_BITS) == GLS_DSTBLEND_SRC_COLOR) - && !((blend & GLS_DSTBLEND_BITS) == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR)) - { - float scale = 1 << tr.overbrightBits; - - baseColor[0] *= scale; - baseColor[1] *= scale; - baseColor[2] *= scale; - vertColor[0] *= scale; - vertColor[1] *= scale; - vertColor[2] *= scale; - } - - // FIXME: find some way to implement this. -#if 0 - // if in greyscale rendering mode turn all color values into greyscale. - if(r_greyscale->integer) - { - int scale; - - for(i = 0; i < tess.numVertexes; i++) - { - scale = (tess.svars.colors[i][0] + tess.svars.colors[i][1] + tess.svars.colors[i][2]) / 3; - tess.svars.colors[i][0] = tess.svars.colors[i][1] = tess.svars.colors[i][2] = scale; - } - } -#endif -} - - -static void ComputeFogValues(vec4_t fogDistanceVector, vec4_t fogDepthVector, float *eyeT) -{ - // from RB_CalcFogTexCoords() - fog_t *fog; - vec3_t local; - - if (!tess.fogNum) - return; - - fog = tr.world->fogs + tess.fogNum; - - VectorSubtract( backEnd.or.origin, backEnd.viewParms.or.origin, local ); - fogDistanceVector[0] = -backEnd.or.modelMatrix[2]; - fogDistanceVector[1] = -backEnd.or.modelMatrix[6]; - fogDistanceVector[2] = -backEnd.or.modelMatrix[10]; - fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.or.axis[0] ); - - // scale the fog vectors based on the fog's thickness - VectorScale4(fogDistanceVector, fog->tcScale, fogDistanceVector); - - // rotate the gradient vector for this orientation - if ( fog->hasSurface ) { - fogDepthVector[0] = fog->surface[0] * backEnd.or.axis[0][0] + - fog->surface[1] * backEnd.or.axis[0][1] + fog->surface[2] * backEnd.or.axis[0][2]; - fogDepthVector[1] = fog->surface[0] * backEnd.or.axis[1][0] + - fog->surface[1] * backEnd.or.axis[1][1] + fog->surface[2] * backEnd.or.axis[1][2]; - fogDepthVector[2] = fog->surface[0] * backEnd.or.axis[2][0] + - fog->surface[1] * backEnd.or.axis[2][1] + fog->surface[2] * backEnd.or.axis[2][2]; - fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.or.origin, fog->surface ); - - *eyeT = DotProduct( backEnd.or.viewOrigin, fogDepthVector ) + fogDepthVector[3]; - } else { - *eyeT = 1; // non-surface fog always has eye inside - } -} - - -static void ComputeFogColorMask( shaderStage_t *pStage, vec4_t fogColorMask ) -{ - switch(pStage->adjustColorsForFog) - { - case ACFF_MODULATE_RGB: - fogColorMask[0] = - fogColorMask[1] = - fogColorMask[2] = 1.0f; - fogColorMask[3] = 0.0f; - break; - case ACFF_MODULATE_ALPHA: - fogColorMask[0] = - fogColorMask[1] = - fogColorMask[2] = 0.0f; - fogColorMask[3] = 1.0f; - break; - case ACFF_MODULATE_RGBA: - fogColorMask[0] = - fogColorMask[1] = - fogColorMask[2] = - fogColorMask[3] = 1.0f; - break; - default: - fogColorMask[0] = - fogColorMask[1] = - fogColorMask[2] = - fogColorMask[3] = 0.0f; - break; - } -} - - -static void ForwardDlight( void ) { - int l; - //vec3_t origin; - //float scale; - float radius; - - int deformGen; - vec5_t deformParams; - - vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; - float eyeT = 0; - - shaderCommands_t *input = &tess; - shaderStage_t *pStage = tess.xstages[0]; - - if ( !backEnd.refdef.num_dlights ) { - return; - } - - ComputeDeformValues(&deformGen, deformParams); - - ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT); - - for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { - dlight_t *dl; - shaderProgram_t *sp; - vec4_t vector; - vec4_t texMatrix; - vec4_t texOffTurb; - - if ( !( tess.dlightBits & ( 1 << l ) ) ) { - continue; // this surface definately doesn't have any of this light - } - - dl = &backEnd.refdef.dlights[l]; - //VectorCopy( dl->transformed, origin ); - radius = dl->radius; - //scale = 1.0f / radius; - - //if (pStage->glslShaderGroup == tr.lightallShader) - { - int index = pStage->glslShaderIndex; - - index &= ~LIGHTDEF_LIGHTTYPE_MASK; - index |= LIGHTDEF_USE_LIGHT_VECTOR; - - sp = &tr.lightallShader[index]; - } - - backEnd.pc.c_lightallDraws++; - - GLSL_BindProgram(sp); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - GLSL_SetUniformVec3(sp, UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin); - GLSL_SetUniformVec3(sp, UNIFORM_LOCALVIEWORIGIN, backEnd.or.viewOrigin); - - GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - - GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); - if (deformGen != DGEN_NONE) - { - GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); - GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); - } - - if ( input->fogNum ) { - vec4_t fogColorMask; - - GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector); - GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector); - GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT); - - ComputeFogColorMask(pStage, fogColorMask); - - GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask); - } - - { - vec4_t baseColor; - vec4_t vertColor; - - ComputeShaderColors(pStage, baseColor, vertColor, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE); - - GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor); - GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor); - } - - if (pStage->alphaGen == AGEN_PORTAL) - { - GLSL_SetUniformFloat(sp, UNIFORM_PORTALRANGE, tess.shader->portalRange); - } - - GLSL_SetUniformInt(sp, UNIFORM_COLORGEN, pStage->rgbGen); - GLSL_SetUniformInt(sp, UNIFORM_ALPHAGEN, pStage->alphaGen); - - GLSL_SetUniformVec3(sp, UNIFORM_DIRECTEDLIGHT, dl->color); - - VectorSet(vector, 0, 0, 0); - GLSL_SetUniformVec3(sp, UNIFORM_AMBIENTLIGHT, vector); - - VectorCopy(dl->origin, vector); - vector[3] = 1.0f; - GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector); - - GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, radius); - - GLSL_SetUniformVec2(sp, UNIFORM_MATERIALINFO, pStage->materialInfo); - - // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light - // where they aren't rendered - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); - - if (pStage->bundle[TB_DIFFUSEMAP].image[0]) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP); - - if (pStage->bundle[TB_NORMALMAP].image[0]) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_NORMALMAP], TB_NORMALMAP); - - if (pStage->bundle[TB_SPECULARMAP].image[0]) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_SPECULARMAP], TB_SPECULARMAP); - - if (r_dlightMode->integer >= 2) - { - GL_SelectTexture(TB_SHADOWMAP); - GL_Bind(tr.shadowCubemaps[l]); - GL_SelectTexture(0); - } - - ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb ); - GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix); - GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, texOffTurb); - - GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen); - - // - // draw - // - - if (input->multiDrawPrimitives) - { - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); - } - - backEnd.pc.c_totalIndexes += tess.numIndexes; - backEnd.pc.c_dlightIndexes += tess.numIndexes; - backEnd.pc.c_dlightVertexes += tess.numVertexes; - } -} - - -static void ProjectPshadowVBOGLSL( void ) { - int l; - vec3_t origin; - float radius; - - int deformGen; - vec5_t deformParams; - - shaderCommands_t *input = &tess; - - if ( !backEnd.refdef.num_pshadows ) { - return; - } - - ComputeDeformValues(&deformGen, deformParams); - - for ( l = 0 ; l < backEnd.refdef.num_pshadows ; l++ ) { - pshadow_t *ps; - shaderProgram_t *sp; - vec4_t vector; - - if ( !( tess.pshadowBits & ( 1 << l ) ) ) { - continue; // this surface definately doesn't have any of this shadow - } - - ps = &backEnd.refdef.pshadows[l]; - VectorCopy( ps->lightOrigin, origin ); - radius = ps->lightRadius; - - sp = &tr.pshadowShader; - - GLSL_BindProgram(sp); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - - VectorCopy(origin, vector); - vector[3] = 1.0f; - GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector); - - VectorScale(ps->lightViewAxis[0], 1.0f / ps->viewRadius, vector); - GLSL_SetUniformVec3(sp, UNIFORM_LIGHTFORWARD, vector); - - VectorScale(ps->lightViewAxis[1], 1.0f / ps->viewRadius, vector); - GLSL_SetUniformVec3(sp, UNIFORM_LIGHTRIGHT, vector); - - VectorScale(ps->lightViewAxis[2], 1.0f / ps->viewRadius, vector); - GLSL_SetUniformVec3(sp, UNIFORM_LIGHTUP, vector); - - GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, radius); - - // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light - // where they aren't rendered - GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); - - GL_BindToTMU( tr.pshadowMaps[l], TB_DIFFUSEMAP ); - - // - // draw - // - - if (input->multiDrawPrimitives) - { - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); - } - - backEnd.pc.c_totalIndexes += tess.numIndexes; - //backEnd.pc.c_dlightIndexes += tess.numIndexes; - } -} - - - -/* -=================== -RB_FogPass - -Blends a fog texture on top of everything else -=================== -*/ -static void RB_FogPass( void ) { - fog_t *fog; - vec4_t color; - vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; - float eyeT = 0; - shaderProgram_t *sp; - - int deformGen; - vec5_t deformParams; - - ComputeDeformValues(&deformGen, deformParams); - - { - int index = 0; - - if (deformGen != DGEN_NONE) - index |= FOGDEF_USE_DEFORM_VERTEXES; - - if (glState.vertexAnimation) - index |= FOGDEF_USE_VERTEX_ANIMATION; - - sp = &tr.fogShader[index]; - } - - backEnd.pc.c_fogDraws++; - - GLSL_BindProgram(sp); - - fog = tr.world->fogs + tess.fogNum; - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - - GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - - GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); - if (deformGen != DGEN_NONE) - { - GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); - GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); - } - - color[0] = ((unsigned char *)(&fog->colorInt))[0] / 255.0f; - color[1] = ((unsigned char *)(&fog->colorInt))[1] / 255.0f; - color[2] = ((unsigned char *)(&fog->colorInt))[2] / 255.0f; - color[3] = ((unsigned char *)(&fog->colorInt))[3] / 255.0f; - GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color); - - ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT); - - GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector); - GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector); - GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT); - - if ( tess.shader->fogPass == FP_EQUAL ) { - GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); - } else { - GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); - } - - if (tess.multiDrawPrimitives) - { - shaderCommands_t *input = &tess; - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVBO(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); - } -} - - -static unsigned int RB_CalcShaderVertexAttribs( shaderCommands_t *input ) -{ - unsigned int vertexAttribs = input->shader->vertexAttribs; - - if(glState.vertexAnimation) - { - vertexAttribs |= ATTR_POSITION2; - if (vertexAttribs & ATTR_NORMAL) - { - vertexAttribs |= ATTR_NORMAL2; -#ifdef USE_VERT_TANGENT_SPACE - vertexAttribs |= ATTR_TANGENT2; -#endif - } - } - - return vertexAttribs; -} - -static void RB_IterateStagesGeneric( shaderCommands_t *input ) -{ - int stage; - - vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; - float eyeT = 0; - - int deformGen; - vec5_t deformParams; - - ComputeDeformValues(&deformGen, deformParams); - - ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT); - - for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) - { - shaderStage_t *pStage = input->xstages[stage]; - shaderProgram_t *sp; - vec4_t texMatrix; - vec4_t texOffTurb; - - if ( !pStage ) - { - break; - } - - if (backEnd.depthFill) - { - if (pStage->glslShaderGroup == tr.lightallShader) - { - int index = 0; - - if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity) - { - index |= LIGHTDEF_ENTITY; - } - - if (pStage->stateBits & GLS_ATEST_BITS) - { - index |= LIGHTDEF_USE_TCGEN_AND_TCMOD; - } - - sp = &pStage->glslShaderGroup[index]; - } - else - { - int shaderAttribs = 0; - - if (tess.shader->numDeforms && !ShaderRequiresCPUDeforms(tess.shader)) - { - shaderAttribs |= GENERICDEF_USE_DEFORM_VERTEXES; - } - - if (glState.vertexAnimation) - { - shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION; - } - - if (pStage->stateBits & GLS_ATEST_BITS) - { - shaderAttribs |= GENERICDEF_USE_TCGEN_AND_TCMOD; - } - - sp = &tr.genericShader[shaderAttribs]; - } - } - else if (pStage->glslShaderGroup == tr.lightallShader) - { - int index = pStage->glslShaderIndex; - - if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity) - { - index |= LIGHTDEF_ENTITY; - } - - if (r_sunlightMode->integer && (backEnd.viewParms.flags & VPF_USESUNLIGHT) && (index & LIGHTDEF_LIGHTTYPE_MASK)) - { - index |= LIGHTDEF_USE_SHADOWMAP; - } - - if (r_lightmap->integer && index & LIGHTDEF_USE_LIGHTMAP) - { - index = LIGHTDEF_USE_LIGHTMAP; - } - - sp = &pStage->glslShaderGroup[index]; - - backEnd.pc.c_lightallDraws++; - } - else - { - sp = GLSL_GetGenericShaderProgram(stage); - - backEnd.pc.c_genericDraws++; - } - - GLSL_BindProgram(sp); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - GLSL_SetUniformVec3(sp, UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin); - GLSL_SetUniformVec3(sp, UNIFORM_LOCALVIEWORIGIN, backEnd.or.viewOrigin); - - GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - - GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); - if (deformGen != DGEN_NONE) - { - GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); - GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); - } - - if ( input->fogNum ) { - GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector); - GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector); - GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT); - } - - GL_State( pStage->stateBits ); - - { - vec4_t baseColor; - vec4_t vertColor; - - ComputeShaderColors(pStage, baseColor, vertColor, pStage->stateBits); - - if ((backEnd.refdef.colorScale != 1.0f) && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL)) - { - // use VectorScale to only scale first three values, not alpha - VectorScale(baseColor, backEnd.refdef.colorScale, baseColor); - VectorScale(vertColor, backEnd.refdef.colorScale, vertColor); - } - - GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor); - GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor); - } - - if (pStage->rgbGen == CGEN_LIGHTING_DIFFUSE) - { - vec4_t vec; - - VectorScale(backEnd.currentEntity->ambientLight, 1.0f / 255.0f, vec); - GLSL_SetUniformVec3(sp, UNIFORM_AMBIENTLIGHT, vec); - - VectorScale(backEnd.currentEntity->directedLight, 1.0f / 255.0f, vec); - GLSL_SetUniformVec3(sp, UNIFORM_DIRECTEDLIGHT, vec); - - VectorCopy(backEnd.currentEntity->lightDir, vec); - vec[3] = 0.0f; - GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vec); - GLSL_SetUniformVec3(sp, UNIFORM_MODELLIGHTDIR, backEnd.currentEntity->modelLightDir); - - GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, 0.0f); - } - - if (pStage->alphaGen == AGEN_PORTAL) - { - GLSL_SetUniformFloat(sp, UNIFORM_PORTALRANGE, tess.shader->portalRange); - } - - GLSL_SetUniformInt(sp, UNIFORM_COLORGEN, pStage->rgbGen); - GLSL_SetUniformInt(sp, UNIFORM_ALPHAGEN, pStage->alphaGen); - - if ( input->fogNum ) - { - vec4_t fogColorMask; - - ComputeFogColorMask(pStage, fogColorMask); - - GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask); - } - - ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb ); - GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix); - GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, texOffTurb); - - GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen); - if (pStage->bundle[0].tcGen == TCGEN_VECTOR) - { - vec3_t vec; - - VectorCopy(pStage->bundle[0].tcGenVectors[0], vec); - GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR0, vec); - VectorCopy(pStage->bundle[0].tcGenVectors[1], vec); - GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR1, vec); - } - - GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); - - GLSL_SetUniformVec2(sp, UNIFORM_MATERIALINFO, pStage->materialInfo); - - //GLSL_SetUniformFloat(sp, UNIFORM_MAPLIGHTSCALE, backEnd.refdef.mapLightScale); - - // - // do multitexture - // - if ( backEnd.depthFill ) - { - if (!(pStage->stateBits & GLS_ATEST_BITS)) - GL_BindToTMU( tr.whiteImage, 0 ); - else if ( pStage->bundle[TB_COLORMAP].image[0] != 0 ) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_COLORMAP], TB_COLORMAP ); - } - else if ( pStage->glslShaderGroup == tr.lightallShader ) - { - int i; - vec4_t enableTextures; - - if (r_sunlightMode->integer && (backEnd.viewParms.flags & VPF_USESUNLIGHT) && (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK)) - { - GL_BindToTMU(tr.screenShadowImage, TB_SHADOWMAP); - GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTAMBIENT, backEnd.refdef.sunAmbCol); - GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTCOLOR, backEnd.refdef.sunCol); - GLSL_SetUniformVec4(sp, UNIFORM_PRIMARYLIGHTORIGIN, backEnd.refdef.sunDir); - } - - VectorSet4(enableTextures, 0, 0, 0, 0); - if ((r_lightmap->integer == 1 || r_lightmap->integer == 2) && pStage->bundle[TB_LIGHTMAP].image[0]) - { - for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) - { - if (i == TB_LIGHTMAP) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_LIGHTMAP], i); - else - GL_BindToTMU( tr.whiteImage, i ); - } - } - else if (r_lightmap->integer == 3 && pStage->bundle[TB_DELUXEMAP].image[0]) - { - for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) - { - if (i == TB_LIGHTMAP) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_DELUXEMAP], i); - else - GL_BindToTMU( tr.whiteImage, i ); - } - } - else - { - qboolean light = (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) != 0; - qboolean fastLight = !(r_normalMapping->integer || r_specularMapping->integer); - - if (pStage->bundle[TB_DIFFUSEMAP].image[0]) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP); - - if (pStage->bundle[TB_LIGHTMAP].image[0]) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_LIGHTMAP], TB_LIGHTMAP); - - // bind textures that are sampled and used in the glsl shader, and - // bind whiteImage to textures that are sampled but zeroed in the glsl shader - // - // alternatives: - // - use the last bound texture - // -> costs more to sample a higher res texture then throw out the result - // - disable texture sampling in glsl shader with #ifdefs, as before - // -> increases the number of shaders that must be compiled - // - if (light && !fastLight) - { - if (pStage->bundle[TB_NORMALMAP].image[0]) - { - R_BindAnimatedImageToTMU( &pStage->bundle[TB_NORMALMAP], TB_NORMALMAP); - enableTextures[0] = 1.0f; - } - else if (r_normalMapping->integer) - GL_BindToTMU( tr.whiteImage, TB_NORMALMAP ); - - if (pStage->bundle[TB_DELUXEMAP].image[0]) - { - R_BindAnimatedImageToTMU( &pStage->bundle[TB_DELUXEMAP], TB_DELUXEMAP); - enableTextures[1] = 1.0f; - } - else if (r_deluxeMapping->integer) - GL_BindToTMU( tr.whiteImage, TB_DELUXEMAP ); - - if (pStage->bundle[TB_SPECULARMAP].image[0]) - { - R_BindAnimatedImageToTMU( &pStage->bundle[TB_SPECULARMAP], TB_SPECULARMAP); - enableTextures[2] = 1.0f; - } - else if (r_specularMapping->integer) - GL_BindToTMU( tr.whiteImage, TB_SPECULARMAP ); - } - - enableTextures[3] = (r_cubeMapping->integer && !(tr.viewParms.flags & VPF_NOCUBEMAPS) && input->cubemapIndex) ? 1.0f : 0.0f; - } - - GLSL_SetUniformVec4(sp, UNIFORM_ENABLETEXTURES, enableTextures); - } - else if ( pStage->bundle[1].image[0] != 0 ) - { - R_BindAnimatedImageToTMU( &pStage->bundle[0], 0 ); - - // - // lightmap/secondary pass - // - if ( r_lightmap->integer ) { - GLSL_SetUniformInt(sp, UNIFORM_TEXTURE1ENV, GL_REPLACE); - } else { - GLSL_SetUniformInt(sp, UNIFORM_TEXTURE1ENV, tess.shader->multitextureEnv); - } - - R_BindAnimatedImageToTMU( &pStage->bundle[1], 1 ); - } - else - { - // - // set state - // - R_BindAnimatedImageToTMU( &pStage->bundle[0], 0 ); - - GLSL_SetUniformInt(sp, UNIFORM_TEXTURE1ENV, 0); - } - - // - // testing cube map - // - if (!(tr.viewParms.flags & VPF_NOCUBEMAPS) && input->cubemapIndex && r_cubeMapping->integer) - GL_BindToTMU( tr.cubemaps[input->cubemapIndex - 1], TB_CUBEMAP); - - // - // draw - // - if (input->multiDrawPrimitives) - { - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); - } - - // allow skipping out to show just lightmaps during development - if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap ) ) - { - break; - } - - if (backEnd.depthFill) - break; - } -} - - -static void RB_RenderShadowmap( shaderCommands_t *input ) -{ - int deformGen; - vec5_t deformParams; - - ComputeDeformValues(&deformGen, deformParams); - - { - shaderProgram_t *sp = &tr.shadowmapShader; - - vec4_t vector; - - GLSL_BindProgram(sp); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); - - GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - - GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); - if (deformGen != DGEN_NONE) - { - GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); - GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); - } - - VectorCopy(backEnd.viewParms.or.origin, vector); - vector[3] = 1.0f; - GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector); - GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, backEnd.viewParms.zFar); - - GL_State( 0 ); - - // - // do multitexture - // - //if ( pStage->glslShaderGroup ) - { - // - // draw - // - - if (input->multiDrawPrimitives) - { - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); - } - } - } -} - - - -/* -** RB_StageIteratorGeneric -*/ -void RB_StageIteratorGeneric( void ) -{ - shaderCommands_t *input; - unsigned int vertexAttribs = 0; - - input = &tess; - - if (!input->numVertexes || !input->numIndexes) - { - return; - } - - if (tess.useInternalVBO) - { - RB_DeformTessGeometry(); - } - - vertexAttribs = RB_CalcShaderVertexAttribs( input ); - - if (tess.useInternalVBO) - { - RB_UpdateVBOs(vertexAttribs); - } - else - { - backEnd.pc.c_staticVboDraws++; - } - - // - // log this call - // - if ( r_logFile->integer ) - { - // don't just call LogComment, or we will get - // a call to va() every frame! - GLimp_LogComment( va("--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name) ); - } - - // - // set face culling appropriately - // - if ((backEnd.viewParms.flags & VPF_DEPTHSHADOW)) - { - //GL_Cull( CT_TWO_SIDED ); - - if (input->shader->cullType == CT_TWO_SIDED) - GL_Cull( CT_TWO_SIDED ); - else if (input->shader->cullType == CT_FRONT_SIDED) - GL_Cull( CT_BACK_SIDED ); - else - GL_Cull( CT_FRONT_SIDED ); - - } - else - GL_Cull( input->shader->cullType ); - - // set polygon offset if necessary - if ( input->shader->polygonOffset ) - { - qglEnable( GL_POLYGON_OFFSET_FILL ); - qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); - } - - // - // Set vertex attribs and pointers - // - GLSL_VertexAttribsState(vertexAttribs); - - // - // render depth if in depthfill mode - // - if (backEnd.depthFill) - { - RB_IterateStagesGeneric( input ); - - // - // reset polygon offset - // - if ( input->shader->polygonOffset ) - { - qglDisable( GL_POLYGON_OFFSET_FILL ); - } - - return; - } - - // - // render shadowmap if in shadowmap mode - // - if (backEnd.viewParms.flags & VPF_SHADOWMAP) - { - if ( input->shader->sort == SS_OPAQUE ) - { - RB_RenderShadowmap( input ); - } - // - // reset polygon offset - // - if ( input->shader->polygonOffset ) - { - qglDisable( GL_POLYGON_OFFSET_FILL ); - } - - return; - } - - // - // - // call shader function - // - RB_IterateStagesGeneric( input ); - - // - // pshadows! - // - if (glRefConfig.framebufferObject && r_shadows->integer == 4 && tess.pshadowBits - && tess.shader->sort <= SS_OPAQUE && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { - ProjectPshadowVBOGLSL(); - } - - - // - // now do any dynamic lighting needed - // - if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE - && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { - if (tess.shader->numUnfoggedPasses == 1 && tess.xstages[0]->glslShaderGroup == tr.lightallShader - && (tess.xstages[0]->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && r_dlightMode->integer) - { - ForwardDlight(); - } - else - { - ProjectDlightTexture(); - } - } - - // - // now do fog - // - if ( tess.fogNum && tess.shader->fogPass ) { - RB_FogPass(); - } - - // - // reset polygon offset - // - if ( input->shader->polygonOffset ) - { - qglDisable( GL_POLYGON_OFFSET_FILL ); - } -} - - -/* -** RB_EndSurface -*/ -void RB_EndSurface( void ) { - shaderCommands_t *input; - - input = &tess; - - if (input->numIndexes == 0 || input->numVertexes == 0) { - return; - } - - if (input->indexes[SHADER_MAX_INDEXES-1] != 0) { - ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_INDEXES hit"); - } - if (input->xyz[SHADER_MAX_VERTEXES-1][0] != 0) { - ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_VERTEXES hit"); - } - - if ( tess.shader == tr.shadowShader ) { - RB_ShadowTessEnd(); - return; - } - - // for debugging of sort order issues, stop rendering after a given sort value - if ( r_debugSort->integer && r_debugSort->integer < tess.shader->sort ) { - return; - } - - // - // update performance counters - // - backEnd.pc.c_shaders++; - backEnd.pc.c_vertexes += tess.numVertexes; - backEnd.pc.c_indexes += tess.numIndexes; - backEnd.pc.c_totalIndexes += tess.numIndexes * tess.numPasses; - - // - // call off to shader specific tess end function - // - tess.currentStageIteratorFunc(); - - // - // draw debugging stuff - // - if ( r_showtris->integer ) { - DrawTris (input); - } - if ( r_shownormals->integer ) { - DrawNormals (input); - } - // clear shader so we can tell we don't have any unclosed surfaces - tess.numIndexes = 0; - tess.numVertexes = 0; - tess.firstIndex = 0; - tess.multiDrawPrimitives = 0; - - GLimp_LogComment( "----------\n" ); -} diff --git a/code/renderergl2/tr_shade_calc.c b/code/renderergl2/tr_shade_calc.c deleted file mode 100644 index c9816fa8b6..0000000000 --- a/code/renderergl2/tr_shade_calc.c +++ /dev/null @@ -1,819 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_shade_calc.c - -#include "tr_local.h" -#if idppc_altivec && !defined(MACOS_X) -#include -#endif - - -#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ ri.ftol( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude)) - -static float *TableForFunc( genFunc_t func ) -{ - switch ( func ) - { - case GF_SIN: - return tr.sinTable; - case GF_TRIANGLE: - return tr.triangleTable; - case GF_SQUARE: - return tr.squareTable; - case GF_SAWTOOTH: - return tr.sawToothTable; - case GF_INVERSE_SAWTOOTH: - return tr.inverseSawToothTable; - case GF_NONE: - default: - break; - } - - ri.Error( ERR_DROP, "TableForFunc called with invalid function '%d' in shader '%s'", func, tess.shader->name ); - return NULL; -} - -/* -** EvalWaveForm -** -** Evaluates a given waveForm_t, referencing backEnd.refdef.time directly -*/ -static float EvalWaveForm( const waveForm_t *wf ) -{ - float *table; - - table = TableForFunc( wf->func ); - - return WAVEVALUE( table, wf->base, wf->amplitude, wf->phase, wf->frequency ); -} - -static float EvalWaveFormClamped( const waveForm_t *wf ) -{ - float glow = EvalWaveForm( wf ); - - if ( glow < 0 ) - { - return 0; - } - - if ( glow > 1 ) - { - return 1; - } - - return glow; -} - -/* -** RB_CalcStretchTexMatrix -*/ -void RB_CalcStretchTexMatrix( const waveForm_t *wf, float *matrix ) -{ - float p; - - p = 1.0f / EvalWaveForm( wf ); - - matrix[0] = p; matrix[2] = 0; matrix[4] = 0.5f - 0.5f * p; - matrix[1] = 0; matrix[3] = p; matrix[5] = 0.5f - 0.5f * p; -} - -/* -==================================================================== - -DEFORMATIONS - -==================================================================== -*/ - -/* -======================== -RB_CalcDeformVertexes - -======================== -*/ -void RB_CalcDeformVertexes( deformStage_t *ds ) -{ - int i; - vec3_t offset; - float scale; - float *xyz = ( float * ) tess.xyz; - uint32_t *normal = tess.normal; - float *table; - - if ( ds->deformationWave.frequency == 0 ) - { - scale = EvalWaveForm( &ds->deformationWave ); - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ ) - { - R_VboUnpackNormal(offset, *normal); - - xyz[0] += offset[0] * scale; - xyz[1] += offset[1] * scale; - xyz[2] += offset[2] * scale; - } - } - else - { - table = TableForFunc( ds->deformationWave.func ); - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ ) - { - float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread; - - scale = WAVEVALUE( table, ds->deformationWave.base, - ds->deformationWave.amplitude, - ds->deformationWave.phase + off, - ds->deformationWave.frequency ); - - R_VboUnpackNormal(offset, *normal); - - xyz[0] += offset[0] * scale; - xyz[1] += offset[1] * scale; - xyz[2] += offset[2] * scale; - } - } -} - -/* -========================= -RB_CalcDeformNormals - -Wiggle the normals for wavy environment mapping -========================= -*/ -void RB_CalcDeformNormals( deformStage_t *ds ) { - int i; - float scale; - float *xyz = ( float * ) tess.xyz; - uint32_t *normal = tess.normal; - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ ) { - vec3_t fNormal; - - R_VboUnpackNormal(fNormal, *normal); - - scale = 0.98f; - scale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, - tess.shaderTime * ds->deformationWave.frequency ); - fNormal[ 0 ] += ds->deformationWave.amplitude * scale; - - scale = 0.98f; - scale = R_NoiseGet4f( 100 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, - tess.shaderTime * ds->deformationWave.frequency ); - fNormal[ 1 ] += ds->deformationWave.amplitude * scale; - - scale = 0.98f; - scale = R_NoiseGet4f( 200 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, - tess.shaderTime * ds->deformationWave.frequency ); - fNormal[ 2 ] += ds->deformationWave.amplitude * scale; - - VectorNormalizeFast( fNormal ); - - *normal = R_VboPackNormal(fNormal); - } -} - -/* -======================== -RB_CalcBulgeVertexes - -======================== -*/ -void RB_CalcBulgeVertexes( deformStage_t *ds ) { - int i; - const float *st = ( const float * ) tess.texCoords[0]; - float *xyz = ( float * ) tess.xyz; - uint32_t *normal = tess.normal; - float now; - - now = backEnd.refdef.time * ds->bulgeSpeed * 0.001f; - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal++ ) { - int off; - float scale; - vec3_t fNormal; - - R_VboUnpackNormal(fNormal, *normal); - - off = (float)( FUNCTABLE_SIZE / (M_PI*2) ) * ( st[0] * ds->bulgeWidth + now ); - - scale = tr.sinTable[ off & FUNCTABLE_MASK ] * ds->bulgeHeight; - - xyz[0] += fNormal[0] * scale; - xyz[1] += fNormal[1] * scale; - xyz[2] += fNormal[2] * scale; - } -} - - -/* -====================== -RB_CalcMoveVertexes - -A deformation that can move an entire surface along a wave path -====================== -*/ -void RB_CalcMoveVertexes( deformStage_t *ds ) { - int i; - float *xyz; - float *table; - float scale; - vec3_t offset; - - table = TableForFunc( ds->deformationWave.func ); - - scale = WAVEVALUE( table, ds->deformationWave.base, - ds->deformationWave.amplitude, - ds->deformationWave.phase, - ds->deformationWave.frequency ); - - VectorScale( ds->moveVector, scale, offset ); - - xyz = ( float * ) tess.xyz; - for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) { - VectorAdd( xyz, offset, xyz ); - } -} - - -/* -============= -DeformText - -Change a polygon into a bunch of text polygons -============= -*/ -void DeformText( const char *text ) { - int i; - vec3_t origin, width, height; - int len; - int ch; - float color[4]; - float bottom, top; - vec3_t mid; - vec3_t fNormal; - - height[0] = 0; - height[1] = 0; - height[2] = -1; - - R_VboUnpackNormal(fNormal, tess.normal[0]); - CrossProduct( fNormal, height, width ); - - // find the midpoint of the box - VectorClear( mid ); - bottom = 999999; - top = -999999; - for ( i = 0 ; i < 4 ; i++ ) { - VectorAdd( tess.xyz[i], mid, mid ); - if ( tess.xyz[i][2] < bottom ) { - bottom = tess.xyz[i][2]; - } - if ( tess.xyz[i][2] > top ) { - top = tess.xyz[i][2]; - } - } - VectorScale( mid, 0.25f, origin ); - - // determine the individual character size - height[0] = 0; - height[1] = 0; - height[2] = ( top - bottom ) * 0.5f; - - VectorScale( width, height[2] * -0.75f, width ); - - // determine the starting position - len = strlen( text ); - VectorMA( origin, (len-1), width, origin ); - - // clear the shader indexes - tess.numIndexes = 0; - tess.numVertexes = 0; - tess.firstIndex = 0; - - color[0] = color[1] = color[2] = color[3] = 1.0f; - - // draw each character - for ( i = 0 ; i < len ; i++ ) { - ch = text[i]; - ch &= 255; - - if ( ch != ' ' ) { - int row, col; - float frow, fcol, size; - - row = ch>>4; - col = ch&15; - - frow = row*0.0625f; - fcol = col*0.0625f; - size = 0.0625f; - - RB_AddQuadStampExt( origin, width, height, color, fcol, frow, fcol + size, frow + size ); - } - VectorMA( origin, -2, width, origin ); - } -} - -/* -================== -GlobalVectorToLocal -================== -*/ -static void GlobalVectorToLocal( const vec3_t in, vec3_t out ) { - out[0] = DotProduct( in, backEnd.or.axis[0] ); - out[1] = DotProduct( in, backEnd.or.axis[1] ); - out[2] = DotProduct( in, backEnd.or.axis[2] ); -} - -/* -===================== -AutospriteDeform - -Assuming all the triangles for this shader are independant -quads, rebuild them as forward facing sprites -===================== -*/ -static void AutospriteDeform( void ) { - int i; - int oldVerts; - float *xyz; - vec3_t mid, delta; - float radius; - vec3_t left, up; - vec3_t leftDir, upDir; - - if ( tess.numVertexes & 3 ) { - ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd vertex count\n", tess.shader->name ); - } - if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) { - ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd index count\n", tess.shader->name ); - } - - oldVerts = tess.numVertexes; - tess.numVertexes = 0; - tess.numIndexes = 0; - tess.firstIndex = 0; - - if ( backEnd.currentEntity != &tr.worldEntity ) { - GlobalVectorToLocal( backEnd.viewParms.or.axis[1], leftDir ); - GlobalVectorToLocal( backEnd.viewParms.or.axis[2], upDir ); - } else { - VectorCopy( backEnd.viewParms.or.axis[1], leftDir ); - VectorCopy( backEnd.viewParms.or.axis[2], upDir ); - } - - for ( i = 0 ; i < oldVerts ; i+=4 ) { - // find the midpoint - xyz = tess.xyz[i]; - - mid[0] = 0.25f * (xyz[0] + xyz[4] + xyz[8] + xyz[12]); - mid[1] = 0.25f * (xyz[1] + xyz[5] + xyz[9] + xyz[13]); - mid[2] = 0.25f * (xyz[2] + xyz[6] + xyz[10] + xyz[14]); - - VectorSubtract( xyz, mid, delta ); - radius = VectorLength( delta ) * 0.707f; // / sqrt(2) - - VectorScale( leftDir, radius, left ); - VectorScale( upDir, radius, up ); - - if ( backEnd.viewParms.isMirror ) { - VectorSubtract( vec3_origin, left, left ); - } - - // compensate for scale in the axes if necessary - if ( backEnd.currentEntity->e.nonNormalizedAxes ) { - float axisLength; - axisLength = VectorLength( backEnd.currentEntity->e.axis[0] ); - if ( !axisLength ) { - axisLength = 0; - } else { - axisLength = 1.0f / axisLength; - } - VectorScale(left, axisLength, left); - VectorScale(up, axisLength, up); - } - - RB_AddQuadStamp( mid, left, up, tess.vertexColors[i] ); - } -} - - -/* -===================== -Autosprite2Deform - -Autosprite2 will pivot a rectangular quad along the center of its long axis -===================== -*/ -int edgeVerts[6][2] = { - { 0, 1 }, - { 0, 2 }, - { 0, 3 }, - { 1, 2 }, - { 1, 3 }, - { 2, 3 } -}; - -static void Autosprite2Deform( void ) { - int i, j, k; - int indexes; - float *xyz; - vec3_t forward; - - if ( tess.numVertexes & 3 ) { - ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd vertex count\n", tess.shader->name ); - } - if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) { - ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd index count\n", tess.shader->name ); - } - - if ( backEnd.currentEntity != &tr.worldEntity ) { - GlobalVectorToLocal( backEnd.viewParms.or.axis[0], forward ); - } else { - VectorCopy( backEnd.viewParms.or.axis[0], forward ); - } - - // this is a lot of work for two triangles... - // we could precalculate a lot of it is an issue, but it would mess up - // the shader abstraction - for ( i = 0, indexes = 0 ; i < tess.numVertexes ; i+=4, indexes+=6 ) { - float lengths[2]; - int nums[2]; - vec3_t mid[2]; - vec3_t major, minor; - float *v1, *v2; - - // find the midpoint - xyz = tess.xyz[i]; - - // identify the two shortest edges - nums[0] = nums[1] = 0; - lengths[0] = lengths[1] = 999999; - - for ( j = 0 ; j < 6 ; j++ ) { - float l; - vec3_t temp; - - v1 = xyz + 4 * edgeVerts[j][0]; - v2 = xyz + 4 * edgeVerts[j][1]; - - VectorSubtract( v1, v2, temp ); - - l = DotProduct( temp, temp ); - if ( l < lengths[0] ) { - nums[1] = nums[0]; - lengths[1] = lengths[0]; - nums[0] = j; - lengths[0] = l; - } else if ( l < lengths[1] ) { - nums[1] = j; - lengths[1] = l; - } - } - - for ( j = 0 ; j < 2 ; j++ ) { - v1 = xyz + 4 * edgeVerts[nums[j]][0]; - v2 = xyz + 4 * edgeVerts[nums[j]][1]; - - mid[j][0] = 0.5f * (v1[0] + v2[0]); - mid[j][1] = 0.5f * (v1[1] + v2[1]); - mid[j][2] = 0.5f * (v1[2] + v2[2]); - } - - // find the vector of the major axis - VectorSubtract( mid[1], mid[0], major ); - - // cross this with the view direction to get minor axis - CrossProduct( major, forward, minor ); - VectorNormalize( minor ); - - // re-project the points - for ( j = 0 ; j < 2 ; j++ ) { - float l; - - v1 = xyz + 4 * edgeVerts[nums[j]][0]; - v2 = xyz + 4 * edgeVerts[nums[j]][1]; - - l = 0.5 * sqrt( lengths[j] ); - - // we need to see which direction this edge - // is used to determine direction of projection - for ( k = 0 ; k < 5 ; k++ ) { - if ( tess.indexes[ indexes + k ] == i + edgeVerts[nums[j]][0] - && tess.indexes[ indexes + k + 1 ] == i + edgeVerts[nums[j]][1] ) { - break; - } - } - - if ( k == 5 ) { - VectorMA( mid[j], l, minor, v1 ); - VectorMA( mid[j], -l, minor, v2 ); - } else { - VectorMA( mid[j], -l, minor, v1 ); - VectorMA( mid[j], l, minor, v2 ); - } - } - } -} - - -/* -===================== -RB_DeformTessGeometry - -===================== -*/ -void RB_DeformTessGeometry( void ) { - int i; - deformStage_t *ds; - - if(!ShaderRequiresCPUDeforms(tess.shader)) - { - // we don't need the following CPU deforms - return; - } - - for ( i = 0 ; i < tess.shader->numDeforms ; i++ ) { - ds = &tess.shader->deforms[ i ]; - - switch ( ds->deformation ) { - case DEFORM_NONE: - break; - case DEFORM_NORMALS: - RB_CalcDeformNormals( ds ); - break; - case DEFORM_WAVE: - RB_CalcDeformVertexes( ds ); - break; - case DEFORM_BULGE: - RB_CalcBulgeVertexes( ds ); - break; - case DEFORM_MOVE: - RB_CalcMoveVertexes( ds ); - break; - case DEFORM_PROJECTION_SHADOW: - RB_ProjectionShadowDeform(); - break; - case DEFORM_AUTOSPRITE: - AutospriteDeform(); - break; - case DEFORM_AUTOSPRITE2: - Autosprite2Deform(); - break; - case DEFORM_TEXT0: - case DEFORM_TEXT1: - case DEFORM_TEXT2: - case DEFORM_TEXT3: - case DEFORM_TEXT4: - case DEFORM_TEXT5: - case DEFORM_TEXT6: - case DEFORM_TEXT7: - DeformText( backEnd.refdef.text[ds->deformation - DEFORM_TEXT0] ); - break; - } - } -} - -/* -==================================================================== - -COLORS - -==================================================================== -*/ - - -/* -** RB_CalcWaveColorSingle -*/ -float RB_CalcWaveColorSingle( const waveForm_t *wf ) -{ - float glow; - - if ( wf->func == GF_NOISE ) { - glow = wf->base + R_NoiseGet4f( 0, 0, 0, ( tess.shaderTime + wf->phase ) * wf->frequency ) * wf->amplitude; - } else { - glow = EvalWaveForm( wf ) * tr.identityLight; - } - - if ( glow < 0 ) { - glow = 0; - } - else if ( glow > 1 ) { - glow = 1; - } - - return glow; -} - -/* -** RB_CalcWaveAlphaSingle -*/ -float RB_CalcWaveAlphaSingle( const waveForm_t *wf ) -{ - return EvalWaveFormClamped( wf ); -} - -/* -** RB_CalcModulateColorsByFog -*/ -void RB_CalcModulateColorsByFog( unsigned char *colors ) { - int i; - float texCoords[SHADER_MAX_VERTEXES][2]; - - // calculate texcoords so we can derive density - // this is not wasted, because it would only have - // been previously called if the surface was opaque - RB_CalcFogTexCoords( texCoords[0] ); - - for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) { - float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] ); - colors[0] *= f; - colors[1] *= f; - colors[2] *= f; - } -} - - -/* -==================================================================== - -TEX COORDS - -==================================================================== -*/ - -/* -======================== -RB_CalcFogTexCoords - -To do the clipped fog plane really correctly, we should use -projected textures, but I don't trust the drivers and it -doesn't fit our shader data. -======================== -*/ -void RB_CalcFogTexCoords( float *st ) { - int i; - float *v; - float s, t; - float eyeT; - qboolean eyeOutside; - fog_t *fog; - vec3_t local; - vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; - - fog = tr.world->fogs + tess.fogNum; - - // all fogging distance is based on world Z units - VectorSubtract( backEnd.or.origin, backEnd.viewParms.or.origin, local ); - fogDistanceVector[0] = -backEnd.or.modelMatrix[2]; - fogDistanceVector[1] = -backEnd.or.modelMatrix[6]; - fogDistanceVector[2] = -backEnd.or.modelMatrix[10]; - fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.or.axis[0] ); - - // scale the fog vectors based on the fog's thickness - fogDistanceVector[0] *= fog->tcScale; - fogDistanceVector[1] *= fog->tcScale; - fogDistanceVector[2] *= fog->tcScale; - fogDistanceVector[3] *= fog->tcScale; - - // rotate the gradient vector for this orientation - if ( fog->hasSurface ) { - fogDepthVector[0] = fog->surface[0] * backEnd.or.axis[0][0] + - fog->surface[1] * backEnd.or.axis[0][1] + fog->surface[2] * backEnd.or.axis[0][2]; - fogDepthVector[1] = fog->surface[0] * backEnd.or.axis[1][0] + - fog->surface[1] * backEnd.or.axis[1][1] + fog->surface[2] * backEnd.or.axis[1][2]; - fogDepthVector[2] = fog->surface[0] * backEnd.or.axis[2][0] + - fog->surface[1] * backEnd.or.axis[2][1] + fog->surface[2] * backEnd.or.axis[2][2]; - fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.or.origin, fog->surface ); - - eyeT = DotProduct( backEnd.or.viewOrigin, fogDepthVector ) + fogDepthVector[3]; - } else { - eyeT = 1; // non-surface fog always has eye inside - } - - // see if the viewpoint is outside - // this is needed for clipping distance even for constant fog - - if ( eyeT < 0 ) { - eyeOutside = qtrue; - } else { - eyeOutside = qfalse; - } - - fogDistanceVector[3] += 1.0/512; - - // calculate density for each point - for (i = 0, v = tess.xyz[0] ; i < tess.numVertexes ; i++, v += 4) { - // calculate the length in fog - s = DotProduct( v, fogDistanceVector ) + fogDistanceVector[3]; - t = DotProduct( v, fogDepthVector ) + fogDepthVector[3]; - - // partially clipped fogs use the T axis - if ( eyeOutside ) { - if ( t < 1.0 ) { - t = 1.0/32; // point is outside, so no fogging - } else { - t = 1.0/32 + 30.0/32 * t / ( t - eyeT ); // cut the distance at the fog plane - } - } else { - if ( t < 0 ) { - t = 1.0/32; // point is outside, so no fogging - } else { - t = 31.0/32; - } - } - - st[0] = s; - st[1] = t; - st += 2; - } -} - -/* -** RB_CalcTurbulentFactors -*/ -void RB_CalcTurbulentFactors( const waveForm_t *wf, float *amplitude, float *now ) -{ - *now = wf->phase + tess.shaderTime * wf->frequency; - *amplitude = wf->amplitude; -} - -/* -** RB_CalcScaleTexMatrix -*/ -void RB_CalcScaleTexMatrix( const float scale[2], float *matrix ) -{ - matrix[0] = scale[0]; matrix[2] = 0.0f; matrix[4] = 0.0f; - matrix[1] = 0.0f; matrix[3] = scale[1]; matrix[5] = 0.0f; -} - -/* -** RB_CalcScrollTexMatrix -*/ -void RB_CalcScrollTexMatrix( const float scrollSpeed[2], float *matrix ) -{ - float timeScale = tess.shaderTime; - float adjustedScrollS, adjustedScrollT; - - adjustedScrollS = scrollSpeed[0] * timeScale; - adjustedScrollT = scrollSpeed[1] * timeScale; - - // clamp so coordinates don't continuously get larger, causing problems - // with hardware limits - adjustedScrollS = adjustedScrollS - floor( adjustedScrollS ); - adjustedScrollT = adjustedScrollT - floor( adjustedScrollT ); - - matrix[0] = 1.0f; matrix[2] = 0.0f; matrix[4] = adjustedScrollS; - matrix[1] = 0.0f; matrix[3] = 1.0f; matrix[5] = adjustedScrollT; -} - -/* -** RB_CalcTransformTexMatrix -*/ -void RB_CalcTransformTexMatrix( const texModInfo_t *tmi, float *matrix ) -{ - matrix[0] = tmi->matrix[0][0]; matrix[2] = tmi->matrix[1][0]; matrix[4] = tmi->translate[0]; - matrix[1] = tmi->matrix[0][1]; matrix[3] = tmi->matrix[1][1]; matrix[5] = tmi->translate[1]; -} - -/* -** RB_CalcRotateTexMatrix -*/ -void RB_CalcRotateTexMatrix( float degsPerSecond, float *matrix ) -{ - float timeScale = tess.shaderTime; - float degs; - int index; - float sinValue, cosValue; - - degs = -degsPerSecond * timeScale; - index = degs * ( FUNCTABLE_SIZE / 360.0f ); - - sinValue = tr.sinTable[ index & FUNCTABLE_MASK ]; - cosValue = tr.sinTable[ ( index + FUNCTABLE_SIZE / 4 ) & FUNCTABLE_MASK ]; - - matrix[0] = cosValue; matrix[2] = -sinValue; matrix[4] = 0.5 - 0.5 * cosValue + 0.5 * sinValue; - matrix[1] = sinValue; matrix[3] = cosValue; matrix[5] = 0.5 - 0.5 * sinValue - 0.5 * cosValue; -} diff --git a/code/renderergl2/tr_shader.c b/code/renderergl2/tr_shader.c deleted file mode 100644 index 6dbac55a36..0000000000 --- a/code/renderergl2/tr_shader.c +++ /dev/null @@ -1,3863 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - -// tr_shader.c -- this file deals with the parsing and definition of shaders - -static char *s_shaderText; - -// the shader is parsed into these global variables, then copied into -// dynamically allocated memory if it is valid. -static shaderStage_t stages[MAX_SHADER_STAGES]; -static shader_t shader; -static texModInfo_t texMods[MAX_SHADER_STAGES][TR_MAX_TEXMODS]; - -#define FILE_HASH_SIZE 1024 -static shader_t* hashTable[FILE_HASH_SIZE]; - -#define MAX_SHADERTEXT_HASH 2048 -static char **shaderTextHashTable[MAX_SHADERTEXT_HASH]; - -/* -================ -return a hash value for the filename -================ -*/ -#ifdef __GNUCC__ - #warning TODO: check if long is ok here -#endif -static long generateHashValue( const char *fname, const int size ) { - int i; - long hash; - char letter; - - hash = 0; - i = 0; - while (fname[i] != '\0') { - letter = tolower(fname[i]); - if (letter =='.') break; // don't include extension - if (letter =='\\') letter = '/'; // damn path names - if (letter == PATH_SEP) letter = '/'; // damn path names - hash+=(long)(letter)*(i+119); - i++; - } - hash = (hash ^ (hash >> 10) ^ (hash >> 20)); - hash &= (size-1); - return hash; -} - -void R_RemapShader(const char *shaderName, const char *newShaderName, const char *timeOffset) { - char strippedName[MAX_QPATH]; - int hash; - shader_t *sh, *sh2; - qhandle_t h; - - sh = R_FindShaderByName( shaderName ); - if (sh == NULL || sh == tr.defaultShader) { - h = RE_RegisterShaderLightMap(shaderName, 0); - sh = R_GetShaderByHandle(h); - } - if (sh == NULL || sh == tr.defaultShader) { - ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: shader %s not found\n", shaderName ); - return; - } - - sh2 = R_FindShaderByName( newShaderName ); - if (sh2 == NULL || sh2 == tr.defaultShader) { - h = RE_RegisterShaderLightMap(newShaderName, 0); - sh2 = R_GetShaderByHandle(h); - } - - if (sh2 == NULL || sh2 == tr.defaultShader) { - ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: new shader %s not found\n", newShaderName ); - return; - } - - // remap all the shaders with the given name - // even tho they might have different lightmaps - COM_StripExtension(shaderName, strippedName, sizeof(strippedName)); - hash = generateHashValue(strippedName, FILE_HASH_SIZE); - for (sh = hashTable[hash]; sh; sh = sh->next) { - if (Q_stricmp(sh->name, strippedName) == 0) { - if (sh != sh2) { - sh->remappedShader = sh2; - } else { - sh->remappedShader = NULL; - } - } - } - if (timeOffset) { - sh2->timeOffset = atof(timeOffset); - } -} - -/* -=============== -ParseVector -=============== -*/ -static qboolean ParseVector( char **text, int count, float *v ) { - char *token; - int i; - - // FIXME: spaces are currently required after parens, should change parseext... - token = COM_ParseExt( text, qfalse ); - if ( strcmp( token, "(" ) ) { - ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name ); - return qfalse; - } - - for ( i = 0 ; i < count ; i++ ) { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) { - ri.Printf( PRINT_WARNING, "WARNING: missing vector element in shader '%s'\n", shader.name ); - return qfalse; - } - v[i] = atof( token ); - } - - token = COM_ParseExt( text, qfalse ); - if ( strcmp( token, ")" ) ) { - ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name ); - return qfalse; - } - - return qtrue; -} - - -/* -=============== -NameToAFunc -=============== -*/ -static unsigned NameToAFunc( const char *funcname ) -{ - if ( !Q_stricmp( funcname, "GT0" ) ) - { - return GLS_ATEST_GT_0; - } - else if ( !Q_stricmp( funcname, "LT128" ) ) - { - return GLS_ATEST_LT_80; - } - else if ( !Q_stricmp( funcname, "GE128" ) ) - { - return GLS_ATEST_GE_80; - } - - ri.Printf( PRINT_WARNING, "WARNING: invalid alphaFunc name '%s' in shader '%s'\n", funcname, shader.name ); - return 0; -} - - -/* -=============== -NameToSrcBlendMode -=============== -*/ -static int NameToSrcBlendMode( const char *name ) -{ - if ( !Q_stricmp( name, "GL_ONE" ) ) - { - return GLS_SRCBLEND_ONE; - } - else if ( !Q_stricmp( name, "GL_ZERO" ) ) - { - return GLS_SRCBLEND_ZERO; - } - else if ( !Q_stricmp( name, "GL_DST_COLOR" ) ) - { - return GLS_SRCBLEND_DST_COLOR; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_COLOR" ) ) - { - return GLS_SRCBLEND_ONE_MINUS_DST_COLOR; - } - else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) ) - { - return GLS_SRCBLEND_SRC_ALPHA; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) ) - { - return GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA; - } - else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) ) - { - if (r_ignoreDstAlpha->integer) - return GLS_SRCBLEND_ONE; - - return GLS_SRCBLEND_DST_ALPHA; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) ) - { - if (r_ignoreDstAlpha->integer) - return GLS_SRCBLEND_ZERO; - - return GLS_SRCBLEND_ONE_MINUS_DST_ALPHA; - } - else if ( !Q_stricmp( name, "GL_SRC_ALPHA_SATURATE" ) ) - { - return GLS_SRCBLEND_ALPHA_SATURATE; - } - - ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name ); - return GLS_SRCBLEND_ONE; -} - -/* -=============== -NameToDstBlendMode -=============== -*/ -static int NameToDstBlendMode( const char *name ) -{ - if ( !Q_stricmp( name, "GL_ONE" ) ) - { - return GLS_DSTBLEND_ONE; - } - else if ( !Q_stricmp( name, "GL_ZERO" ) ) - { - return GLS_DSTBLEND_ZERO; - } - else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) ) - { - return GLS_DSTBLEND_SRC_ALPHA; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) ) - { - return GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } - else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) ) - { - if (r_ignoreDstAlpha->integer) - return GLS_DSTBLEND_ONE; - - return GLS_DSTBLEND_DST_ALPHA; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) ) - { - if (r_ignoreDstAlpha->integer) - return GLS_DSTBLEND_ZERO; - - return GLS_DSTBLEND_ONE_MINUS_DST_ALPHA; - } - else if ( !Q_stricmp( name, "GL_SRC_COLOR" ) ) - { - return GLS_DSTBLEND_SRC_COLOR; - } - else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_COLOR" ) ) - { - return GLS_DSTBLEND_ONE_MINUS_SRC_COLOR; - } - - ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name ); - return GLS_DSTBLEND_ONE; -} - -/* -=============== -NameToGenFunc -=============== -*/ -static genFunc_t NameToGenFunc( const char *funcname ) -{ - if ( !Q_stricmp( funcname, "sin" ) ) - { - return GF_SIN; - } - else if ( !Q_stricmp( funcname, "square" ) ) - { - return GF_SQUARE; - } - else if ( !Q_stricmp( funcname, "triangle" ) ) - { - return GF_TRIANGLE; - } - else if ( !Q_stricmp( funcname, "sawtooth" ) ) - { - return GF_SAWTOOTH; - } - else if ( !Q_stricmp( funcname, "inversesawtooth" ) ) - { - return GF_INVERSE_SAWTOOTH; - } - else if ( !Q_stricmp( funcname, "noise" ) ) - { - return GF_NOISE; - } - - ri.Printf( PRINT_WARNING, "WARNING: invalid genfunc name '%s' in shader '%s'\n", funcname, shader.name ); - return GF_SIN; -} - - -/* -=================== -ParseWaveForm -=================== -*/ -static void ParseWaveForm( char **text, waveForm_t *wave ) -{ - char *token; - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->func = NameToGenFunc( token ); - - // BASE, AMP, PHASE, FREQ - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->base = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->amplitude = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->phase = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name ); - return; - } - wave->frequency = atof( token ); -} - - -/* -=================== -ParseTexMod -=================== -*/ -static void ParseTexMod( char *_text, shaderStage_t *stage ) -{ - const char *token; - char **text = &_text; - texModInfo_t *tmi; - - if ( stage->bundle[0].numTexMods == TR_MAX_TEXMODS ) { - ri.Error( ERR_DROP, "ERROR: too many tcMod stages in shader '%s'", shader.name ); - return; - } - - tmi = &stage->bundle[0].texMods[stage->bundle[0].numTexMods]; - stage->bundle[0].numTexMods++; - - token = COM_ParseExt( text, qfalse ); - - // - // turb - // - if ( !Q_stricmp( token, "turb" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.base = atof( token ); - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name ); - return; - } - tmi->wave.amplitude = atof( token ); - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name ); - return; - } - tmi->wave.phase = atof( token ); - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name ); - return; - } - tmi->wave.frequency = atof( token ); - - tmi->type = TMOD_TURBULENT; - } - // - // scale - // - else if ( !Q_stricmp( token, "scale" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name ); - return; - } - tmi->scale[0] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name ); - return; - } - tmi->scale[1] = atof( token ); - tmi->type = TMOD_SCALE; - } - // - // scroll - // - else if ( !Q_stricmp( token, "scroll" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name ); - return; - } - tmi->scroll[0] = atof( token ); - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name ); - return; - } - tmi->scroll[1] = atof( token ); - tmi->type = TMOD_SCROLL; - } - // - // stretch - // - else if ( !Q_stricmp( token, "stretch" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.func = NameToGenFunc( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.base = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.amplitude = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.phase = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name ); - return; - } - tmi->wave.frequency = atof( token ); - - tmi->type = TMOD_STRETCH; - } - // - // transform - // - else if ( !Q_stricmp( token, "transform" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->matrix[0][0] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->matrix[0][1] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->matrix[1][0] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->matrix[1][1] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->translate[0] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name ); - return; - } - tmi->translate[1] = atof( token ); - - tmi->type = TMOD_TRANSFORM; - } - // - // rotate - // - else if ( !Q_stricmp( token, "rotate" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing tcMod rotate parms in shader '%s'\n", shader.name ); - return; - } - tmi->rotateSpeed = atof( token ); - tmi->type = TMOD_ROTATE; - } - // - // entityTranslate - // - else if ( !Q_stricmp( token, "entityTranslate" ) ) - { - tmi->type = TMOD_ENTITY_TRANSLATE; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown tcMod '%s' in shader '%s'\n", token, shader.name ); - } -} - - -/* -=================== -ParseStage -=================== -*/ -static qboolean ParseStage( shaderStage_t *stage, char **text ) -{ - char *token; - int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0; - qboolean depthMaskExplicit = qfalse; - - stage->active = qtrue; - - while ( 1 ) - { - token = COM_ParseExt( text, qtrue ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: no matching '}' found\n" ); - return qfalse; - } - - if ( token[0] == '}' ) - { - break; - } - // - // map - // - else if ( !Q_stricmp( token, "map" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'map' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - if ( !Q_stricmp( token, "$whiteimage" ) ) - { - stage->bundle[0].image[0] = tr.whiteImage; - continue; - } - else if ( !Q_stricmp( token, "$lightmap" ) ) - { - stage->bundle[0].isLightmap = qtrue; - if ( shader.lightmapIndex < 0 ) { - stage->bundle[0].image[0] = tr.whiteImage; - } else { - stage->bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; - } - continue; - } - else if ( !Q_stricmp( token, "$deluxemap" ) ) - { - if (!tr.worldDeluxeMapping) - { - ri.Printf( PRINT_WARNING, "WARNING: shader '%s' wants a deluxe map in a map compiled without them\n", shader.name ); - return qfalse; - } - - stage->bundle[0].isLightmap = qtrue; - if ( shader.lightmapIndex < 0 ) { - stage->bundle[0].image[0] = tr.whiteImage; - } else { - stage->bundle[0].image[0] = tr.deluxemaps[shader.lightmapIndex]; - } - continue; - } - else - { - imgType_t type = IMGTYPE_COLORALPHA; - imgFlags_t flags = IMGFLAG_NONE; - - if (!shader.noMipMaps) - flags |= IMGFLAG_MIPMAP; - - if (!shader.noPicMip) - flags |= IMGFLAG_PICMIP; - - if (stage->type == ST_NORMALMAP || stage->type == ST_NORMALPARALLAXMAP) - { - type = IMGTYPE_NORMAL; - flags |= IMGFLAG_NOLIGHTSCALE; - - if (stage->type == ST_NORMALPARALLAXMAP) - type = IMGTYPE_NORMALHEIGHT; - } - else - { - if (r_genNormalMaps->integer) - flags |= IMGFLAG_GENNORMALMAP; - - if (r_srgb->integer) - flags |= IMGFLAG_SRGB; - } - - stage->bundle[0].image[0] = R_FindImageFile( token, type, flags ); - - if ( !stage->bundle[0].image[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - } - } - // - // clampmap - // - else if ( !Q_stricmp( token, "clampmap" ) ) - { - imgType_t type = IMGTYPE_COLORALPHA; - imgFlags_t flags = IMGFLAG_CLAMPTOEDGE; - - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampmap' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - if (!shader.noMipMaps) - flags |= IMGFLAG_MIPMAP; - - if (!shader.noPicMip) - flags |= IMGFLAG_PICMIP; - - if (stage->type == ST_NORMALMAP || stage->type == ST_NORMALPARALLAXMAP) - { - type = IMGTYPE_NORMAL; - flags |= IMGFLAG_NOLIGHTSCALE; - - if (stage->type == ST_NORMALPARALLAXMAP) - type = IMGTYPE_NORMALHEIGHT; - } - else - { - if (r_genNormalMaps->integer) - flags |= IMGFLAG_GENNORMALMAP; - - if (r_srgb->integer) - flags |= IMGFLAG_SRGB; - } - - - stage->bundle[0].image[0] = R_FindImageFile( token, type, flags ); - if ( !stage->bundle[0].image[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - } - // - // animMap .... - // - else if ( !Q_stricmp( token, "animMap" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'animMmap' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - stage->bundle[0].imageAnimationSpeed = atof( token ); - - // parse up to MAX_IMAGE_ANIMATIONS animations - while ( 1 ) { - int num; - - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) { - break; - } - num = stage->bundle[0].numImageAnimations; - if ( num < MAX_IMAGE_ANIMATIONS ) { - imgFlags_t flags = IMGFLAG_NONE; - - if (!shader.noMipMaps) - flags |= IMGFLAG_MIPMAP; - - if (!shader.noPicMip) - flags |= IMGFLAG_PICMIP; - - if (r_srgb->integer) - flags |= IMGFLAG_SRGB; - - stage->bundle[0].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags ); - if ( !stage->bundle[0].image[num] ) - { - ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - stage->bundle[0].numImageAnimations++; - } - } - } - else if ( !Q_stricmp( token, "videoMap" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMmap' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - stage->bundle[0].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); - if (stage->bundle[0].videoMapHandle != -1) { - stage->bundle[0].isVideoMap = qtrue; - stage->bundle[0].image[0] = tr.scratchImage[stage->bundle[0].videoMapHandle]; - } - } - // - // alphafunc - // - else if ( !Q_stricmp( token, "alphaFunc" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'alphaFunc' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - atestBits = NameToAFunc( token ); - } - // - // depthFunc - // - else if ( !Q_stricmp( token, "depthfunc" ) ) - { - token = COM_ParseExt( text, qfalse ); - - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'depthfunc' keyword in shader '%s'\n", shader.name ); - return qfalse; - } - - if ( !Q_stricmp( token, "lequal" ) ) - { - depthFuncBits = 0; - } - else if ( !Q_stricmp( token, "equal" ) ) - { - depthFuncBits = GLS_DEPTHFUNC_EQUAL; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown depthfunc '%s' in shader '%s'\n", token, shader.name ); - continue; - } - } - // - // detail - // - else if ( !Q_stricmp( token, "detail" ) ) - { - stage->isDetail = qtrue; - } - // - // blendfunc - // or blendfunc - // - else if ( !Q_stricmp( token, "blendfunc" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name ); - continue; - } - // check for "simple" blends first - if ( !Q_stricmp( token, "add" ) ) { - blendSrcBits = GLS_SRCBLEND_ONE; - blendDstBits = GLS_DSTBLEND_ONE; - } else if ( !Q_stricmp( token, "filter" ) ) { - blendSrcBits = GLS_SRCBLEND_DST_COLOR; - blendDstBits = GLS_DSTBLEND_ZERO; - } else if ( !Q_stricmp( token, "blend" ) ) { - blendSrcBits = GLS_SRCBLEND_SRC_ALPHA; - blendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } else { - // complex double blends - blendSrcBits = NameToSrcBlendMode( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name ); - continue; - } - blendDstBits = NameToDstBlendMode( token ); - } - - // clear depth mask for blended surfaces - if ( !depthMaskExplicit ) - { - depthMaskBits = 0; - } - } - // - // stage - // - else if(!Q_stricmp(token, "stage")) - { - token = COM_ParseExt(text, qfalse); - if(token[0] == 0) - { - ri.Printf(PRINT_WARNING, "WARNING: missing parameters for stage in shader '%s'\n", shader.name); - continue; - } - - if(!Q_stricmp(token, "diffuseMap")) - { - stage->type = ST_DIFFUSEMAP; - } - else if(!Q_stricmp(token, "normalMap") || !Q_stricmp(token, "bumpMap")) - { - stage->type = ST_NORMALMAP; - } - else if(!Q_stricmp(token, "normalParallaxMap") || !Q_stricmp(token, "bumpParallaxMap")) - { - if (r_parallaxMapping->integer) - stage->type = ST_NORMALPARALLAXMAP; - else - stage->type = ST_NORMALMAP; - } - else if(!Q_stricmp(token, "specularMap")) - { - stage->type = ST_SPECULARMAP; - stage->materialInfo[0] = 1.0f; - stage->materialInfo[1] = 1.0f; - } - else - { - ri.Printf(PRINT_WARNING, "WARNING: unknown stage parameter '%s' in shader '%s'\n", token, shader.name); - continue; - } - } - // - // specularReflectance - // - else if (!Q_stricmp(token, "specularreflectance")) - { - token = COM_ParseExt(text, qfalse); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for specular reflectance in shader '%s'\n", shader.name ); - continue; - } - stage->materialInfo[0] = atof( token ); - } - // - // specularExponent - // - else if (!Q_stricmp(token, "specularexponent")) - { - float exponent; - - token = COM_ParseExt(text, qfalse); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for specular exponent in shader '%s'\n", shader.name ); - continue; - } - - exponent = atof( token ); - - // Change shininess to gloss - // FIXME: assumes max exponent of 8192 and min of 1, must change here if altered in lightall_fp.glsl - exponent = CLAMP(exponent, 1.0, 8192.0); - - stage->materialInfo[1] = log(exponent) / log(8192.0); - } - // - // gloss - // - else if (!Q_stricmp(token, "gloss")) - { - token = COM_ParseExt(text, qfalse); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameter for gloss in shader '%s'\n", shader.name ); - continue; - } - - stage->materialInfo[1] = atof( token ); - } - // - // rgbGen - // - else if ( !Q_stricmp( token, "rgbGen" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameters for rgbGen in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "wave" ) ) - { - ParseWaveForm( text, &stage->rgbWave ); - stage->rgbGen = CGEN_WAVEFORM; - } - else if ( !Q_stricmp( token, "const" ) ) - { - vec3_t color; - - ParseVector( text, 3, color ); - stage->constantColor[0] = 255 * color[0]; - stage->constantColor[1] = 255 * color[1]; - stage->constantColor[2] = 255 * color[2]; - - stage->rgbGen = CGEN_CONST; - } - else if ( !Q_stricmp( token, "identity" ) ) - { - stage->rgbGen = CGEN_IDENTITY; - } - else if ( !Q_stricmp( token, "identityLighting" ) ) - { - stage->rgbGen = CGEN_IDENTITY_LIGHTING; - } - else if ( !Q_stricmp( token, "entity" ) ) - { - stage->rgbGen = CGEN_ENTITY; - } - else if ( !Q_stricmp( token, "oneMinusEntity" ) ) - { - stage->rgbGen = CGEN_ONE_MINUS_ENTITY; - } - else if ( !Q_stricmp( token, "vertex" ) ) - { - stage->rgbGen = CGEN_VERTEX; - if ( stage->alphaGen == 0 ) { - stage->alphaGen = AGEN_VERTEX; - } - } - else if ( !Q_stricmp( token, "exactVertex" ) ) - { - stage->rgbGen = CGEN_EXACT_VERTEX; - } - else if ( !Q_stricmp( token, "vertexLit" ) ) - { - stage->rgbGen = CGEN_VERTEX_LIT; - if ( stage->alphaGen == 0 ) { - stage->alphaGen = AGEN_VERTEX; - } - } - else if ( !Q_stricmp( token, "exactVertexLit" ) ) - { - stage->rgbGen = CGEN_EXACT_VERTEX_LIT; - } - else if ( !Q_stricmp( token, "lightingDiffuse" ) ) - { - stage->rgbGen = CGEN_LIGHTING_DIFFUSE; - } - else if ( !Q_stricmp( token, "oneMinusVertex" ) ) - { - stage->rgbGen = CGEN_ONE_MINUS_VERTEX; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown rgbGen parameter '%s' in shader '%s'\n", token, shader.name ); - continue; - } - } - // - // alphaGen - // - else if ( !Q_stricmp( token, "alphaGen" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parameters for alphaGen in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "wave" ) ) - { - ParseWaveForm( text, &stage->alphaWave ); - stage->alphaGen = AGEN_WAVEFORM; - } - else if ( !Q_stricmp( token, "const" ) ) - { - token = COM_ParseExt( text, qfalse ); - stage->constantColor[3] = 255 * atof( token ); - stage->alphaGen = AGEN_CONST; - } - else if ( !Q_stricmp( token, "identity" ) ) - { - stage->alphaGen = AGEN_IDENTITY; - } - else if ( !Q_stricmp( token, "entity" ) ) - { - stage->alphaGen = AGEN_ENTITY; - } - else if ( !Q_stricmp( token, "oneMinusEntity" ) ) - { - stage->alphaGen = AGEN_ONE_MINUS_ENTITY; - } - else if ( !Q_stricmp( token, "vertex" ) ) - { - stage->alphaGen = AGEN_VERTEX; - } - else if ( !Q_stricmp( token, "lightingSpecular" ) ) - { - stage->alphaGen = AGEN_LIGHTING_SPECULAR; - } - else if ( !Q_stricmp( token, "oneMinusVertex" ) ) - { - stage->alphaGen = AGEN_ONE_MINUS_VERTEX; - } - else if ( !Q_stricmp( token, "portal" ) ) - { - stage->alphaGen = AGEN_PORTAL; - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - shader.portalRange = 256; - ri.Printf( PRINT_WARNING, "WARNING: missing range parameter for alphaGen portal in shader '%s', defaulting to 256\n", shader.name ); - } - else - { - shader.portalRange = atof( token ); - } - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown alphaGen parameter '%s' in shader '%s'\n", token, shader.name ); - continue; - } - } - // - // tcGen - // - else if ( !Q_stricmp(token, "texgen") || !Q_stricmp( token, "tcGen" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing texgen parm in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "environment" ) ) - { - stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED; - } - else if ( !Q_stricmp( token, "lightmap" ) ) - { - stage->bundle[0].tcGen = TCGEN_LIGHTMAP; - } - else if ( !Q_stricmp( token, "texture" ) || !Q_stricmp( token, "base" ) ) - { - stage->bundle[0].tcGen = TCGEN_TEXTURE; - } - else if ( !Q_stricmp( token, "vector" ) ) - { - ParseVector( text, 3, stage->bundle[0].tcGenVectors[0] ); - ParseVector( text, 3, stage->bundle[0].tcGenVectors[1] ); - - stage->bundle[0].tcGen = TCGEN_VECTOR; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown texgen parm in shader '%s'\n", shader.name ); - } - } - // - // tcMod <...> - // - else if ( !Q_stricmp( token, "tcMod" ) ) - { - char buffer[1024] = ""; - - while ( 1 ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - break; - strcat( buffer, token ); - strcat( buffer, " " ); - } - - ParseTexMod( buffer, stage ); - - continue; - } - // - // depthmask - // - else if ( !Q_stricmp( token, "depthwrite" ) ) - { - depthMaskBits = GLS_DEPTHMASK_TRUE; - depthMaskExplicit = qtrue; - - continue; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name ); - return qfalse; - } - } - - // - // if cgen isn't explicitly specified, use either identity or identitylighting - // - if ( stage->rgbGen == CGEN_BAD ) { - if ( blendSrcBits == 0 || - blendSrcBits == GLS_SRCBLEND_ONE || - blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) { - stage->rgbGen = CGEN_IDENTITY_LIGHTING; - } else { - stage->rgbGen = CGEN_IDENTITY; - } - } - - - // - // implicitly assume that a GL_ONE GL_ZERO blend mask disables blending - // - if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && - ( blendDstBits == GLS_DSTBLEND_ZERO ) ) - { - blendDstBits = blendSrcBits = 0; - depthMaskBits = GLS_DEPTHMASK_TRUE; - } - - // decide which agens we can skip - if ( stage->alphaGen == AGEN_IDENTITY ) { - if ( stage->rgbGen == CGEN_IDENTITY - || stage->rgbGen == CGEN_LIGHTING_DIFFUSE ) { - stage->alphaGen = AGEN_SKIP; - } - } - - // - // compute state bits - // - stage->stateBits = depthMaskBits | - blendSrcBits | blendDstBits | - atestBits | - depthFuncBits; - - return qtrue; -} - -/* -=============== -ParseDeform - -deformVertexes wave -deformVertexes normal -deformVertexes move -deformVertexes bulge -deformVertexes projectionShadow -deformVertexes autoSprite -deformVertexes autoSprite2 -deformVertexes text[0-7] -=============== -*/ -static void ParseDeform( char **text ) { - char *token; - deformStage_t *ds; - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deform parm in shader '%s'\n", shader.name ); - return; - } - - if ( shader.numDeforms == MAX_SHADER_DEFORMS ) { - ri.Printf( PRINT_WARNING, "WARNING: MAX_SHADER_DEFORMS in '%s'\n", shader.name ); - return; - } - - ds = &shader.deforms[ shader.numDeforms ]; - shader.numDeforms++; - - if ( !Q_stricmp( token, "projectionShadow" ) ) { - ds->deformation = DEFORM_PROJECTION_SHADOW; - return; - } - - if ( !Q_stricmp( token, "autosprite" ) ) { - ds->deformation = DEFORM_AUTOSPRITE; - return; - } - - if ( !Q_stricmp( token, "autosprite2" ) ) { - ds->deformation = DEFORM_AUTOSPRITE2; - return; - } - - if ( !Q_stricmpn( token, "text", 4 ) ) { - int n; - - n = token[4] - '0'; - if ( n < 0 || n > 7 ) { - n = 0; - } - ds->deformation = DEFORM_TEXT0 + n; - return; - } - - if ( !Q_stricmp( token, "bulge" ) ) { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name ); - return; - } - ds->bulgeWidth = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name ); - return; - } - ds->bulgeHeight = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name ); - return; - } - ds->bulgeSpeed = atof( token ); - - ds->deformation = DEFORM_BULGE; - return; - } - - if ( !Q_stricmp( token, "wave" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); - return; - } - - if ( atof( token ) != 0 ) - { - ds->deformationSpread = 1.0f / atof( token ); - } - else - { - ds->deformationSpread = 100.0f; - ri.Printf( PRINT_WARNING, "WARNING: illegal div value of 0 in deformVertexes command for shader '%s'\n", shader.name ); - } - - ParseWaveForm( text, &ds->deformationWave ); - ds->deformation = DEFORM_WAVE; - return; - } - - if ( !Q_stricmp( token, "normal" ) ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); - return; - } - ds->deformationWave.amplitude = atof( token ); - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); - return; - } - ds->deformationWave.frequency = atof( token ); - - ds->deformation = DEFORM_NORMALS; - return; - } - - if ( !Q_stricmp( token, "move" ) ) { - int i; - - for ( i = 0 ; i < 3 ; i++ ) { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name ); - return; - } - ds->moveVector[i] = atof( token ); - } - - ParseWaveForm( text, &ds->deformationWave ); - ds->deformation = DEFORM_MOVE; - return; - } - - ri.Printf( PRINT_WARNING, "WARNING: unknown deformVertexes subtype '%s' found in shader '%s'\n", token, shader.name ); -} - - -/* -=============== -ParseSkyParms - -skyParms -=============== -*/ -static void ParseSkyParms( char **text ) { - char *token; - static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"}; - char pathname[MAX_QPATH]; - int i; - imgFlags_t imgFlags = IMGFLAG_MIPMAP | IMGFLAG_PICMIP; - - if (r_srgb->integer) - imgFlags |= IMGFLAG_SRGB; - - // outerbox - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name ); - return; - } - if ( strcmp( token, "-" ) ) { - for (i=0 ; i<6 ; i++) { - Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga" - , token, suf[i] ); - shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, imgFlags | IMGFLAG_CLAMPTOEDGE ); - - if ( !shader.sky.outerbox[i] ) { - shader.sky.outerbox[i] = tr.defaultImage; - } - } - } - - // cloudheight - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name ); - return; - } - shader.sky.cloudHeight = atof( token ); - if ( !shader.sky.cloudHeight ) { - shader.sky.cloudHeight = 512; - } - R_InitSkyTexCoords( shader.sky.cloudHeight ); - - - // innerbox - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name ); - return; - } - if ( strcmp( token, "-" ) ) { - for (i=0 ; i<6 ; i++) { - Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga" - , token, suf[i] ); - shader.sky.innerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, imgFlags ); - if ( !shader.sky.innerbox[i] ) { - shader.sky.innerbox[i] = tr.defaultImage; - } - } - } - - shader.isSky = qtrue; -} - - -/* -================= -ParseSort -================= -*/ -void ParseSort( char **text ) { - char *token; - - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) { - ri.Printf( PRINT_WARNING, "WARNING: missing sort parameter in shader '%s'\n", shader.name ); - return; - } - - if ( !Q_stricmp( token, "portal" ) ) { - shader.sort = SS_PORTAL; - } else if ( !Q_stricmp( token, "sky" ) ) { - shader.sort = SS_ENVIRONMENT; - } else if ( !Q_stricmp( token, "opaque" ) ) { - shader.sort = SS_OPAQUE; - }else if ( !Q_stricmp( token, "decal" ) ) { - shader.sort = SS_DECAL; - } else if ( !Q_stricmp( token, "seeThrough" ) ) { - shader.sort = SS_SEE_THROUGH; - } else if ( !Q_stricmp( token, "banner" ) ) { - shader.sort = SS_BANNER; - } else if ( !Q_stricmp( token, "additive" ) ) { - shader.sort = SS_BLEND1; - } else if ( !Q_stricmp( token, "nearest" ) ) { - shader.sort = SS_NEAREST; - } else if ( !Q_stricmp( token, "underwater" ) ) { - shader.sort = SS_UNDERWATER; - } else { - shader.sort = atof( token ); - } -} - - - -// this table is also present in q3map - -typedef struct { - char *name; - int clearSolid, surfaceFlags, contents; -} infoParm_t; - -infoParm_t infoParms[] = { - // server relevant contents - {"water", 1, 0, CONTENTS_WATER }, - {"slime", 1, 0, CONTENTS_SLIME }, // mildly damaging - {"lava", 1, 0, CONTENTS_LAVA }, // very damaging - {"playerclip", 1, 0, CONTENTS_PLAYERCLIP }, - {"monsterclip", 1, 0, CONTENTS_MONSTERCLIP }, - {"nodrop", 1, 0, CONTENTS_NODROP }, // don't drop items or leave bodies (death fog, lava, etc) - {"nonsolid", 1, SURF_NONSOLID, 0}, // clears the solid flag - - // utility relevant attributes - {"origin", 1, 0, CONTENTS_ORIGIN }, // center of rotating brushes - {"trans", 0, 0, CONTENTS_TRANSLUCENT }, // don't eat contained surfaces - {"detail", 0, 0, CONTENTS_DETAIL }, // don't include in structural bsp - {"structural", 0, 0, CONTENTS_STRUCTURAL }, // force into structural bsp even if trnas - {"areaportal", 1, 0, CONTENTS_AREAPORTAL }, // divides areas - {"clusterportal", 1,0, CONTENTS_CLUSTERPORTAL }, // for bots - {"donotenter", 1, 0, CONTENTS_DONOTENTER }, // for bots - - {"fog", 1, 0, CONTENTS_FOG}, // carves surfaces entering - {"sky", 0, SURF_SKY, 0 }, // emit light from an environment map - {"lightfilter", 0, SURF_LIGHTFILTER, 0 }, // filter light going through it - {"alphashadow", 0, SURF_ALPHASHADOW, 0 }, // test light on a per-pixel basis - {"hint", 0, SURF_HINT, 0 }, // use as a primary splitter - - // server attributes - {"slick", 0, SURF_SLICK, 0 }, - {"noimpact", 0, SURF_NOIMPACT, 0 }, // don't make impact explosions or marks - {"nomarks", 0, SURF_NOMARKS, 0 }, // don't make impact marks, but still explode - {"ladder", 0, SURF_LADDER, 0 }, - {"nodamage", 0, SURF_NODAMAGE, 0 }, - {"metalsteps", 0, SURF_METALSTEPS,0 }, - {"flesh", 0, SURF_FLESH, 0 }, - {"nosteps", 0, SURF_NOSTEPS, 0 }, - - // drawsurf attributes - {"nodraw", 0, SURF_NODRAW, 0 }, // don't generate a drawsurface (or a lightmap) - {"pointlight", 0, SURF_POINTLIGHT, 0 }, // sample lighting at vertexes - {"nolightmap", 0, SURF_NOLIGHTMAP,0 }, // don't generate a lightmap - {"nodlight", 0, SURF_NODLIGHT, 0 }, // don't ever add dynamic lights - {"dust", 0, SURF_DUST, 0} // leave a dust trail when walking on this surface -}; - - -/* -=============== -ParseSurfaceParm - -surfaceparm -=============== -*/ -static void ParseSurfaceParm( char **text ) { - char *token; - int numInfoParms = ARRAY_LEN( infoParms ); - int i; - - token = COM_ParseExt( text, qfalse ); - for ( i = 0 ; i < numInfoParms ; i++ ) { - if ( !Q_stricmp( token, infoParms[i].name ) ) { - shader.surfaceFlags |= infoParms[i].surfaceFlags; - shader.contentFlags |= infoParms[i].contents; -#if 0 - if ( infoParms[i].clearSolid ) { - si->contents &= ~CONTENTS_SOLID; - } -#endif - break; - } - } -} - -/* -================= -ParseShader - -The current text pointer is at the explicit text definition of the -shader. Parse it into the global shader variable. Later functions -will optimize it. -================= -*/ -static qboolean ParseShader( char **text ) -{ - char *token; - int s; - - s = 0; - - token = COM_ParseExt( text, qtrue ); - if ( token[0] != '{' ) - { - ri.Printf( PRINT_WARNING, "WARNING: expecting '{', found '%s' instead in shader '%s'\n", token, shader.name ); - return qfalse; - } - - while ( 1 ) - { - token = COM_ParseExt( text, qtrue ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: no concluding '}' in shader %s\n", shader.name ); - return qfalse; - } - - // end of shader definition - if ( token[0] == '}' ) - { - break; - } - // stage definition - else if ( token[0] == '{' ) - { - if ( s >= MAX_SHADER_STAGES ) { - ri.Printf( PRINT_WARNING, "WARNING: too many stages in shader %s\n", shader.name ); - return qfalse; - } - - if ( !ParseStage( &stages[s], text ) ) - { - return qfalse; - } - stages[s].active = qtrue; - s++; - - continue; - } - // skip stuff that only the QuakeEdRadient needs - else if ( !Q_stricmpn( token, "qer", 3 ) ) { - SkipRestOfLine( text ); - continue; - } - // sun parms - else if ( !Q_stricmp( token, "q3map_sun" ) || !Q_stricmp( token, "q3map_sunExt" ) || !Q_stricmp( token, "q3gl2_sun" ) ) { - float a, b; - qboolean isGL2Sun = qfalse; - - if (!Q_stricmp( token, "q3gl2_sun" ) && r_sunShadows->integer ) - { - isGL2Sun = qtrue; - tr.sunShadows = qtrue; - } - - token = COM_ParseExt( text, qfalse ); - tr.sunLight[0] = atof( token ); - token = COM_ParseExt( text, qfalse ); - tr.sunLight[1] = atof( token ); - token = COM_ParseExt( text, qfalse ); - tr.sunLight[2] = atof( token ); - - VectorNormalize( tr.sunLight ); - - token = COM_ParseExt( text, qfalse ); - a = atof( token ); - VectorScale( tr.sunLight, a, tr.sunLight); - - token = COM_ParseExt( text, qfalse ); - a = atof( token ); - a = a / 180 * M_PI; - - token = COM_ParseExt( text, qfalse ); - b = atof( token ); - b = b / 180 * M_PI; - - tr.sunDirection[0] = cos( a ) * cos( b ); - tr.sunDirection[1] = sin( a ) * cos( b ); - tr.sunDirection[2] = sin( b ); - - if (isGL2Sun) - { - token = COM_ParseExt( text, qfalse ); - tr.mapLightScale = atof(token); - - token = COM_ParseExt( text, qfalse ); - tr.sunShadowScale = atof(token); - } - - SkipRestOfLine( text ); - continue; - } - // tonemap parms - else if ( !Q_stricmp( token, "q3gl2_tonemap" ) ) { - token = COM_ParseExt( text, qfalse ); - tr.toneMinAvgMaxLevel[0] = atof( token ); - token = COM_ParseExt( text, qfalse ); - tr.toneMinAvgMaxLevel[1] = atof( token ); - token = COM_ParseExt( text, qfalse ); - tr.toneMinAvgMaxLevel[2] = atof( token ); - - token = COM_ParseExt( text, qfalse ); - tr.autoExposureMinMax[0] = atof( token ); - token = COM_ParseExt( text, qfalse ); - tr.autoExposureMinMax[1] = atof( token ); - - SkipRestOfLine( text ); - continue; - } - else if ( !Q_stricmp( token, "deformVertexes" ) ) { - ParseDeform( text ); - continue; - } - else if ( !Q_stricmp( token, "tesssize" ) ) { - SkipRestOfLine( text ); - continue; - } - else if ( !Q_stricmp( token, "clampTime" ) ) { - token = COM_ParseExt( text, qfalse ); - if (token[0]) { - shader.clampTime = atof(token); - } - } - // skip stuff that only the q3map needs - else if ( !Q_stricmpn( token, "q3map", 5 ) ) { - SkipRestOfLine( text ); - continue; - } - // skip stuff that only q3map or the server needs - else if ( !Q_stricmp( token, "surfaceParm" ) ) { - ParseSurfaceParm( text ); - continue; - } - // no mip maps - else if ( !Q_stricmp( token, "nomipmaps" ) ) - { - shader.noMipMaps = qtrue; - shader.noPicMip = qtrue; - continue; - } - // no picmip adjustment - else if ( !Q_stricmp( token, "nopicmip" ) ) - { - shader.noPicMip = qtrue; - continue; - } - // polygonOffset - else if ( !Q_stricmp( token, "polygonOffset" ) ) - { - shader.polygonOffset = qtrue; - continue; - } - // entityMergable, allowing sprite surfaces from multiple entities - // to be merged into one batch. This is a savings for smoke - // puffs and blood, but can't be used for anything where the - // shader calcs (not the surface function) reference the entity color or scroll - else if ( !Q_stricmp( token, "entityMergable" ) ) - { - shader.entityMergable = qtrue; - continue; - } - // fogParms - else if ( !Q_stricmp( token, "fogParms" ) ) - { - if ( !ParseVector( text, 3, shader.fogParms.color ) ) { - return qfalse; - } - - token = COM_ParseExt( text, qfalse ); - if ( !token[0] ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing parm for 'fogParms' keyword in shader '%s'\n", shader.name ); - continue; - } - shader.fogParms.depthForOpaque = atof( token ); - - // skip any old gradient directions - SkipRestOfLine( text ); - continue; - } - // portal - else if ( !Q_stricmp(token, "portal") ) - { - shader.sort = SS_PORTAL; - shader.isPortal = qtrue; - continue; - } - // skyparms - else if ( !Q_stricmp( token, "skyparms" ) ) - { - ParseSkyParms( text ); - continue; - } - // light determines flaring in q3map, not needed here - else if ( !Q_stricmp(token, "light") ) - { - COM_ParseExt( text, qfalse ); - continue; - } - // cull - else if ( !Q_stricmp( token, "cull") ) - { - token = COM_ParseExt( text, qfalse ); - if ( token[0] == 0 ) - { - ri.Printf( PRINT_WARNING, "WARNING: missing cull parms in shader '%s'\n", shader.name ); - continue; - } - - if ( !Q_stricmp( token, "none" ) || !Q_stricmp( token, "twosided" ) || !Q_stricmp( token, "disable" ) ) - { - shader.cullType = CT_TWO_SIDED; - } - else if ( !Q_stricmp( token, "back" ) || !Q_stricmp( token, "backside" ) || !Q_stricmp( token, "backsided" ) ) - { - shader.cullType = CT_BACK_SIDED; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: invalid cull parm '%s' in shader '%s'\n", token, shader.name ); - } - continue; - } - // sort - else if ( !Q_stricmp( token, "sort" ) ) - { - ParseSort( text ); - continue; - } - else - { - ri.Printf( PRINT_WARNING, "WARNING: unknown general shader parameter '%s' in '%s'\n", token, shader.name ); - return qfalse; - } - } - - // - // ignore shaders that don't have any stages, unless it is a sky or fog - // - if ( s == 0 && !shader.isSky && !(shader.contentFlags & CONTENTS_FOG ) ) { - return qfalse; - } - - shader.explicitlyDefined = qtrue; - - return qtrue; -} - -/* -======================================================================================== - -SHADER OPTIMIZATION AND FOGGING - -======================================================================================== -*/ - -/* -=================== -ComputeStageIteratorFunc - -See if we can use on of the simple fastpath stage functions, -otherwise set to the generic stage function -=================== -*/ -static void ComputeStageIteratorFunc( void ) -{ - shader.optimalStageIteratorFunc = RB_StageIteratorGeneric; - - // - // see if this should go into the sky path - // - if ( shader.isSky ) - { - shader.optimalStageIteratorFunc = RB_StageIteratorSky; - return; - } -} - -/* -=================== -ComputeVertexAttribs - -Check which vertex attributes we only need, so we -don't need to submit/copy all of them. -=================== -*/ -static void ComputeVertexAttribs(void) -{ - int i, stage; - - // dlights always need ATTR_NORMAL - shader.vertexAttribs = ATTR_POSITION | ATTR_NORMAL; - - // portals always need normals, for SurfIsOffscreen() - if (shader.isPortal) - { - shader.vertexAttribs |= ATTR_NORMAL; - } - - if (shader.defaultShader) - { - shader.vertexAttribs |= ATTR_TEXCOORD; - return; - } - - if(shader.numDeforms) - { - for ( i = 0; i < shader.numDeforms; i++) - { - deformStage_t *ds = &shader.deforms[i]; - - switch (ds->deformation) - { - case DEFORM_BULGE: - shader.vertexAttribs |= ATTR_NORMAL | ATTR_TEXCOORD; - break; - - case DEFORM_AUTOSPRITE: - shader.vertexAttribs |= ATTR_NORMAL | ATTR_COLOR; - break; - - case DEFORM_WAVE: - case DEFORM_NORMALS: - case DEFORM_TEXT0: - case DEFORM_TEXT1: - case DEFORM_TEXT2: - case DEFORM_TEXT3: - case DEFORM_TEXT4: - case DEFORM_TEXT5: - case DEFORM_TEXT6: - case DEFORM_TEXT7: - shader.vertexAttribs |= ATTR_NORMAL; - break; - - default: - case DEFORM_NONE: - case DEFORM_MOVE: - case DEFORM_PROJECTION_SHADOW: - case DEFORM_AUTOSPRITE2: - break; - } - } - } - - for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) - { - shaderStage_t *pStage = &stages[stage]; - - if ( !pStage->active ) - { - break; - } - - if (pStage->glslShaderGroup == tr.lightallShader) - { - shader.vertexAttribs |= ATTR_NORMAL; - -#ifdef USE_VERT_TANGENT_SPACE - if ((pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && !(r_normalMapping->integer == 0 && r_specularMapping->integer == 0)) - { - shader.vertexAttribs |= ATTR_TANGENT; - } -#endif - - switch (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) - { - case LIGHTDEF_USE_LIGHTMAP: - case LIGHTDEF_USE_LIGHT_VERTEX: - shader.vertexAttribs |= ATTR_LIGHTDIRECTION; - break; - default: - break; - } - } - - for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) - { - if ( pStage->bundle[i].image[0] == 0 ) - { - continue; - } - - switch(pStage->bundle[i].tcGen) - { - case TCGEN_TEXTURE: - shader.vertexAttribs |= ATTR_TEXCOORD; - break; - case TCGEN_LIGHTMAP: - shader.vertexAttribs |= ATTR_LIGHTCOORD; - break; - case TCGEN_ENVIRONMENT_MAPPED: - shader.vertexAttribs |= ATTR_NORMAL; - break; - - default: - break; - } - } - - switch(pStage->rgbGen) - { - case CGEN_EXACT_VERTEX: - case CGEN_VERTEX: - case CGEN_EXACT_VERTEX_LIT: - case CGEN_VERTEX_LIT: - case CGEN_ONE_MINUS_VERTEX: - shader.vertexAttribs |= ATTR_COLOR; - break; - - case CGEN_LIGHTING_DIFFUSE: - shader.vertexAttribs |= ATTR_NORMAL; - break; - - default: - break; - } - - switch(pStage->alphaGen) - { - case AGEN_LIGHTING_SPECULAR: - shader.vertexAttribs |= ATTR_NORMAL; - break; - - case AGEN_VERTEX: - case AGEN_ONE_MINUS_VERTEX: - shader.vertexAttribs |= ATTR_COLOR; - break; - - default: - break; - } - } -} - -typedef struct { - int blendA; - int blendB; - - int multitextureEnv; - int multitextureBlend; -} collapse_t; - -static collapse_t collapse[] = { - { 0, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, - GL_MODULATE, 0 }, - - { 0, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, - GL_MODULATE, 0 }, - - { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, - GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, - - { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, - GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, - - { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, - GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, - - { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, - GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR }, - - { 0, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, - GL_ADD, 0 }, - - { GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, - GL_ADD, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE }, -#if 0 - { 0, GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_SRCBLEND_SRC_ALPHA, - GL_DECAL, 0 }, -#endif - { -1 } -}; - -/* -================ -CollapseMultitexture - -Attempt to combine two stages into a single multitexture stage -FIXME: I think modulated add + modulated add collapses incorrectly -================= -*/ -static qboolean CollapseMultitexture( void ) { - int abits, bbits; - int i; - textureBundle_t tmpBundle; - - if ( !qglActiveTextureARB ) { - return qfalse; - } - - // make sure both stages are active - if ( !stages[0].active || !stages[1].active ) { - return qfalse; - } - - // on voodoo2, don't combine different tmus - if ( glConfig.driverType == GLDRV_VOODOO ) { - if ( stages[0].bundle[0].image[0]->TMU == - stages[1].bundle[0].image[0]->TMU ) { - return qfalse; - } - } - - abits = stages[0].stateBits; - bbits = stages[1].stateBits; - - // make sure that both stages have identical state other than blend modes - if ( ( abits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) != - ( bbits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) ) { - return qfalse; - } - - abits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - bbits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - - // search for a valid multitexture blend function - for ( i = 0; collapse[i].blendA != -1 ; i++ ) { - if ( abits == collapse[i].blendA - && bbits == collapse[i].blendB ) { - break; - } - } - - // nothing found - if ( collapse[i].blendA == -1 ) { - return qfalse; - } - - // GL_ADD is a separate extension - if ( collapse[i].multitextureEnv == GL_ADD && !glConfig.textureEnvAddAvailable ) { - return qfalse; - } - - // make sure waveforms have identical parameters - if ( ( stages[0].rgbGen != stages[1].rgbGen ) || - ( stages[0].alphaGen != stages[1].alphaGen ) ) { - return qfalse; - } - - // an add collapse can only have identity colors - if ( collapse[i].multitextureEnv == GL_ADD && stages[0].rgbGen != CGEN_IDENTITY ) { - return qfalse; - } - - if ( stages[0].rgbGen == CGEN_WAVEFORM ) - { - if ( memcmp( &stages[0].rgbWave, - &stages[1].rgbWave, - sizeof( stages[0].rgbWave ) ) ) - { - return qfalse; - } - } - if ( stages[0].alphaGen == AGEN_WAVEFORM ) - { - if ( memcmp( &stages[0].alphaWave, - &stages[1].alphaWave, - sizeof( stages[0].alphaWave ) ) ) - { - return qfalse; - } - } - - - // make sure that lightmaps are in bundle 1 for 3dfx - if ( stages[0].bundle[0].isLightmap ) - { - tmpBundle = stages[0].bundle[0]; - stages[0].bundle[0] = stages[1].bundle[0]; - stages[0].bundle[1] = tmpBundle; - } - else - { - stages[0].bundle[1] = stages[1].bundle[0]; - } - - // set the new blend state bits - shader.multitextureEnv = collapse[i].multitextureEnv; - stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - stages[0].stateBits |= collapse[i].multitextureBlend; - - // - // move down subsequent shaders - // - memmove( &stages[1], &stages[2], sizeof( stages[0] ) * ( MAX_SHADER_STAGES - 2 ) ); - Com_Memset( &stages[MAX_SHADER_STAGES-1], 0, sizeof( stages[0] ) ); - - return qtrue; -} - -static void CollapseStagesToLightall(shaderStage_t *diffuse, - shaderStage_t *normal, shaderStage_t *specular, shaderStage_t *lightmap, - qboolean useLightVector, qboolean useLightVertex, qboolean parallax, qboolean tcgen) -{ - int defs = 0; - - //ri.Printf(PRINT_ALL, "shader %s has diffuse %s", shader.name, diffuse->bundle[0].image[0]->imgName); - - // reuse diffuse, mark others inactive - diffuse->type = ST_GLSL; - - if (lightmap) - { - //ri.Printf(PRINT_ALL, ", lightmap"); - diffuse->bundle[TB_LIGHTMAP] = lightmap->bundle[0]; - defs |= LIGHTDEF_USE_LIGHTMAP; - } - else if (useLightVector) - { - defs |= LIGHTDEF_USE_LIGHT_VECTOR; - } - else if (useLightVertex) - { - defs |= LIGHTDEF_USE_LIGHT_VERTEX; - } - - if (r_deluxeMapping->integer && tr.worldDeluxeMapping && lightmap) - { - //ri.Printf(PRINT_ALL, ", deluxemap"); - diffuse->bundle[TB_DELUXEMAP] = lightmap->bundle[0]; - diffuse->bundle[TB_DELUXEMAP].image[0] = tr.deluxemaps[shader.lightmapIndex]; - } - - if (r_normalMapping->integer) - { - image_t *diffuseImg; - if (normal) - { - //ri.Printf(PRINT_ALL, ", normalmap %s", normal->bundle[0].image[0]->imgName); - diffuse->bundle[TB_NORMALMAP] = normal->bundle[0]; - if (parallax && r_parallaxMapping->integer) - defs |= LIGHTDEF_USE_PARALLAXMAP; - } - else if ((lightmap || useLightVector || useLightVertex) && (diffuseImg = diffuse->bundle[TB_DIFFUSEMAP].image[0])) - { - char normalName[MAX_QPATH]; - image_t *normalImg; - imgFlags_t normalFlags = (diffuseImg->flags & ~(IMGFLAG_GENNORMALMAP | IMGFLAG_SRGB)) | IMGFLAG_NOLIGHTSCALE; - - COM_StripExtension(diffuseImg->imgName, normalName, MAX_QPATH); - Q_strcat(normalName, MAX_QPATH, "_n"); - - normalImg = R_FindImageFile(normalName, IMGTYPE_NORMAL, normalFlags); - - if (normalImg) - { - diffuse->bundle[TB_NORMALMAP] = diffuse->bundle[0]; - diffuse->bundle[TB_NORMALMAP].numImageAnimations = 0; - diffuse->bundle[TB_NORMALMAP].image[0] = normalImg; - - if (parallax && r_parallaxMapping->integer) - defs |= LIGHTDEF_USE_PARALLAXMAP; - } - } - } - - if (r_specularMapping->integer) - { - if (specular) - { - //ri.Printf(PRINT_ALL, ", specularmap %s", specular->bundle[0].image[0]->imgName); - diffuse->bundle[TB_SPECULARMAP] = specular->bundle[0]; - diffuse->materialInfo[0] = specular->materialInfo[0]; - diffuse->materialInfo[1] = specular->materialInfo[1]; - } - } - - if (tcgen || diffuse->bundle[0].numTexMods) - { - defs |= LIGHTDEF_USE_TCGEN_AND_TCMOD; - } - - //ri.Printf(PRINT_ALL, ".\n"); - - diffuse->glslShaderGroup = tr.lightallShader; - diffuse->glslShaderIndex = defs; -} - - -static qboolean CollapseStagesToGLSL(void) -{ - int i, j, numStages; - qboolean skip = qfalse; - - // skip shaders with deforms - if (shader.numDeforms != 0) - { - skip = qtrue; - } - - if (!skip) - { - // if 2+ stages and first stage is lightmap, switch them - // this makes it easier for the later bits to process - if (stages[0].active && stages[0].bundle[0].tcGen == TCGEN_LIGHTMAP && stages[1].active) - { - int blendBits = stages[1].stateBits & ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - - if (blendBits == (GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO) - || blendBits == (GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR)) - { - int stateBits0 = stages[0].stateBits; - int stateBits1 = stages[1].stateBits; - shaderStage_t swapStage; - - swapStage = stages[0]; - stages[0] = stages[1]; - stages[1] = swapStage; - - stages[0].stateBits = stateBits0; - stages[1].stateBits = stateBits1; - } - } - } - - if (!skip) - { - // scan for shaders that aren't supported - for (i = 0; i < MAX_SHADER_STAGES; i++) - { - shaderStage_t *pStage = &stages[i]; - - if (!pStage->active) - continue; - - if (pStage->adjustColorsForFog) - { - skip = qtrue; - break; - } - - if (pStage->bundle[0].tcGen == TCGEN_LIGHTMAP) - { - int blendBits = pStage->stateBits & ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - - if (blendBits != (GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO) - && blendBits != (GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR)) - { - skip = qtrue; - break; - } - } - - switch(pStage->bundle[0].tcGen) - { - case TCGEN_TEXTURE: - case TCGEN_LIGHTMAP: - case TCGEN_ENVIRONMENT_MAPPED: - case TCGEN_VECTOR: - break; - default: - skip = qtrue; - break; - } - - switch(pStage->alphaGen) - { - case AGEN_LIGHTING_SPECULAR: - case AGEN_PORTAL: - skip = qtrue; - break; - default: - break; - } - } - } - - if (!skip) - { - for (i = 0; i < MAX_SHADER_STAGES; i++) - { - shaderStage_t *pStage = &stages[i]; - shaderStage_t *diffuse, *normal, *specular, *lightmap; - qboolean parallax, tcgen, diffuselit, vertexlit; - - if (!pStage->active) - continue; - - // skip normal and specular maps - if (pStage->type != ST_COLORMAP) - continue; - - // skip lightmaps - if (pStage->bundle[0].tcGen == TCGEN_LIGHTMAP) - continue; - - diffuse = pStage; - normal = NULL; - parallax = qfalse; - specular = NULL; - lightmap = NULL; - - // we have a diffuse map, find matching normal, specular, and lightmap - for (j = i + 1; j < MAX_SHADER_STAGES; j++) - { - shaderStage_t *pStage2 = &stages[j]; - - if (!pStage2->active) - continue; - - switch(pStage2->type) - { - case ST_NORMALMAP: - if (!normal) - { - normal = pStage2; - } - break; - - case ST_NORMALPARALLAXMAP: - if (!normal) - { - normal = pStage2; - parallax = qtrue; - } - break; - - case ST_SPECULARMAP: - if (!specular) - { - specular = pStage2; - } - break; - - case ST_COLORMAP: - if (pStage2->bundle[0].tcGen == TCGEN_LIGHTMAP) - { - lightmap = pStage2; - } - break; - - default: - break; - } - } - - tcgen = qfalse; - if (diffuse->bundle[0].tcGen == TCGEN_ENVIRONMENT_MAPPED - || diffuse->bundle[0].tcGen == TCGEN_LIGHTMAP - || diffuse->bundle[0].tcGen == TCGEN_VECTOR) - { - tcgen = qtrue; - } - - diffuselit = qfalse; - if (diffuse->rgbGen == CGEN_LIGHTING_DIFFUSE) - { - diffuselit = qtrue; - } - - vertexlit = qfalse; - if (diffuse->rgbGen == CGEN_VERTEX_LIT || diffuse->rgbGen == CGEN_EXACT_VERTEX_LIT) - { - vertexlit = qtrue; - } - - CollapseStagesToLightall(diffuse, normal, specular, lightmap, diffuselit, vertexlit, parallax, tcgen); - } - - // deactivate lightmap stages - for (i = 0; i < MAX_SHADER_STAGES; i++) - { - shaderStage_t *pStage = &stages[i]; - - if (!pStage->active) - continue; - - if (pStage->bundle[0].tcGen == TCGEN_LIGHTMAP) - { - pStage->active = qfalse; - } - } - } - - // deactivate normal and specular stages - for (i = 0; i < MAX_SHADER_STAGES; i++) - { - shaderStage_t *pStage = &stages[i]; - - if (!pStage->active) - continue; - - if (pStage->type == ST_NORMALMAP) - { - pStage->active = qfalse; - } - - if (pStage->type == ST_NORMALPARALLAXMAP) - { - pStage->active = qfalse; - } - - if (pStage->type == ST_SPECULARMAP) - { - pStage->active = qfalse; - } - } - - // remove inactive stages - numStages = 0; - for (i = 0; i < MAX_SHADER_STAGES; i++) - { - if (!stages[i].active) - continue; - - if (i == numStages) - { - numStages++; - continue; - } - - stages[numStages] = stages[i]; - stages[i].active = qfalse; - numStages++; - } - - if (numStages == i && i >= 2 && CollapseMultitexture()) - numStages--; - - // convert any remaining lightmap stages to a lighting pass with a white texture - // only do this with r_sunlightMode non-zero, as it's only for correct shadows. - if (r_sunlightMode->integer && shader.numDeforms == 0) - { - for (i = 0; i < MAX_SHADER_STAGES; i++) - { - shaderStage_t *pStage = &stages[i]; - - if (!pStage->active) - continue; - - if (pStage->adjustColorsForFog) - continue; - - if (pStage->bundle[TB_DIFFUSEMAP].tcGen == TCGEN_LIGHTMAP) - { - pStage->glslShaderGroup = tr.lightallShader; - pStage->glslShaderIndex = LIGHTDEF_USE_LIGHTMAP; - pStage->bundle[TB_LIGHTMAP] = pStage->bundle[TB_DIFFUSEMAP]; - pStage->bundle[TB_DIFFUSEMAP].image[0] = tr.whiteImage; - pStage->bundle[TB_DIFFUSEMAP].isLightmap = qfalse; - pStage->bundle[TB_DIFFUSEMAP].tcGen = TCGEN_TEXTURE; - } - } - } - - // convert any remaining lightingdiffuse stages to a lighting pass - if (shader.numDeforms == 0) - { - for (i = 0; i < MAX_SHADER_STAGES; i++) - { - shaderStage_t *pStage = &stages[i]; - - if (!pStage->active) - continue; - - if (pStage->adjustColorsForFog) - continue; - - if (pStage->rgbGen == CGEN_LIGHTING_DIFFUSE) - { - pStage->glslShaderGroup = tr.lightallShader; - pStage->glslShaderIndex = LIGHTDEF_USE_LIGHT_VECTOR; - - if (pStage->bundle[0].tcGen != TCGEN_TEXTURE || pStage->bundle[0].numTexMods != 0) - pStage->glslShaderIndex |= LIGHTDEF_USE_TCGEN_AND_TCMOD; - } - } - } - - // insert default material info if needed - for (i = 0; i < MAX_SHADER_STAGES; i++) - { - shaderStage_t *pStage = &stages[i]; - - if (!pStage->active) - continue; - - if (pStage->glslShaderGroup != tr.lightallShader) - continue; - - if ((pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) == 0) - continue; - - if (!pStage->bundle[TB_SPECULARMAP].image[0] && r_specularMapping->integer) - { - if (!pStage->materialInfo[0]) - pStage->materialInfo[0] = r_baseSpecular->value; - if (!pStage->materialInfo[1]) - pStage->materialInfo[1] = r_baseGloss->value; - } - } - - return numStages; -} - -/* -============= - -FixRenderCommandList -https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493 -Arnout: this is a nasty issue. Shaders can be registered after drawsurfaces are generated -but before the frame is rendered. This will, for the duration of one frame, cause drawsurfaces -to be rendered with bad shaders. To fix this, need to go through all render commands and fix -sortedIndex. -============== -*/ -static void FixRenderCommandList( int newShader ) { - renderCommandList_t *cmdList = &backEndData->commands; - - if( cmdList ) { - const void *curCmd = cmdList->cmds; - - while ( 1 ) { - curCmd = PADP(curCmd, sizeof(void *)); - - switch ( *(const int *)curCmd ) { - case RC_SET_COLOR: - { - const setColorCommand_t *sc_cmd = (const setColorCommand_t *)curCmd; - curCmd = (const void *)(sc_cmd + 1); - break; - } - case RC_STRETCH_PIC: - { - const stretchPicCommand_t *sp_cmd = (const stretchPicCommand_t *)curCmd; - curCmd = (const void *)(sp_cmd + 1); - break; - } - case RC_DRAW_SURFS: - { - int i; - drawSurf_t *drawSurf; - shader_t *shader; - int fogNum; - int entityNum; - int dlightMap; - int pshadowMap; - int sortedIndex; - const drawSurfsCommand_t *ds_cmd = (const drawSurfsCommand_t *)curCmd; - - for( i = 0, drawSurf = ds_cmd->drawSurfs; i < ds_cmd->numDrawSurfs; i++, drawSurf++ ) { - R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlightMap, &pshadowMap ); - sortedIndex = (( drawSurf->sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1)); - if( sortedIndex >= newShader ) { - sortedIndex++; - drawSurf->sort = (sortedIndex << QSORT_SHADERNUM_SHIFT) | entityNum | ( fogNum << QSORT_FOGNUM_SHIFT ) | ( (int)pshadowMap << QSORT_PSHADOW_SHIFT) | (int)dlightMap; - } - } - curCmd = (const void *)(ds_cmd + 1); - break; - } - case RC_DRAW_BUFFER: - { - const drawBufferCommand_t *db_cmd = (const drawBufferCommand_t *)curCmd; - curCmd = (const void *)(db_cmd + 1); - break; - } - case RC_SWAP_BUFFERS: - { - const swapBuffersCommand_t *sb_cmd = (const swapBuffersCommand_t *)curCmd; - curCmd = (const void *)(sb_cmd + 1); - break; - } - case RC_END_OF_LIST: - default: - return; - } - } - } -} - -/* -============== -SortNewShader - -Positions the most recently created shader in the tr.sortedShaders[] -array so that the shader->sort key is sorted reletive to the other -shaders. - -Sets shader->sortedIndex -============== -*/ -static void SortNewShader( void ) { - int i; - float sort; - shader_t *newShader; - - newShader = tr.shaders[ tr.numShaders - 1 ]; - sort = newShader->sort; - - for ( i = tr.numShaders - 2 ; i >= 0 ; i-- ) { - if ( tr.sortedShaders[ i ]->sort <= sort ) { - break; - } - tr.sortedShaders[i+1] = tr.sortedShaders[i]; - tr.sortedShaders[i+1]->sortedIndex++; - } - - // Arnout: fix rendercommandlist - // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493 - FixRenderCommandList( i+1 ); - - newShader->sortedIndex = i+1; - tr.sortedShaders[i+1] = newShader; -} - - -/* -==================== -GeneratePermanentShader -==================== -*/ -static shader_t *GeneratePermanentShader( void ) { - shader_t *newShader; - int i, b; - int size, hash; - - if ( tr.numShaders == MAX_SHADERS ) { - ri.Printf( PRINT_WARNING, "WARNING: GeneratePermanentShader - MAX_SHADERS hit\n"); - return tr.defaultShader; - } - - newShader = ri.Hunk_Alloc( sizeof( shader_t ), h_low ); - - *newShader = shader; - - if ( shader.sort <= SS_OPAQUE ) { - newShader->fogPass = FP_EQUAL; - } else if ( shader.contentFlags & CONTENTS_FOG ) { - newShader->fogPass = FP_LE; - } - - tr.shaders[ tr.numShaders ] = newShader; - newShader->index = tr.numShaders; - - tr.sortedShaders[ tr.numShaders ] = newShader; - newShader->sortedIndex = tr.numShaders; - - tr.numShaders++; - - for ( i = 0 ; i < newShader->numUnfoggedPasses ; i++ ) { - if ( !stages[i].active ) { - break; - } - newShader->stages[i] = ri.Hunk_Alloc( sizeof( stages[i] ), h_low ); - *newShader->stages[i] = stages[i]; - - for ( b = 0 ; b < NUM_TEXTURE_BUNDLES ; b++ ) { - size = newShader->stages[i]->bundle[b].numTexMods * sizeof( texModInfo_t ); - newShader->stages[i]->bundle[b].texMods = ri.Hunk_Alloc( size, h_low ); - Com_Memcpy( newShader->stages[i]->bundle[b].texMods, stages[i].bundle[b].texMods, size ); - } - } - - SortNewShader(); - - hash = generateHashValue(newShader->name, FILE_HASH_SIZE); - newShader->next = hashTable[hash]; - hashTable[hash] = newShader; - - return newShader; -} - -/* -================= -VertexLightingCollapse - -If vertex lighting is enabled, only render a single -pass, trying to guess which is the correct one to best aproximate -what it is supposed to look like. -================= -*/ -static void VertexLightingCollapse( void ) { - int stage; - shaderStage_t *bestStage; - int bestImageRank; - int rank; - - // if we aren't opaque, just use the first pass - if ( shader.sort == SS_OPAQUE ) { - - // pick the best texture for the single pass - bestStage = &stages[0]; - bestImageRank = -999999; - - for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) { - shaderStage_t *pStage = &stages[stage]; - - if ( !pStage->active ) { - break; - } - rank = 0; - - if ( pStage->bundle[0].isLightmap ) { - rank -= 100; - } - if ( pStage->bundle[0].tcGen != TCGEN_TEXTURE ) { - rank -= 5; - } - if ( pStage->bundle[0].numTexMods ) { - rank -= 5; - } - if ( pStage->rgbGen != CGEN_IDENTITY && pStage->rgbGen != CGEN_IDENTITY_LIGHTING ) { - rank -= 3; - } - - if ( rank > bestImageRank ) { - bestImageRank = rank; - bestStage = pStage; - } - } - - stages[0].bundle[0] = bestStage->bundle[0]; - stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); - stages[0].stateBits |= GLS_DEPTHMASK_TRUE; - if ( shader.lightmapIndex == LIGHTMAP_NONE ) { - stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE; - } else { - stages[0].rgbGen = CGEN_EXACT_VERTEX; - } - stages[0].alphaGen = AGEN_SKIP; - } else { - // don't use a lightmap (tesla coils) - if ( stages[0].bundle[0].isLightmap ) { - stages[0] = stages[1]; - } - - // if we were in a cross-fade cgen, hack it to normal - if ( stages[0].rgbGen == CGEN_ONE_MINUS_ENTITY || stages[1].rgbGen == CGEN_ONE_MINUS_ENTITY ) { - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - } - if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_SAWTOOTH ) - && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_INVERSE_SAWTOOTH ) ) { - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - } - if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_INVERSE_SAWTOOTH ) - && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_SAWTOOTH ) ) { - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - } - } - - for ( stage = 1; stage < MAX_SHADER_STAGES; stage++ ) { - shaderStage_t *pStage = &stages[stage]; - - if ( !pStage->active ) { - break; - } - - Com_Memset( pStage, 0, sizeof( *pStage ) ); - } -} - -/* -========================= -FinishShader - -Returns a freshly allocated shader with all the needed info -from the current global working shader -========================= -*/ -static shader_t *FinishShader( void ) { - int stage; - qboolean hasLightmapStage; - qboolean vertexLightmap; - - hasLightmapStage = qfalse; - vertexLightmap = qfalse; - - // - // set sky stuff appropriate - // - if ( shader.isSky ) { - shader.sort = SS_ENVIRONMENT; - } - - // - // set polygon offset - // - if ( shader.polygonOffset && !shader.sort ) { - shader.sort = SS_DECAL; - } - - // - // set appropriate stage information - // - for ( stage = 0; stage < MAX_SHADER_STAGES; ) { - shaderStage_t *pStage = &stages[stage]; - - if ( !pStage->active ) { - break; - } - - // check for a missing texture - if ( !pStage->bundle[0].image[0] ) { - ri.Printf( PRINT_WARNING, "Shader %s has a stage with no image\n", shader.name ); - pStage->active = qfalse; - stage++; - continue; - } - - // - // ditch this stage if it's detail and detail textures are disabled - // - if ( pStage->isDetail && !r_detailTextures->integer ) - { - int index; - - for(index = stage + 1; index < MAX_SHADER_STAGES; index++) - { - if(!stages[index].active) - break; - } - - if(index < MAX_SHADER_STAGES) - memmove(pStage, pStage + 1, sizeof(*pStage) * (index - stage)); - else - { - if(stage + 1 < MAX_SHADER_STAGES) - memmove(pStage, pStage + 1, sizeof(*pStage) * (index - stage - 1)); - - Com_Memset(&stages[index - 1], 0, sizeof(*stages)); - } - - continue; - } - - // - // default texture coordinate generation - // - if ( pStage->bundle[0].isLightmap ) { - if ( pStage->bundle[0].tcGen == TCGEN_BAD ) { - pStage->bundle[0].tcGen = TCGEN_LIGHTMAP; - } - hasLightmapStage = qtrue; - } else { - if ( pStage->bundle[0].tcGen == TCGEN_BAD ) { - pStage->bundle[0].tcGen = TCGEN_TEXTURE; - } - } - - - // not a true lightmap but we want to leave existing - // behaviour in place and not print out a warning - //if (pStage->rgbGen == CGEN_VERTEX) { - // vertexLightmap = qtrue; - //} - - - - // - // determine sort order and fog color adjustment - // - if ( ( pStage->stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) && - ( stages[0].stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) ) { - int blendSrcBits = pStage->stateBits & GLS_SRCBLEND_BITS; - int blendDstBits = pStage->stateBits & GLS_DSTBLEND_BITS; - - // fog color adjustment only works for blend modes that have a contribution - // that aproaches 0 as the modulate values aproach 0 -- - // GL_ONE, GL_ONE - // GL_ZERO, GL_ONE_MINUS_SRC_COLOR - // GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA - - // modulate, additive - if ( ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE ) ) || - ( ( blendSrcBits == GLS_SRCBLEND_ZERO ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR ) ) ) { - pStage->adjustColorsForFog = ACFF_MODULATE_RGB; - } - // strict blend - else if ( ( blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) ) - { - pStage->adjustColorsForFog = ACFF_MODULATE_ALPHA; - } - // premultiplied alpha - else if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) ) - { - pStage->adjustColorsForFog = ACFF_MODULATE_RGBA; - } else { - // we can't adjust this one correctly, so it won't be exactly correct in fog - } - - // don't screw with sort order if this is a portal or environment - if ( !shader.sort ) { - // see through item, like a grill or grate - if ( pStage->stateBits & GLS_DEPTHMASK_TRUE ) { - shader.sort = SS_SEE_THROUGH; - } else { - shader.sort = SS_BLEND0; - } - } - } - - stage++; - } - - // there are times when you will need to manually apply a sort to - // opaque alpha tested shaders that have later blend passes - if ( !shader.sort ) { - shader.sort = SS_OPAQUE; - } - - // - // if we are in r_vertexLight mode, never use a lightmap texture - // - if ( stage > 1 && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) ) { - VertexLightingCollapse(); - hasLightmapStage = qfalse; - } - - // - // look for multitexture potential - // - stage = CollapseStagesToGLSL(); - - if ( shader.lightmapIndex >= 0 && !hasLightmapStage ) { - if (vertexLightmap) { - ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has VERTEX forced lightmap!\n", shader.name ); - } else { - ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has lightmap but no lightmap stage!\n", shader.name ); - // Don't set this, it will just add duplicate shaders to the hash - //shader.lightmapIndex = LIGHTMAP_NONE; - } - } - - - // - // compute number of passes - // - shader.numUnfoggedPasses = stage; - - // fogonly shaders don't have any normal passes - if (stage == 0 && !shader.isSky) - shader.sort = SS_FOG; - - // determine which stage iterator function is appropriate - ComputeStageIteratorFunc(); - - // determine which vertex attributes this shader needs - ComputeVertexAttribs(); - - return GeneratePermanentShader(); -} - -//======================================================================================== - -/* -==================== -FindShaderInShaderText - -Scans the combined text description of all the shader files for -the given shader name. - -return NULL if not found - -If found, it will return a valid shader -===================== -*/ -static char *FindShaderInShaderText( const char *shadername ) { - - char *token, *p; - - int i, hash; - - hash = generateHashValue(shadername, MAX_SHADERTEXT_HASH); - - if(shaderTextHashTable[hash]) - { - for (i = 0; shaderTextHashTable[hash][i]; i++) - { - p = shaderTextHashTable[hash][i]; - token = COM_ParseExt(&p, qtrue); - - if(!Q_stricmp(token, shadername)) - return p; - } - } - - p = s_shaderText; - - if ( !p ) { - return NULL; - } - - // look for label - while ( 1 ) { - token = COM_ParseExt( &p, qtrue ); - if ( token[0] == 0 ) { - break; - } - - if ( !Q_stricmp( token, shadername ) ) { - return p; - } - else { - // skip the definition - SkipBracedSection( &p, 0 ); - } - } - - return NULL; -} - - -/* -================== -R_FindShaderByName - -Will always return a valid shader, but it might be the -default shader if the real one can't be found. -================== -*/ -shader_t *R_FindShaderByName( const char *name ) { - char strippedName[MAX_QPATH]; - int hash; - shader_t *sh; - - if ( (name==NULL) || (name[0] == 0) ) { - return tr.defaultShader; - } - - COM_StripExtension(name, strippedName, sizeof(strippedName)); - - hash = generateHashValue(strippedName, FILE_HASH_SIZE); - - // - // see if the shader is already loaded - // - for (sh=hashTable[hash]; sh; sh=sh->next) { - // NOTE: if there was no shader or image available with the name strippedName - // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we - // have to check all default shaders otherwise for every call to R_FindShader - // with that same strippedName a new default shader is created. - if (Q_stricmp(sh->name, strippedName) == 0) { - // match found - return sh; - } - } - - return tr.defaultShader; -} - - -/* -=============== -R_FindShader - -Will always return a valid shader, but it might be the -default shader if the real one can't be found. - -In the interest of not requiring an explicit shader text entry to -be defined for every single image used in the game, three default -shader behaviors can be auto-created for any image: - -If lightmapIndex == LIGHTMAP_NONE, then the image will have -dynamic diffuse lighting applied to it, as apropriate for most -entity skin surfaces. - -If lightmapIndex == LIGHTMAP_2D, then the image will be used -for 2D rendering unless an explicit shader is found - -If lightmapIndex == LIGHTMAP_BY_VERTEX, then the image will use -the vertex rgba modulate values, as apropriate for misc_model -pre-lit surfaces. - -Other lightmapIndex values will have a lightmap stage created -and src*dest blending applied with the texture, as apropriate for -most world construction surfaces. - -=============== -*/ -shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ) { - char strippedName[MAX_QPATH]; - int i, hash; - char *shaderText; - image_t *image; - shader_t *sh; - - if ( name[0] == 0 ) { - return tr.defaultShader; - } - - // use (fullbright) vertex lighting if the bsp file doesn't have - // lightmaps - if ( lightmapIndex >= 0 && lightmapIndex >= tr.numLightmaps ) { - lightmapIndex = LIGHTMAP_BY_VERTEX; - } else if ( lightmapIndex < LIGHTMAP_2D ) { - // negative lightmap indexes cause stray pointers (think tr.lightmaps[lightmapIndex]) - ri.Printf( PRINT_WARNING, "WARNING: shader '%s' has invalid lightmap index of %d\n", name, lightmapIndex ); - lightmapIndex = LIGHTMAP_BY_VERTEX; - } - - COM_StripExtension(name, strippedName, sizeof(strippedName)); - - hash = generateHashValue(strippedName, FILE_HASH_SIZE); - - // - // see if the shader is already loaded - // - for (sh = hashTable[hash]; sh; sh = sh->next) { - // NOTE: if there was no shader or image available with the name strippedName - // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we - // have to check all default shaders otherwise for every call to R_FindShader - // with that same strippedName a new default shader is created. - if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) && - !Q_stricmp(sh->name, strippedName)) { - // match found - return sh; - } - } - - // clear the global shader - Com_Memset( &shader, 0, sizeof( shader ) ); - Com_Memset( &stages, 0, sizeof( stages ) ); - Q_strncpyz(shader.name, strippedName, sizeof(shader.name)); - shader.lightmapIndex = lightmapIndex; - for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) { - stages[i].bundle[0].texMods = texMods[i]; - } - - // - // attempt to define shader from an explicit parameter file - // - shaderText = FindShaderInShaderText( strippedName ); - if ( shaderText ) { - // enable this when building a pak file to get a global list - // of all explicit shaders - if ( r_printShaders->integer ) { - ri.Printf( PRINT_ALL, "*SHADER* %s\n", name ); - } - - if ( !ParseShader( &shaderText ) ) { - // had errors, so use default shader - shader.defaultShader = qtrue; - } - sh = FinishShader(); - return sh; - } - - - // - // if not defined in the in-memory shader descriptions, - // look for a single supported image file - // - { - imgFlags_t flags; - - flags = IMGFLAG_NONE; - - if (r_srgb->integer) - flags |= IMGFLAG_SRGB; - - if (mipRawImage) - { - flags |= IMGFLAG_MIPMAP | IMGFLAG_PICMIP; - - if (r_genNormalMaps->integer) - flags |= IMGFLAG_GENNORMALMAP; - } - else - { - flags |= IMGFLAG_CLAMPTOEDGE; - } - - image = R_FindImageFile( name, IMGTYPE_COLORALPHA, flags ); - if ( !image ) { - ri.Printf( PRINT_DEVELOPER, "Couldn't find image file for shader %s\n", name ); - shader.defaultShader = qtrue; - return FinishShader(); - } - } - - // - // create the default shading commands - // - if ( shader.lightmapIndex == LIGHTMAP_NONE ) { - // dynamic colors at vertexes - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE; - stages[0].stateBits = GLS_DEFAULT; - } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) { - // explicit colors at vertexes - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_EXACT_VERTEX; - stages[0].alphaGen = AGEN_SKIP; - stages[0].stateBits = GLS_DEFAULT; - } else if ( shader.lightmapIndex == LIGHTMAP_2D ) { - // GUI elements - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_VERTEX; - stages[0].alphaGen = AGEN_VERTEX; - stages[0].stateBits = GLS_DEPTHTEST_DISABLE | - GLS_SRCBLEND_SRC_ALPHA | - GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) { - // fullbright level - stages[0].bundle[0].image[0] = tr.whiteImage; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - stages[0].stateBits = GLS_DEFAULT; - - stages[1].bundle[0].image[0] = image; - stages[1].active = qtrue; - stages[1].rgbGen = CGEN_IDENTITY; - stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; - } else { - // two pass lightmap - stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; - stages[0].bundle[0].isLightmap = qtrue; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation - // for identitylight - stages[0].stateBits = GLS_DEFAULT; - - stages[1].bundle[0].image[0] = image; - stages[1].active = qtrue; - stages[1].rgbGen = CGEN_IDENTITY; - stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; - } - - return FinishShader(); -} - - -qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage) { - int i, hash; - shader_t *sh; - - hash = generateHashValue(name, FILE_HASH_SIZE); - - // probably not necessary since this function - // only gets called from tr_font.c with lightmapIndex == LIGHTMAP_2D - // but better safe than sorry. - if ( lightmapIndex >= tr.numLightmaps ) { - lightmapIndex = LIGHTMAP_WHITEIMAGE; - } - - // - // see if the shader is already loaded - // - for (sh=hashTable[hash]; sh; sh=sh->next) { - // NOTE: if there was no shader or image available with the name strippedName - // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we - // have to check all default shaders otherwise for every call to R_FindShader - // with that same strippedName a new default shader is created. - if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) && - // index by name - !Q_stricmp(sh->name, name)) { - // match found - return sh->index; - } - } - - // clear the global shader - Com_Memset( &shader, 0, sizeof( shader ) ); - Com_Memset( &stages, 0, sizeof( stages ) ); - Q_strncpyz(shader.name, name, sizeof(shader.name)); - shader.lightmapIndex = lightmapIndex; - for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) { - stages[i].bundle[0].texMods = texMods[i]; - } - - // - // create the default shading commands - // - if ( shader.lightmapIndex == LIGHTMAP_NONE ) { - // dynamic colors at vertexes - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE; - stages[0].stateBits = GLS_DEFAULT; - } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) { - // explicit colors at vertexes - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_EXACT_VERTEX; - stages[0].alphaGen = AGEN_SKIP; - stages[0].stateBits = GLS_DEFAULT; - } else if ( shader.lightmapIndex == LIGHTMAP_2D ) { - // GUI elements - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_VERTEX; - stages[0].alphaGen = AGEN_VERTEX; - stages[0].stateBits = GLS_DEPTHTEST_DISABLE | - GLS_SRCBLEND_SRC_ALPHA | - GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) { - // fullbright level - stages[0].bundle[0].image[0] = tr.whiteImage; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_IDENTITY_LIGHTING; - stages[0].stateBits = GLS_DEFAULT; - - stages[1].bundle[0].image[0] = image; - stages[1].active = qtrue; - stages[1].rgbGen = CGEN_IDENTITY; - stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; - } else { - // two pass lightmap - stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; - stages[0].bundle[0].isLightmap = qtrue; - stages[0].active = qtrue; - stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation - // for identitylight - stages[0].stateBits = GLS_DEFAULT; - - stages[1].bundle[0].image[0] = image; - stages[1].active = qtrue; - stages[1].rgbGen = CGEN_IDENTITY; - stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; - } - - sh = FinishShader(); - return sh->index; -} - - -/* -==================== -RE_RegisterShader - -This is the exported shader entry point for the rest of the system -It will always return an index that will be valid. - -This should really only be used for explicit shaders, because there is no -way to ask for different implicit lighting modes (vertex, lightmap, etc) -==================== -*/ -qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex ) { - shader_t *sh; - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" ); - return 0; - } - - sh = R_FindShader( name, lightmapIndex, qtrue ); - - // we want to return 0 if the shader failed to - // load for some reason, but R_FindShader should - // still keep a name allocated for it, so if - // something calls RE_RegisterShader again with - // the same name, we don't try looking for it again - if ( sh->defaultShader ) { - return 0; - } - - return sh->index; -} - - -/* -==================== -RE_RegisterShader - -This is the exported shader entry point for the rest of the system -It will always return an index that will be valid. - -This should really only be used for explicit shaders, because there is no -way to ask for different implicit lighting modes (vertex, lightmap, etc) -==================== -*/ -qhandle_t RE_RegisterShader( const char *name ) { - shader_t *sh; - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" ); - return 0; - } - - sh = R_FindShader( name, LIGHTMAP_2D, qtrue ); - - // we want to return 0 if the shader failed to - // load for some reason, but R_FindShader should - // still keep a name allocated for it, so if - // something calls RE_RegisterShader again with - // the same name, we don't try looking for it again - if ( sh->defaultShader ) { - return 0; - } - - return sh->index; -} - - -/* -==================== -RE_RegisterShaderNoMip - -For menu graphics that should never be picmiped -==================== -*/ -qhandle_t RE_RegisterShaderNoMip( const char *name ) { - shader_t *sh; - - if ( strlen( name ) >= MAX_QPATH ) { - ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" ); - return 0; - } - - sh = R_FindShader( name, LIGHTMAP_2D, qfalse ); - - // we want to return 0 if the shader failed to - // load for some reason, but R_FindShader should - // still keep a name allocated for it, so if - // something calls RE_RegisterShader again with - // the same name, we don't try looking for it again - if ( sh->defaultShader ) { - return 0; - } - - return sh->index; -} - -/* -==================== -R_GetShaderByHandle - -When a handle is passed in by another module, this range checks -it and returns a valid (possibly default) shader_t to be used internally. -==================== -*/ -shader_t *R_GetShaderByHandle( qhandle_t hShader ) { - if ( hShader < 0 ) { - ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader ); - return tr.defaultShader; - } - if ( hShader >= tr.numShaders ) { - ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader ); - return tr.defaultShader; - } - return tr.shaders[hShader]; -} - -/* -=============== -R_ShaderList_f - -Dump information on all valid shaders to the console -A second parameter will cause it to print in sorted order -=============== -*/ -void R_ShaderList_f (void) { - int i; - int count; - shader_t *shader; - - ri.Printf (PRINT_ALL, "-----------------------\n"); - - count = 0; - for ( i = 0 ; i < tr.numShaders ; i++ ) { - if ( ri.Cmd_Argc() > 1 ) { - shader = tr.sortedShaders[i]; - } else { - shader = tr.shaders[i]; - } - - ri.Printf( PRINT_ALL, "%i ", shader->numUnfoggedPasses ); - - if (shader->lightmapIndex >= 0 ) { - ri.Printf (PRINT_ALL, "L "); - } else { - ri.Printf (PRINT_ALL, " "); - } - if ( shader->multitextureEnv == GL_ADD ) { - ri.Printf( PRINT_ALL, "MT(a) " ); - } else if ( shader->multitextureEnv == GL_MODULATE ) { - ri.Printf( PRINT_ALL, "MT(m) " ); - } else if ( shader->multitextureEnv == GL_DECAL ) { - ri.Printf( PRINT_ALL, "MT(d) " ); - } else { - ri.Printf( PRINT_ALL, " " ); - } - if ( shader->explicitlyDefined ) { - ri.Printf( PRINT_ALL, "E " ); - } else { - ri.Printf( PRINT_ALL, " " ); - } - - if ( shader->optimalStageIteratorFunc == RB_StageIteratorGeneric ) { - ri.Printf( PRINT_ALL, "gen " ); - } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorSky ) { - ri.Printf( PRINT_ALL, "sky " ); - } else { - ri.Printf( PRINT_ALL, " " ); - } - - if ( shader->defaultShader ) { - ri.Printf (PRINT_ALL, ": %s (DEFAULTED)\n", shader->name); - } else { - ri.Printf (PRINT_ALL, ": %s\n", shader->name); - } - count++; - } - ri.Printf (PRINT_ALL, "%i total shaders\n", count); - ri.Printf (PRINT_ALL, "------------------\n"); -} - -/* -==================== -ScanAndLoadShaderFiles - -Finds and loads all .shader files, combining them into -a single large text block that can be scanned for shader names -===================== -*/ -#define MAX_SHADER_FILES 4096 -static void ScanAndLoadShaderFiles( void ) -{ - char **shaderFiles; - char *buffers[MAX_SHADER_FILES]; - char *p; - int numShaderFiles; - int i; - char *oldp, *token, *hashMem, *textEnd; - int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size; - char shaderName[MAX_QPATH]; - int shaderLine; - - long sum = 0, summand; - // scan for shader files - shaderFiles = ri.FS_ListFiles( "scripts", ".shader", &numShaderFiles ); - - if ( !shaderFiles || !numShaderFiles ) - { - ri.Printf( PRINT_WARNING, "WARNING: no shader files found\n" ); - return; - } - - if ( numShaderFiles > MAX_SHADER_FILES ) { - numShaderFiles = MAX_SHADER_FILES; - } - - // load and parse shader files - for ( i = 0; i < numShaderFiles; i++ ) - { - char filename[MAX_QPATH]; - - // look for a .mtr file first - { - char *ext; - Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] ); - if ( (ext = strrchr(filename, '.')) ) - { - strcpy(ext, ".mtr"); - } - - if ( ri.FS_ReadFile( filename, NULL ) <= 0 ) - { - Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] ); - } - } - - ri.Printf( PRINT_DEVELOPER, "...loading '%s'\n", filename ); - summand = ri.FS_ReadFile( filename, (void **)&buffers[i] ); - - if ( !buffers[i] ) - ri.Error( ERR_DROP, "Couldn't load %s", filename ); - - // Do a simple check on the shader structure in that file to make sure one bad shader file cannot fuck up all other shaders. - p = buffers[i]; - COM_BeginParseSession(filename); - while(1) - { - token = COM_ParseExt(&p, qtrue); - - if(!*token) - break; - - Q_strncpyz(shaderName, token, sizeof(shaderName)); - shaderLine = COM_GetCurrentParseLine(); - - token = COM_ParseExt(&p, qtrue); - if(token[0] != '{' || token[1] != '\0') - { - ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing opening brace", - filename, shaderName, shaderLine); - if (token[0]) - { - ri.Printf(PRINT_WARNING, " (found \"%s\" on line %d)", token, COM_GetCurrentParseLine()); - } - ri.Printf(PRINT_WARNING, ".\n"); - ri.FS_FreeFile(buffers[i]); - buffers[i] = NULL; - break; - } - - if(!SkipBracedSection(&p, 1)) - { - ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing closing brace.\n", - filename, shaderName, shaderLine); - ri.FS_FreeFile(buffers[i]); - buffers[i] = NULL; - break; - } - } - - - if (buffers[i]) - sum += summand; - } - - // build single large buffer - s_shaderText = ri.Hunk_Alloc( sum + numShaderFiles*2, h_low ); - s_shaderText[ 0 ] = '\0'; - textEnd = s_shaderText; - - // free in reverse order, so the temp files are all dumped - for ( i = numShaderFiles - 1; i >= 0 ; i-- ) - { - if ( !buffers[i] ) - continue; - - strcat( textEnd, buffers[i] ); - strcat( textEnd, "\n" ); - textEnd += strlen( textEnd ); - ri.FS_FreeFile( buffers[i] ); - } - - COM_Compress( s_shaderText ); - - // free up memory - ri.FS_FreeFileList( shaderFiles ); - - Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes)); - size = 0; - - p = s_shaderText; - // look for shader names - while ( 1 ) { - token = COM_ParseExt( &p, qtrue ); - if ( token[0] == 0 ) { - break; - } - - hash = generateHashValue(token, MAX_SHADERTEXT_HASH); - shaderTextHashTableSizes[hash]++; - size++; - SkipBracedSection(&p, 0); - } - - size += MAX_SHADERTEXT_HASH; - - hashMem = ri.Hunk_Alloc( size * sizeof(char *), h_low ); - - for (i = 0; i < MAX_SHADERTEXT_HASH; i++) { - shaderTextHashTable[i] = (char **) hashMem; - hashMem = ((char *) hashMem) + ((shaderTextHashTableSizes[i] + 1) * sizeof(char *)); - } - - Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes)); - - p = s_shaderText; - // look for shader names - while ( 1 ) { - oldp = p; - token = COM_ParseExt( &p, qtrue ); - if ( token[0] == 0 ) { - break; - } - - hash = generateHashValue(token, MAX_SHADERTEXT_HASH); - shaderTextHashTable[hash][shaderTextHashTableSizes[hash]++] = oldp; - - SkipBracedSection(&p, 0); - } - - return; - -} - - -/* -==================== -CreateInternalShaders -==================== -*/ -static void CreateInternalShaders( void ) { - tr.numShaders = 0; - - // init the default shader - Com_Memset( &shader, 0, sizeof( shader ) ); - Com_Memset( &stages, 0, sizeof( stages ) ); - - Q_strncpyz( shader.name, "", sizeof( shader.name ) ); - - shader.lightmapIndex = LIGHTMAP_NONE; - stages[0].bundle[0].image[0] = tr.defaultImage; - stages[0].active = qtrue; - stages[0].stateBits = GLS_DEFAULT; - tr.defaultShader = FinishShader(); - - // shadow shader is just a marker - Q_strncpyz( shader.name, "", sizeof( shader.name ) ); - shader.sort = SS_STENCIL_SHADOW; - tr.shadowShader = FinishShader(); -} - -static void CreateExternalShaders( void ) { - tr.projectionShadowShader = R_FindShader( "projectionShadow", LIGHTMAP_NONE, qtrue ); - tr.flareShader = R_FindShader( "flareShader", LIGHTMAP_NONE, qtrue ); - - // Hack to make fogging work correctly on flares. Fog colors are calculated - // in tr_flare.c already. - if(!tr.flareShader->defaultShader) - { - int index; - - for(index = 0; index < tr.flareShader->numUnfoggedPasses; index++) - { - tr.flareShader->stages[index]->adjustColorsForFog = ACFF_NONE; - tr.flareShader->stages[index]->stateBits |= GLS_DEPTHTEST_DISABLE; - } - } - - tr.sunShader = R_FindShader( "sun", LIGHTMAP_NONE, qtrue ); - - tr.sunFlareShader = R_FindShader( "gfx/2d/sunflare", LIGHTMAP_NONE, qtrue); - - // HACK: if sunflare is missing, make one using the flare image or dlight image - if (tr.sunFlareShader->defaultShader) - { - image_t *image; - - if (!tr.flareShader->defaultShader && tr.flareShader->stages[0] && tr.flareShader->stages[0]->bundle[0].image[0]) - image = tr.flareShader->stages[0]->bundle[0].image[0]; - else - image = tr.dlightImage; - - Com_Memset( &shader, 0, sizeof( shader ) ); - Com_Memset( &stages, 0, sizeof( stages ) ); - - Q_strncpyz( shader.name, "gfx/2d/sunflare", sizeof( shader.name ) ); - - shader.lightmapIndex = LIGHTMAP_NONE; - stages[0].bundle[0].image[0] = image; - stages[0].active = qtrue; - stages[0].stateBits = GLS_DEFAULT; - tr.sunFlareShader = FinishShader(); - } - -} - -/* -================== -R_InitShaders -================== -*/ -void R_InitShaders( void ) { - ri.Printf( PRINT_ALL, "Initializing Shaders\n" ); - - Com_Memset(hashTable, 0, sizeof(hashTable)); - - CreateInternalShaders(); - - ScanAndLoadShaderFiles(); - - CreateExternalShaders(); -} diff --git a/code/renderergl2/tr_shadows.c b/code/renderergl2/tr_shadows.c deleted file mode 100644 index f412b00d3e..0000000000 --- a/code/renderergl2/tr_shadows.c +++ /dev/null @@ -1,343 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - - -/* - - for a projection shadow: - - point[x] += light vector * ( z - shadow plane ) - point[y] += - point[z] = shadow plane - - 1 0 light[x] / light[z] - -*/ - -typedef struct { - int i2; - int facing; -} edgeDef_t; - -#define MAX_EDGE_DEFS 32 - -static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS]; -static int numEdgeDefs[SHADER_MAX_VERTEXES]; -static int facing[SHADER_MAX_INDEXES/3]; - -void R_AddEdgeDef( int i1, int i2, int facing ) { - int c; - - c = numEdgeDefs[ i1 ]; - if ( c == MAX_EDGE_DEFS ) { - return; // overflow - } - edgeDefs[ i1 ][ c ].i2 = i2; - edgeDefs[ i1 ][ c ].facing = facing; - - numEdgeDefs[ i1 ]++; -} - -void R_RenderShadowEdges( void ) { - int i; - -#if 0 - int numTris; - - // dumb way -- render every triangle's edges - numTris = tess.numIndexes / 3; - - for ( i = 0 ; i < numTris ; i++ ) { - int i1, i2, i3; - - if ( !facing[i] ) { - continue; - } - - i1 = tess.indexes[ i*3 + 0 ]; - i2 = tess.indexes[ i*3 + 1 ]; - i3 = tess.indexes[ i*3 + 2 ]; - - qglBegin( GL_TRIANGLE_STRIP ); - qglVertex3fv( tess.xyz[ i1 ] ); - qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); - qglVertex3fv( tess.xyz[ i2 ] ); - qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); - qglVertex3fv( tess.xyz[ i3 ] ); - qglVertex3fv( tess.xyz[ i3 + tess.numVertexes ] ); - qglVertex3fv( tess.xyz[ i1 ] ); - qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] ); - qglEnd(); - } -#else - int c, c2; - int j, k; - int i2; - int c_edges, c_rejected; - int hit[2]; - - // an edge is NOT a silhouette edge if its face doesn't face the light, - // or if it has a reverse paired edge that also faces the light. - // A well behaved polyhedron would have exactly two faces for each edge, - // but lots of models have dangling edges or overfanned edges - c_edges = 0; - c_rejected = 0; - - for ( i = 0 ; i < tess.numVertexes ; i++ ) { - c = numEdgeDefs[ i ]; - for ( j = 0 ; j < c ; j++ ) { - if ( !edgeDefs[ i ][ j ].facing ) { - continue; - } - - hit[0] = 0; - hit[1] = 0; - - i2 = edgeDefs[ i ][ j ].i2; - c2 = numEdgeDefs[ i2 ]; - for ( k = 0 ; k < c2 ; k++ ) { - if ( edgeDefs[ i2 ][ k ].i2 == i ) { - hit[ edgeDefs[ i2 ][ k ].facing ]++; - } - } - - // if it doesn't share the edge with another front facing - // triangle, it is a sil edge - if ( hit[ 1 ] == 0 ) { - qglBegin( GL_TRIANGLE_STRIP ); - qglVertex3fv( tess.xyz[ i ] ); - qglVertex3fv( tess.xyz[ i + tess.numVertexes ] ); - qglVertex3fv( tess.xyz[ i2 ] ); - qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] ); - qglEnd(); - c_edges++; - } else { - c_rejected++; - } - } - } -#endif -} - -/* -================= -RB_ShadowTessEnd - -triangleFromEdge[ v1 ][ v2 ] - - - set triangle from edge( v1, v2, tri ) - if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) { - } -================= -*/ -void RB_ShadowTessEnd( void ) { - int i; - int numTris; - vec3_t lightDir; - GLboolean rgba[4]; - - // we can only do this if we have enough space in the vertex buffers - if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) { - return; - } - - if ( glConfig.stencilBits < 4 ) { - return; - } - - VectorCopy( backEnd.currentEntity->lightDir, lightDir ); - - // project vertexes away from light direction - for ( i = 0 ; i < tess.numVertexes ; i++ ) { - VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] ); - } - - // decide which triangles face the light - Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes ); - - numTris = tess.numIndexes / 3; - for ( i = 0 ; i < numTris ; i++ ) { - int i1, i2, i3; - vec3_t d1, d2, normal; - float *v1, *v2, *v3; - float d; - - i1 = tess.indexes[ i*3 + 0 ]; - i2 = tess.indexes[ i*3 + 1 ]; - i3 = tess.indexes[ i*3 + 2 ]; - - v1 = tess.xyz[ i1 ]; - v2 = tess.xyz[ i2 ]; - v3 = tess.xyz[ i3 ]; - - VectorSubtract( v2, v1, d1 ); - VectorSubtract( v3, v1, d2 ); - CrossProduct( d1, d2, normal ); - - d = DotProduct( normal, lightDir ); - if ( d > 0 ) { - facing[ i ] = 1; - } else { - facing[ i ] = 0; - } - - // create the edges - R_AddEdgeDef( i1, i2, facing[ i ] ); - R_AddEdgeDef( i2, i3, facing[ i ] ); - R_AddEdgeDef( i3, i1, facing[ i ] ); - } - - // draw the silhouette edges - - GL_Bind( tr.whiteImage ); - qglEnable( GL_CULL_FACE ); - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - qglColor3f( 0.2f, 0.2f, 0.2f ); - - // don't write to the color buffer - qglGetBooleanv(GL_COLOR_WRITEMASK, rgba); - qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); - - qglEnable( GL_STENCIL_TEST ); - qglStencilFunc( GL_ALWAYS, 1, 255 ); - - // mirrors have the culling order reversed - if ( backEnd.viewParms.isMirror ) { - qglCullFace( GL_FRONT ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); - - R_RenderShadowEdges(); - - qglCullFace( GL_BACK ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); - - R_RenderShadowEdges(); - } else { - qglCullFace( GL_BACK ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); - - R_RenderShadowEdges(); - - qglCullFace( GL_FRONT ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); - - R_RenderShadowEdges(); - } - - - // reenable writing to the color buffer - qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]); -} - - -/* -================= -RB_ShadowFinish - -Darken everything that is is a shadow volume. -We have to delay this until everything has been shadowed, -because otherwise shadows from different body parts would -overlap and double darken. -================= -*/ -void RB_ShadowFinish( void ) { - if ( r_shadows->integer != 2 ) { - return; - } - if ( glConfig.stencilBits < 4 ) { - return; - } - qglEnable( GL_STENCIL_TEST ); - qglStencilFunc( GL_NOTEQUAL, 0, 255 ); - - qglDisable (GL_CLIP_PLANE0); - qglDisable (GL_CULL_FACE); - - GL_Bind( tr.whiteImage ); - - qglLoadIdentity (); - - qglColor3f( 0.6f, 0.6f, 0.6f ); - GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO ); - -// qglColor3f( 1, 0, 0 ); -// GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - - qglBegin( GL_QUADS ); - qglVertex3f( -100, 100, -10 ); - qglVertex3f( 100, 100, -10 ); - qglVertex3f( 100, -100, -10 ); - qglVertex3f( -100, -100, -10 ); - qglEnd (); - - qglColor4f(1,1,1,1); - qglDisable( GL_STENCIL_TEST ); -} - - -/* -================= -RB_ProjectionShadowDeform - -================= -*/ -void RB_ProjectionShadowDeform( void ) { - float *xyz; - int i; - float h; - vec3_t ground; - vec3_t light; - float groundDist; - float d; - vec3_t lightDir; - - xyz = ( float * ) tess.xyz; - - ground[0] = backEnd.or.axis[0][2]; - ground[1] = backEnd.or.axis[1][2]; - ground[2] = backEnd.or.axis[2][2]; - - groundDist = backEnd.or.origin[2] - backEnd.currentEntity->e.shadowPlane; - - VectorCopy( backEnd.currentEntity->lightDir, lightDir ); - d = DotProduct( lightDir, ground ); - // don't let the shadows get too long or go negative - if ( d < 0.5 ) { - VectorMA( lightDir, (0.5 - d), ground, lightDir ); - d = DotProduct( lightDir, ground ); - } - d = 1.0 / d; - - light[0] = lightDir[0] * d; - light[1] = lightDir[1] * d; - light[2] = lightDir[2] * d; - - for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) { - h = DotProduct( xyz, ground ) + groundDist; - - xyz[0] -= light[0] * h; - xyz[1] -= light[1] * h; - xyz[2] -= light[2] * h; - } -} diff --git a/code/renderergl2/tr_sky.c b/code/renderergl2/tr_sky.c deleted file mode 100644 index 6a22031889..0000000000 --- a/code/renderergl2/tr_sky.c +++ /dev/null @@ -1,912 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_sky.c -#include "tr_local.h" - -#define SKY_SUBDIVISIONS 8 -#define HALF_SKY_SUBDIVISIONS (SKY_SUBDIVISIONS/2) - -static float s_cloudTexCoords[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2]; -static float s_cloudTexP[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1]; - -/* -=================================================================================== - -POLYGON TO BOX SIDE PROJECTION - -=================================================================================== -*/ - -static vec3_t sky_clip[6] = -{ - {1,1,0}, - {1,-1,0}, - {0,-1,1}, - {0,1,1}, - {1,0,1}, - {-1,0,1} -}; - -static float sky_mins[2][6], sky_maxs[2][6]; -static float sky_min, sky_max; - -/* -================ -AddSkyPolygon -================ -*/ -static void AddSkyPolygon (int nump, vec3_t vecs) -{ - int i,j; - vec3_t v, av; - float s, t, dv; - int axis; - float *vp; - // s = [0]/[2], t = [1]/[2] - static int vec_to_st[6][3] = - { - {-2,3,1}, - {2,3,-1}, - - {1,3,2}, - {-1,3,-2}, - - {-2,-1,3}, - {-2,1,-3} - - // {-1,2,3}, - // {1,2,-3} - }; - - // decide which face it maps to - VectorCopy (vec3_origin, v); - for (i=0, vp=vecs ; i av[1] && av[0] > av[2]) - { - if (v[0] < 0) - axis = 1; - else - axis = 0; - } - else if (av[1] > av[2] && av[1] > av[0]) - { - if (v[1] < 0) - axis = 3; - else - axis = 2; - } - else - { - if (v[2] < 0) - axis = 5; - else - axis = 4; - } - - // project new texture coords - for (i=0 ; i 0) - dv = vecs[j - 1]; - else - dv = -vecs[-j - 1]; - if (dv < 0.001) - continue; // don't divide by zero - j = vec_to_st[axis][0]; - if (j < 0) - s = -vecs[-j -1] / dv; - else - s = vecs[j-1] / dv; - j = vec_to_st[axis][1]; - if (j < 0) - t = -vecs[-j -1] / dv; - else - t = vecs[j-1] / dv; - - if (s < sky_mins[0][axis]) - sky_mins[0][axis] = s; - if (t < sky_mins[1][axis]) - sky_mins[1][axis] = t; - if (s > sky_maxs[0][axis]) - sky_maxs[0][axis] = s; - if (t > sky_maxs[1][axis]) - sky_maxs[1][axis] = t; - } -} - -#define ON_EPSILON 0.1f // point on plane side epsilon -#define MAX_CLIP_VERTS 64 -/* -================ -ClipSkyPolygon -================ -*/ -static void ClipSkyPolygon (int nump, vec3_t vecs, int stage) -{ - float *norm; - float *v; - qboolean front, back; - float d, e; - float dists[MAX_CLIP_VERTS]; - int sides[MAX_CLIP_VERTS]; - vec3_t newv[2][MAX_CLIP_VERTS]; - int newc[2]; - int i, j; - - if (nump > MAX_CLIP_VERTS-2) - ri.Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS"); - if (stage == 6) - { // fully clipped, so draw it - AddSkyPolygon (nump, vecs); - return; - } - - front = back = qfalse; - norm = sky_clip[stage]; - for (i=0, v = vecs ; i ON_EPSILON) - { - front = qtrue; - sides[i] = SIDE_FRONT; - } - else if (d < -ON_EPSILON) - { - back = qtrue; - sides[i] = SIDE_BACK; - } - else - sides[i] = SIDE_ON; - dists[i] = d; - } - - if (!front || !back) - { // not clipped - ClipSkyPolygon (nump, vecs, stage+1); - return; - } - - // clip it - sides[i] = sides[0]; - dists[i] = dists[0]; - VectorCopy (vecs, (vecs+(i*3)) ); - newc[0] = newc[1] = 0; - - for (i=0, v = vecs ; inumIndexes; i += 3 ) - { - for (j = 0 ; j < 3 ; j++) - { - VectorSubtract( input->xyz[input->indexes[i+j]], - backEnd.viewParms.or.origin, - p[j] ); - } - ClipSkyPolygon( 3, p[0], 0 ); - } -} - -/* -=================================================================================== - -CLOUD VERTEX GENERATION - -=================================================================================== -*/ - -/* -** MakeSkyVec -** -** Parms: s, t range from -1 to 1 -*/ -static void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXYZ ) -{ - // 1 = s, 2 = t, 3 = 2048 - static int st_to_vec[6][3] = - { - {3,-1,2}, - {-3,1,2}, - - {1,3,2}, - {-1,-3,2}, - - {-2,-1,3}, // 0 degrees yaw, look straight up - {2,-1,-3} // look straight down - }; - - vec3_t b; - int j, k; - float boxSize; - - boxSize = backEnd.viewParms.zFar / 1.75; // div sqrt(3) - b[0] = s*boxSize; - b[1] = t*boxSize; - b[2] = boxSize; - - for (j=0 ; j<3 ; j++) - { - k = st_to_vec[axis][j]; - if (k < 0) - { - outXYZ[j] = -b[-k - 1]; - } - else - { - outXYZ[j] = b[k - 1]; - } - } - - // avoid bilerp seam - s = (s+1)*0.5; - t = (t+1)*0.5; - if (s < sky_min) - { - s = sky_min; - } - else if (s > sky_max) - { - s = sky_max; - } - - if (t < sky_min) - { - t = sky_min; - } - else if (t > sky_max) - { - t = sky_max; - } - - t = 1.0 - t; - - - if ( outSt ) - { - outSt[0] = s; - outSt[1] = t; - } -} - -static int sky_texorder[6] = {0,2,1,3,4,5}; -static vec3_t s_skyPoints[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1]; -static float s_skyTexCoords[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2]; - -static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] ) -{ - int s, t; - int firstVertex = tess.numVertexes; - //int firstIndex = tess.numIndexes; - int minIndex = tess.minIndex; - int maxIndex = tess.maxIndex; - vec4_t color; - - //tess.numVertexes = 0; - //tess.numIndexes = 0; - tess.firstIndex = tess.numIndexes; - - GL_Bind( image ); - GL_Cull( CT_TWO_SIDED ); - - for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) - { - for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) - { - tess.xyz[tess.numVertexes][0] = s_skyPoints[t][s][0]; - tess.xyz[tess.numVertexes][1] = s_skyPoints[t][s][1]; - tess.xyz[tess.numVertexes][2] = s_skyPoints[t][s][2]; - tess.xyz[tess.numVertexes][3] = 1.0; - - tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0]; - tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1]; - - tess.numVertexes++; - - if(tess.numVertexes >= SHADER_MAX_VERTEXES) - { - ri.Error(ERR_DROP, "SHADER_MAX_VERTEXES hit in DrawSkySideVBO()"); - } - } - } - - for ( t = 0; t < maxs[1] - mins[1]; t++ ) - { - for ( s = 0; s < maxs[0] - mins[0]; s++ ) - { - if (tess.numIndexes + 6 >= SHADER_MAX_INDEXES) - { - ri.Error(ERR_DROP, "SHADER_MAX_INDEXES hit in DrawSkySideVBO()"); - } - - tess.indexes[tess.numIndexes++] = s + t * (maxs[0] - mins[0] + 1) + firstVertex; - tess.indexes[tess.numIndexes++] = s + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex; - tess.indexes[tess.numIndexes++] = (s + 1) + t * (maxs[0] - mins[0] + 1) + firstVertex; - - tess.indexes[tess.numIndexes++] = (s + 1) + t * (maxs[0] - mins[0] + 1) + firstVertex; - tess.indexes[tess.numIndexes++] = s + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex; - tess.indexes[tess.numIndexes++] = (s + 1) + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex; - } - } - - tess.minIndex = firstVertex; - tess.maxIndex = tess.numVertexes; - - // FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function - RB_UpdateVBOs(ATTR_POSITION | ATTR_TEXCOORD); -/* - { - shaderProgram_t *sp = &tr.textureColorShader; - - GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD); - GLSL_BindProgram(sp); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - - color[0] = - color[1] = - color[2] = tr.identityLight; - color[3] = 1.0f; - GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color); - } -*/ - { - shaderProgram_t *sp = &tr.lightallShader[0]; - vec4_t vector; - - GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD); - GLSL_BindProgram(sp); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - - color[0] = - color[1] = - color[2] = (r_softOverbright->integer ? 1.0 : tr.identityLight) * backEnd.refdef.colorScale; - color[3] = 1.0f; - GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, color); - - color[0] = - color[1] = - color[2] = - color[3] = 0.0f; - GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, color); - - VectorSet4(vector, 1.0, 0.0, 0.0, 1.0); - GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, vector); - - VectorSet4(vector, 0.0, 0.0, 0.0, 0.0); - GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, vector); - } - - R_DrawElementsVBO(tess.numIndexes - tess.firstIndex, tess.firstIndex, tess.minIndex, tess.maxIndex); - - //qglDrawElements(GL_TRIANGLES, tess.numIndexes - tess.firstIndex, GL_INDEX_TYPE, BUFFER_OFFSET(tess.firstIndex * sizeof(glIndex_t))); - - //R_BindNullVBO(); - //R_BindNullIBO(); - - tess.numIndexes = tess.firstIndex; - tess.numVertexes = firstVertex; - tess.firstIndex = 0; - tess.minIndex = minIndex; - tess.maxIndex = maxIndex; -} - -static void DrawSkyBox( shader_t *shader ) -{ - int i; - - sky_min = 0; - sky_max = 1; - - Com_Memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) ); - - for (i=0 ; i<6 ; i++) - { - int sky_mins_subd[2], sky_maxs_subd[2]; - int s, t; - - sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - - if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) || - ( sky_mins[1][i] >= sky_maxs[1][i] ) ) - { - continue; - } - - sky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS; - sky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS; - sky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS; - sky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS; - - if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS; - if ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS; - - if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS; - if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS; - - // - // iterate through the subdivisions - // - for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ ) - { - for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ ) - { - MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - i, - s_skyTexCoords[t][s], - s_skyPoints[t][s] ); - } - } - - DrawSkySide( shader->sky.outerbox[sky_texorder[i]], - sky_mins_subd, - sky_maxs_subd ); - } - -} - -static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean addIndexes ) -{ - int s, t; - int vertexStart = tess.numVertexes; - int tHeight, sWidth; - - tHeight = maxs[1] - mins[1] + 1; - sWidth = maxs[0] - mins[0] + 1; - - for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) - { - for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) - { - VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0]; - tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1]; - - tess.numVertexes++; - - if ( tess.numVertexes >= SHADER_MAX_VERTEXES ) - { - ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()" ); - } - } - } - - // only add indexes for one pass, otherwise it would draw multiple times for each pass - if ( addIndexes ) { - for ( t = 0; t < tHeight-1; t++ ) - { - for ( s = 0; s < sWidth-1; s++ ) - { - tess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth ); - tess.numIndexes++; - tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth ); - tess.numIndexes++; - tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth ); - tess.numIndexes++; - - tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth ); - tess.numIndexes++; - tess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth ); - tess.numIndexes++; - tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth ); - tess.numIndexes++; - } - } - } -} - -static void FillCloudBox( const shader_t *shader, int stage ) -{ - int i; - - for ( i =0; i < 6; i++ ) - { - int sky_mins_subd[2], sky_maxs_subd[2]; - int s, t; - float MIN_T; - - if ( 1 ) // FIXME? shader->sky.fullClouds ) - { - MIN_T = -HALF_SKY_SUBDIVISIONS; - - // still don't want to draw the bottom, even if fullClouds - if ( i == 5 ) - continue; - } - else - { - switch( i ) - { - case 0: - case 1: - case 2: - case 3: - MIN_T = -1; - break; - case 5: - // don't draw clouds beneath you - continue; - case 4: // top - default: - MIN_T = -HALF_SKY_SUBDIVISIONS; - break; - } - } - - sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; - - if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) || - ( sky_mins[1][i] >= sky_maxs[1][i] ) ) - { - continue; - } - - sky_mins_subd[0] = ri.ftol(sky_mins[0][i] * HALF_SKY_SUBDIVISIONS); - sky_mins_subd[1] = ri.ftol(sky_mins[1][i] * HALF_SKY_SUBDIVISIONS); - sky_maxs_subd[0] = ri.ftol(sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS); - sky_maxs_subd[1] = ri.ftol(sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS); - - if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS; - if ( sky_mins_subd[1] < MIN_T ) - sky_mins_subd[1] = MIN_T; - else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS; - - if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS; - else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS; - if ( sky_maxs_subd[1] < MIN_T ) - sky_maxs_subd[1] = MIN_T; - else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) - sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS; - - // - // iterate through the subdivisions - // - for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ ) - { - for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ ) - { - MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - i, - NULL, - s_skyPoints[t][s] ); - - s_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0]; - s_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1]; - } - } - - // only add indexes for first stage - FillCloudySkySide( sky_mins_subd, sky_maxs_subd, ( stage == 0 ) ); - } -} - -/* -** R_BuildCloudData -*/ -void R_BuildCloudData( shaderCommands_t *input ) -{ - int i; - shader_t *shader; - - shader = input->shader; - - assert( shader->isSky ); - - sky_min = 1.0 / 256.0f; // FIXME: not correct? - sky_max = 255.0 / 256.0f; - - // set up for drawing - tess.numIndexes = 0; - tess.numVertexes = 0; - tess.firstIndex = 0; - - if ( shader->sky.cloudHeight ) - { - for ( i = 0; i < MAX_SHADER_STAGES; i++ ) - { - if ( !tess.xstages[i] ) { - break; - } - FillCloudBox( shader, i ); - } - } -} - -/* -** R_InitSkyTexCoords -** Called when a sky shader is parsed -*/ -#define SQR( a ) ((a)*(a)) -void R_InitSkyTexCoords( float heightCloud ) -{ - int i, s, t; - float radiusWorld = 4096; - float p; - float sRad, tRad; - vec3_t skyVec; - vec3_t v; - - // init zfar so MakeSkyVec works even though - // a world hasn't been bounded - backEnd.viewParms.zFar = 1024; - - for ( i = 0; i < 6; i++ ) - { - for ( t = 0; t <= SKY_SUBDIVISIONS; t++ ) - { - for ( s = 0; s <= SKY_SUBDIVISIONS; s++ ) - { - // compute vector from view origin to sky side integral point - MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, - i, - NULL, - skyVec ); - - // compute parametric value 'p' that intersects with cloud layer - p = ( 1.0f / ( 2 * DotProduct( skyVec, skyVec ) ) ) * - ( -2 * skyVec[2] * radiusWorld + - 2 * sqrt( SQR( skyVec[2] ) * SQR( radiusWorld ) + - 2 * SQR( skyVec[0] ) * radiusWorld * heightCloud + - SQR( skyVec[0] ) * SQR( heightCloud ) + - 2 * SQR( skyVec[1] ) * radiusWorld * heightCloud + - SQR( skyVec[1] ) * SQR( heightCloud ) + - 2 * SQR( skyVec[2] ) * radiusWorld * heightCloud + - SQR( skyVec[2] ) * SQR( heightCloud ) ) ); - - s_cloudTexP[i][t][s] = p; - - // compute intersection point based on p - VectorScale( skyVec, p, v ); - v[2] += radiusWorld; - - // compute vector from world origin to intersection point 'v' - VectorNormalize( v ); - - sRad = Q_acos( v[0] ); - tRad = Q_acos( v[1] ); - - s_cloudTexCoords[i][t][s][0] = sRad; - s_cloudTexCoords[i][t][s][1] = tRad; - } - } - } -} - -//====================================================================================== - -/* -** RB_DrawSun -*/ -void RB_DrawSun( float scale, shader_t *shader ) { - float size; - float dist; - vec3_t origin, vec1, vec2; - - if ( !backEnd.skyRenderedThisView ) { - return; - } - - //qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); - //qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); - { - // FIXME: this could be a lot cleaner - mat4_t translation, modelview; - - Mat4Translation( backEnd.viewParms.or.origin, translation ); - Mat4Multiply( backEnd.viewParms.world.modelMatrix, translation, modelview ); - GL_SetModelviewMatrix( modelview ); - } - - dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) - size = dist * scale; - - VectorScale( tr.sunDirection, dist, origin ); - PerpendicularVector( vec1, tr.sunDirection ); - CrossProduct( tr.sunDirection, vec1, vec2 ); - - VectorScale( vec1, size, vec1 ); - VectorScale( vec2, size, vec2 ); - - // farthest depth range - qglDepthRange( 1.0, 1.0 ); - - RB_BeginSurface( shader, 0, 0 ); - - RB_AddQuadStamp(origin, vec1, vec2, colorWhite); - - RB_EndSurface(); - - // back to normal depth range - qglDepthRange( 0.0, 1.0 ); -} - - - - -/* -================ -RB_StageIteratorSky - -All of the visible sky triangles are in tess - -Other things could be stuck in here, like birds in the sky, etc -================ -*/ -void RB_StageIteratorSky( void ) { - if ( r_fastsky->integer ) { - return; - } - - // go through all the polygons and project them onto - // the sky box to see which blocks on each side need - // to be drawn - RB_ClipSkyPolygons( &tess ); - - // r_showsky will let all the sky blocks be drawn in - // front of everything to allow developers to see how - // much sky is getting sucked in - if ( r_showsky->integer ) { - qglDepthRange( 0.0, 0.0 ); - } else { - qglDepthRange( 1.0, 1.0 ); - } - - // draw the outer skybox - if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) { - mat4_t oldmodelview; - - GL_State( 0 ); - //qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); - - { - // FIXME: this could be a lot cleaner - mat4_t trans, product; - - Mat4Copy( glState.modelview, oldmodelview ); - Mat4Translation( backEnd.viewParms.or.origin, trans ); - Mat4Multiply( glState.modelview, trans, product ); - GL_SetModelviewMatrix( product ); - - } - - DrawSkyBox( tess.shader ); - - GL_SetModelviewMatrix( oldmodelview ); - } - - // generate the vertexes for all the clouds, which will be drawn - // by the generic shader routine - R_BuildCloudData( &tess ); - - RB_StageIteratorGeneric(); - - // draw the inner skybox - - - // back to normal depth range - qglDepthRange( 0.0, 1.0 ); - - // note that sky was drawn so we will draw a sun later - backEnd.skyRenderedThisView = qtrue; -} - - - - - diff --git a/code/renderergl2/tr_subs.c b/code/renderergl2/tr_subs.c deleted file mode 100644 index 6f4901287c..0000000000 --- a/code/renderergl2/tr_subs.c +++ /dev/null @@ -1,48 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2010 James Canete (use.less01@gmail.com) - -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_subs.c - common function replacements for modular renderer - -#include "tr_local.h" - -void QDECL Com_Printf( const char *msg, ... ) -{ - va_list argptr; - char text[1024]; - - va_start(argptr, msg); - Q_vsnprintf(text, sizeof(text), msg, argptr); - va_end(argptr); - - ri.Printf(PRINT_ALL, "%s", text); -} - -void QDECL Com_Error( int level, const char *error, ... ) -{ - va_list argptr; - char text[1024]; - - va_start(argptr, error); - Q_vsnprintf(text, sizeof(text), error, argptr); - va_end(argptr); - - ri.Error(level, "%s", text); -} diff --git a/code/renderergl2/tr_surface.c b/code/renderergl2/tr_surface.c deleted file mode 100644 index 825582bd21..0000000000 --- a/code/renderergl2/tr_surface.c +++ /dev/null @@ -1,1650 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; 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" -#if idppc_altivec && !defined(MACOS_X) -#include -#endif - -/* - - 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, tess.fogNum, tess.cubemapIndex ); -} - -void RB_CheckVBOandIBO(VBO_t *vbo, IBO_t *ibo) -{ - if (!(vbo == glState.currentVBO && ibo == glState.currentIBO) || tess.multiDrawPrimitives >= MAX_MULTIDRAW_PRIMITIVES) - { - RB_EndSurface(); - RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex); - - R_BindVBO(vbo); - R_BindIBO(ibo); - } - - if (vbo != tess.vbo && ibo != tess.ibo) - tess.useInternalVBO = qfalse; -} - - -/* -============== -RB_AddQuadStampExt -============== -*/ -void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, float color[4], 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.or.axis[0], normal ); - - tess.normal[ndx] = - tess.normal[ndx+1] = - tess.normal[ndx+2] = - tess.normal[ndx+3] = R_VboPackNormal(normal); - - // standard square texture coordinates - VectorSet2(tess.texCoords[ndx ][0], s1, t1); - VectorSet2(tess.texCoords[ndx ][1], s1, t1); - - VectorSet2(tess.texCoords[ndx+1][0], s2, t1); - VectorSet2(tess.texCoords[ndx+1][1], s2, t1); - - VectorSet2(tess.texCoords[ndx+2][0], s2, t2); - VectorSet2(tess.texCoords[ndx+2][1], s2, t2); - - VectorSet2(tess.texCoords[ndx+3][0], s1, t2); - VectorSet2(tess.texCoords[ndx+3][1], s1, t2); - - // constant color all the way around - // should this be identity and let the shader specify from entity? - VectorCopy4(color, tess.vertexColors[ndx]); - VectorCopy4(color, tess.vertexColors[ndx+1]); - VectorCopy4(color, tess.vertexColors[ndx+2]); - VectorCopy4(color, tess.vertexColors[ndx+3]); - - tess.numVertexes += 4; - tess.numIndexes += 6; -} - -/* -============== -RB_AddQuadStamp -============== -*/ -void RB_AddQuadStamp( vec3_t origin, vec3_t left, vec3_t up, float color[4] ) { - RB_AddQuadStampExt( origin, left, up, color, 0, 0, 1, 1 ); -} - - -/* -============== -RB_InstantQuad - -based on Tess_InstantQuad from xreal -============== -*/ -void RB_InstantQuad2(vec4_t quadVerts[4], vec2_t texCoords[4]) -{ - GLimp_LogComment("--- RB_InstantQuad2 ---\n"); - - tess.numVertexes = 0; - tess.numIndexes = 0; - tess.firstIndex = 0; - - VectorCopy4(quadVerts[0], tess.xyz[tess.numVertexes]); - VectorCopy2(texCoords[0], tess.texCoords[tess.numVertexes][0]); - tess.numVertexes++; - - VectorCopy4(quadVerts[1], tess.xyz[tess.numVertexes]); - VectorCopy2(texCoords[1], tess.texCoords[tess.numVertexes][0]); - tess.numVertexes++; - - VectorCopy4(quadVerts[2], tess.xyz[tess.numVertexes]); - VectorCopy2(texCoords[2], tess.texCoords[tess.numVertexes][0]); - tess.numVertexes++; - - VectorCopy4(quadVerts[3], tess.xyz[tess.numVertexes]); - VectorCopy2(texCoords[3], tess.texCoords[tess.numVertexes][0]); - tess.numVertexes++; - - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 1; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 3; - tess.minIndex = 0; - tess.maxIndex = 3; - - RB_UpdateVBOs(ATTR_POSITION | ATTR_TEXCOORD); - - GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD); - - R_DrawElementsVBO(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); - - tess.numIndexes = 0; - tess.numVertexes = 0; - tess.firstIndex = 0; - tess.minIndex = 0; - tess.maxIndex = 0; -} - - -void RB_InstantQuad(vec4_t quadVerts[4]) -{ - vec2_t texCoords[4]; - - VectorSet2(texCoords[0], 0.0f, 0.0f); - VectorSet2(texCoords[1], 1.0f, 0.0f); - VectorSet2(texCoords[2], 1.0f, 1.0f); - VectorSet2(texCoords[3], 0.0f, 1.0f); - - GLSL_BindProgram(&tr.textureColorShader); - - GLSL_SetUniformMat4(&tr.textureColorShader, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - GLSL_SetUniformVec4(&tr.textureColorShader, UNIFORM_COLOR, colorWhite); - - RB_InstantQuad2(quadVerts, texCoords); -} - - -/* -============== -RB_SurfaceSprite -============== -*/ -static void RB_SurfaceSprite( void ) { - vec3_t left, up; - float radius; - float colors[4]; - trRefEntity_t *ent = backEnd.currentEntity; - - // calculate the xyz locations for the four corners - radius = ent->e.radius; - if ( ent->e.rotation == 0 ) { - VectorScale( backEnd.viewParms.or.axis[1], radius, left ); - VectorScale( backEnd.viewParms.or.axis[2], radius, up ); - } else { - float s, c; - float ang; - - ang = M_PI * ent->e.rotation / 180; - s = sin( ang ); - c = cos( ang ); - - VectorScale( backEnd.viewParms.or.axis[1], c * radius, left ); - VectorMA( left, -s * radius, backEnd.viewParms.or.axis[2], left ); - - VectorScale( backEnd.viewParms.or.axis[2], c * radius, up ); - VectorMA( up, s * radius, backEnd.viewParms.or.axis[1], up ); - } - if ( backEnd.viewParms.isMirror ) { - VectorSubtract( vec3_origin, left, left ); - } - - VectorScale4(ent->e.shaderRGBA, 1.0f / 255.0f, colors); - - RB_AddQuadStamp( ent->e.origin, left, up, colors ); -} - - -/* -============= -RB_SurfacePolychain -============= -*/ -static 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]; - tess.vertexColors[numv][0] = p->verts[ i ].modulate[0] / 255.0f; - tess.vertexColors[numv][1] = p->verts[ i ].modulate[1] / 255.0f; - tess.vertexColors[numv][2] = p->verts[ i ].modulate[2] / 255.0f; - tess.vertexColors[numv][3] = p->verts[ i ].modulate[3] / 255.0f; - - 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.numVertexes = numv; -} - -static void RB_SurfaceVertsAndIndexes( int numVerts, srfVert_t *verts, int numIndexes, glIndex_t *indexes, int dlightBits, int pshadowBits) -{ - int i; - glIndex_t *inIndex; - srfVert_t *dv; - float *xyz, *texCoords, *lightCoords; - uint32_t *lightdir; - uint32_t *normal; -#ifdef USE_VERT_TANGENT_SPACE - uint32_t *tangent; -#endif - glIndex_t *outIndex; - float *color; - - RB_CheckVBOandIBO(tess.vbo, tess.ibo); - - RB_CHECKOVERFLOW( numVerts, numIndexes ); - - inIndex = indexes; - outIndex = &tess.indexes[ tess.numIndexes ]; - for ( i = 0 ; i < numIndexes ; i++ ) { - *outIndex++ = tess.numVertexes + *inIndex++; - } - tess.numIndexes += numIndexes; - - if ( tess.shader->vertexAttribs & ATTR_POSITION ) - { - dv = verts; - xyz = tess.xyz[ tess.numVertexes ]; - for ( i = 0 ; i < numVerts ; i++, dv++, xyz+=4 ) - VectorCopy(dv->xyz, xyz); - } - - if ( tess.shader->vertexAttribs & ATTR_NORMAL ) - { - dv = verts; - normal = &tess.normal[ tess.numVertexes ]; - for ( i = 0 ; i < numVerts ; i++, dv++, normal++ ) - *normal = R_VboPackNormal(dv->normal); - } - -#ifdef USE_VERT_TANGENT_SPACE - if ( tess.shader->vertexAttribs & ATTR_TANGENT ) - { - dv = verts; - tangent = &tess.tangent[ tess.numVertexes ]; - for ( i = 0 ; i < numVerts ; i++, dv++, tangent++ ) - *tangent = R_VboPackTangent(dv->tangent); - } -#endif - - if ( tess.shader->vertexAttribs & ATTR_TEXCOORD ) - { - dv = verts; - texCoords = tess.texCoords[ tess.numVertexes ][0]; - for ( i = 0 ; i < numVerts ; i++, dv++, texCoords+=4 ) - VectorCopy2(dv->st, texCoords); - } - - if ( tess.shader->vertexAttribs & ATTR_LIGHTCOORD ) - { - dv = verts; - lightCoords = tess.texCoords[ tess.numVertexes ][1]; - for ( i = 0 ; i < numVerts ; i++, dv++, lightCoords+=4 ) - VectorCopy2(dv->lightmap, lightCoords); - } - - if ( tess.shader->vertexAttribs & ATTR_COLOR ) - { - dv = verts; - color = tess.vertexColors[ tess.numVertexes ]; - for ( i = 0 ; i < numVerts ; i++, dv++, color+=4 ) - VectorCopy4(dv->vertexColors, color); - } - - if ( tess.shader->vertexAttribs & ATTR_LIGHTDIRECTION ) - { - dv = verts; - lightdir = &tess.lightdir[ tess.numVertexes ]; - for ( i = 0 ; i < numVerts ; i++, dv++, lightdir++ ) - *lightdir = R_VboPackNormal(dv->lightdir); - } - -#if 0 // nothing even uses vertex dlightbits - for ( i = 0 ; i < numVerts ; i++ ) { - tess.vertexDlightBits[ tess.numVertexes + i ] = dlightBits; - } -#endif - - tess.dlightBits |= dlightBits; - tess.pshadowBits |= pshadowBits; - - tess.numVertexes += numVerts; -} - -static qboolean RB_SurfaceVbo(VBO_t *vbo, IBO_t *ibo, int numVerts, int numIndexes, int firstIndex, int minIndex, int maxIndex, int dlightBits, int pshadowBits, qboolean shaderCheck) -{ - int i, mergeForward, mergeBack; - GLvoid *firstIndexOffset, *lastIndexOffset; - - if (!vbo || !ibo) - { - return qfalse; - } - - if (shaderCheck && !(!ShaderRequiresCPUDeforms(tess.shader) && !tess.shader->isSky && !tess.shader->isPortal)) - { - return qfalse; - } - - RB_CheckVBOandIBO(vbo, ibo); - - tess.dlightBits |= dlightBits; - tess.pshadowBits |= pshadowBits; - - // merge this into any existing multidraw primitives - mergeForward = -1; - mergeBack = -1; - firstIndexOffset = BUFFER_OFFSET(firstIndex * sizeof(glIndex_t)); - lastIndexOffset = BUFFER_OFFSET((firstIndex + numIndexes) * sizeof(glIndex_t)); - - if (r_mergeMultidraws->integer) - { - i = 0; - - if (r_mergeMultidraws->integer == 1) - { - // lazy merge, only check the last primitive - if (tess.multiDrawPrimitives) - { - i = tess.multiDrawPrimitives - 1; - } - } - - for (; i < tess.multiDrawPrimitives; i++) - { - if (tess.multiDrawLastIndex[i] == firstIndexOffset) - { - mergeBack = i; - } - - if (lastIndexOffset == tess.multiDrawFirstIndex[i]) - { - mergeForward = i; - } - } - } - - if (mergeBack != -1 && mergeForward == -1) - { - tess.multiDrawNumIndexes[mergeBack] += numIndexes; - tess.multiDrawLastIndex[mergeBack] = tess.multiDrawFirstIndex[mergeBack] + tess.multiDrawNumIndexes[mergeBack]; - tess.multiDrawMinIndex[mergeBack] = MIN(tess.multiDrawMinIndex[mergeBack], minIndex); - tess.multiDrawMaxIndex[mergeBack] = MAX(tess.multiDrawMaxIndex[mergeBack], maxIndex); - backEnd.pc.c_multidrawsMerged++; - } - else if (mergeBack == -1 && mergeForward != -1) - { - tess.multiDrawNumIndexes[mergeForward] += numIndexes; - tess.multiDrawFirstIndex[mergeForward] = firstIndexOffset; - tess.multiDrawLastIndex[mergeForward] = tess.multiDrawFirstIndex[mergeForward] + tess.multiDrawNumIndexes[mergeForward]; - tess.multiDrawMinIndex[mergeForward] = MIN(tess.multiDrawMinIndex[mergeForward], minIndex); - tess.multiDrawMaxIndex[mergeForward] = MAX(tess.multiDrawMaxIndex[mergeForward], maxIndex); - backEnd.pc.c_multidrawsMerged++; - } - else if (mergeBack != -1 && mergeForward != -1) - { - tess.multiDrawNumIndexes[mergeBack] += numIndexes + tess.multiDrawNumIndexes[mergeForward]; - tess.multiDrawLastIndex[mergeBack] = tess.multiDrawFirstIndex[mergeBack] + tess.multiDrawNumIndexes[mergeBack]; - tess.multiDrawMinIndex[mergeBack] = MIN(tess.multiDrawMinIndex[mergeBack], MIN(tess.multiDrawMinIndex[mergeForward], minIndex)); - tess.multiDrawMaxIndex[mergeBack] = MAX(tess.multiDrawMaxIndex[mergeBack], MAX(tess.multiDrawMaxIndex[mergeForward], maxIndex)); - tess.multiDrawPrimitives--; - - if (mergeForward != tess.multiDrawPrimitives) - { - tess.multiDrawNumIndexes[mergeForward] = tess.multiDrawNumIndexes[tess.multiDrawPrimitives]; - tess.multiDrawFirstIndex[mergeForward] = tess.multiDrawFirstIndex[tess.multiDrawPrimitives]; - } - backEnd.pc.c_multidrawsMerged += 2; - } - else if (mergeBack == -1 && mergeForward == -1) - { - tess.multiDrawNumIndexes[tess.multiDrawPrimitives] = numIndexes; - tess.multiDrawFirstIndex[tess.multiDrawPrimitives] = firstIndexOffset; - tess.multiDrawLastIndex[tess.multiDrawPrimitives] = lastIndexOffset; - tess.multiDrawMinIndex[tess.multiDrawPrimitives] = minIndex; - tess.multiDrawMaxIndex[tess.multiDrawPrimitives] = maxIndex; - tess.multiDrawPrimitives++; - } - - backEnd.pc.c_multidraws++; - - tess.numIndexes += numIndexes; - tess.numVertexes += numVerts; - - return qtrue; -} - -/* -============= -RB_SurfaceTriangles -============= -*/ -static void RB_SurfaceTriangles( srfBspSurface_t *srf ) { - if( RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, - srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qtrue ) ) - { - return; - } - - RB_SurfaceVertsAndIndexes(srf->numVerts, srf->verts, srf->numIndexes, - srf->indexes, srf->dlightBits, srf->pshadowBits); -} - - - -/* -============== -RB_SurfaceBeam -============== -*/ -static void RB_SurfaceBeam( void ) -{ -#define NUM_BEAM_SEGS 6 - refEntity_t *e; - shaderProgram_t *sp = &tr.textureColorShader; - 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 ); - - // FIXME: Quake3 doesn't use this, so I never tested it - tess.numVertexes = 0; - tess.numIndexes = 0; - tess.firstIndex = 0; - tess.minIndex = 0; - tess.maxIndex = 0; - - for ( i = 0; i <= NUM_BEAM_SEGS; i++ ) { - VectorCopy(start_points[ i % NUM_BEAM_SEGS ], tess.xyz[tess.numVertexes++]); - VectorCopy(end_points [ i % NUM_BEAM_SEGS ], tess.xyz[tess.numVertexes++]); - } - - for ( i = 0; i < NUM_BEAM_SEGS; i++ ) { - tess.indexes[tess.numIndexes++] = i * 2; - tess.indexes[tess.numIndexes++] = (i + 1) * 2; - tess.indexes[tess.numIndexes++] = 1 + i * 2; - - tess.indexes[tess.numIndexes++] = 1 + i * 2; - tess.indexes[tess.numIndexes++] = (i + 1) * 2; - tess.indexes[tess.numIndexes++] = 1 + (i + 1) * 2; - } - - tess.minIndex = 0; - tess.maxIndex = tess.numVertexes; - - // FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function - RB_UpdateVBOs(ATTR_POSITION); - - GLSL_VertexAttribsState(ATTR_POSITION); - GLSL_BindProgram(sp); - - GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - - GLSL_SetUniformVec4(sp, UNIFORM_COLOR, colorRed); - - R_DrawElementsVBO(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); - - tess.numIndexes = 0; - tess.numVertexes = 0; - tess.firstIndex = 0; - tess.minIndex = 0; - tess.maxIndex = 0; -} - -//================================================================================ - -static void DoRailCore( const vec3_t start, const vec3_t end, const vec3_t up, float len, float spanWidth ) -{ - float spanWidth2; - int vbase; - float t = len / 256.0f; - - RB_CHECKOVERFLOW( 4, 6 ); - - vbase = tess.numVertexes; - - spanWidth2 = -spanWidth; - - // FIXME: use quad stamp? - VectorMA( start, spanWidth, up, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 0.25 / 255.0f; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 0.25 / 255.0f; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 0.25 / 255.0f; - tess.numVertexes++; - - VectorMA( start, spanWidth2, up, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] / 255.0f; - tess.numVertexes++; - - VectorMA( end, spanWidth, up, tess.xyz[tess.numVertexes] ); - - tess.texCoords[tess.numVertexes][0][0] = t; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] / 255.0f; - tess.numVertexes++; - - VectorMA( end, spanWidth2, up, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = t; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] / 255.0f; - tess.numVertexes++; - - tess.indexes[tess.numIndexes++] = vbase; - tess.indexes[tess.numIndexes++] = vbase + 1; - tess.indexes[tess.numIndexes++] = vbase + 2; - - tess.indexes[tess.numIndexes++] = vbase + 2; - tess.indexes[tess.numIndexes++] = vbase + 1; - tess.indexes[tess.numIndexes++] = vbase + 3; -} - -static void DoRailDiscs( int numSegs, const vec3_t start, const vec3_t dir, const vec3_t right, const vec3_t up ) -{ - int i; - vec3_t pos[4]; - vec3_t v; - int spanWidth = r_railWidth->integer; - float c, s; - float scale; - - if ( numSegs > 1 ) - numSegs--; - if ( !numSegs ) - return; - - scale = 0.25; - - for ( i = 0; i < 4; i++ ) - { - c = cos( DEG2RAD( 45 + i * 90 ) ); - s = sin( DEG2RAD( 45 + i * 90 ) ); - v[0] = ( right[0] * c + up[0] * s ) * scale * spanWidth; - v[1] = ( right[1] * c + up[1] * s ) * scale * spanWidth; - v[2] = ( right[2] * c + up[2] * s ) * scale * spanWidth; - VectorAdd( start, v, pos[i] ); - - if ( numSegs > 1 ) - { - // offset by 1 segment if we're doing a long distance shot - VectorAdd( pos[i], dir, pos[i] ); - } - } - - for ( i = 0; i < numSegs; i++ ) - { - int j; - - RB_CHECKOVERFLOW( 4, 6 ); - - for ( j = 0; j < 4; j++ ) - { - VectorCopy( pos[j], tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = ( j < 2 ); - tess.texCoords[tess.numVertexes][0][1] = ( j && j != 3 ); - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] / 255.0f; - tess.numVertexes++; - - VectorAdd( pos[j], dir, pos[j] ); - } - - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 0; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 3; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 1; - tess.indexes[tess.numIndexes++] = tess.numVertexes - 4 + 2; - } -} - -/* -** RB_SurfaceRailRinges -*/ -static void RB_SurfaceRailRings( void ) { - refEntity_t *e; - int numSegs; - int len; - vec3_t vec; - vec3_t right, up; - vec3_t start, end; - - e = &backEnd.currentEntity->e; - - VectorCopy( e->oldorigin, start ); - VectorCopy( e->origin, end ); - - // compute variables - VectorSubtract( end, start, vec ); - len = VectorNormalize( vec ); - MakeNormalVectors( vec, right, up ); - numSegs = ( len ) / r_railSegmentLength->value; - if ( numSegs <= 0 ) { - numSegs = 1; - } - - VectorScale( vec, r_railSegmentLength->value, vec ); - - DoRailDiscs( numSegs, start, vec, right, up ); -} - -/* -** RB_SurfaceRailCore -*/ -static void RB_SurfaceRailCore( void ) { - refEntity_t *e; - int len; - vec3_t right; - vec3_t vec; - vec3_t start, end; - vec3_t v1, v2; - - e = &backEnd.currentEntity->e; - - VectorCopy( e->oldorigin, start ); - VectorCopy( e->origin, end ); - - VectorSubtract( end, start, vec ); - len = VectorNormalize( vec ); - - // compute side vector - VectorSubtract( start, backEnd.viewParms.or.origin, v1 ); - VectorNormalize( v1 ); - VectorSubtract( end, backEnd.viewParms.or.origin, v2 ); - VectorNormalize( v2 ); - CrossProduct( v1, v2, right ); - VectorNormalize( right ); - - DoRailCore( start, end, right, len, r_railCoreWidth->integer ); -} - -/* -** RB_SurfaceLightningBolt -*/ -static void RB_SurfaceLightningBolt( void ) { - refEntity_t *e; - int len; - vec3_t right; - vec3_t vec; - vec3_t start, end; - vec3_t v1, v2; - int i; - - e = &backEnd.currentEntity->e; - - VectorCopy( e->oldorigin, end ); - VectorCopy( e->origin, start ); - - // compute variables - VectorSubtract( end, start, vec ); - len = VectorNormalize( vec ); - - // compute side vector - VectorSubtract( start, backEnd.viewParms.or.origin, v1 ); - VectorNormalize( v1 ); - VectorSubtract( end, backEnd.viewParms.or.origin, v2 ); - VectorNormalize( v2 ); - CrossProduct( v1, v2, right ); - VectorNormalize( right ); - - for ( i = 0 ; i < 4 ; i++ ) { - vec3_t temp; - - DoRailCore( start, end, right, len, 8 ); - RotatePointAroundVector( temp, vec, right, 45 ); - VectorCopy( temp, right ); - } -} - -#if 0 -/* -** VectorArrayNormalize -* -* The inputs to this routing seem to always be close to length = 1.0 (about 0.6 to 2.0) -* This means that we don't have to worry about zero length or enormously long vectors. -*/ -static void VectorArrayNormalize(vec4_t *normals, unsigned int count) -{ -// assert(count); - -#if idppc - { - register float half = 0.5; - register float one = 1.0; - float *components = (float *)normals; - - // Vanilla PPC code, but since PPC has a reciprocal square root estimate instruction, - // runs *much* faster than calling sqrt(). We'll use a single Newton-Raphson - // refinement step to get a little more precision. This seems to yeild results - // that are correct to 3 decimal places and usually correct to at least 4 (sometimes 5). - // (That is, for the given input range of about 0.6 to 2.0). - do { - float x, y, z; - float B, y0, y1; - - x = components[0]; - y = components[1]; - z = components[2]; - components += 4; - B = x*x + y*y + z*z; - -#ifdef __GNUC__ - asm("frsqrte %0,%1" : "=f" (y0) : "f" (B)); -#else - y0 = __frsqrte(B); -#endif - y1 = y0 + half*y0*(one - B*y0*y0); - - x = x * y1; - y = y * y1; - components[-4] = x; - z = z * y1; - components[-3] = y; - components[-2] = z; - } while(count--); - } -#else // No assembly version for this architecture, or C_ONLY defined - // given the input, it's safe to call VectorNormalizeFast - while (count--) { - VectorNormalizeFast(normals[0]); - normals++; - } -#endif - -} -#endif - - - -/* -** LerpMeshVertexes -*/ -#if 0 -#if idppc_altivec -static void LerpMeshVertexes_altivec(md3Surface_t *surf, float backlerp) -{ - short *oldXyz, *newXyz, *oldNormals, *newNormals; - float *outXyz, *outNormal; - float oldXyzScale QALIGN(16); - float newXyzScale QALIGN(16); - float oldNormalScale QALIGN(16); - float newNormalScale QALIGN(16); - int vertNum; - unsigned lat, lng; - int numVerts; - - outXyz = tess.xyz[tess.numVertexes]; - outNormal = tess.normal[tess.numVertexes]; - - newXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.frame * surf->numVerts * 4); - newNormals = newXyz + 3; - - newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp); - newNormalScale = 1.0 - backlerp; - - numVerts = surf->numVerts; - - if ( backlerp == 0 ) { - vector signed short newNormalsVec0; - vector signed short newNormalsVec1; - vector signed int newNormalsIntVec; - vector float newNormalsFloatVec; - vector float newXyzScaleVec; - vector unsigned char newNormalsLoadPermute; - vector unsigned char newNormalsStorePermute; - vector float zero; - - newNormalsStorePermute = vec_lvsl(0,(float *)&newXyzScaleVec); - newXyzScaleVec = *(vector float *)&newXyzScale; - newXyzScaleVec = vec_perm(newXyzScaleVec,newXyzScaleVec,newNormalsStorePermute); - newXyzScaleVec = vec_splat(newXyzScaleVec,0); - newNormalsLoadPermute = vec_lvsl(0,newXyz); - newNormalsStorePermute = vec_lvsr(0,outXyz); - zero = (vector float)vec_splat_s8(0); - // - // just copy the vertexes - // - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - newXyz += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - newNormalsLoadPermute = vec_lvsl(0,newXyz); - newNormalsStorePermute = vec_lvsr(0,outXyz); - newNormalsVec0 = vec_ld(0,newXyz); - newNormalsVec1 = vec_ld(16,newXyz); - newNormalsVec0 = vec_perm(newNormalsVec0,newNormalsVec1,newNormalsLoadPermute); - newNormalsIntVec = vec_unpackh(newNormalsVec0); - newNormalsFloatVec = vec_ctf(newNormalsIntVec,0); - newNormalsFloatVec = vec_madd(newNormalsFloatVec,newXyzScaleVec,zero); - newNormalsFloatVec = vec_perm(newNormalsFloatVec,newNormalsFloatVec,newNormalsStorePermute); - //outXyz[0] = newXyz[0] * newXyzScale; - //outXyz[1] = newXyz[1] * newXyzScale; - //outXyz[2] = newXyz[2] * newXyzScale; - - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - vec_ste(newNormalsFloatVec,0,outXyz); - vec_ste(newNormalsFloatVec,4,outXyz); - vec_ste(newNormalsFloatVec,8,outXyz); - } - } else { - // - // interpolate and copy the vertex and normal - // - oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.oldframe * surf->numVerts * 4); - oldNormals = oldXyz + 3; - - oldXyzScale = MD3_XYZ_SCALE * backlerp; - oldNormalScale = backlerp; - - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - vec3_t uncompressedOldNormal, uncompressedNewNormal; - - // interpolate the xyz - outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale; - outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale; - outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale; - - // FIXME: interpolate lat/long instead? - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - lat = ( oldNormals[0] >> 8 ) & 0xff; - lng = ( oldNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - - uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale; - outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale; - outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale; - -// VectorNormalize (outNormal); - } - VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts); - } -} -#endif -#endif - -static void LerpMeshVertexes_scalar(mdvSurface_t *surf, float backlerp) -{ -#if 0 - short *oldXyz, *newXyz, *oldNormals, *newNormals; - float *outXyz, *outNormal; - float oldXyzScale, newXyzScale; - float oldNormalScale, newNormalScale; - int vertNum; - unsigned lat, lng; - int numVerts; - - outXyz = tess.xyz[tess.numVertexes]; - outNormal = tess.normal[tess.numVertexes]; - - newXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.frame * surf->numVerts * 4); - newNormals = newXyz + 3; - - newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp); - newNormalScale = 1.0 - backlerp; - - numVerts = surf->numVerts; - - if ( backlerp == 0 ) { - // - // just copy the vertexes - // - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - newXyz += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - - outXyz[0] = newXyz[0] * newXyzScale; - outXyz[1] = newXyz[1] * newXyzScale; - outXyz[2] = newXyz[2] * newXyzScale; - - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - } - } else { - // - // interpolate and copy the vertex and normal - // - oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.oldframe * surf->numVerts * 4); - oldNormals = oldXyz + 3; - - oldXyzScale = MD3_XYZ_SCALE * backlerp; - oldNormalScale = backlerp; - - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - vec3_t uncompressedOldNormal, uncompressedNewNormal; - - // interpolate the xyz - outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale; - outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale; - outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale; - - // FIXME: interpolate lat/long instead? - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - lat = ( oldNormals[0] >> 8 ) & 0xff; - lng = ( oldNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - - uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale; - outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale; - outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale; - -// VectorNormalize (outNormal); - } - VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts); - } -#endif - float *outXyz; - uint32_t *outNormal; - mdvVertex_t *newVerts; - int vertNum; - - newVerts = surf->verts + backEnd.currentEntity->e.frame * surf->numVerts; - - outXyz = tess.xyz[tess.numVertexes]; - outNormal = &tess.normal[tess.numVertexes]; - - if (backlerp == 0) - { - // - // just copy the vertexes - // - - for (vertNum=0 ; vertNum < surf->numVerts ; vertNum++) - { - vec3_t normal; - - VectorCopy(newVerts->xyz, outXyz); - VectorCopy(newVerts->normal, normal); - - *outNormal = R_VboPackNormal(normal); - - newVerts++; - outXyz += 4; - outNormal++; - } - } - else - { - // - // interpolate and copy the vertex and normal - // - - mdvVertex_t *oldVerts; - - oldVerts = surf->verts + backEnd.currentEntity->e.oldframe * surf->numVerts; - - for (vertNum=0 ; vertNum < surf->numVerts ; vertNum++) - { - vec3_t normal; - - VectorLerp(newVerts->xyz, oldVerts->xyz, backlerp, outXyz); - VectorLerp(newVerts->normal, oldVerts->normal, backlerp, normal); - VectorNormalize(normal); - - *outNormal = R_VboPackNormal(normal); - - newVerts++; - oldVerts++; - outXyz += 4; - outNormal++; - } - } - -} - -static void LerpMeshVertexes(mdvSurface_t *surf, float backlerp) -{ -#if 0 -#if idppc_altivec - if (com_altivec->integer) { - // must be in a seperate function or G3 systems will crash. - LerpMeshVertexes_altivec( surf, backlerp ); - return; - } -#endif // idppc_altivec -#endif - LerpMeshVertexes_scalar( surf, backlerp ); -} - - -/* -============= -RB_SurfaceMesh -============= -*/ -static void RB_SurfaceMesh(mdvSurface_t *surface) { - int j; - float backlerp; - mdvSt_t *texCoords; - int Bob, Doug; - int numVerts; - - if ( backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame ) { - backlerp = 0; - } else { - backlerp = backEnd.currentEntity->e.backlerp; - } - - RB_CHECKOVERFLOW( surface->numVerts, surface->numIndexes ); - - LerpMeshVertexes (surface, backlerp); - - Bob = tess.numIndexes; - Doug = tess.numVertexes; - for (j = 0 ; j < surface->numIndexes ; j++) { - tess.indexes[Bob + j] = Doug + surface->indexes[j]; - } - tess.numIndexes += surface->numIndexes; - - texCoords = surface->st; - - numVerts = surface->numVerts; - for ( j = 0; j < numVerts; j++ ) { - tess.texCoords[Doug + j][0][0] = texCoords[j].st[0]; - tess.texCoords[Doug + j][0][1] = texCoords[j].st[1]; - // FIXME: fill in lightmapST for completeness? - } - - tess.numVertexes += surface->numVerts; - -} - - -/* -============== -RB_SurfaceFace -============== -*/ -static void RB_SurfaceFace( srfBspSurface_t *srf ) { - if( RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, - srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qtrue ) ) - { - return; - } - - RB_SurfaceVertsAndIndexes(srf->numVerts, srf->verts, srf->numIndexes, - srf->indexes, srf->dlightBits, srf->pshadowBits); -} - - -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.or.axis[0][0] + local[1] * backEnd.or.axis[1][0] + - local[2] * backEnd.or.axis[2][0] + backEnd.or.origin[0]; - world[1] = local[0] * backEnd.or.axis[0][1] + local[1] * backEnd.or.axis[1][1] + - local[2] * backEnd.or.axis[2][1] + backEnd.or.origin[1]; - world[2] = local[0] * backEnd.or.axis[0][2] + local[1] * backEnd.or.axis[1][2] + - local[2] * backEnd.or.axis[2][2] + backEnd.or.origin[2]; - - VectorSubtract( world, backEnd.viewParms.or.origin, world ); - d = DotProduct( world, backEnd.viewParms.or.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 -============= -*/ -static void RB_SurfaceGrid( srfBspSurface_t *srf ) { - int i, j; - float *xyz; - float *texCoords, *lightCoords; - uint32_t *normal; -#ifdef USE_VERT_TANGENT_SPACE - uint32_t *tangent; -#endif - float *color; - uint32_t *lightdir; - srfVert_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 pshadowBits; - //int *vDlightBits; - - if( RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, - srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qtrue ) ) - { - return; - } - - dlightBits = srf->dlightBits; - tess.dlightBits |= dlightBits; - - pshadowBits = srf->pshadowBits; - tess.pshadowBits |= pshadowBits; - - // determine the allowable discrepance - lodError = LodErrorForVolume( srf->lodOrigin, srf->lodRadius ); - - // determine which rows and columns of the subdivision - // we are actually going to use - widthTable[0] = 0; - lodWidth = 1; - for ( i = 1 ; i < srf->width-1 ; i++ ) { - if ( srf->widthLodError[i] <= lodError ) { - widthTable[lodWidth] = i; - lodWidth++; - } - } - widthTable[lodWidth] = srf->width-1; - lodWidth++; - - heightTable[0] = 0; - lodHeight = 1; - for ( i = 1 ; i < srf->height-1 ; i++ ) { - if ( srf->heightLodError[i] <= lodError ) { - heightTable[lodHeight] = i; - lodHeight++; - } - } - heightTable[lodHeight] = srf->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; - 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, tess.fogNum, tess.cubemapIndex ); - } 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]; -#ifdef USE_VERT_TANGENT_SPACE - tangent = &tess.tangent[numVertexes]; -#endif - texCoords = tess.texCoords[numVertexes][0]; - lightCoords = tess.texCoords[numVertexes][1]; - color = tess.vertexColors[numVertexes]; - lightdir = &tess.lightdir[numVertexes]; - //vDlightBits = &tess.vertexDlightBits[numVertexes]; - - for ( i = 0 ; i < rows ; i++ ) { - for ( j = 0 ; j < lodWidth ; j++ ) { - dv = srf->verts + heightTable[ used + i ] * srf->width - + widthTable[ j ]; - - if ( tess.shader->vertexAttribs & ATTR_POSITION ) - { - VectorCopy(dv->xyz, xyz); - xyz += 4; - } - - if ( tess.shader->vertexAttribs & ATTR_NORMAL ) - { - *normal++ = R_VboPackNormal(dv->normal); - } - -#ifdef USE_VERT_TANGENT_SPACE - if ( tess.shader->vertexAttribs & ATTR_TANGENT ) - { - *tangent++ = R_VboPackTangent(dv->tangent); - } -#endif - if ( tess.shader->vertexAttribs & ATTR_TEXCOORD ) - { - VectorCopy2(dv->st, texCoords); - texCoords += 4; - } - - if ( tess.shader->vertexAttribs & ATTR_LIGHTCOORD ) - { - VectorCopy2(dv->lightmap, lightCoords); - lightCoords += 4; - } - - if ( tess.shader->vertexAttribs & ATTR_COLOR ) - { - VectorCopy4(dv->vertexColors, color); - color += 4; - } - - if ( tess.shader->vertexAttribs & ATTR_LIGHTDIRECTION ) - { - *lightdir++ = R_VboPackNormal(dv->lightdir); - } - - //*vDlightBits++ = dlightBits; - } - } - - - // 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 -=================== -*/ -static void RB_SurfaceAxis( void ) { - // FIXME: implement this -#if 0 - GL_Bind( tr.whiteImage ); - GL_State( GLS_DEFAULT ); - 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 ); -#endif -} - -//=========================================================================== - -/* -==================== -RB_SurfaceEntity - -Entities that have a single procedurally generated surface -==================== -*/ -static void RB_SurfaceEntity( surfaceType_t *surfType ) { - switch( backEnd.currentEntity->e.reType ) { - case RT_SPRITE: - RB_SurfaceSprite(); - break; - case RT_BEAM: - RB_SurfaceBeam(); - break; - case RT_RAIL_CORE: - RB_SurfaceRailCore(); - break; - case RT_RAIL_RINGS: - RB_SurfaceRailRings(); - break; - case RT_LIGHTNING: - RB_SurfaceLightningBolt(); - break; - default: - RB_SurfaceAxis(); - break; - } -} - -static void RB_SurfaceBad( surfaceType_t *surfType ) { - ri.Printf( PRINT_ALL, "Bad surface tesselated.\n" ); -} - -static void RB_SurfaceFlare(srfFlare_t *surf) -{ - if (r_flares->integer) - RB_AddFlare(surf, tess.fogNum, surf->origin, surf->color, surf->normal); -} - -static void RB_SurfaceVBOMesh(srfBspSurface_t * srf) -{ - RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, srf->firstIndex, - srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qfalse ); -} - -void RB_SurfaceVBOMDVMesh(srfVBOMDVMesh_t * surface) -{ - //mdvModel_t *mdvModel; - //mdvSurface_t *mdvSurface; - refEntity_t *refEnt; - - GLimp_LogComment("--- RB_SurfaceVBOMDVMesh ---\n"); - - if(!surface->vbo || !surface->ibo) - return; - - //RB_CheckVBOandIBO(surface->vbo, surface->ibo); - RB_EndSurface(); - RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex); - - R_BindVBO(surface->vbo); - R_BindIBO(surface->ibo); - - tess.useInternalVBO = qfalse; - - tess.numIndexes += surface->numIndexes; - tess.numVertexes += surface->numVerts; - tess.minIndex = surface->minIndex; - tess.maxIndex = surface->maxIndex; - - //mdvModel = surface->mdvModel; - //mdvSurface = surface->mdvSurface; - - refEnt = &backEnd.currentEntity->e; - - if(refEnt->oldframe == refEnt->frame) - { - glState.vertexAttribsInterpolation = 0; - } - else - { - glState.vertexAttribsInterpolation = refEnt->backlerp; - } - - glState.vertexAttribsOldFrame = refEnt->oldframe; - glState.vertexAttribsNewFrame = refEnt->frame; - glState.vertexAnimation = qtrue; - - RB_EndSurface(); - - // So we don't lerp surfaces that shouldn't be lerped - glState.vertexAnimation = qfalse; -} - -static void RB_SurfaceDisplayList( srfDisplayList_t *surf ) { - // all apropriate state must be set in RB_BeginSurface - // this isn't implemented yet... - qglCallList( surf->listNum ); -} - -static void RB_SurfaceSkip( void *surf ) { -} - - -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_SurfaceTriangles, // SF_TRIANGLES, - (void(*)(void*))RB_SurfacePolychain, // SF_POLY, - (void(*)(void*))RB_SurfaceMesh, // SF_MDV, - (void(*)(void*))RB_MDRSurfaceAnim, // SF_MDR, - (void(*)(void*))RB_IQMSurfaceAnim, // SF_IQM, - (void(*)(void*))RB_SurfaceFlare, // SF_FLARE, - (void(*)(void*))RB_SurfaceEntity, // SF_ENTITY - (void(*)(void*))RB_SurfaceDisplayList, // SF_DISPLAY_LIST - (void(*)(void*))RB_SurfaceVBOMesh, // SF_VBO_MESH, - (void(*)(void*))RB_SurfaceVBOMDVMesh, // SF_VBO_MDVMESH -}; diff --git a/code/renderergl2/tr_vbo.c b/code/renderergl2/tr_vbo.c deleted file mode 100644 index dc0f33beb3..0000000000 --- a/code/renderergl2/tr_vbo.c +++ /dev/null @@ -1,971 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2007-2009 Robert Beckebans - -This file is part of XreaL source code. - -XreaL 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. - -XreaL 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 XreaL source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_vbo.c -#include "tr_local.h" - - -uint32_t R_VboPackTangent(vec4_t v) -{ - if (glRefConfig.packedNormalDataType == GL_UNSIGNED_INT_2_10_10_10_REV) - { - return (((uint32_t)(v[3] * 1.5f + 2.0f )) << 30) - | (((uint32_t)(v[2] * 511.5f + 512.0f)) << 20) - | (((uint32_t)(v[1] * 511.5f + 512.0f)) << 10) - | (((uint32_t)(v[0] * 511.5f + 512.0f))); - } - else - { - return (((uint32_t)(v[3] * 127.5f + 128.0f)) << 24) - | (((uint32_t)(v[2] * 127.5f + 128.0f)) << 16) - | (((uint32_t)(v[1] * 127.5f + 128.0f)) << 8) - | (((uint32_t)(v[0] * 127.5f + 128.0f))); - } -} - -uint32_t R_VboPackNormal(vec3_t v) -{ - if (glRefConfig.packedNormalDataType == GL_UNSIGNED_INT_2_10_10_10_REV) - { - return (((uint32_t)(v[2] * 511.5f + 512.0f)) << 20) - | (((uint32_t)(v[1] * 511.5f + 512.0f)) << 10) - | (((uint32_t)(v[0] * 511.5f + 512.0f))); - } - else - { - return (((uint32_t)(v[2] * 127.5f + 128.0f)) << 16) - | (((uint32_t)(v[1] * 127.5f + 128.0f)) << 8) - | (((uint32_t)(v[0] * 127.5f + 128.0f))); - } -} - -void R_VboUnpackTangent(vec4_t v, uint32_t b) -{ - if (glRefConfig.packedNormalDataType == GL_UNSIGNED_INT_2_10_10_10_REV) - { - v[0] = ((b) & 0x3ff) * 1.0f/511.5f - 1.0f; - v[1] = ((b >> 10) & 0x3ff) * 1.0f/511.5f - 1.0f; - v[2] = ((b >> 20) & 0x3ff) * 1.0f/511.5f - 1.0f; - v[3] = ((b >> 30) & 0x3) * 1.0f/1.5f - 1.0f; - } - else - { - v[0] = ((b) & 0xff) * 1.0f/127.5f - 1.0f; - v[1] = ((b >> 8) & 0xff) * 1.0f/127.5f - 1.0f; - v[2] = ((b >> 16) & 0xff) * 1.0f/127.5f - 1.0f; - v[3] = ((b >> 24) & 0xff) * 1.0f/127.5f - 1.0f; - } -} - -void R_VboUnpackNormal(vec3_t v, uint32_t b) -{ - if (glRefConfig.packedNormalDataType == GL_UNSIGNED_INT_2_10_10_10_REV) - { - v[0] = ((b) & 0x3ff) * 1.0f/511.5f - 1.0f; - v[1] = ((b >> 10) & 0x3ff) * 1.0f/511.5f - 1.0f; - v[2] = ((b >> 20) & 0x3ff) * 1.0f/511.5f - 1.0f; - } - else - { - v[0] = ((b) & 0xff) * 1.0f/127.5f - 1.0f; - v[1] = ((b >> 8) & 0xff) * 1.0f/127.5f - 1.0f; - v[2] = ((b >> 16) & 0xff) * 1.0f/127.5f - 1.0f; - } -} - -/* -============ -R_CreateVBO -============ -*/ -VBO_t *R_CreateVBO(const char *name, byte * vertexes, int vertexesSize, vboUsage_t usage) -{ - VBO_t *vbo; - int glUsage; - - switch (usage) - { - case VBO_USAGE_STATIC: - glUsage = GL_STATIC_DRAW_ARB; - break; - - case VBO_USAGE_DYNAMIC: - glUsage = GL_DYNAMIC_DRAW_ARB; - break; - - default: - Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage); - return NULL; - } - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "R_CreateVBO: \"%s\" is too long", name); - } - - if ( tr.numVBOs == MAX_VBOS ) { - ri.Error( ERR_DROP, "R_CreateVBO: MAX_VBOS hit"); - } - - R_IssuePendingRenderCommands(); - - vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low); - tr.numVBOs++; - - memset(vbo, 0, sizeof(*vbo)); - - Q_strncpyz(vbo->name, name, sizeof(vbo->name)); - - vbo->vertexesSize = vertexesSize; - - qglGenBuffersARB(1, &vbo->vertexesVBO); - - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO); - qglBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexesSize, vertexes, glUsage); - - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - - glState.currentVBO = NULL; - - GL_CheckErrors(); - - return vbo; -} - -/* -============ -R_CreateVBO2 -============ -*/ -VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * verts, unsigned int stateBits, vboUsage_t usage) -{ - VBO_t *vbo; - int i; - - byte *data; - int dataSize; - int dataOfs; - - int glUsage; - - switch (usage) - { - case VBO_USAGE_STATIC: - glUsage = GL_STATIC_DRAW_ARB; - break; - - case VBO_USAGE_DYNAMIC: - glUsage = GL_DYNAMIC_DRAW_ARB; - break; - - default: - Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage); - return NULL; - } - - if(!numVertexes) - return NULL; - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "R_CreateVBO2: \"%s\" is too long", name); - } - - if ( tr.numVBOs == MAX_VBOS ) { - ri.Error( ERR_DROP, "R_CreateVBO2: MAX_VBOS hit"); - } - - R_IssuePendingRenderCommands(); - - vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low); - tr.numVBOs++; - - memset(vbo, 0, sizeof(*vbo)); - - Q_strncpyz(vbo->name, name, sizeof(vbo->name)); - - if (usage == VBO_USAGE_STATIC) - { - // since these vertex attributes are never altered, interleave them - vbo->ofs_xyz = 0; - dataSize = sizeof(verts[0].xyz); - - if(stateBits & ATTR_NORMAL) - { - vbo->ofs_normal = dataSize; - dataSize += sizeof(uint32_t); - } - -#ifdef USE_VERT_TANGENT_SPACE - if(stateBits & ATTR_TANGENT) - { - vbo->ofs_tangent = dataSize; - dataSize += sizeof(uint32_t); - } -#endif - - if(stateBits & ATTR_TEXCOORD) - { - vbo->ofs_st = dataSize; - dataSize += sizeof(verts[0].st); - } - - if(stateBits & ATTR_LIGHTCOORD) - { - vbo->ofs_lightmap = dataSize; - dataSize += sizeof(verts[0].lightmap); - } - - if(stateBits & ATTR_COLOR) - { - vbo->ofs_vertexcolor = dataSize; - dataSize += sizeof(verts[0].vertexColors); - } - - if(stateBits & ATTR_LIGHTDIRECTION) - { - vbo->ofs_lightdir = dataSize; - dataSize += sizeof(uint32_t); - } - - vbo->stride_xyz = dataSize; - vbo->stride_normal = dataSize; -#ifdef USE_VERT_TANGENT_SPACE - vbo->stride_tangent = dataSize; -#endif - vbo->stride_st = dataSize; - vbo->stride_lightmap = dataSize; - vbo->stride_vertexcolor = dataSize; - vbo->stride_lightdir = dataSize; - - // create VBO - dataSize *= numVertexes; - data = ri.Hunk_AllocateTempMemory(dataSize); - dataOfs = 0; - - //ri.Printf(PRINT_ALL, "CreateVBO: %d, %d %d %d %d %d, %d %d %d %d %d\n", dataSize, vbo->ofs_xyz, vbo->ofs_normal, vbo->ofs_st, vbo->ofs_lightmap, vbo->ofs_vertexcolor, - //vbo->stride_xyz, vbo->stride_normal, vbo->stride_st, vbo->stride_lightmap, vbo->stride_vertexcolor); - - for (i = 0; i < numVertexes; i++) - { - // xyz - memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz)); - dataOfs += sizeof(verts[i].xyz); - - // normal - if(stateBits & ATTR_NORMAL) - { - uint32_t *p = (uint32_t *)(data + dataOfs); - - *p = R_VboPackNormal(verts[i].normal); - - dataOfs += sizeof(uint32_t); - } - -#ifdef USE_VERT_TANGENT_SPACE - // tangent - if(stateBits & ATTR_TANGENT) - { - uint32_t *p = (uint32_t *)(data + dataOfs); - - *p = R_VboPackTangent(verts[i].tangent); - - dataOfs += sizeof(uint32_t); - } -#endif - - // vertex texcoords - if(stateBits & ATTR_TEXCOORD) - { - memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st)); - dataOfs += sizeof(verts[i].st); - } - - // feed vertex lightmap texcoords - if(stateBits & ATTR_LIGHTCOORD) - { - memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap)); - dataOfs += sizeof(verts[i].lightmap); - } - - // feed vertex colors - if(stateBits & ATTR_COLOR) - { - memcpy(data + dataOfs, &verts[i].vertexColors, sizeof(verts[i].vertexColors)); - dataOfs += sizeof(verts[i].vertexColors); - } - - // feed vertex light directions - if(stateBits & ATTR_LIGHTDIRECTION) - { - uint32_t *p = (uint32_t *)(data + dataOfs); - - *p = R_VboPackNormal(verts[i].lightdir); - - dataOfs += sizeof(uint32_t); - } - } - } - else - { - // since these vertex attributes may be changed, put them in flat arrays - dataSize = sizeof(verts[0].xyz); - - if(stateBits & ATTR_NORMAL) - { - dataSize += sizeof(uint32_t); - } - -#ifdef USE_VERT_TANGENT_SPACE - if(stateBits & ATTR_TANGENT) - { - dataSize += sizeof(uint32_t); - } -#endif - - if(stateBits & ATTR_TEXCOORD) - { - dataSize += sizeof(verts[0].st); - } - - if(stateBits & ATTR_LIGHTCOORD) - { - dataSize += sizeof(verts[0].lightmap); - } - - if(stateBits & ATTR_COLOR) - { - dataSize += sizeof(verts[0].vertexColors); - } - - if(stateBits & ATTR_LIGHTDIRECTION) - { - dataSize += sizeof(uint32_t); - } - - // create VBO - dataSize *= numVertexes; - data = ri.Hunk_AllocateTempMemory(dataSize); - dataOfs = 0; - - vbo->ofs_xyz = 0; - vbo->ofs_normal = 0; -#ifdef USE_VERT_TANGENT_SPACE - vbo->ofs_tangent = 0; -#endif - vbo->ofs_st = 0; - vbo->ofs_lightmap = 0; - vbo->ofs_vertexcolor = 0; - vbo->ofs_lightdir = 0; - - vbo->stride_xyz = sizeof(verts[0].xyz); - vbo->stride_normal = sizeof(uint32_t); -#ifdef USE_VERT_TANGENT_SPACE - vbo->stride_tangent = sizeof(uint32_t); -#endif - vbo->stride_vertexcolor = sizeof(verts[0].vertexColors); - vbo->stride_st = sizeof(verts[0].st); - vbo->stride_lightmap = sizeof(verts[0].lightmap); - vbo->stride_lightdir = sizeof(uint32_t); - - //ri.Printf(PRINT_ALL, "2CreateVBO: %d, %d %d %d %d %d, %d %d %d %d %d\n", dataSize, vbo->ofs_xyz, vbo->ofs_normal, vbo->ofs_st, vbo->ofs_lightmap, vbo->ofs_vertexcolor, - //vbo->stride_xyz, vbo->stride_normal, vbo->stride_st, vbo->stride_lightmap, vbo->stride_vertexcolor); - - // xyz - for (i = 0; i < numVertexes; i++) - { - memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz)); - dataOfs += sizeof(verts[i].xyz); - } - - // normal - if(stateBits & ATTR_NORMAL) - { - vbo->ofs_normal = dataOfs; - for (i = 0; i < numVertexes; i++) - { - uint32_t *p = (uint32_t *)(data + dataOfs); - - *p = R_VboPackNormal(verts[i].normal); - - dataOfs += sizeof(uint32_t); - } - } - -#ifdef USE_VERT_TANGENT_SPACE - // tangent - if(stateBits & ATTR_TANGENT) - { - vbo->ofs_tangent = dataOfs; - for (i = 0; i < numVertexes; i++) - { - uint32_t *p = (uint32_t *)(data + dataOfs); - - *p = R_VboPackTangent(verts[i].tangent); - - dataOfs += sizeof(uint32_t); - } - } -#endif - - // vertex texcoords - if(stateBits & ATTR_TEXCOORD) - { - vbo->ofs_st = dataOfs; - for (i = 0; i < numVertexes; i++) - { - memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st)); - dataOfs += sizeof(verts[i].st); - } - } - - // feed vertex lightmap texcoords - if(stateBits & ATTR_LIGHTCOORD) - { - vbo->ofs_lightmap = dataOfs; - for (i = 0; i < numVertexes; i++) - { - memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap)); - dataOfs += sizeof(verts[i].lightmap); - } - } - - // feed vertex colors - if(stateBits & ATTR_COLOR) - { - vbo->ofs_vertexcolor = dataOfs; - for (i = 0; i < numVertexes; i++) - { - memcpy(data + dataOfs, &verts[i].vertexColors, sizeof(verts[i].vertexColors)); - dataOfs += sizeof(verts[i].vertexColors); - } - } - - // feed vertex lightdirs - if(stateBits & ATTR_LIGHTDIRECTION) - { - vbo->ofs_lightdir = dataOfs; - for (i = 0; i < numVertexes; i++) - { - uint32_t *p = (uint32_t *)(data + dataOfs); - - *p = R_VboPackNormal(verts[i].lightdir); - - dataOfs += sizeof(uint32_t); - } - } - } - - - vbo->vertexesSize = dataSize; - - qglGenBuffersARB(1, &vbo->vertexesVBO); - - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO); - qglBufferDataARB(GL_ARRAY_BUFFER_ARB, dataSize, data, glUsage); - - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - - glState.currentVBO = NULL; - - GL_CheckErrors(); - - ri.Hunk_FreeTempMemory(data); - - return vbo; -} - - -/* -============ -R_CreateIBO -============ -*/ -IBO_t *R_CreateIBO(const char *name, byte * indexes, int indexesSize, vboUsage_t usage) -{ - IBO_t *ibo; - int glUsage; - - switch (usage) - { - case VBO_USAGE_STATIC: - glUsage = GL_STATIC_DRAW_ARB; - break; - - case VBO_USAGE_DYNAMIC: - glUsage = GL_DYNAMIC_DRAW_ARB; - break; - - default: - Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage); - return NULL; - } - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "R_CreateIBO: \"%s\" is too long", name); - } - - if ( tr.numIBOs == MAX_IBOS ) { - ri.Error( ERR_DROP, "R_CreateIBO: MAX_IBOS hit"); - } - - R_IssuePendingRenderCommands(); - - ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low); - tr.numIBOs++; - - Q_strncpyz(ibo->name, name, sizeof(ibo->name)); - - ibo->indexesSize = indexesSize; - - qglGenBuffersARB(1, &ibo->indexesVBO); - - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO); - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage); - - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - - glState.currentIBO = NULL; - - GL_CheckErrors(); - - return ibo; -} - -/* -============ -R_CreateIBO2 -============ -*/ -IBO_t *R_CreateIBO2(const char *name, int numIndexes, glIndex_t * inIndexes, vboUsage_t usage) -{ - IBO_t *ibo; - int i; - - glIndex_t *indexes; - int indexesSize; - - int glUsage; - - switch (usage) - { - case VBO_USAGE_STATIC: - glUsage = GL_STATIC_DRAW_ARB; - break; - - case VBO_USAGE_DYNAMIC: - glUsage = GL_DYNAMIC_DRAW_ARB; - break; - - default: - Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage); - return NULL; - } - - if(!numIndexes) - return NULL; - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "R_CreateIBO2: \"%s\" is too long", name); - } - - if ( tr.numIBOs == MAX_IBOS ) { - ri.Error( ERR_DROP, "R_CreateIBO2: MAX_IBOS hit"); - } - - R_IssuePendingRenderCommands(); - - ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low); - tr.numIBOs++; - - Q_strncpyz(ibo->name, name, sizeof(ibo->name)); - - indexesSize = numIndexes * sizeof(glIndex_t); - indexes = ri.Hunk_AllocateTempMemory(indexesSize); - - for(i = 0; i < numIndexes; i++) - { - indexes[i] = inIndexes[i]; - } - - ibo->indexesSize = indexesSize; - - qglGenBuffersARB(1, &ibo->indexesVBO); - - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO); - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage); - - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - - glState.currentIBO = NULL; - - GL_CheckErrors(); - - ri.Hunk_FreeTempMemory(indexes); - - return ibo; -} - -/* -============ -R_BindVBO -============ -*/ -void R_BindVBO(VBO_t * vbo) -{ - if(!vbo) - { - //R_BindNullVBO(); - ri.Error(ERR_DROP, "R_BindNullVBO: NULL vbo"); - return; - } - - if(r_logFile->integer) - { - // don't just call LogComment, or we will get a call to va() every frame! - GLimp_LogComment(va("--- R_BindVBO( %s ) ---\n", vbo->name)); - } - - if(glState.currentVBO != vbo) - { - glState.currentVBO = vbo; - glState.vertexAttribPointersSet = 0; - - glState.vertexAttribsInterpolation = 0; - glState.vertexAttribsOldFrame = 0; - glState.vertexAttribsNewFrame = 0; - glState.vertexAnimation = qfalse; - - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO); - - backEnd.pc.c_vboVertexBuffers++; - } -} - -/* -============ -R_BindNullVBO -============ -*/ -void R_BindNullVBO(void) -{ - GLimp_LogComment("--- R_BindNullVBO ---\n"); - - if(glState.currentVBO) - { - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - glState.currentVBO = NULL; - } - - GL_CheckErrors(); -} - -/* -============ -R_BindIBO -============ -*/ -void R_BindIBO(IBO_t * ibo) -{ - if(!ibo) - { - //R_BindNullIBO(); - ri.Error(ERR_DROP, "R_BindIBO: NULL ibo"); - return; - } - - if(r_logFile->integer) - { - // don't just call LogComment, or we will get a call to va() every frame! - GLimp_LogComment(va("--- R_BindIBO( %s ) ---\n", ibo->name)); - } - - if(glState.currentIBO != ibo) - { - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO); - - glState.currentIBO = ibo; - - backEnd.pc.c_vboIndexBuffers++; - } -} - -/* -============ -R_BindNullIBO -============ -*/ -void R_BindNullIBO(void) -{ - GLimp_LogComment("--- R_BindNullIBO ---\n"); - - if(glState.currentIBO) - { - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - glState.currentIBO = NULL; - glState.vertexAttribPointersSet = 0; - } -} - -/* -============ -R_InitVBOs -============ -*/ -void R_InitVBOs(void) -{ - int dataSize; - int offset; - - ri.Printf(PRINT_ALL, "------- R_InitVBOs -------\n"); - - tr.numVBOs = 0; - tr.numIBOs = 0; - - dataSize = sizeof(tess.xyz[0]); - dataSize += sizeof(tess.normal[0]); -#ifdef USE_VERT_TANGENT_SPACE - dataSize += sizeof(tess.tangent[0]); -#endif - dataSize += sizeof(tess.vertexColors[0]); - dataSize += sizeof(tess.texCoords[0][0]) * 2; - dataSize += sizeof(tess.lightdir[0]); - dataSize *= SHADER_MAX_VERTEXES; - - tess.vbo = R_CreateVBO("tessVertexArray_VBO", NULL, dataSize, VBO_USAGE_DYNAMIC); - - offset = 0; - - tess.vbo->ofs_xyz = offset; offset += sizeof(tess.xyz[0]) * SHADER_MAX_VERTEXES; - tess.vbo->ofs_normal = offset; offset += sizeof(tess.normal[0]) * SHADER_MAX_VERTEXES; -#ifdef USE_VERT_TANGENT_SPACE - tess.vbo->ofs_tangent = offset; offset += sizeof(tess.tangent[0]) * SHADER_MAX_VERTEXES; -#endif - // these next two are actually interleaved - tess.vbo->ofs_st = offset; - tess.vbo->ofs_lightmap = offset + sizeof(tess.texCoords[0][0]); - offset += sizeof(tess.texCoords[0][0]) * 2 * SHADER_MAX_VERTEXES; - - tess.vbo->ofs_vertexcolor = offset; offset += sizeof(tess.vertexColors[0]) * SHADER_MAX_VERTEXES; - tess.vbo->ofs_lightdir = offset; - - tess.vbo->stride_xyz = sizeof(tess.xyz[0]); - tess.vbo->stride_normal = sizeof(tess.normal[0]); -#ifdef USE_VERT_TANGENT_SPACE - tess.vbo->stride_tangent = sizeof(tess.tangent[0]); -#endif - tess.vbo->stride_vertexcolor = sizeof(tess.vertexColors[0]); - tess.vbo->stride_st = sizeof(tess.texCoords[0][0]) * 2; - tess.vbo->stride_lightmap = sizeof(tess.texCoords[0][0]) * 2; - tess.vbo->stride_lightdir = sizeof(tess.lightdir[0]); - - dataSize = sizeof(tess.indexes[0]) * SHADER_MAX_INDEXES; - - tess.ibo = R_CreateIBO("tessVertexArray_IBO", NULL, dataSize, VBO_USAGE_DYNAMIC); - - R_BindNullVBO(); - R_BindNullIBO(); - - GL_CheckErrors(); -} - -/* -============ -R_ShutdownVBOs -============ -*/ -void R_ShutdownVBOs(void) -{ - int i; - VBO_t *vbo; - IBO_t *ibo; - - ri.Printf(PRINT_ALL, "------- R_ShutdownVBOs -------\n"); - - R_BindNullVBO(); - R_BindNullIBO(); - - - for(i = 0; i < tr.numVBOs; i++) - { - vbo = tr.vbos[i]; - - if(vbo->vertexesVBO) - { - qglDeleteBuffersARB(1, &vbo->vertexesVBO); - } - - //ri.Free(vbo); - } - - for(i = 0; i < tr.numIBOs; i++) - { - ibo = tr.ibos[i]; - - if(ibo->indexesVBO) - { - qglDeleteBuffersARB(1, &ibo->indexesVBO); - } - - //ri.Free(ibo); - } - - tr.numVBOs = 0; - tr.numIBOs = 0; -} - -/* -============ -R_VBOList_f -============ -*/ -void R_VBOList_f(void) -{ - int i; - VBO_t *vbo; - IBO_t *ibo; - int vertexesSize = 0; - int indexesSize = 0; - - ri.Printf(PRINT_ALL, " size name\n"); - ri.Printf(PRINT_ALL, "----------------------------------------------------------\n"); - - for(i = 0; i < tr.numVBOs; i++) - { - vbo = tr.vbos[i]; - - ri.Printf(PRINT_ALL, "%d.%02d MB %s\n", vbo->vertexesSize / (1024 * 1024), - (vbo->vertexesSize % (1024 * 1024)) * 100 / (1024 * 1024), vbo->name); - - vertexesSize += vbo->vertexesSize; - } - - for(i = 0; i < tr.numIBOs; i++) - { - ibo = tr.ibos[i]; - - ri.Printf(PRINT_ALL, "%d.%02d MB %s\n", ibo->indexesSize / (1024 * 1024), - (ibo->indexesSize % (1024 * 1024)) * 100 / (1024 * 1024), ibo->name); - - indexesSize += ibo->indexesSize; - } - - ri.Printf(PRINT_ALL, " %i total VBOs\n", tr.numVBOs); - ri.Printf(PRINT_ALL, " %d.%02d MB total vertices memory\n", vertexesSize / (1024 * 1024), - (vertexesSize % (1024 * 1024)) * 100 / (1024 * 1024)); - - ri.Printf(PRINT_ALL, " %i total IBOs\n", tr.numIBOs); - ri.Printf(PRINT_ALL, " %d.%02d MB total triangle indices memory\n", indexesSize / (1024 * 1024), - (indexesSize % (1024 * 1024)) * 100 / (1024 * 1024)); -} - - -/* -============== -RB_UpdateVBOs - -Adapted from Tess_UpdateVBOs from xreal - -Update the default VBO to replace the client side vertex arrays -============== -*/ -void RB_UpdateVBOs(unsigned int attribBits) -{ - GLimp_LogComment("--- RB_UpdateVBOs ---\n"); - - backEnd.pc.c_dynamicVboDraws++; - - // update the default VBO - if(tess.numVertexes > 0 && tess.numVertexes <= SHADER_MAX_VERTEXES) - { - R_BindVBO(tess.vbo); - - // orphan old buffer so we don't stall on it - qglBufferDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->vertexesSize, NULL, GL_DYNAMIC_DRAW_ARB); - - if(attribBits & ATTR_BITS) - { - if(attribBits & ATTR_POSITION) - { - //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_xyz, tess.numVertexes * sizeof(tess.xyz[0])); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_xyz, tess.numVertexes * sizeof(tess.xyz[0]), tess.xyz); - } - - if(attribBits & ATTR_TEXCOORD || attribBits & ATTR_LIGHTCOORD) - { - // these are interleaved, so we update both if either need it - //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_st, tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_st, tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2, tess.texCoords); - } - - if(attribBits & ATTR_NORMAL) - { - //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0])); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0]), tess.normal); - } - -#ifdef USE_VERT_TANGENT_SPACE - if(attribBits & ATTR_TANGENT) - { - //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0])); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0]), tess.tangent); - } -#endif - - if(attribBits & ATTR_COLOR) - { - //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0])); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0]), tess.vertexColors); - } - - if(attribBits & ATTR_LIGHTDIRECTION) - { - //ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_lightdir, tess.numVertexes * sizeof(tess.lightdir[0])); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_lightdir, tess.numVertexes * sizeof(tess.lightdir[0]), tess.lightdir); - } - } - else - { - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_xyz, tess.numVertexes * sizeof(tess.xyz[0]), tess.xyz); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_st, tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2, tess.texCoords); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0]), tess.normal); -#ifdef USE_VERT_TANGENT_SPACE - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0]), tess.tangent); -#endif - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0]), tess.vertexColors); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_lightdir, tess.numVertexes * sizeof(tess.lightdir[0]), tess.lightdir); - } - - } - - // update the default IBO - if(tess.numIndexes > 0 && tess.numIndexes <= SHADER_MAX_INDEXES) - { - R_BindIBO(tess.ibo); - - // orphan old buffer so we don't stall on it - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, tess.ibo->indexesSize, NULL, GL_DYNAMIC_DRAW_ARB); - - qglBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, tess.numIndexes * sizeof(tess.indexes[0]), tess.indexes); - } -} diff --git a/code/renderergl2/tr_world.c b/code/renderergl2/tr_world.c deleted file mode 100644 index dba15c454c..0000000000 --- a/code/renderergl2/tr_world.c +++ /dev/null @@ -1,858 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "tr_local.h" - - - -/* -================ -R_CullSurface - -Tries to cull surfaces before they are lighted or -added to the sorting list. -================ -*/ -static qboolean R_CullSurface( msurface_t *surf ) { - if ( r_nocull->integer || surf->cullinfo.type == CULLINFO_NONE) { - return qfalse; - } - - if ( *surf->data == SF_GRID && r_nocurves->integer ) { - return qtrue; - } - - if (surf->cullinfo.type & CULLINFO_PLANE) - { - // Only true for SF_FACE, so treat like its own function - float d; - cullType_t ct; - - if ( !r_facePlaneCull->integer ) { - return qfalse; - } - - ct = surf->shader->cullType; - - if (ct == CT_TWO_SIDED) - { - return qfalse; - } - - // don't cull for depth shadow - /* - if ( tr.viewParms.flags & VPF_DEPTHSHADOW ) - { - return qfalse; - } - */ - - // shadowmaps draw back surfaces - if ( tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW) ) - { - if (ct == CT_FRONT_SIDED) - { - ct = CT_BACK_SIDED; - } - else - { - ct = CT_FRONT_SIDED; - } - } - - // do proper cull for orthographic projection - if (tr.viewParms.flags & VPF_ORTHOGRAPHIC) { - d = DotProduct(tr.viewParms.or.axis[0], surf->cullinfo.plane.normal); - if ( ct == CT_FRONT_SIDED ) { - if (d > 0) - return qtrue; - } else { - if (d < 0) - return qtrue; - } - return qfalse; - } - - d = DotProduct (tr.or.viewOrigin, surf->cullinfo.plane.normal); - - // don't cull exactly on the plane, because there are levels of rounding - // through the BSP, ICD, and hardware that may cause pixel gaps if an - // epsilon isn't allowed here - if ( ct == CT_FRONT_SIDED ) { - if ( d < surf->cullinfo.plane.dist - 8 ) { - return qtrue; - } - } else { - if ( d > surf->cullinfo.plane.dist + 8 ) { - return qtrue; - } - } - - return qfalse; - } - - if (surf->cullinfo.type & CULLINFO_SPHERE) - { - int sphereCull; - - if ( tr.currentEntityNum != REFENTITYNUM_WORLD ) { - sphereCull = R_CullLocalPointAndRadius( surf->cullinfo.localOrigin, surf->cullinfo.radius ); - } else { - sphereCull = R_CullPointAndRadius( surf->cullinfo.localOrigin, surf->cullinfo.radius ); - } - - if ( sphereCull == CULL_OUT ) - { - return qtrue; - } - } - - if (surf->cullinfo.type & CULLINFO_BOX) - { - int boxCull; - - if ( tr.currentEntityNum != REFENTITYNUM_WORLD ) { - boxCull = R_CullLocalBox( surf->cullinfo.bounds ); - } else { - boxCull = R_CullBox( surf->cullinfo.bounds ); - } - - if ( boxCull == CULL_OUT ) - { - return qtrue; - } - } - - return qfalse; -} - - -/* -==================== -R_DlightSurface - -The given surface is going to be drawn, and it touches a leaf -that is touched by one or more dlights, so try to throw out -more dlights if possible. -==================== -*/ -static int R_DlightSurface( msurface_t *surf, int dlightBits ) { - float d; - int i; - dlight_t *dl; - - if ( surf->cullinfo.type & CULLINFO_PLANE ) - { - for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { - if ( ! ( dlightBits & ( 1 << i ) ) ) { - continue; - } - dl = &tr.refdef.dlights[i]; - d = DotProduct( dl->origin, surf->cullinfo.plane.normal ) - surf->cullinfo.plane.dist; - if ( d < -dl->radius || d > dl->radius ) { - // dlight doesn't reach the plane - dlightBits &= ~( 1 << i ); - } - } - } - - if ( surf->cullinfo.type & CULLINFO_BOX ) - { - for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { - if ( ! ( dlightBits & ( 1 << i ) ) ) { - continue; - } - dl = &tr.refdef.dlights[i]; - if ( dl->origin[0] - dl->radius > surf->cullinfo.bounds[1][0] - || dl->origin[0] + dl->radius < surf->cullinfo.bounds[0][0] - || dl->origin[1] - dl->radius > surf->cullinfo.bounds[1][1] - || dl->origin[1] + dl->radius < surf->cullinfo.bounds[0][1] - || dl->origin[2] - dl->radius > surf->cullinfo.bounds[1][2] - || dl->origin[2] + dl->radius < surf->cullinfo.bounds[0][2] ) { - // dlight doesn't reach the bounds - dlightBits &= ~( 1 << i ); - } - } - } - - if ( surf->cullinfo.type & CULLINFO_SPHERE ) - { - for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { - if ( ! ( dlightBits & ( 1 << i ) ) ) { - continue; - } - dl = &tr.refdef.dlights[i]; - if (!SpheresIntersect(dl->origin, dl->radius, surf->cullinfo.localOrigin, surf->cullinfo.radius)) - { - // dlight doesn't reach the bounds - dlightBits &= ~( 1 << i ); - } - } - } - - switch(*surf->data) - { - case SF_FACE: - case SF_GRID: - case SF_TRIANGLES: - case SF_VBO_MESH: - ((srfBspSurface_t *)surf->data)->dlightBits = dlightBits; - break; - - default: - dlightBits = 0; - break; - } - - if ( dlightBits ) { - tr.pc.c_dlightSurfaces++; - } else { - tr.pc.c_dlightSurfacesCulled++; - } - - return dlightBits; -} - -/* -==================== -R_PshadowSurface - -Just like R_DlightSurface, cull any we can -==================== -*/ -static int R_PshadowSurface( msurface_t *surf, int pshadowBits ) { - float d; - int i; - pshadow_t *ps; - - if ( surf->cullinfo.type & CULLINFO_PLANE ) - { - for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) { - if ( ! ( pshadowBits & ( 1 << i ) ) ) { - continue; - } - ps = &tr.refdef.pshadows[i]; - d = DotProduct( ps->lightOrigin, surf->cullinfo.plane.normal ) - surf->cullinfo.plane.dist; - if ( d < -ps->lightRadius || d > ps->lightRadius ) { - // pshadow doesn't reach the plane - pshadowBits &= ~( 1 << i ); - } - } - } - - if ( surf->cullinfo.type & CULLINFO_BOX ) - { - for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) { - if ( ! ( pshadowBits & ( 1 << i ) ) ) { - continue; - } - ps = &tr.refdef.pshadows[i]; - if ( ps->lightOrigin[0] - ps->lightRadius > surf->cullinfo.bounds[1][0] - || ps->lightOrigin[0] + ps->lightRadius < surf->cullinfo.bounds[0][0] - || ps->lightOrigin[1] - ps->lightRadius > surf->cullinfo.bounds[1][1] - || ps->lightOrigin[1] + ps->lightRadius < surf->cullinfo.bounds[0][1] - || ps->lightOrigin[2] - ps->lightRadius > surf->cullinfo.bounds[1][2] - || ps->lightOrigin[2] + ps->lightRadius < surf->cullinfo.bounds[0][2] - || BoxOnPlaneSide(surf->cullinfo.bounds[0], surf->cullinfo.bounds[1], &ps->cullPlane) == 2 ) { - // pshadow doesn't reach the bounds - pshadowBits &= ~( 1 << i ); - } - } - } - - if ( surf->cullinfo.type & CULLINFO_SPHERE ) - { - for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) { - if ( ! ( pshadowBits & ( 1 << i ) ) ) { - continue; - } - ps = &tr.refdef.pshadows[i]; - if (!SpheresIntersect(ps->viewOrigin, ps->viewRadius, surf->cullinfo.localOrigin, surf->cullinfo.radius) - || DotProduct( surf->cullinfo.localOrigin, ps->cullPlane.normal ) - ps->cullPlane.dist < -surf->cullinfo.radius) - { - // pshadow doesn't reach the bounds - pshadowBits &= ~( 1 << i ); - } - } - } - - switch(*surf->data) - { - case SF_FACE: - case SF_GRID: - case SF_TRIANGLES: - case SF_VBO_MESH: - ((srfBspSurface_t *)surf->data)->pshadowBits = pshadowBits; - break; - - default: - pshadowBits = 0; - break; - } - - if ( pshadowBits ) { - //tr.pc.c_dlightSurfaces++; - } - - return pshadowBits; -} - - -/* -====================== -R_AddWorldSurface -====================== -*/ -static void R_AddWorldSurface( msurface_t *surf, int dlightBits, int pshadowBits ) { - // FIXME: bmodel fog? - - // try to cull before dlighting or adding - if ( R_CullSurface( surf ) ) { - return; - } - - // check for dlighting - if ( dlightBits ) { - dlightBits = R_DlightSurface( surf, dlightBits ); - dlightBits = ( dlightBits != 0 ); - } - - // check for pshadows - /*if ( pshadowBits ) */{ - pshadowBits = R_PshadowSurface( surf, pshadowBits); - pshadowBits = ( pshadowBits != 0 ); - } - - R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits, pshadowBits, surf->cubemapIndex ); -} - -/* -============================================================= - - BRUSH MODELS - -============================================================= -*/ - -/* -================= -R_AddBrushModelSurfaces -================= -*/ -void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) { - bmodel_t *bmodel; - int clip; - model_t *pModel; - int i; - - pModel = R_GetModelByHandle( ent->e.hModel ); - - bmodel = pModel->bmodel; - - clip = R_CullLocalBox( bmodel->bounds ); - if ( clip == CULL_OUT ) { - return; - } - - R_SetupEntityLighting( &tr.refdef, ent ); - R_DlightBmodel( bmodel ); - - for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) { - int surf = bmodel->firstSurface + i; - - if (tr.world->surfacesViewCount[surf] != tr.viewCount) - { - tr.world->surfacesViewCount[surf] = tr.viewCount; - R_AddWorldSurface( tr.world->surfaces + surf, tr.currentEntity->needDlights, 0 ); - } - } -} - - -/* -============================================================= - - WORLD MODEL - -============================================================= -*/ - - -/* -================ -R_RecursiveWorldNode -================ -*/ -static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits, int pshadowBits ) { - - do { - int newDlights[2]; - unsigned int newPShadows[2]; - - // if the node wasn't marked as potentially visible, exit - // pvs is skipped for depth shadows - if (!(tr.viewParms.flags & VPF_DEPTHSHADOW) && node->visCounts[tr.visIndex] != tr.visCounts[tr.visIndex]) { - return; - } - - // if the bounding volume is outside the frustum, nothing - // inside can be visible OPTIMIZE: don't do this all the way to leafs? - - if ( !r_nocull->integer ) { - int r; - - if ( planeBits & 1 ) { - r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[0]); - if (r == 2) { - return; // culled - } - if ( r == 1 ) { - planeBits &= ~1; // all descendants will also be in front - } - } - - if ( planeBits & 2 ) { - r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[1]); - if (r == 2) { - return; // culled - } - if ( r == 1 ) { - planeBits &= ~2; // all descendants will also be in front - } - } - - if ( planeBits & 4 ) { - r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[2]); - if (r == 2) { - return; // culled - } - if ( r == 1 ) { - planeBits &= ~4; // all descendants will also be in front - } - } - - if ( planeBits & 8 ) { - r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[3]); - if (r == 2) { - return; // culled - } - if ( r == 1 ) { - planeBits &= ~8; // all descendants will also be in front - } - } - - if ( planeBits & 16 ) { - r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[4]); - if (r == 2) { - return; // culled - } - if ( r == 1 ) { - planeBits &= ~16; // all descendants will also be in front - } - } - } - - if ( node->contents != -1 ) { - break; - } - - // node is just a decision point, so go down both sides - // since we don't care about sort orders, just go positive to negative - - // determine which dlights are needed - newDlights[0] = 0; - newDlights[1] = 0; - if ( dlightBits ) { - int i; - - for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { - dlight_t *dl; - float dist; - - if ( dlightBits & ( 1 << i ) ) { - dl = &tr.refdef.dlights[i]; - dist = DotProduct( dl->origin, node->plane->normal ) - node->plane->dist; - - if ( dist > -dl->radius ) { - newDlights[0] |= ( 1 << i ); - } - if ( dist < dl->radius ) { - newDlights[1] |= ( 1 << i ); - } - } - } - } - - newPShadows[0] = 0; - newPShadows[1] = 0; - if ( pshadowBits ) { - int i; - - for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) { - pshadow_t *shadow; - float dist; - - if ( pshadowBits & ( 1 << i ) ) { - shadow = &tr.refdef.pshadows[i]; - dist = DotProduct( shadow->lightOrigin, node->plane->normal ) - node->plane->dist; - - if ( dist > -shadow->lightRadius ) { - newPShadows[0] |= ( 1 << i ); - } - if ( dist < shadow->lightRadius ) { - newPShadows[1] |= ( 1 << i ); - } - } - } - } - - // recurse down the children, front side first - R_RecursiveWorldNode (node->children[0], planeBits, newDlights[0], newPShadows[0] ); - - // tail recurse - node = node->children[1]; - dlightBits = newDlights[1]; - pshadowBits = newPShadows[1]; - } while ( 1 ); - - { - // leaf node, so add mark surfaces - int c; - int surf, *view; - - tr.pc.c_leafs++; - - // add to z buffer bounds - if ( node->mins[0] < tr.viewParms.visBounds[0][0] ) { - tr.viewParms.visBounds[0][0] = node->mins[0]; - } - if ( node->mins[1] < tr.viewParms.visBounds[0][1] ) { - tr.viewParms.visBounds[0][1] = node->mins[1]; - } - if ( node->mins[2] < tr.viewParms.visBounds[0][2] ) { - tr.viewParms.visBounds[0][2] = node->mins[2]; - } - - if ( node->maxs[0] > tr.viewParms.visBounds[1][0] ) { - tr.viewParms.visBounds[1][0] = node->maxs[0]; - } - if ( node->maxs[1] > tr.viewParms.visBounds[1][1] ) { - tr.viewParms.visBounds[1][1] = node->maxs[1]; - } - if ( node->maxs[2] > tr.viewParms.visBounds[1][2] ) { - tr.viewParms.visBounds[1][2] = node->maxs[2]; - } - - // add merged and unmerged surfaces - if (tr.world->viewSurfaces && !r_nocurves->integer) - view = tr.world->viewSurfaces + node->firstmarksurface; - else - view = tr.world->marksurfaces + node->firstmarksurface; - - c = node->nummarksurfaces; - while (c--) { - // just mark it as visible, so we don't jump out of the cache derefencing the surface - surf = *view; - if (surf < 0) - { - if (tr.world->mergedSurfacesViewCount[-surf - 1] != tr.viewCount) - { - tr.world->mergedSurfacesViewCount[-surf - 1] = tr.viewCount; - tr.world->mergedSurfacesDlightBits[-surf - 1] = dlightBits; - tr.world->mergedSurfacesPshadowBits[-surf - 1] = pshadowBits; - } - else - { - tr.world->mergedSurfacesDlightBits[-surf - 1] |= dlightBits; - tr.world->mergedSurfacesPshadowBits[-surf - 1] |= pshadowBits; - } - } - else - { - if (tr.world->surfacesViewCount[surf] != tr.viewCount) - { - tr.world->surfacesViewCount[surf] = tr.viewCount; - tr.world->surfacesDlightBits[surf] = dlightBits; - tr.world->surfacesPshadowBits[surf] = pshadowBits; - } - else - { - tr.world->surfacesDlightBits[surf] |= dlightBits; - tr.world->surfacesPshadowBits[surf] |= pshadowBits; - } - } - view++; - } - } - -} - - -/* -=============== -R_PointInLeaf -=============== -*/ -static mnode_t *R_PointInLeaf( const vec3_t p ) { - mnode_t *node; - float d; - cplane_t *plane; - - if ( !tr.world ) { - ri.Error (ERR_DROP, "R_PointInLeaf: bad model"); - } - - node = tr.world->nodes; - while( 1 ) { - if (node->contents != -1) { - break; - } - plane = node->plane; - d = DotProduct (p,plane->normal) - plane->dist; - if (d > 0) { - node = node->children[0]; - } else { - node = node->children[1]; - } - } - - return node; -} - -/* -============== -R_ClusterPVS -============== -*/ -static const byte *R_ClusterPVS (int cluster) { - if (!tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) { - return tr.world->novis; - } - - return tr.world->vis + cluster * tr.world->clusterBytes; -} - -/* -================= -R_inPVS -================= -*/ -qboolean R_inPVS( const vec3_t p1, const vec3_t p2 ) { - mnode_t *leaf; - byte *vis; - - leaf = R_PointInLeaf( p1 ); - vis = ri.CM_ClusterPVS( leaf->cluster ); // why not R_ClusterPVS ?? - leaf = R_PointInLeaf( p2 ); - - if ( !(vis[leaf->cluster>>3] & (1<<(leaf->cluster&7))) ) { - return qfalse; - } - return qtrue; -} - -/* -=============== -R_MarkLeaves - -Mark the leaves and nodes that are in the PVS for the current -cluster -=============== -*/ -static void R_MarkLeaves (void) { - const byte *vis; - mnode_t *leaf, *parent; - int i; - int cluster; - - // lockpvs lets designers walk around to determine the - // extent of the current pvs - if ( r_lockpvs->integer ) { - return; - } - - // current viewcluster - leaf = R_PointInLeaf( tr.viewParms.pvsOrigin ); - cluster = leaf->cluster; - - // if the cluster is the same and the area visibility matrix - // hasn't changed, we don't need to mark everything again - - for(i = 0; i < MAX_VISCOUNTS; i++) - { - if(tr.visClusters[i] == cluster) - { - //tr.visIndex = i; - break; - } - } - - // if r_showcluster was just turned on, remark everything - if(i != MAX_VISCOUNTS && !tr.refdef.areamaskModified && !r_showcluster->modified)// && !r_dynamicBspOcclusionCulling->modified) - { - if(tr.visClusters[i] != tr.visClusters[tr.visIndex] && r_showcluster->integer) - { - ri.Printf(PRINT_ALL, "found cluster:%i area:%i index:%i\n", cluster, leaf->area, i); - } - tr.visIndex = i; - return; - } - - // if the areamask was modified, invalidate all visclusters - // this caused doors to open into undrawn areas - if (tr.refdef.areamaskModified) - { - memset(tr.visClusters, -2, sizeof(tr.visClusters)); - } - - tr.visIndex = (tr.visIndex + 1) % MAX_VISCOUNTS; - tr.visCounts[tr.visIndex]++; - tr.visClusters[tr.visIndex] = cluster; - - if ( r_showcluster->modified || r_showcluster->integer ) { - r_showcluster->modified = qfalse; - if ( r_showcluster->integer ) { - ri.Printf( PRINT_ALL, "cluster:%i area:%i\n", cluster, leaf->area ); - } - } - - // set all nodes to visible if there is no vis - // this caused some levels to simply not render - if (r_novis->integer || !tr.world->vis || tr.visClusters[tr.visIndex] == -1) { - for (i=0 ; inumnodes ; i++) { - if (tr.world->nodes[i].contents != CONTENTS_SOLID) { - tr.world->nodes[i].visCounts[tr.visIndex] = tr.visCounts[tr.visIndex]; - } - } - return; - } - - vis = R_ClusterPVS(tr.visClusters[tr.visIndex]); - - for (i=0,leaf=tr.world->nodes ; inumnodes ; i++, leaf++) { - cluster = leaf->cluster; - if ( cluster < 0 || cluster >= tr.world->numClusters ) { - continue; - } - - // check general pvs - if ( !(vis[cluster>>3] & (1<<(cluster&7))) ) { - continue; - } - - // check for door connection - if ( (tr.refdef.areamask[leaf->area>>3] & (1<<(leaf->area&7)) ) ) { - continue; // not visible - } - - parent = leaf; - do { - if(parent->visCounts[tr.visIndex] == tr.visCounts[tr.visIndex]) - break; - parent->visCounts[tr.visIndex] = tr.visCounts[tr.visIndex]; - parent = parent->parent; - } while (parent); - } -} - - -/* -============= -R_AddWorldSurfaces -============= -*/ -void R_AddWorldSurfaces (void) { - int planeBits, dlightBits, pshadowBits; - - if ( !r_drawworld->integer ) { - return; - } - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return; - } - - tr.currentEntityNum = REFENTITYNUM_WORLD; - tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT; - - // determine which leaves are in the PVS / areamask - if (!(tr.viewParms.flags & VPF_DEPTHSHADOW)) - R_MarkLeaves (); - - // clear out the visible min/max - ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] ); - - // perform frustum culling and flag all the potentially visible surfaces - if ( tr.refdef.num_dlights > 32 ) { - tr.refdef.num_dlights = 32 ; - } - - if ( tr.refdef.num_pshadows > 32 ) { - tr.refdef.num_pshadows = 32 ; - } - - planeBits = (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 31 : 15; - - if ( tr.viewParms.flags & VPF_DEPTHSHADOW ) - { - dlightBits = 0; - pshadowBits = 0; - } - else if ( !(tr.viewParms.flags & VPF_SHADOWMAP) ) - { - dlightBits = ( 1 << tr.refdef.num_dlights ) - 1; - pshadowBits = ( 1 << tr.refdef.num_pshadows ) - 1; - } - else - { - dlightBits = ( 1 << tr.refdef.num_dlights ) - 1; - pshadowBits = 0; - } - - R_RecursiveWorldNode( tr.world->nodes, planeBits, dlightBits, pshadowBits); - - // now add all the potentially visible surfaces - // also mask invisible dlights for next frame - { - int i; - - tr.refdef.dlightMask = 0; - - for (i = 0; i < tr.world->numWorldSurfaces; i++) - { - if (tr.world->surfacesViewCount[i] != tr.viewCount) - continue; - - R_AddWorldSurface( tr.world->surfaces + i, tr.world->surfacesDlightBits[i], tr.world->surfacesPshadowBits[i] ); - tr.refdef.dlightMask |= tr.world->surfacesDlightBits[i]; - } - for (i = 0; i < tr.world->numMergedSurfaces; i++) - { - if (tr.world->mergedSurfacesViewCount[i] != tr.viewCount) - continue; - - R_AddWorldSurface( tr.world->mergedSurfaces + i, tr.world->mergedSurfacesDlightBits[i], tr.world->mergedSurfacesPshadowBits[i] ); - tr.refdef.dlightMask |= tr.world->mergedSurfacesDlightBits[i]; - } - - tr.refdef.dlightMask = ~tr.refdef.dlightMask; - } -} From 59ffa68c98354dc62704d40f73a8aaffbde283c8 Mon Sep 17 00:00:00 2001 From: leilei- Date: Thu, 20 Nov 2025 22:44:57 -0500 Subject: [PATCH 19/20] - Cgame entity glow renderer hookup - R_ShowImages: Adjust for overbright - a tribute to Rebecca Heineman and Jennell Jaquays --- code/renderer_oa/tr_backend.c | 2 ++ code/renderer_oa/tr_image.c | 51 ++++++++++++++++++++++++++++++++ code/renderer_oa/tr_local.h | 2 +- code/renderer_oa/tr_shade_calc.c | 12 ++++++++ code/renderercommon/tr_types.h | 4 +++ 5 files changed, 70 insertions(+), 1 deletion(-) diff --git a/code/renderer_oa/tr_backend.c b/code/renderer_oa/tr_backend.c index e33cf4d7e8..869e11ab41 100644 --- a/code/renderer_oa/tr_backend.c +++ b/code/renderer_oa/tr_backend.c @@ -1457,6 +1457,7 @@ void RB_ShowImages( void ) { image_t *image; float x, y, w, h; int start, end; + float col = 1 * tr.identityLight; // leilei - overbright fix if ( !backEnd.projection2D ) { RB_SetGL2D(); @@ -1484,6 +1485,7 @@ void RB_ShowImages( void ) { GL_Bind( image ); qglBegin (GL_QUADS); + qglColor3f (col,col,col); // leilei - overbright fix qglTexCoord2f( 0, 0 ); qglVertex2f( x, y ); qglTexCoord2f( 1, 0 ); diff --git a/code/renderer_oa/tr_image.c b/code/renderer_oa/tr_image.c index 407d7866eb..13941f1c3d 100644 --- a/code/renderer_oa/tr_image.c +++ b/code/renderer_oa/tr_image.c @@ -2354,6 +2354,56 @@ image_t *R_FindImageFileIfItsThere( const char *name, imgType_t type, imgFlags_t } + + +/* +================ +Rebecca Heineman + + 1963-2025 + +Jennell Jaquays + + 1956-2024 +================ +*/ + +static void R_ebeccaHeineman( void ) { + int x,y; + byte data[16][16][4]; + + for (x=0 ; x<16 ; x++) { + for (y=0 ; y<16 ; y++) { + + if (y<3 || y>12) // blue + { + data[y][x][0] = 31; + data[y][x][1] = 206; + data[y][x][2] = 250; + } + else if (y<6 || y>9) // pink + { + data[y][x][0] = 245; + data[y][x][1] = 169; + data[y][x][2] = 184; + } + else // white + { + data[y][x][0] = 255; + data[y][x][1] = 255; + data[y][x][2] = 255; + } + // data[y][x][0] = + // data[y][x][1] = + // data[y][x][2] = b; + data[y][x][3] = 255; + } + } + tr.transRights = R_CreateImage("thankYouRebeccaHeineman&JennellJaquays", (byte *)data, 16, 16, IMGTYPE_COLORALPHA, IMGFLAG_CLAMPTOEDGE, 0 ); +} + + + /* ================ R_CreateDlightImage @@ -2561,6 +2611,7 @@ void R_CreateBuiltinImages( void ) { tr.scratchImage[x] = R_CreateImage("*scratch", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_PICMIP | IMGFLAG_CLAMPTOEDGE, 0); } + R_ebeccaHeineman(); R_CreateDlightImage(); diff --git a/code/renderer_oa/tr_local.h b/code/renderer_oa/tr_local.h index f8a3913e79..0ae6b4aae6 100644 --- a/code/renderer_oa/tr_local.h +++ b/code/renderer_oa/tr_local.h @@ -1317,7 +1317,7 @@ typedef struct { qboolean placeholderFogAvail; qboolean placeholderAvail; - + image_t *transRights; // leilei } trGlobals_t; diff --git a/code/renderer_oa/tr_shade_calc.c b/code/renderer_oa/tr_shade_calc.c index 4e72dedab0..41f44a2f1b 100644 --- a/code/renderer_oa/tr_shade_calc.c +++ b/code/renderer_oa/tr_shade_calc.c @@ -1845,6 +1845,13 @@ void RB_CalcDiffuseColor( unsigned char *colors ) RB_CalcDiffuseColor_scalar( colors ); } + // leilei - glow property + if ((backEnd.currentEntity->e.glow >= 1337 && backEnd.currentEntity->e.glow <= 1340 )) // look for 1337-1340 as compatibility so we don't get malformed glows from old cgames + { + RB_GlowBlend( colors, backEnd.currentEntity->e.glowcol, (backEnd.currentEntity->e.glow - 1337) ); + } + + } @@ -2203,6 +2210,11 @@ void RB_CalcMaterials( unsigned char *colors, int ambient, int diffuse, int spec // TODO: Low detail materials RB_CalcMaterialColor( colors, 1, ambient, diffuse, specular, emissive, spechard, alpha ); + // leilei - glow property + if ((backEnd.currentEntity->e.glow >= 1337 && backEnd.currentEntity->e.glow <= 1340 )) // look for 1337-1340 as compatibility so we don't get malformed glows from old cgames + { + RB_GlowBlend( colors, backEnd.currentEntity->e.glowcol, (backEnd.currentEntity->e.glow - 1337) ); + } } diff --git a/code/renderercommon/tr_types.h b/code/renderercommon/tr_types.h index 0f382ba551..c70a6078f6 100644 --- a/code/renderercommon/tr_types.h +++ b/code/renderercommon/tr_types.h @@ -122,6 +122,10 @@ typedef struct { vec3_t eyepos[2]; // looking from vec3_t eyelook; // looking from + // leilei - glow + + int glow; // glow security + fx + int glowcol; // glow color in hexadecimal } refEntity_t; From d8d245842fcd9b7933ec5cf1bdde0fd577a9b84f Mon Sep 17 00:00:00 2001 From: leilei- Date: Fri, 21 Nov 2025 17:44:14 -0500 Subject: [PATCH 20/20] RB_UVcolor: casting as gcc 14 hates this line makefile - because gcc 14 is fussier, i'll do this wrt VMA for now. --- Makefile | 1 + code/renderer_oa/tr_shade_calc.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 18ae5e7007..a26fc79599 100644 --- a/Makefile +++ b/Makefile @@ -1183,6 +1183,7 @@ BASE_CFLAGS += -Wformat=2 -Wno-format-zero-length -Wformat-security -Wno-format- BASE_CFLAGS += -Wstrict-aliasing=2 -Wmissing-format-attribute BASE_CFLAGS += -Wdisabled-optimization BASE_CFLAGS += -Werror-implicit-function-declaration +BASE_CFLAGS += -Wno-int-conversion ifeq ($(V),1) echo_cmd=@: diff --git a/code/renderer_oa/tr_shade_calc.c b/code/renderer_oa/tr_shade_calc.c index 41f44a2f1b..bc56b854da 100644 --- a/code/renderer_oa/tr_shade_calc.c +++ b/code/renderer_oa/tr_shade_calc.c @@ -1588,7 +1588,7 @@ static void RB_UVColor( unsigned char *colors, int glowcol, int fx ) v = tess.xyz[0]; normal = tess.normal[0]; - texc = tess.texCoords[0]; + texc = (float*) tess.texCoords[0]; numVertexes = tess.numVertexes; for (i = 0 ; i < numVertexes ; i++, v += 4, texc+=2 ) {