09 Dec 2009

This commit is contained in:
g-cont 2009-12-09 00:00:00 +03:00 committed by Alibek Omarov
parent fea3c34e68
commit e2027e6330
24 changed files with 1022 additions and 41 deletions

View File

@ -225,6 +225,10 @@ SOURCE=.\global\r_particle.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\global\r_weather.cpp
# End Source File
# Begin Source File
SOURCE=.\global\tempents.cpp SOURCE=.\global\tempents.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -289,6 +293,10 @@ SOURCE=.\global\r_particle.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\global\r_weather.h
# End Source File
# Begin Source File
SOURCE=.\global\utils.h SOURCE=.\global\utils.h
# End Source File # End Source File
# Begin Source File # Begin Source File

View File

@ -11,6 +11,7 @@
#include "r_particle.h" #include "r_particle.h"
#include "ev_hldm.h" #include "ev_hldm.h"
#include "pm_shared.h" #include "pm_shared.h"
#include "r_weather.h"
cl_enginefuncs_t g_engfuncs; cl_enginefuncs_t g_engfuncs;
cl_globalvars_t *gpGlobals; cl_globalvars_t *gpGlobals;
@ -71,6 +72,8 @@ int HUD_VidInit( void )
if( g_pParticleSystems ) if( g_pParticleSystems )
g_pParticleSystems->ClearSystems(); g_pParticleSystems->ClearSystems();
ResetRain ();
gHUD.VidInit(); gHUD.VidInit();
return 1; return 1;
@ -96,7 +99,9 @@ void HUD_Init( void )
delete g_pParticleSystems; delete g_pParticleSystems;
g_pParticleSystems = NULL; g_pParticleSystems = NULL;
} }
g_pParticleSystems = new ParticleSystemManager(); g_pParticleSystems = new ParticleSystemManager();
InitRain(); // init weather system
gHUD.Init(); gHUD.Init();

View File

