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
# Begin Source File
SOURCE=.\global\r_weather.cpp
# End Source File
# Begin Source File
SOURCE=.\global\tempents.cpp
# End Source File
# Begin Source File
@ -289,6 +293,10 @@ SOURCE=.\global\r_particle.h
# End Source File
# Begin Source File
SOURCE=.\global\r_weather.h
# End Source File
# Begin Source File
SOURCE=.\global\utils.h
# End Source File
# Begin Source File

View File

@ -11,6 +11,7 @@
#include "r_particle.h"
#include "ev_hldm.h"
#include "pm_shared.h"
#include "r_weather.h"
cl_enginefuncs_t g_engfuncs;
cl_globalvars_t *gpGlobals;
@ -70,6 +71,8 @@ int HUD_VidInit( void )
{
if( g_pParticleSystems )
g_pParticleSystems->ClearSystems();
ResetRain ();
gHUD.VidInit();
@ -96,7 +99,9 @@ void HUD_Init( void )
delete g_pParticleSystems;
g_pParticleSystems = NULL;
}
g_pParticleSystems = new ParticleSystemManager();
InitRain(); // init weather system
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 LOAD_FILE (*g_engfuncs.pfnLoadFile)
#define FILE_EXISTS (*g_engfuncs.pfnFileExists)
#define FREE_FILE FREE
#define FREE_FILE (*g_engfuncs.pfnFreeFile)
#define DELETE_FILE (*g_engfuncs.pfnRemoveFile)
#define LOAD_LIBRARY (*g_engfuncs.pfnLoadLibrary)
#define GET_PROC_ADDRESS (*g_engfuncs.pfnGetProcAddress)

View File

@ -118,7 +118,7 @@ void ParticleSystemManager::UpdateSystems( void )
ParticleSystem* pLast = NULL;
ParticleSystem*pLastSorted = NULL;
// SortSystems();
SortSystems();
pSystem = m_pFirstSystem;
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 "utils.h"
#include "r_particle.h"
#include "r_weather.h"
void HUD_DrawTriangles( void )
{
@ -13,6 +14,7 @@ void HUD_DrawTriangles( void )
void HUD_DrawTransparentTriangles( void )
{
R_DrawWeather();
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 );
}
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
// 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 Draw_VidInit( void );
// mathlib
extern void AngleMatrix( const vec3_t angles, float (*matrix)[4] );
// from cl_view.c
extern void DrawProgressBar( void );
extern edict_t *spot;

View File

@ -204,10 +204,10 @@ typedef enum
} walkmove_t;
// 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_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_STRAFE 1 // moves in direction specified, no matter which way monster is facing
#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_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
// edict movetype
typedef enum
@ -318,10 +318,6 @@ typedef enum
#define CL_ACTIVE 2 // draw normal hud
#define CL_PAUSED 3 // pause when active
// client key destination
#define KEY_GAME 1
#define KEY_HUDMENU 2
// built-in particle-system flags
#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_THIRDPERSON (1<<5) // enable chase cam instead firstperson
// engine built-in default shader
#define MAP_DEFAULT_SHADER "*black"
// client modelindexes
#define NULLENT_INDEX -1 // engine always return NULL, only for internal use
#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

View File

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

View File

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

View File

@ -890,8 +890,6 @@ void CL_InitWorld( void )
ent->v.movetype = MOVETYPE_PUSH;
clgame.globals->numEntities = 1;
clgame.globals->mapname = MAKE_STRING( cl.configstrings[CS_NAME] );
clgame.globals->coop = Cvar_VariableInteger( "coop" );
clgame.globals->teamplay = Cvar_VariableInteger( "teamplay" );
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
@ -2314,6 +2393,7 @@ static efxapi_t gEfxApi =
pfnFindExplosionPlane,
pfnDecalIndexFromName,
pfnDecalIndex,
pfnLightForPoint,
};
static event_api_t gEventApi =
@ -2326,6 +2406,12 @@ static event_api_t gEventApi =
pfnRandomLong,
pfnHookEvent,
pfnKillEvents,
pfnPlaySound,
pfnStopSound,
pfnFindModelIndex,
pfnIsLocal,
pfnLocalPlayerViewheight,
pfnStopAllSounds
};
// engine callbacks