@ -136,7 +136,7 @@ inline void CL_PlaySound( int iSound, float flVolume, Vector &pos, float pitch =
#define RANDOM_FLOAT (*g_engfuncs.pEventAPI->EV_RandomFloat) #define RANDOM_FLOAT (*g_engfuncs.pEventAPI->EV_RandomFloat)
#define LOAD_FILE (*g_engfuncs.pfnLoadFile) #define LOAD_FILE (*g_engfuncs.pfnLoadFile)
#define FILE_EXISTS (*g_engfuncs.pfnFileExists) #define FILE_EXISTS (*g_engfuncs.pfnFileExists)
#define FREE_FILE FREE #define FREE_FILE (*g_engfuncs.pfnFreeFile)
#define DELETE_FILE (*g_engfuncs.pfnRemoveFile) #define DELETE_FILE (*g_engfuncs.pfnRemoveFile)
#define LOAD_LIBRARY (*g_engfuncs.pfnLoadLibrary) #define LOAD_LIBRARY (*g_engfuncs.pfnLoadLibrary)
#define GET_PROC_ADDRESS (*g_engfuncs.pfnGetProcAddress) #define GET_PROC_ADDRESS (*g_engfuncs.pfnGetProcAddress)

View File

@ -118,7 +118,7 @@ void ParticleSystemManager::UpdateSystems( void )
ParticleSystem* pLast = NULL; ParticleSystem* pLast = NULL;
ParticleSystem*pLastSorted = NULL; ParticleSystem*pLastSorted = NULL;
// SortSystems(); SortSystems();
pSystem = m_pFirstSystem; pSystem = m_pFirstSystem;
while( pSystem ) while( pSystem )

698
client/global/r_weather.cpp Normal file
View File

@ -0,0 +1,698 @@
//=======================================================================
// Copyright (C) Shambler Team 2005
// rain.cpp - TriAPI weather effects
// based on original code from BUzer
//=======================================================================
#include "extdll.h"
#include "utils.h"
#include "effects_api.h"
#include "triangle_api.h"
#include "hud.h"
#include "r_weather.h"
void WaterLandingEffect( cl_drip *drip );
void ParseRainFile( void );
cl_drip FirstChainDrip;
cl_rainfx FirstChainFX;
double rain_curtime; // current time
double rain_oldtime; // last time we have updated drips
double rain_timedelta; // difference between old time and current time
double rain_nextspawntime; // when the next drip should be spawned
cvar_t *cl_debugrain;
int dripcounter = 0;
int fxcounter = 0;
HSPRITE hsprWaterRing;
HSPRITE hsprDripTexture;
/*
=================================
ProcessRain
Must think every frame.
=================================
*/
void ProcessRain( void )
{
rain_oldtime = rain_curtime; // save old time
rain_curtime = GetClientTime();
rain_timedelta = rain_curtime - rain_oldtime;
// first frame
if ( rain_oldtime == 0 )
{
// fix first frame bug with nextspawntime
rain_nextspawntime = GetClientTime();
ParseRainFile();
return;
}
if ( gHUD.Rain.dripsPerSecond == 0 && FirstChainDrip.p_Next == NULL )
{
// keep nextspawntime correct
rain_nextspawntime = rain_curtime;
return;
}
if ( v_paused ) return; // not in pause
double timeBetweenDrips = 1 / (double)gHUD.Rain.dripsPerSecond;
cl_drip* curDrip = FirstChainDrip.p_Next;
cl_drip* nextDrip = NULL;
edict_t *player = GetLocalPlayer();
if( !player ) return; // not in game
// save debug info
float debug_lifetime = 0;
int debug_howmany = 0;
int debug_attempted = 0;
int debug_dropped = 0;
while ( curDrip != NULL ) // go through list
{
nextDrip = curDrip->p_Next; // save pointer to next drip
if ( gHUD.Rain.weatherMode == 0 )
curDrip->origin.z -= rain_timedelta * DRIPSPEED; // rain
else curDrip->origin.z -= rain_timedelta * SNOWSPEED; // snow
curDrip->origin.x += rain_timedelta * curDrip->xDelta;
curDrip->origin.y += rain_timedelta * curDrip->yDelta;
// remove drip if its origin lower than minHeight
if ( curDrip->origin.z < curDrip->minHeight )
{
if ( curDrip->landInWater/* && gHUD.Rain.weatherMode == 0*/ )
WaterLandingEffect( curDrip ); // create water rings
if ( cl_debugrain->value )
{
debug_lifetime += (rain_curtime - curDrip->birthTime);
debug_howmany++;
}
curDrip->p_Prev->p_Next = curDrip->p_Next; // link chain
if ( nextDrip != NULL )
nextDrip->p_Prev = curDrip->p_Prev;
delete curDrip;
dripcounter--;
}
curDrip = nextDrip; // restore pointer, so we can continue moving through chain
}
int maxDelta; // maximum height randomize distance
float falltime;
if ( gHUD.Rain.weatherMode == 0 )
{
maxDelta = DRIPSPEED * rain_timedelta; // for rain
falltime = (gHUD.Rain.globalHeight + 4096) / DRIPSPEED;
}
else
{
maxDelta = SNOWSPEED * rain_timedelta; // for snow
falltime = (gHUD.Rain.globalHeight + 4096) / SNOWSPEED;
}
while ( rain_nextspawntime < rain_curtime )
{
rain_nextspawntime += timeBetweenDrips;
if ( cl_debugrain->value ) debug_attempted++;
if ( dripcounter < MAXDRIPS ) // check for overflow
{
float deathHeight;
Vector vecStart, vecEnd;
vecStart[0] = RANDOM_FLOAT( player->v.origin.x - gHUD.Rain.distFromPlayer, player->v.origin.x + gHUD.Rain.distFromPlayer );
vecStart[1] = RANDOM_FLOAT( player->v.origin.y - gHUD.Rain.distFromPlayer, player->v.origin.y + gHUD.Rain.distFromPlayer );
vecStart[2] = gHUD.Rain.globalHeight;
float xDelta = gHUD.Rain.windX + RANDOM_FLOAT( gHUD.Rain.randX * -1, gHUD.Rain.randX );
float yDelta = gHUD.Rain.windY + RANDOM_FLOAT( gHUD.Rain.randY * -1, gHUD.Rain.randY );
// find a point at bottom of map
vecEnd[0] = falltime * xDelta;
vecEnd[1] = falltime * yDelta;
vecEnd[2] = -4096;
TraceResult tr;
TRACE_HULL( vecStart, vecStart + vecEnd, true, 1, player, &tr );
if ( tr.fStartSolid || tr.fAllSolid )
{
if ( cl_debugrain->value > 1 )
debug_dropped++;
continue; // drip cannot be placed
}
// falling to water?
int contents = POINT_CONTENTS( tr.vecEndPos );
if ( contents == CONTENTS_WATER )
{
// NOTE: in Xash3D PM_WaterEntity always return a valid water volume or NULL
// so not needs to run additional checks here
edict_t *pWater = g_engfuncs.pfnWaterEntity( tr.vecEndPos );
if ( pWater )
{
deathHeight = pWater->v.maxs[2];
}
else
{
// hit the world
deathHeight = tr.vecEndPos[2];
}
}
else
{
deathHeight = tr.vecEndPos[2];
}
// just in case..
if ( deathHeight > vecStart[2] )
{
ALERT( at_error, "rain: can't create drip in water\n" );
continue;
}
cl_drip *newClDrip = new cl_drip;
if ( !newClDrip )
{
gHUD.Rain.dripsPerSecond = 0; // disable rain
ALERT( at_error, "rain: failed to allocate object!\n");
return;
}
vecStart[2] -= RANDOM_FLOAT( 0, maxDelta ); // randomize a bit
newClDrip->alpha = RANDOM_FLOAT( 0.12, 0.2 );
newClDrip->origin = vecStart;
newClDrip->xDelta = xDelta;
newClDrip->yDelta = yDelta;
newClDrip->birthTime = rain_curtime; // store time when it was spawned
newClDrip->minHeight = deathHeight;
if ( contents == CONTENTS_WATER )
newClDrip->landInWater = 1;
else newClDrip->landInWater = 0;
// add to first place in chain
newClDrip->p_Next = FirstChainDrip.p_Next;
newClDrip->p_Prev = &FirstChainDrip;
if ( newClDrip->p_Next != NULL )
newClDrip->p_Next->p_Prev = newClDrip;
FirstChainDrip.p_Next = newClDrip;
dripcounter++;
}
else
{
if ( cl_debugrain->value )
ALERT( at_error, "rain: drip limit overflow! %i > %i\n", dripcounter, MAXDRIPS );
return;
}
}
if ( cl_debugrain->value ) // print debug info
{
ALERT( at_console, "Rain info: Drips exist: %i\n", dripcounter );
ALERT( at_console, "Rain info: FX's exist: %i\n", fxcounter );
ALERT( at_console, "Rain info: Attempted/Dropped: %i, %i\n", debug_attempted, debug_dropped );
if ( debug_howmany )
{
float ave = debug_lifetime / (float)debug_howmany;
ALERT( at_console, "Rain info: Average drip life time: %f\n", ave);
}
else ALERT( at_console, "Rain info: Average drip life time: --\n" );
}
return;
}
/*
=================================
WaterLandingEffect
=================================
*/
void WaterLandingEffect( cl_drip *drip )
{
if ( fxcounter >= MAXFX )
{
ALERT( at_console, "Rain error: FX limit overflow!\n" );
return;
}
cl_rainfx *newFX = new cl_rainfx;
if ( !newFX )
{
ALERT( at_console, "Rain error: failed to allocate FX object!\n");
return;
}
newFX->alpha = RANDOM_FLOAT( 0.6, 0.9 );
newFX->origin = drip->origin;
newFX->origin[2] = drip->minHeight; // correct position
newFX->birthTime = GetClientTime();
newFX->life = RANDOM_FLOAT( 0.7f, 1.0f );
// add to first place in chain
newFX->p_Next = FirstChainFX.p_Next;
newFX->p_Prev = &FirstChainFX;
if ( newFX->p_Next != NULL )
newFX->p_Next->p_Prev = newFX;
FirstChainFX.p_Next = newFX;
fxcounter++;
}
/*
=================================
ProcessFXObjects
Remove all fx objects with out time to live
Call every frame before ProcessRain
=================================
*/
void ProcessFXObjects( void )
{
float curtime = GetClientTime();
cl_rainfx* curFX = FirstChainFX.p_Next;
cl_rainfx* nextFX = NULL;
while ( curFX != NULL ) // go through FX objects list
{
nextFX = curFX->p_Next; // save pointer to next
// delete current?
if (( curFX->birthTime + curFX->life ) < curtime )
{
curFX->p_Prev->p_Next = curFX->p_Next; // link chain
if ( nextFX != NULL )
nextFX->p_Prev = curFX->p_Prev;
delete curFX;
fxcounter--;
}
curFX = nextFX; // restore pointer
}
}
/*
=================================
ResetRain
clear memory, delete all objects
=================================
*/
void ResetRain( void )
{
// delete all drips
cl_drip* delDrip = FirstChainDrip.p_Next;
FirstChainDrip.p_Next = NULL;
while ( delDrip != NULL )
{
cl_drip* nextDrip = delDrip->p_Next; // save pointer to next drip in chain
delete delDrip;
delDrip = nextDrip; // restore pointer
dripcounter--;
}
// delete all FX objects
cl_rainfx* delFX = FirstChainFX.p_Next;
FirstChainFX.p_Next = NULL;
while ( delFX != NULL )
{
cl_rainfx* nextFX = delFX->p_Next;
delete delFX;
delFX = nextFX;
fxcounter--;
}
InitRain();
return;
}
/*
=================================
InitRain
initialze system
=================================
*/
void InitRain( void )
{
cl_debugrain = CVAR_REGISTER( "cl_debugrain", "0", 0, "display rain debug info (trace missing, drops etc)" );
gHUD.Rain.dripsPerSecond = 0;
gHUD.Rain.distFromPlayer = 0;
gHUD.Rain.windX = 0;
gHUD.Rain.windY = 0;
gHUD.Rain.randX = 0;
gHUD.Rain.randY = 0;
gHUD.Rain.weatherMode = 0;
gHUD.Rain.globalHeight = 0;
FirstChainDrip.birthTime = 0;
FirstChainDrip.minHeight = 0;
FirstChainDrip.origin[0]=0;
FirstChainDrip.origin[1]=0;
FirstChainDrip.origin[2]=0;
FirstChainDrip.alpha = 0;
FirstChainDrip.xDelta = 0;
FirstChainDrip.yDelta = 0;
FirstChainDrip.landInWater = 0;
FirstChainDrip.p_Next = NULL;
FirstChainDrip.p_Prev = NULL;
FirstChainFX.alpha = 0;
FirstChainFX.birthTime = 0;
FirstChainFX.life = 0;
FirstChainFX.origin[0] = 0;
FirstChainFX.origin[1] = 0;
FirstChainFX.origin[2] = 0;
FirstChainFX.p_Next = NULL;
FirstChainFX.p_Prev = NULL;
rain_oldtime = 0;
rain_curtime = 0;
rain_nextspawntime = 0;
// engine will be free unused shaders after each change map
// so reload it again
hsprWaterRing = 0;
hsprDripTexture = 0;
return;
}
/*
===========================
ParseRainFile
List of settings:
drips - max raindrips\snowflakes
distance - radius of rain\snow
windx - wind shift X
windy - wind shift Y
randx - random shift X
randy - random shift Y
mode - rain = 0\snow =1
height - max height to create raindrips\snowflakes
===========================
*/
void ParseRainFile( void )
{
if ( gHUD.Rain.distFromPlayer != 0 || gHUD.Rain.dripsPerSecond != 0 || gHUD.Rain.globalHeight != 0 )
return;
char mapname[256], filepath[256];
const char *token = NULL;
const char *pfile;
char *afile;
strcpy( mapname, STRING( gpGlobals->mapname ));
if ( strlen( mapname ) == 0 )
{
ALERT( at_error, "rain: unable to read map name\n" );
return;
}
// Xash3D always set bare mapname without path and extension
// mapname[strlen(mapname)-4] = 0;
sprintf( filepath, "scripts/weather/%s.txt", mapname );
afile = (char *)LOAD_FILE( filepath, NULL );
pfile = afile;
if ( !pfile )
{
if (cl_debugrain->value > 1 )
ALERT( at_error, "rain: couldn't open rain settings file %s\n", mapname );
return;
}
while ( true )
{
token = COM_ParseToken( &pfile );
if( !token ) break;
if ( !stricmp( token, "drips" )) // dripsPerSecond
{
token = COM_ParseToken( &pfile );
gHUD.Rain.dripsPerSecond = atoi( token );
}
else if ( !stricmp( token, "distance" )) // distFromPlayer
{
token = COM_ParseToken( &pfile );
gHUD.Rain.distFromPlayer = atof( token );
}
else if ( !stricmp( token, "windx" )) // windX
{
token = COM_ParseToken( &pfile );
gHUD.Rain.windX = atof( token );
}
else if ( !stricmp( token, "windy" )) // windY
{
token = COM_ParseToken( &pfile );
gHUD.Rain.windY = atof( token );
}
else if ( !stricmp( token, "randx" )) // randX
{
token = COM_ParseToken( &pfile );
gHUD.Rain.randX = atof( token );
}
else if ( !stricmp( token, "randy" )) // randY
{
token = COM_ParseToken( &pfile );
gHUD.Rain.randY = atof( token );
}
else if ( !stricmp( token, "mode" )) // weatherMode
{
token = COM_ParseToken( &pfile );
gHUD.Rain.weatherMode = atoi( token );
}
else if ( !stricmp( token, "height" )) // globalHeight
{
token = COM_ParseToken( &pfile );
gHUD.Rain.globalHeight = atof( token );
}
else ALERT( at_error, "rain: unknown token %s in file %s\n", token, mapname );
}
FREE_FILE( afile );
}
//-----------------------------------------------------
void SetPoint( float x, float y, float z, float (*matrix)[4] )
{
Vector point = Vector( x, y, z ), result;
result.x = DotProduct( point, matrix[0] ) + matrix[0][3];
result.y = DotProduct( point, matrix[1] ) + matrix[1][3];
result.z = DotProduct( point, matrix[2] ) + matrix[2][3];
g_engfuncs.pTriAPI->Vertex3f( result[0], result[1], result[2] );
}
/*
=================================
DrawRain
draw raindrips and snowflakes
=================================
*/
void DrawRain( void )
{
if ( FirstChainDrip.p_Next == NULL )
return; // no drips to draw
if( hsprDripTexture == 0 )
{
if ( gHUD.Rain.weatherMode == 0 )
{
// load rain sprite
hsprDripTexture = g_engfuncs.pTriAPI->LoadShader( "sprites/raindrop.spr", false );
}
else
{
// load snow sprite
hsprDripTexture = g_engfuncs.pTriAPI->LoadShader( "sprites/snowflake.spr", false );
}
}
if( hsprDripTexture <= 0 ) return;
float visibleHeight = gHUD.Rain.globalHeight - SNOWFADEDIST;
// usual triapi stuff
g_engfuncs.pTriAPI->Enable( TRI_SHADER );
g_engfuncs.pTriAPI->Bind( hsprDripTexture, 0 );
g_engfuncs.pTriAPI->RenderMode( kRenderTransAdd );
g_engfuncs.pTriAPI->CullFace( TRI_NONE );
// go through drips list
cl_drip *Drip = FirstChainDrip.p_Next;
edict_t *player = GetLocalPlayer();
if( !player ) return; // not in game yet
if ( gHUD.Rain.weatherMode == 0 ) // draw rain
{
while ( Drip != NULL )
{
cl_drip* nextdDrip = Drip->p_Next;
Vector2D toPlayer;
toPlayer.x = player->v.origin[0] - Drip->origin[0];
toPlayer.y = player->v.origin[1] - Drip->origin[1];
toPlayer = toPlayer.Normalize();
toPlayer.x *= DRIP_SPRITE_HALFWIDTH;
toPlayer.y *= DRIP_SPRITE_HALFWIDTH;
float shiftX = (Drip->xDelta / DRIPSPEED) * DRIP_SPRITE_HALFHEIGHT;
float shiftY = (Drip->yDelta / DRIPSPEED) * DRIP_SPRITE_HALFHEIGHT;
g_engfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, Drip->alpha );
g_engfuncs.pTriAPI->Begin( TRI_TRIANGLES );
g_engfuncs.pTriAPI->TexCoord2f( 0, 0 );
g_engfuncs.pTriAPI->Vertex3f( Drip->origin[0]-toPlayer.y - shiftX, Drip->origin[1]+toPlayer.x - shiftY,Drip->origin[2] + DRIP_SPRITE_HALFHEIGHT );
g_engfuncs.pTriAPI->TexCoord2f( 0.5, 1 );
g_engfuncs.pTriAPI->Vertex3f( Drip->origin[0] + shiftX, Drip->origin[1] + shiftY, Drip->origin[2]-DRIP_SPRITE_HALFHEIGHT );
g_engfuncs.pTriAPI->TexCoord2f( 1, 0 );
g_engfuncs.pTriAPI->Vertex3f( Drip->origin[0]+toPlayer.y - shiftX, Drip->origin[1]-toPlayer.x - shiftY, Drip->origin[2]+DRIP_SPRITE_HALFHEIGHT);
g_engfuncs.pTriAPI->End();
Drip = nextdDrip;
}
}
else // draw snow
{
Vector normal;
GetViewAngles( (float *)normal );
float matrix[3][4];
AngleMatrix( normal, matrix ); // calc view matrix
while ( Drip != NULL )
{
cl_drip* nextdDrip = Drip->p_Next;
matrix[0][3] = Drip->origin[0]; // write origin to matrix
matrix[1][3] = Drip->origin[1];
matrix[2][3] = Drip->origin[2];
// apply start fading effect
float alpha = (Drip->origin[2] <= visibleHeight) ? Drip->alpha : ((gHUD.Rain.globalHeight - Drip->origin[2]) / (float)SNOWFADEDIST) * Drip->alpha;
g_engfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, alpha );
g_engfuncs.pTriAPI->Begin( TRI_QUADS );
g_engfuncs.pTriAPI->TexCoord2f( 0, 0 );
SetPoint( 0, SNOW_SPRITE_HALFSIZE, SNOW_SPRITE_HALFSIZE, matrix );
g_engfuncs.pTriAPI->TexCoord2f( 0, 1 );
SetPoint( 0, SNOW_SPRITE_HALFSIZE, -SNOW_SPRITE_HALFSIZE, matrix );
g_engfuncs.pTriAPI->TexCoord2f( 1, 1 );
SetPoint( 0, -SNOW_SPRITE_HALFSIZE, -SNOW_SPRITE_HALFSIZE, matrix );
g_engfuncs.pTriAPI->TexCoord2f( 1, 0 );
SetPoint( 0, -SNOW_SPRITE_HALFSIZE, SNOW_SPRITE_HALFSIZE, matrix );
g_engfuncs.pTriAPI->End();
Drip = nextdDrip;
}
}
g_engfuncs.pTriAPI->Disable( TRI_SHADER );
}
/*
=================================
DrawFXObjects
=================================
*/
void DrawFXObjects( void )
{
if ( FirstChainFX.p_Next == NULL )
return; // no objects to draw
float curtime = GetClientTime();
// usual triapi stuff
if( hsprWaterRing == 0 ) // in case what we don't want search it if not found
{
// load water ring sprite
hsprWaterRing = g_engfuncs.pTriAPI->LoadShader( "sprites/waterring.spr", false );
}
if( hsprWaterRing <= 0 ) return; // don't waste time
g_engfuncs.pTriAPI->Enable( TRI_SHADER );
g_engfuncs.pTriAPI->Bind( hsprWaterRing, 0 );
g_engfuncs.pTriAPI->RenderMode( kRenderTransAdd );
g_engfuncs.pTriAPI->CullFace( TRI_NONE );
// go through objects list
cl_rainfx* curFX = FirstChainFX.p_Next;
while ( curFX != NULL )
{
cl_rainfx* nextFX = curFX->p_Next;
// fadeout
float alpha = ((curFX->birthTime + curFX->life - curtime) / curFX->life) * curFX->alpha;
float size = (curtime - curFX->birthTime) * MAXRINGHALFSIZE;
float color[3];
// UNDONE: calc lighting right
g_engfuncs.pEfxAPI->R_LightForPoint( (const float *)curFX->origin, color );
// ALERT( at_console, "color %g %g %g\n", color[0], color[1], color[2] );
g_engfuncs.pTriAPI->Color4f( 0.4 + color[0], 0.4 + color[1], 0.4 + color[2], alpha );
g_engfuncs.pTriAPI->Begin( TRI_QUADS );
g_engfuncs.pTriAPI->TexCoord2f( 0, 0 );
g_engfuncs.pTriAPI->Vertex3f( curFX->origin[0] - size, curFX->origin[1] - size, curFX->origin[2] );
g_engfuncs.pTriAPI->TexCoord2f( 0, 1 );
g_engfuncs.pTriAPI->Vertex3f( curFX->origin[0] - size, curFX->origin[1] + size, curFX->origin[2] );
g_engfuncs.pTriAPI->TexCoord2f( 1, 1 );
g_engfuncs.pTriAPI->Vertex3f( curFX->origin[0] + size, curFX->origin[1] + size, curFX->origin[2] );
g_engfuncs.pTriAPI->TexCoord2f( 1, 0 );
g_engfuncs.pTriAPI->Vertex3f( curFX->origin[0] + size, curFX->origin[1] - size, curFX->origin[2] );
g_engfuncs.pTriAPI->End();
curFX = nextFX;
}
g_engfuncs.pTriAPI->Disable( TRI_SHADER );
}
/*
=================================
DrawAll
=================================
*/
void R_DrawWeather( void )
{
ProcessFXObjects();
ProcessRain();
DrawRain();
DrawFXObjects();
}

65
client/global/r_weather.h Normal file
View File

@ -0,0 +1,65 @@
/***
*
* Copyright (c) 1996-2004, Shambler Team. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Shambler Team. All other use, distribution, or modification is prohibited
* without written permission from Shambler Team.
*
****/
/*
====== rain.h ========================================================
*/
#ifndef __RAIN_H__
#define __RAIN_H__
#define DRIPSPEED 900 // speed of raindrips (pixel per secs)
#define SNOWSPEED 200 // speed of snowflakes
#define SNOWFADEDIST 80
#define MAXDRIPS 3000 // max raindrops
#define MAXFX 3000 // max effects
#define DRIP_SPRITE_HALFHEIGHT 46
#define DRIP_SPRITE_HALFWIDTH 8
#define SNOW_SPRITE_HALFSIZE 3
// radius water rings
#define MAXRINGHALFSIZE 25
typedef struct cl_drip
{
float birthTime;
float minHeight; // minimal height to kill raindrop
vec3_t origin;
float alpha;
float xDelta; // side speed
float yDelta;
int landInWater;
cl_drip* p_Next; // next drip in chain
cl_drip* p_Prev; // previous drip in chain
} cl_drip_t;
typedef struct cl_rainfx
{
float birthTime;
float life;
vec3_t origin;
float alpha;
cl_rainfx* p_Next; // next fx in chain
cl_rainfx* p_Prev; // previous fx in chain
} cl_rainfx_t;
void R_DrawWeather( void );
void ResetRain( void );
void InitRain( void );
#endif