View File

@ -700,7 +700,9 @@ void CL_PrepVideo( void )
Cvar_SetValue( "scr_loading", 0.0f ); // reset progress bar
MsgDev( D_LOAD, "CL_PrepVideo: %s\n", cl.configstrings[CS_NAME] );
// 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 );
CM_BeginRegistration( mapname, true, &map_checksum );
re->BeginRegistration( mapname, CM_VisData()); // load map

View File

@ -552,6 +552,7 @@ void CL_ClearEffects( void );
void CL_TestLights( void );
void CL_TestEntities( void );
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 );
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 );

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_HEIGHT 480
extern cvar_t *scr_width;

View File

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

View File

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

View File

@ -64,15 +64,10 @@ void CBaseParticle::Spawn( void )
{
Precache();
pev->origin.z += 72;
UTIL_SetModel( edict(), "sprites/null.spr" );
UTIL_SetOrigin( this, pev->origin );
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 ))
m_iState = STATE_ON;
else m_iState = STATE_OFF;

View File

@ -155,14 +155,14 @@ Beta 13.12.09
129. fixup sound orientation OK
130. don't show console on changelevel 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
134. dx sound engine complete OK
135. implement dsp OK
136. re-vision uimenu
137. complete rewriting physic.dll OK
138. implement hashtable for loaded sounds OK
139. finalize triangle API
139. finalize triangle API OK
140. net_msg is buggly!!!! OK
141. implement client predicting OK
142. finalize CL_Move and CL_LinkEdict OK
@ -188,7 +188,7 @@ Beta 13.12.09
162. rewrote auto-classify OK
163. rewrote sv_phys.c OK
164. remove vprogs.dll OK
165. finalize EventAPI
165. finalize EventAPI OK
166. move cl_input.c into client.dll OK
167. fix all founded errors
168. release at 13/12/2009

View File

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

View File

@ -643,6 +643,7 @@ void R_DrawMeshes( void )
int i;
meshbuffer_t *meshbuf;
Tri_RenderCallback( false );
RI.previousentity = NULL;
if( RI.meshlist->num_opaque_meshes )
{
@ -652,8 +653,8 @@ void R_DrawMeshes( void )
R_BatchMeshBuffer( meshbuf, NULL );
}
Tri_RenderCallback( false );
Tri_RenderCallback( true );
if( RI.meshlist->num_translucent_meshes )
{
meshbuf = RI.meshlist->meshbuffer_translucent;
@ -662,8 +663,6 @@ void R_DrawMeshes( void )
R_BatchMeshBuffer( meshbuf, NULL );
}
Tri_RenderCallback( true );
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 )
@ -125,7 +125,7 @@ int CreateNewFloatPlane( vec3_t normal, vec_t dist )
p = &mapplanes[nummapplanes];
VectorCopy( normal, p->normal );
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 );
(p+1)->dist = -dist;

View File

@ -53,6 +53,7 @@ byte* bsp_base;
bool bsp_halflife = false;
dmiptexname_t *mipnames = NULL;
int mip_count = 0;
file_t *detail_txt;
bool MipExist( const char *name )
{
@ -67,10 +68,77 @@ bool MipExist( const char *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 )
{
dmiptexlump_t *m;
string genericname;
const char *det_name;
mip_t *mip;
int i, k;
int *dofs, size;
@ -83,6 +151,8 @@ void Conv_BspTextures( const char *name, dlump_t *l, const char *ext )
m->nummiptex = LittleLong( m->nummiptex );
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 ));
mip_count = 0;
@ -94,9 +164,15 @@ void Conv_BspTextures( const char *name, dlump_t *l, const char *ext )
// needs to simulate directly loading
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
// 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
k = com.strlen( com.strrchr( mip->name, '*' ));
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
}
mip_count = 0; // freed and invaliadte
FS_Close( detail_txt );
}
/*