View File

@ -6,6 +6,7 @@
#include "extdll.h" #include "extdll.h"
#include "utils.h" #include "utils.h"
#include "r_particle.h" #include "r_particle.h"
#include "r_weather.h"
void HUD_DrawTriangles( void ) void HUD_DrawTriangles( void )
{ {
@ -13,6 +14,7 @@ void HUD_DrawTriangles( void )
void HUD_DrawTransparentTriangles( void ) void HUD_DrawTransparentTriangles( void )
{ {
R_DrawWeather();
g_pParticleSystems->UpdateSystems(); g_pParticleSystems->UpdateSystems();
} }

View File

@ -357,6 +357,36 @@ void DrawProgressBar( void )
DrawImageBar( CVAR_GET_FLOAT( "scr_download" ), "m_download", (ScreenWidth - 128)>>1, ScreenHeight - 60 ); DrawImageBar( CVAR_GET_FLOAT( "scr_download" ), "m_download", (ScreenWidth - 128)>>1, ScreenHeight - 60 );
} }
void AngleMatrix( const vec3_t angles, float (*matrix)[4] )
{
float angle;
float sr, sp, sy, cr, cp, cy;
angle = angles[YAW] * (M_PI*2 / 360);
sy = sin( angle );
cy = cos( angle );
angle = angles[PITCH] * (M_PI*2 / 360);
sp = sin( angle );
cp = cos( angle );
angle = angles[ROLL] * (M_PI*2 / 360);
sr = sin( angle );
cr = cos( angle );
// matrix = (YAW * PITCH) * ROLL
matrix[0][0] = cp*cy;
matrix[1][0] = cp*sy;
matrix[2][0] = -sp;
matrix[0][1] = sr*sp*cy+cr*-sy;
matrix[1][1] = sr*sp*sy+cr*cy;
matrix[2][1] = sr*cp;
matrix[0][2] = (cr*sp*cy+-sr*-sy);
matrix[1][2] = (cr*sp*sy+-sr*cy);
matrix[2][2] = cr*cp;
matrix[0][3] = 0.0;
matrix[1][3] = 0.0;
matrix[2][3] = 0.0;
}
// //
// hl2 fade - this supports multiple fading // hl2 fade - this supports multiple fading
// FIXME: make Class CHudFade instead of C-style code? // FIXME: make Class CHudFade instead of C-style code?

View File

@ -166,6 +166,9 @@ extern void DrawGenericBar( float percent, int w, int h );
extern void DrawGenericBar( float percent, int x, int y, int w, int h ); extern void DrawGenericBar( float percent, int x, int y, int w, int h );
extern void Draw_VidInit( void ); extern void Draw_VidInit( void );
// mathlib
extern void AngleMatrix( const vec3_t angles, float (*matrix)[4] );
// from cl_view.c // from cl_view.c
extern void DrawProgressBar( void ); extern void DrawProgressBar( void );
extern edict_t *spot; extern edict_t *spot;

View File

@ -204,10 +204,10 @@ typedef enum
} walkmove_t; } walkmove_t;
// monster's move to origin stuff // monster's move to origin stuff
#define MOVE_START_TURN_DIST 64 // when this far away from moveGoal, start turning to face next goal #define MOVE_START_TURN_DIST 64 // when this far away from moveGoal, start turning to face next goal
#define MOVE_STUCK_DIST 32 // if a monster can't step this far, it is stuck. #define MOVE_STUCK_DIST 32 // if a monster can't step this far, it is stuck.
#define MOVE_NORMAL 0 // normal move in the direction monster is facing #define MOVE_NORMAL 0 // normal move in the direction monster is facing
#define MOVE_STRAFE 1 // moves in direction specified, no matter which way monster is facing #define MOVE_STRAFE 1 // moves in direction specified, no matter which way monster is facing
// edict movetype // edict movetype
typedef enum typedef enum
@ -318,10 +318,6 @@ typedef enum
#define CL_ACTIVE 2 // draw normal hud #define CL_ACTIVE 2 // draw normal hud
#define CL_PAUSED 3 // pause when active #define CL_PAUSED 3 // pause when active
// client key destination
#define KEY_GAME 1
#define KEY_HUDMENU 2
// built-in particle-system flags // built-in particle-system flags
#define PARTICLE_GRAVITY 40 // default particle gravity #define PARTICLE_GRAVITY 40 // default particle gravity
@ -347,21 +343,8 @@ typedef enum
#define RDF_NOFOVADJUSTMENT (1<<4) // do not adjust fov for widescreen #define RDF_NOFOVADJUSTMENT (1<<4) // do not adjust fov for widescreen
#define RDF_THIRDPERSON (1<<5) // enable chase cam instead firstperson #define RDF_THIRDPERSON (1<<5) // enable chase cam instead firstperson
// engine built-in default shader
#define MAP_DEFAULT_SHADER "*black"
// client modelindexes // client modelindexes
#define NULLENT_INDEX -1 // engine always return NULL, only for internal use #define NULLENT_INDEX -1 // engine always return NULL, only for internal use
#define VIEWENT_INDEX -2 // can get viewmodel for local client #define VIEWENT_INDEX -2 // can get viewmodel for local client
// basic console charwidths
#define TINYCHAR_WIDTH (SMALLCHAR_WIDTH)
#define TINYCHAR_HEIGHT (SMALLCHAR_HEIGHT/2)
#define SMALLCHAR_WIDTH 8
#define SMALLCHAR_HEIGHT 16
#define BIGCHAR_WIDTH 16
#define BIGCHAR_HEIGHT 24
#define GIANTCHAR_WIDTH 32
#define GIANTCHAR_HEIGHT 48
#endif//CONST_H #endif//CONST_H

View File

@ -52,6 +52,7 @@ typedef struct efxapi_s
void (*CL_FindExplosionPlane)( const float *origin, float radius, float *result ); void (*CL_FindExplosionPlane)( const float *origin, float radius, float *result );
int (*CL_DecalIndexFromName)( const char *szDecalName ); int (*CL_DecalIndexFromName)( const char *szDecalName );
int (*CL_DecalIndex)( int id ); int (*CL_DecalIndex)( int id );
void (*R_LightForPoint)( const float *rgflOrigin, float *lightValue );
} efxapi_t; } efxapi_t;
#endif//EFFECTS_API_H #endif//EFFECTS_API_H

View File

@ -1117,6 +1117,12 @@ bool pfnAddParticle( cparticle_t *src, HSPRITE shader, int flags )
return true; return true;
} }
void pfnLightForPoint( const vec3_t point, vec3_t ambientLight )
{
if( re ) re->LightForPoint( point, ambientLight );
else VectorClear( ambientLight );
}
/* /*
=============== ===============
CL_ResetEvent CL_ResetEvent

View File

@ -890,8 +890,6 @@ void CL_InitWorld( void )
ent->v.movetype = MOVETYPE_PUSH; ent->v.movetype = MOVETYPE_PUSH;
clgame.globals->numEntities = 1; clgame.globals->numEntities = 1;
clgame.globals->mapname = MAKE_STRING( cl.configstrings[CS_NAME] );
clgame.globals->coop = Cvar_VariableInteger( "coop" ); clgame.globals->coop = Cvar_VariableInteger( "coop" );
clgame.globals->teamplay = Cvar_VariableInteger( "teamplay" ); clgame.globals->teamplay = Cvar_VariableInteger( "teamplay" );
clgame.globals->deathmatch = Cvar_VariableInteger( "deathmatch" ); clgame.globals->deathmatch = Cvar_VariableInteger( "deathmatch" );
@ -1961,6 +1959,87 @@ static void pfnKillEvents( int entnum, const char *eventname )
} }
} }
/*
=============
pfnPlaySound
=============
*/
void pfnPlaySound( edict_t *ent, float *org, int chan, const char *samp, float vol, float attn, int flags, int pitch )
{
int entindex = 0;
if( CL_IsValidEdict( ent )) entindex = ent->serialnumber;
S_StartSound( org, entindex, chan, S_RegisterSound( samp ), vol, attn, pitch, flags );
}
/*
=============
pfnStopSound
=============
*/
void pfnStopSound( int ent, int channel, const char *sample )
{
S_StartSound( vec3_origin, ent, channel, S_RegisterSound( sample ), 1.0f, ATTN_NORM, PITCH_NORM, SND_STOP );
}
/*
=============
pfnFindModelIndex
=============
*/
int pfnFindModelIndex( const char *model )
{
int i;
if( !model || !*model ) return 0;
for( i = 1; i < MAX_MODELS; i++ )
{
if( !com.strcmp( model, cl.configstrings[CS_MODELS+i] ))
return i;
}
return 0;
}
/*
=============
pfnIsLocal
=============
*/
int pfnIsLocal( int playernum )
{
if( playernum == cl.playernum )
return true;
return false;
}
/*
=============
pfnLocalPlayerViewheight
=============
*/
void pfnLocalPlayerViewheight( float *view_ofs )
{
// predicted or smoothed
if( view_ofs ) VectorCopy( cl.predicted_viewofs, view_ofs );
}
/*
=============
pfnStopAllSounds
=============
*/
void pfnStopAllSounds( edict_t *ent, int entchannel )
{
// FIXME: this not valid code
S_StopAllSounds ();
}
/* /*
============= =============
VGui_GetPanel VGui_GetPanel
@ -2314,6 +2393,7 @@ static efxapi_t gEfxApi =
pfnFindExplosionPlane, pfnFindExplosionPlane,
pfnDecalIndexFromName, pfnDecalIndexFromName,
pfnDecalIndex, pfnDecalIndex,
pfnLightForPoint,
}; };
static event_api_t gEventApi = static event_api_t gEventApi =
@ -2326,6 +2406,12 @@ static event_api_t gEventApi =
pfnRandomLong, pfnRandomLong,
pfnHookEvent, pfnHookEvent,
pfnKillEvents, pfnKillEvents,
pfnPlaySound,
pfnStopSound,
pfnFindModelIndex,
pfnIsLocal,
pfnLocalPlayerViewheight,
pfnStopAllSounds
}; };
// engine callbacks // engine callbacks

View File

@ -700,7 +700,9 @@ void CL_PrepVideo( void )
Cvar_SetValue( "scr_loading", 0.0f ); // reset progress bar Cvar_SetValue( "scr_loading", 0.0f ); // reset progress bar
MsgDev( D_LOAD, "CL_PrepVideo: %s\n", cl.configstrings[CS_NAME] ); MsgDev( D_LOAD, "CL_PrepVideo: %s\n", cl.configstrings[CS_NAME] );
// let the render dll load the map // let the render dll load the map
clgame.globals->mapname = MAKE_STRING( cl.configstrings[CS_NAME] );
com.strncpy( mapname, cl.configstrings[CS_MODELS+1], MAX_STRING ); com.strncpy( mapname, cl.configstrings[CS_MODELS+1], MAX_STRING );
CM_BeginRegistration( mapname, true, &map_checksum ); CM_BeginRegistration( mapname, true, &map_checksum );
re->BeginRegistration( mapname, CM_VisData()); // load map re->BeginRegistration( mapname, CM_VisData()); // load map

View File

@ -552,6 +552,7 @@ void CL_ClearEffects( void );
void CL_TestLights( void ); void CL_TestLights( void );
void CL_TestEntities( void ); void CL_TestEntities( void );
void CL_FindExplosionPlane( const vec3_t origin, float radius, vec3_t result ); void CL_FindExplosionPlane( const vec3_t origin, float radius, vec3_t result );
void pfnLightForPoint( const vec3_t point, vec3_t ambientLight );
bool pfnAddParticle( cparticle_t *src, HSPRITE shader, int flags ); bool pfnAddParticle( cparticle_t *src, HSPRITE shader, int flags );
void pfnAddDecal( float *org, float *dir, float *rgba, float rot, float rad, HSPRITE hSpr, int flags ); void pfnAddDecal( float *org, float *dir, float *rgba, float rot, float rad, HSPRITE hSpr, int flags );
void pfnAddDLight( const float *org, const float *rgb, float radius, float time, int flags, int key ); void pfnAddDLight( const float *org, const float *rgb, float radius, float time, int flags, int key );

View File

@ -30,6 +30,16 @@
============================================================== ==============================================================
*/ */
// basic console charwidths
#define TINYCHAR_WIDTH (SMALLCHAR_WIDTH)
#define TINYCHAR_HEIGHT (SMALLCHAR_HEIGHT/2)
#define SMALLCHAR_WIDTH 8
#define SMALLCHAR_HEIGHT 16
#define BIGCHAR_WIDTH 16
#define BIGCHAR_HEIGHT 24
#define GIANTCHAR_WIDTH 32
#define GIANTCHAR_HEIGHT 48
#define SCREEN_WIDTH 640 #define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480 #define SCREEN_HEIGHT 480
extern cvar_t *scr_width; extern cvar_t *scr_width;

View File

@ -20,6 +20,7 @@
#define bound(min, num, max) ((num) >= (min) ? ((num) < (max) ? (num) : (max)) : (min)) #define bound(min, num, max) ((num) >= (min) ? ((num) < (max) ? (num) : (max)) : (min))
#define MAX_STRING_TABLES 8 // seperately stringsystems #define MAX_STRING_TABLES 8 // seperately stringsystems
#define MAX_MODS 128 // environment games that engine can keep visible #define MAX_MODS 128 // environment games that engine can keep visible
#define MAP_DEFAULT_SHADER "*black" // engine built-in default shader
#ifndef __cplusplus #ifndef __cplusplus
#define bool BOOL // sizeof( int ) #define bool BOOL // sizeof( int )
#endif #endif

View File

@ -35,6 +35,7 @@ public:
}; };
LINK_ENTITY_TO_CLASS( func_wall, CFuncWall ); LINK_ENTITY_TO_CLASS( func_wall, CFuncWall );
LINK_ENTITY_TO_CLASS( func_static, CFuncWall ); LINK_ENTITY_TO_CLASS( func_static, CFuncWall );
LINK_ENTITY_TO_CLASS( func_bossgate, CFuncWall );
LINK_ENTITY_TO_CLASS( func_wall_toggle, CFuncWall ); LINK_ENTITY_TO_CLASS( func_wall_toggle, CFuncWall );
LINK_ENTITY_TO_CLASS( func_illusionary, CFuncWall ); LINK_ENTITY_TO_CLASS( func_illusionary, CFuncWall );
@ -42,11 +43,19 @@ void CFuncWall :: Spawn( void )
{ {
CBaseBrush::Spawn(); CBaseBrush::Spawn();
if(FClassnameIs(pev, "func_illusionary" )) if( FClassnameIs( pev, "func_illusionary" ))
{ {
pev->solid = SOLID_NOT; pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_NONE; pev->movetype = MOVETYPE_NONE;
} }
else if( FClassnameIs( pev, "func_bossgate" ))
{
if(( gpGlobals->serverflags & 15 ) == 15 )
{
UTIL_Remove( this );
return; // all episodes completed
}
}
else else
{ {
pev->solid = SOLID_BSP; pev->solid = SOLID_BSP;

View File

@ -64,15 +64,10 @@ void CBaseParticle::Spawn( void )
{ {
Precache(); Precache();
pev->origin.z += 72;
UTIL_SetModel( edict(), "sprites/null.spr" ); UTIL_SetModel( edict(), "sprites/null.spr" );
UTIL_SetOrigin( this, pev->origin ); UTIL_SetOrigin( this, pev->origin );
pev->solid = SOLID_NOT; pev->solid = SOLID_NOT;
// TESTONLY: don't forget to remove
pev->angles = Vector( 0, 90, 0 );
if( pev->spawnflags & SF_START_ON || FStringNull( pev->targetname )) if( pev->spawnflags & SF_START_ON || FStringNull( pev->targetname ))
m_iState = STATE_ON; m_iState = STATE_ON;
else m_iState = STATE_OFF; else m_iState = STATE_OFF;

View File

@ -155,14 +155,14 @@ Beta 13.12.09
129. fixup sound orientation OK 129. fixup sound orientation OK
130. don't show console on changelevel OK 130. don't show console on changelevel OK
131. fixup teleports and trigger push's OK 131. fixup teleports and trigger push's OK
132. implement _detail.txt lists for hl 132. implement _detail.txt lists for hl OK
133. new sound\render system version replacement OK 133. new sound\render system version replacement OK
134. dx sound engine complete OK 134. dx sound engine complete OK
135. implement dsp OK 135. implement dsp OK
136. re-vision uimenu 136. re-vision uimenu
137. complete rewriting physic.dll OK 137. complete rewriting physic.dll OK
138. implement hashtable for loaded sounds OK 138. implement hashtable for loaded sounds OK
139. finalize triangle API 139. finalize triangle API OK
140. net_msg is buggly!!!! OK 140. net_msg is buggly!!!! OK
141. implement client predicting OK 141. implement client predicting OK
142. finalize CL_Move and CL_LinkEdict OK 142. finalize CL_Move and CL_LinkEdict OK
@ -188,7 +188,7 @@ Beta 13.12.09
162. rewrote auto-classify OK 162. rewrote auto-classify OK
163. rewrote sv_phys.c OK 163. rewrote sv_phys.c OK
164. remove vprogs.dll OK 164. remove vprogs.dll OK
165. finalize EventAPI 165. finalize EventAPI OK
166. move cl_input.c into client.dll OK 166. move cl_input.c into client.dll OK
167. fix all founded errors 167. fix all founded errors
168. release at 13/12/2009 168. release at 13/12/2009

View File

@ -1670,7 +1670,7 @@ void R_ModifyColor( const ref_stage_t *pass )
} }
break; break;
case RGBGEN_LIGHTING_AMBIENT_ONLY: case RGBGEN_LIGHTING_AMBIENT_ONLY:
if( RI.currententity && !( RI.params & RP_SHADOWMAPVIEW ) ) if( RI.currententity && !( RI.params & RP_SHADOWMAPVIEW ))
{ {
vec4_t ambient; vec4_t ambient;

View File

@ -643,6 +643,7 @@ void R_DrawMeshes( void )
int i; int i;
meshbuffer_t *meshbuf; meshbuffer_t *meshbuf;
Tri_RenderCallback( false );
RI.previousentity = NULL; RI.previousentity = NULL;
if( RI.meshlist->num_opaque_meshes ) if( RI.meshlist->num_opaque_meshes )
{ {
@ -652,8 +653,8 @@ void R_DrawMeshes( void )
R_BatchMeshBuffer( meshbuf, NULL ); R_BatchMeshBuffer( meshbuf, NULL );
} }
Tri_RenderCallback( false );
Tri_RenderCallback( true );
if( RI.meshlist->num_translucent_meshes ) if( RI.meshlist->num_translucent_meshes )
{ {
meshbuf = RI.meshlist->meshbuffer_translucent; meshbuf = RI.meshlist->meshbuffer_translucent;
@ -662,8 +663,6 @@ void R_DrawMeshes( void )
R_BatchMeshBuffer( meshbuf, NULL ); R_BatchMeshBuffer( meshbuf, NULL );
} }
Tri_RenderCallback( true );
R_LoadIdentity(); R_LoadIdentity();
} }

View File

@ -75,7 +75,7 @@ bool PlaneEqual( plane_t *p, vec3_t normal, vec_t dist )
/* /*
================= =================
PlaneTypeForNormal MapPlaneTypeForNormal
================= =================
*/ */
int MapPlaneTypeForNormal( const vec3_t normal ) int MapPlaneTypeForNormal( const vec3_t normal )
@ -125,7 +125,7 @@ int CreateNewFloatPlane( vec3_t normal, vec_t dist )
p = &mapplanes[nummapplanes]; p = &mapplanes[nummapplanes];
VectorCopy( normal, p->normal ); VectorCopy( normal, p->normal );
p->dist = dist; p->dist = dist;
p->type = (p+1)->type = PlaneTypeForNormal( p->normal ); p->type = (p+1)->type = MapPlaneTypeForNormal( p->normal );
VectorSubtract( vec3_origin, normal, (p+1)->normal ); VectorSubtract( vec3_origin, normal, (p+1)->normal );
(p+1)->dist = -dist; (p+1)->dist = -dist;

View File

@ -53,6 +53,7 @@ byte* bsp_base;
bool bsp_halflife = false; bool bsp_halflife = false;
dmiptexname_t *mipnames = NULL; dmiptexname_t *mipnames = NULL;
int mip_count = 0; int mip_count = 0;
file_t *detail_txt;
bool MipExist( const char *name ) bool MipExist( const char *name )
{ {
@ -67,10 +68,77 @@ bool MipExist( const char *name )
return FS_FileExists( name ); return FS_FileExists( name );
} }
static const char *DetailTextureForName( const char *name )
{
if( !name || !*name ) return NULL;
if( !com.strnicmp( name, "sky", 3 ))
return NULL; // never details for sky
// never apply details for liquids
if( !com.strnicmp( name + 1, "!lava", 5 ))
return NULL;
if( !com.strnicmp( name + 1, "!slime", 6 ))
return NULL;
if( !com.strnicmp( name, "!cur_90", 7 ))
return NULL;
if( !com.strnicmp( name, "!cur_0", 6 ))
return NULL;
if( !com.strnicmp( name, "!cur_270", 8 ))
return NULL;
if( !com.strnicmp( name, "!cur_180", 8 ))
return NULL;
if( !com.strnicmp( name, "!cur_up", 7 ))
return NULL;
if( !com.strnicmp( name, "!cur_dwn", 8 ))
return NULL;
if( name[0] == '!' )
return NULL;
// never apply details to the special textures
if( !com.strnicmp( name, "origin", 6 ))
return NULL;
if( !com.strnicmp( name, "clip", 4 ))
return NULL;
if( !com.strnicmp( name, "hint", 4 ))
return NULL;
if( !com.strnicmp( name, "skip", 4 ))
return NULL;
if( !com.strnicmp( name, "translucent", 11 ))
return NULL;
if( !com.strnicmp( name, "3dsky", 5 ))
return NULL;
if( name[0] == '@' )
return NULL;
// last check ...
if( !com.strnicmp( name, "null", 4 ))
return NULL;
// at this point we can apply detail textures to the current
if( com.stristr( name, "brick" )) return "dt_brick";
if( com.stristr( name, "carpet" )) return "dt_carpet1";
if( com.stristr( name, "crete" )) return "dt_conc";
if( com.stristr( name, "generic" )) return va( "dt_fabric%i", Com_RandomLong( 1, 2 ));
if( com.stristr( name, "grass" )) return "dt_grass1";
if( com.stristr( name, "ground" ) || com.stristr( name, "gnd" ))
return va( "dt_ground%i", Com_RandomLong( 1, 5 ));
if( com.stristr( name, "metal" ) || com.stristr( name, "metl" ))
return va( "dt_metal%i", Com_RandomLong( 1, 2 ));
if( com.stristr( name, "rock" )) return "dt_rock1";
if( com.stristr( name, "snow" )) return va( "dt_snow%i", Com_RandomLong( 1, 2 ));
if( com.stristr( name, "stone" )) return va( "dt_stone%i", Com_RandomLong( 1, 4 ));
if( com.stristr( name, "steel" )) return "dt_steel1";
if( com.stristr( name, "wood" )) return va( "dt_wood%i", Com_RandomLong( 1, 3 ));
// apply default detail texture
return "dt_brick";
}
void Conv_BspTextures( const char *name, dlump_t *l, const char *ext ) void Conv_BspTextures( const char *name, dlump_t *l, const char *ext )
{ {
dmiptexlump_t *m; dmiptexlump_t *m;
string genericname; string genericname;
const char *det_name;
mip_t *mip; mip_t *mip;
int i, k; int i, k;
int *dofs, size; int *dofs, size;
@ -83,6 +151,8 @@ void Conv_BspTextures( const char *name, dlump_t *l, const char *ext )
m->nummiptex = LittleLong( m->nummiptex ); m->nummiptex = LittleLong( m->nummiptex );
dofs = m->dataofs; dofs = m->dataofs;
detail_txt = FS_Open( va( "%s/%s_detail.txt", gs_gamedir, name ), "wb" );
mipnames = Mem_Realloc( basepool, mipnames, m->nummiptex * sizeof( dmiptexname_t )); mipnames = Mem_Realloc( basepool, mipnames, m->nummiptex * sizeof( dmiptexname_t ));
mip_count = 0; mip_count = 0;
@ -94,9 +164,15 @@ void Conv_BspTextures( const char *name, dlump_t *l, const char *ext )
// needs to simulate directly loading // needs to simulate directly loading
mip = (mip_t *)((byte *)m + dofs[i]); mip = (mip_t *)((byte *)m + dofs[i]);
if( !LittleLong( mip->offsets[0] )) continue; // not in bsp
// build detailtexture string
det_name = DetailTextureForName( mip->name ); // lookup both registers
com.strnlwr( mip->name, mip->name, sizeof( mip->name )); // name com.strnlwr( mip->name, mip->name, sizeof( mip->name )); // name
// detailtexture detected
if( det_name ) FS_Printf( detail_txt, "%s detail/%s 10.0 10.0\n", mip->name, det_name );
if( !LittleLong( mip->offsets[0] )) continue; // not in bsp, skipped
// check for '*' symbol issues // check for '*' symbol issues
k = com.strlen( com.strrchr( mip->name, '*' )); k = com.strlen( com.strrchr( mip->name, '*' ));
if( k ) mip->name[com.strlen(mip->name)-k] = '!'; // quake1 issues if( k ) mip->name[com.strlen(mip->name)-k] = '!'; // quake1 issues
@ -124,6 +200,7 @@ void Conv_BspTextures( const char *name, dlump_t *l, const char *ext )
ConvMIP( va("%s/%s", name, mip->name ), buffer, size, ext ); // convert it ConvMIP( va("%s/%s", name, mip->name ), buffer, size, ext ); // convert it
} }
mip_count = 0; // freed and invaliadte mip_count = 0; // freed and invaliadte
FS_Close( detail_txt );
} }
/* /*