a1batross 2020-08-31 01:15:53 +03:00
commit 0455f5d6e2
833 changed files with 366356 additions and 0 deletions

31
backup.bat Normal file
View File

@ -0,0 +1,31 @@
@echo off
color 4F
echo XashXT Group 2006 (C)
echo Prepare source for backup
echo.
if exist backup.log del /f /q backup.log
if not exist D:\Paranoia2\!backup/ mkdir D:\Paranoia2\!backup\
echo Prepare OK!
echo Please wait: backup in progress
C:\Progra~1\WinRar\rar a -agMMMYYYY-DD D:\Paranoia2\!backup\.rar -dh -m5 @backup.lst >>backup.log
if errorlevel 1 goto error
if errorlevel 0 goto ok
:ok
cls
echo Source was sucessfully backuped
echo and stored in folder "backup"
echo Press any key for exit. :-)
if exist backup.log del /f /q backup.log
exit
:error
echo ******************************
echo ***********Error!*************
echo ******************************
echo **See backup.log for details**
echo ******************************
echo ******************************
echo.
echo press any key for exit :-(
pause>nul
exit

45
backup.lst Normal file
View File

@ -0,0 +1,45 @@
//=======================================================================
// Copyright XashXT Group 2007 ©
// list with backup directories
//=======================================================================
// global stuff
paranoia_sdk.dsw
debug.bat
backup.lst
backup.bat
release.bat
cl_dll\
cl_dll\hl\
cl_dll\render\
common\
dlls\
engine\
game_shared\
mainui\
mainui\legacy
p2_launch\
pm_shared\
utils\
utils\bsp31migrate\
utils\common\
utils\decal2tga\
utils\hlmv\
utils\hlsv\
utils\mxtk\
utils\makefont\
utils\maketex\
utils\makewad\
utils\p2bsp\
utils\p2csg\
utils\p2rad\
utils\p2vis\
utils\reqtest\
utils\squish\
utils\stalker2tga\
utils\spritegen\
utils\studiomdl\
utils\vgui\
utils\vgui\include\
utils\vgui\lib\win32_vc6\

124
bspextra.h Normal file
View File

@ -0,0 +1,124 @@
/*
bspfile.h - BSP format included q1, hl1 support
Copyright (C) 2010 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef BSPEXTRAFILE_H
#define BSPEXTRAFILE_H
/*
==============================================================================
EXTRA BSP INFO
==============================================================================
*/
#define IDEXTRAHEADER (('H'<<24)+('S'<<16)+('A'<<8)+'X') // little-endian "XASH"
#define EXTRA_VERSION 3 // ver. 1 was occupied by old versions of XashXT, ver. 2 was occupied by old vesrions of P2:savior
#define MAX_MAP_CUBEMAPS 1024
#define MAX_MAP_LANDSCAPES 8192 // can be increased but not needs
#define MAX_MAP_LEAFLIGHTS 0x40000 // can be increased but not needs
#define MAX_MAP_WORLDLIGHTS 65535 // including a light surfaces too
#define LUMP_VERTNORMALS 0 // phong shaded vertex normals
#define LUMP_LIGHTVECS 1 // deluxemap data
#define LUMP_CUBEMAPS 2 // cubemap description
#define LUMP_LANDSCAPES 3 // landscape and lightmap resolution info
#define LUMP_LEAF_LIGHTING 4 // contain compressed light cubes per empty leafs
#define LUMP_WORLDLIGHTS 5 // list of all the virtual and real lights (used to relight models in-game)
#define LUMP_COLLISION 6 // physics engine collision hull dump
#define LUMP_AINODEGRAPH 7 // node graph that stored into the bsp
#define EXTRA_LUMPS 8 // count of the extra lumps
#define LM_ENVIRONMENT_STYLE 20 // light_environment always handle into separate style, so we can ignore it
typedef struct
{
int id; // must be little endian XASH
int version;
dlump_t lumps[EXTRA_LUMPS];
} dextrahdr_t;
// MODIFIED: int flags -> short flags, short landscape (total struct size not changed!)
typedef struct
{
float vecs[2][4]; // texmatrix [s/t][xyz offset]
int miptex;
short flags;
short landscape;
} dtexinfo_t;
//============================================================================
typedef struct
{
float normal[3];
} dnormal_t;
typedef struct
{
short origin[3]; // position of light snapped to the nearest integer
short size; // cubemap side size
} dcubemap_t;
typedef struct
{
byte color[6][3]; // 6 sides 1x1 (single pixel per side)
} dsample_t;
typedef struct
{
dsample_t cube;
short origin[3];
short leafnum; // leaf that contain this sample
} dleafambient_t;
typedef struct
{
char landname[16]; // name of decsription in mapname_land.txt
word texture_step; // default is 16, pixels\luxels ratio
word max_extent; // default is 16, subdivision step ((texture_step * max_extent) - texture_step)
short groupid; // to determine equal landscapes from various groups
} dlandscape_t;
typedef enum
{
emit_surface,
emit_point,
emit_spotlight,
emit_skylight
} emittype_t;
#define VERTEXNORMAL_CONE_INNER_ANGLE DEG2RAD( 7.275 )
#define DWL_FLAGS_INAMBIENTCUBE 0x0001 // This says that the light was put into the per-leaf ambient cubes.
typedef struct
{
byte emittype;
byte style;
byte flags; // will be set in ComputeLeafAmbientLighting
short origin[3]; // light abs origin
float intensity[3]; // RGB
float normal[3]; // for surfaces and spotlights
float stopdot; // for spotlights
float stopdot2; // for spotlights
float fade; // falloff scaling for linear and inverse square falloff 1.0 = normal, 0.5 = farther, 2.0 = shorter etc
float radius; // light radius
short leafnum; // light linked into this leaf
byte falloff; // falloff style 0 = default (inverse square), 1 = inverse falloff, 2 = inverse square (arghrad compat)
word facenum; // face number for emit_surface
short modelnumber; // g-cont. we can't link lights with entities by entity number so we link it by bmodel number
} dworldlight_t;
#endif//BSPFILE_H

1247
cl_dll/ammo.cpp Normal file

File diff suppressed because it is too large Load Diff

64
cl_dll/ammo.h Normal file
View File

@ -0,0 +1,64 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef __AMMO_H__
#define __AMMO_H__
#define MAX_WEAPON_NAME 128
#define WEAPON_FLAGS_SELECTONEMPTY 1
#define WEAPON_IS_ONTARGET 0x40
struct WEAPON
{
char szName[MAX_WEAPON_NAME];
int iAmmoType;
int iAmmo2Type;
int iMax1;
int iMax2;
int iSlot;
int iSlotPos;
int iFlags;
int iId;
int iClip;
int iCount; // # of itesm in plist
HSPRITE hActive;
wrect_t rcActive;
HSPRITE hInactive;
wrect_t rcInactive;
HSPRITE hNoAmmo; // buz
wrect_t rcNoAmmo; // buz
HSPRITE hAmmo;
wrect_t rcAmmo;
HSPRITE hAmmo2;
wrect_t rcAmmo2;
HSPRITE hCrosshair;
wrect_t rcCrosshair;
HSPRITE hAutoaim;
wrect_t rcAutoaim;
HSPRITE hZoomedCrosshair;
wrect_t rcZoomedCrosshair;
HSPRITE hZoomedAutoaim;
wrect_t rcZoomedAutoaim;
};
typedef int AMMO;
#endif

159
cl_dll/ammo_secondary.cpp Normal file
View File

@ -0,0 +1,159 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// ammo_secondary.cpp
//
// implementation of CHudAmmoSecondary class
//
#include "hud.h"
#include "cl_util.h"
#include <string.h>
#include <stdio.h>
#include "parsemsg.h"
DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoVal );
DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoIcon );
int CHudAmmoSecondary :: Init( void )
{
HOOK_MESSAGE( SecAmmoVal );
HOOK_MESSAGE( SecAmmoIcon );
gHUD.AddHudElem(this);
m_HUD_ammoicon = 0;
for ( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ )
m_iAmmoAmounts[i] = -1; // -1 means don't draw this value
Reset();
return 1;
}
void CHudAmmoSecondary :: Reset( void )
{
m_fFade = 0;
}
int CHudAmmoSecondary :: VidInit( void )
{
return 1;
}
int CHudAmmoSecondary :: Draw(float flTime)
{
if ( (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) )
return 1;
// draw secondary ammo icons above normal ammo readout
int a, x, y, r, g, b, AmmoWidth;
UnpackRGB( r, g, b, gHUD.m_iHUDColor ); //LRC
a = (int) max( MIN_ALPHA, m_fFade );
if (m_fFade > 0)
m_fFade -= (gHUD.m_flTimeDelta * 20); // slowly lower alpha to fade out icons
ScaleColors( r, g, b, a );
AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left;
y = ScreenHeight - (gHUD.m_iFontHeight*4); // this is one font height higher than the weapon ammo values
x = ScreenWidth - AmmoWidth;
if ( m_HUD_ammoicon )
{
// Draw the ammo icon
x -= (gHUD.GetSpriteRect(m_HUD_ammoicon).right - gHUD.GetSpriteRect(m_HUD_ammoicon).left);
y -= (gHUD.GetSpriteRect(m_HUD_ammoicon).top - gHUD.GetSpriteRect(m_HUD_ammoicon).bottom);
SPR_Set( gHUD.GetSprite(m_HUD_ammoicon), r, g, b );
SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_ammoicon) );
}
else
{ // move the cursor by the '0' char instead, since we don't have an icon to work with
x -= AmmoWidth;
y -= (gHUD.GetSpriteRect(gHUD.m_HUD_number_0).top - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).bottom);
}
// draw the ammo counts, in reverse order, from right to left
for ( int i = MAX_SEC_AMMO_VALUES-1; i >= 0; i-- )
{
if ( m_iAmmoAmounts[i] < 0 )
continue; // negative ammo amounts imply that they shouldn't be drawn
// half a char gap between the ammo number and the previous pic
x -= (AmmoWidth / 2);
// draw the number, right-aligned
x -= (gHUD.GetNumWidth( m_iAmmoAmounts[i], DHN_DRAWZERO ) * AmmoWidth);
gHUD.DrawHudNumber( x, y, DHN_DRAWZERO, m_iAmmoAmounts[i], r, g, b );
if ( i != 0 )
{
// draw the divider bar
x -= (AmmoWidth / 2);
FillRGBA(x, y, (AmmoWidth/10), gHUD.m_iFontHeight, r, g, b, a);
}
}
return 1;
}
// Message handler for Secondary Ammo Value
// accepts one value:
// string: sprite name
int CHudAmmoSecondary :: MsgFunc_SecAmmoIcon( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
m_HUD_ammoicon = gHUD.GetSpriteIndex( READ_STRING() );
return 1;
}
// Message handler for Secondary Ammo Icon
// Sets an ammo value
// takes two values:
// byte: ammo index
// byte: ammo value
int CHudAmmoSecondary :: MsgFunc_SecAmmoVal( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
int index = READ_BYTE();
if ( index < 0 || index >= MAX_SEC_AMMO_VALUES )
return 1;
m_iAmmoAmounts[index] = READ_BYTE();
m_iFlags |= HUD_ACTIVE;
// check to see if there is anything left to draw
int count = 0;
for ( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ )
{
count += max( 0, m_iAmmoAmounts[i] );
}
if ( count == 0 )
{ // the ammo fields are all empty, so turn off this hud area
m_iFlags &= ~HUD_ACTIVE;
return 1;
}
// make the icons light up
m_fFade = 200.0f;
return 1;
}

190
cl_dll/ammohistory.cpp Normal file
View File

@ -0,0 +1,190 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// ammohistory.cpp
//
#include "hud.h"
#include "cl_util.h"
#include "parsemsg.h"
#include <string.h>
#include <stdio.h>
#include "ammohistory.h"
HistoryResource gHR;
#define AMMO_PICKUP_GAP (gHR.iHistoryGap+5)
#define AMMO_PICKUP_PICK_HEIGHT (32 + (gHR.iHistoryGap * 2))
#define AMMO_PICKUP_HEIGHT_MAX (ScreenHeight - 100)
#define MAX_ITEM_NAME 32
int HISTORY_DRAW_TIME = 5;
// keep a list of items
struct ITEM_INFO
{
char szName[MAX_ITEM_NAME];
HSPRITE spr;
wrect_t rect;
};
void HistoryResource :: AddToHistory( int iType, int iId, int iCount )
{
if ( iType == HISTSLOT_AMMO && !iCount )
return; // no amount, so don't add
if ( (((AMMO_PICKUP_GAP * iCurrentHistorySlot) + AMMO_PICKUP_PICK_HEIGHT) > AMMO_PICKUP_HEIGHT_MAX) || (iCurrentHistorySlot >= MAX_HISTORY) )
{ // the pic would have to be drawn too high
// so start from the bottom
iCurrentHistorySlot = 0;
}
HIST_ITEM *freeslot = &rgAmmoHistory[iCurrentHistorySlot++]; // default to just writing to the first slot
HISTORY_DRAW_TIME = CVAR_GET_FLOAT( "hud_drawhistory_time" );
freeslot->type = iType;
freeslot->iId = iId;
freeslot->iCount = iCount;
freeslot->DisplayTime = gHUD.m_flTime + HISTORY_DRAW_TIME;
}
void HistoryResource :: AddToHistory( int iType, const char *szName, int iCount )
{
if ( iType != HISTSLOT_ITEM )
return;
if ( (((AMMO_PICKUP_GAP * iCurrentHistorySlot) + AMMO_PICKUP_PICK_HEIGHT) > AMMO_PICKUP_HEIGHT_MAX) || (iCurrentHistorySlot >= MAX_HISTORY) )
{ // the pic would have to be drawn too high
// so start from the bottom
iCurrentHistorySlot = 0;
}
HIST_ITEM *freeslot = &rgAmmoHistory[iCurrentHistorySlot++]; // default to just writing to the first slot
// I am really unhappy with all the code in this file
int i = gHUD.GetSpriteIndex( szName );
if ( i == -1 )
return; // unknown sprite name, don't add it to history
freeslot->iId = i;
freeslot->type = iType;
freeslot->iCount = iCount;
HISTORY_DRAW_TIME = CVAR_GET_FLOAT( "hud_drawhistory_time" );
freeslot->DisplayTime = gHUD.m_flTime + HISTORY_DRAW_TIME;
}
void HistoryResource :: CheckClearHistory( void )
{
for ( int i = 0; i < MAX_HISTORY; i++ )
{
if ( rgAmmoHistory[i].type )
return;
}
iCurrentHistorySlot = 0;
}
//
// Draw Ammo pickup history
//
int HistoryResource :: DrawAmmoHistory( float flTime )
{
for ( int i = 0; i < MAX_HISTORY; i++ )
{
if ( rgAmmoHistory[i].type )
{
rgAmmoHistory[i].DisplayTime = min( rgAmmoHistory[i].DisplayTime, gHUD.m_flTime + HISTORY_DRAW_TIME );
if ( rgAmmoHistory[i].DisplayTime <= flTime )
{ // pic drawing time has expired
memset( &rgAmmoHistory[i], 0, sizeof(HIST_ITEM) );
CheckClearHistory();
}
else if ( rgAmmoHistory[i].type == HISTSLOT_AMMO )
{
wrect_t rcPic;
HSPRITE *spr = gWR.GetAmmoPicFromWeapon( rgAmmoHistory[i].iId, rcPic );
int r, g, b;
UnpackRGB(r,g,b, gHUD.m_iHUDColor);
float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80;
ScaleColors(r, g, b, min(scale, 255) );
// Draw the pic
int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i));
int xpos = ScreenWidth - 24;
if ( spr && *spr ) // weapon isn't loaded yet so just don't draw the pic
{ // the dll has to make sure it has sent info the weapons you need
SPR_Set( *spr, r, g, b );
SPR_DrawAdditive( 0, xpos, ypos, &rcPic );
}
// Draw the number
gHUD.DrawHudNumberString( xpos - 10, ypos, xpos - 100, rgAmmoHistory[i].iCount, r, g, b );
}
else if ( rgAmmoHistory[i].type == HISTSLOT_WEAP )
{
WEAPON *weap = gWR.GetWeapon( rgAmmoHistory[i].iId );
if ( !weap )
return 1; // we don't know about the weapon yet, so don't draw anything
int r, g, b;
UnpackRGB(r,g,b, gHUD.m_iHUDColor);
if ( !gWR.HasAmmo( weap ) )
UnpackRGB(r,g,b, RGB_REDISH); // if the weapon doesn't have ammo, display it as red
float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80;
ScaleColors(r, g, b, min(scale, 255) );
int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i));
int xpos = ScreenWidth - (weap->rcInactive.right - weap->rcInactive.left);
SPR_Set( weap->hInactive, r, g, b );
SPR_DrawAdditive( 0, xpos, ypos, &weap->rcInactive );
}
else if ( rgAmmoHistory[i].type == HISTSLOT_ITEM )
{
int r, g, b;
if ( !rgAmmoHistory[i].iId )
continue; // sprite not loaded
wrect_t rect = gHUD.GetSpriteRect( rgAmmoHistory[i].iId );
UnpackRGB(r,g,b, gHUD.m_iHUDColor);
float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80;
ScaleColors(r, g, b, min(scale, 255) );
int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i));
int xpos = ScreenWidth - (rect.right - rect.left) - 10;
SPR_Set( gHUD.GetSprite( rgAmmoHistory[i].iId ), r, g, b );
SPR_DrawAdditive( 0, xpos, ypos, &rect );
}
}
}
return 1;
}

154
cl_dll/ammohistory.h Normal file
View File

@ -0,0 +1,154 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// ammohistory.h
//
// this is the max number of items in each bucket
#define MAX_WEAPON_POSITIONS MAX_WEAPON_SLOTS
extern WEAPON *gpActiveSel;
class WeaponsResource
{
public: // buz: made public to access from drawing code (valves idea about WR is suxx)
// Information about weapons & ammo
WEAPON rgWeapons[MAX_WEAPONS]; // Weapons Array
// counts of weapons * ammo
WEAPON* rgSlots[MAX_WEAPON_SLOTS+1][MAX_WEAPON_POSITIONS+1]; // The slots currently in use by weapons. The value is a pointer to the weapon; if it's NULL, no weapon is there
int riAmmo[MAX_AMMO_SLOTS]; // count of each ammo type
public:
void Init( void )
{
memset( rgWeapons, 0, sizeof rgWeapons );
Reset();
}
void Reset( void )
{
iOldWeaponBits = 0;
m_iSelectedColumn = -1;
memset( rgSlots, 0, sizeof rgSlots );
memset( riAmmo, 0, sizeof riAmmo );
}
///// WEAPON /////
int iOldWeaponBits;
WEAPON *GetWeapon( int iId ) { return &rgWeapons[iId]; }
void AddWeapon( WEAPON *wp )
{
rgWeapons[ wp->iId ] = *wp;
LoadWeaponSprites( &rgWeapons[ wp->iId ] );
}
void PickupWeapon( WEAPON *wp )
{
rgSlots[ wp->iSlot ][ wp->iSlotPos ] = wp;
if ((m_iSelectedColumn == wp->iSlot) && !gpActiveSel) // buz: menu active, but no weapons in this category
gpActiveSel = wp;
}
void DropWeapon( WEAPON *wp )
{
rgSlots[ wp->iSlot ][ wp->iSlotPos ] = NULL;
if (wp == gpActiveSel) // buz: removed current weapon
gpActiveSel = GetFirstPos( wp->iSlot );
}
void DropAllWeapons( void )
{
for ( int i = 0; i < MAX_WEAPONS; i++ )
{
if ( rgWeapons[i].iId )
DropWeapon( &rgWeapons[i] );
}
}
WEAPON* GetWeaponSlot( int slot, int pos ) { return rgSlots[slot][pos]; }
void LoadWeaponSprites( WEAPON* wp );
void LoadAllWeaponSprites( void );
WEAPON* GetFirstPos( int iSlot );
WEAPON* GetLastPos( int iSlot ); // buz
void SelectSlot( int iSlot, int fAdvance, int iDirection );
WEAPON* GetNextActivePos( int iSlot, int iSlotPos );
WEAPON* GetPrevActivePos( int iSlot, int iSlotPos ); // buz
int HasAmmo( WEAPON *p );
///// AMMO /////
AMMO GetAmmo( int iId ) { return iId; }
void SetAmmo( int iId, int iCount ) { riAmmo[ iId ] = iCount; }
int CountAmmo( int iId );
HSPRITE* GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect );
int m_iSelectedColumn; // buz: -1 means menu inactive
float m_rgColumnSizes[MAX_WEAPON_SLOTS]; // buz
};
extern WeaponsResource gWR;
#define MAX_HISTORY 12
enum {
HISTSLOT_EMPTY,
HISTSLOT_AMMO,
HISTSLOT_WEAP,
HISTSLOT_ITEM,
};
class HistoryResource
{
private:
struct HIST_ITEM {
int type;
float DisplayTime; // the time at which this item should be removed from the history
int iCount;
int iId;
};
HIST_ITEM rgAmmoHistory[MAX_HISTORY];
public:
void Init( void )
{
Reset();
}
void Reset( void )
{
memset( rgAmmoHistory, 0, sizeof rgAmmoHistory );
}
int iHistoryGap;
int iCurrentHistorySlot;
void AddToHistory( int iType, int iId, int iCount = 0 );
void AddToHistory( int iType, const char *szName, int iCount = 0 );
void CheckClearHistory( void );
int DrawAmmoHistory( float flTime );
};
extern HistoryResource gHR;

145
cl_dll/battery.cpp Normal file
View File

@ -0,0 +1,145 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// battery.cpp
//
// implementation of CHudBattery class
//
#include "hud.h"
#include "cl_util.h"
#include "parsemsg.h"
#include <string.h>
#include <stdio.h>
#include "vgui_TeamFortressViewport.h" // buz
#include "vgui_hud.h" // buz
DECLARE_MESSAGE(m_Battery, Battery)
int CHudBattery::Init(void)
{
m_iBat = 0;
m_fFade = 0;
m_iFlags = 0;
HOOK_MESSAGE(Battery);
gHUD.AddHudElem(this);
return 1;
};
int CHudBattery::VidInit(void)
{
int HUD_suit_empty = gHUD.GetSpriteIndex( "suit_empty" );
int HUD_suit_full = gHUD.GetSpriteIndex( "suit_full" );
m_hSprite1 = m_hSprite2 = 0; // delaying get sprite handles until we know the sprites are loaded
m_prc1 = &gHUD.GetSpriteRect( HUD_suit_empty );
m_prc2 = &gHUD.GetSpriteRect( HUD_suit_full );
m_iHeight = m_prc2->bottom - m_prc1->top;
m_fFade = 0;
return 1;
};
int CHudBattery:: MsgFunc_Battery(const char *pszName, int iSize, void *pbuf )
{
m_iFlags |= HUD_ACTIVE;
BEGIN_READ( pbuf, iSize );
int x = READ_SHORT();
if( x != m_iBat )
{
m_fFade = FADE_TIME;
m_iBat = x;
}
gViewPort->m_pHud2->UpdateArmor(x); // buz
return 1;
}
int CHudBattery::Draw(float flTime)
{
return 1; // buz: dont draw battery..
if ( gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH )
return 1;
int r, g, b, x, y, a;
wrect_t rc;
rc = *m_prc2;
rc.top += m_iHeight * ((float)(100-(min(100,m_iBat))) * 0.01); // battery can go from 0 to 100 so * 0.01 goes from 0 to 1
UnpackRGB(r,g,b, gHUD.m_iHUDColor);
if (!FBitSet( gHUD.m_iHideHUDDisplay, ITEM_SUIT ))
return 1;
// Has health changed? Flash the health #
if (m_fFade)
{
if (m_fFade > FADE_TIME)
m_fFade = FADE_TIME;
m_fFade -= (gHUD.m_flTimeDelta * 20);
if (m_fFade <= 0)
{
a = 128;
m_fFade = 0;
}
// Fade the health number back to dim
a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128;
}
else
a = MIN_ALPHA;
ScaleColors(r, g, b, a );
int iOffset = (m_prc1->bottom - m_prc1->top)/6;
y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2;
x = ScreenWidth/5;
// make sure we have the right sprite handles
if ( !m_hSprite1 )
m_hSprite1 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_empty" ) );
if ( !m_hSprite2 )
m_hSprite2 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_full" ) );
SPR_Set(m_hSprite1, r, g, b );
SPR_DrawAdditive( 0, x, y - iOffset, m_prc1);
if (rc.bottom > rc.top)
{
SPR_Set(m_hSprite2, r, g, b );
SPR_DrawAdditive( 0, x, y - iOffset + (rc.top - m_prc2->top), &rc);
}
x += (m_prc1->right - m_prc1->left);
x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iBat, r, g, b);
return 1;
}

24
cl_dll/camera.h Normal file
View File

@ -0,0 +1,24 @@
//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
// Camera.h -- defines and such for a 3rd person camera
// NOTE: must include quakedef.h first
#ifndef _CAMERA_H_
#define _CAMEA_H_
// pitch, yaw, dist
extern vec3_t cam_ofs;
// Using third person camera
extern int cam_thirdperson;
void CAM_Init( void );
void CAM_ClearStates( void );
void CAM_StartMouseMove(void);
void CAM_EndMouseMove(void);
#endif // _CAMERA_H_

344
cl_dll/cdll_int.cpp Normal file
View File

@ -0,0 +1,344 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// cdll_int.c
//
// this implementation handles the linking of the engine to the DLL
//
#include "hud.h"
#include "cl_util.h"
#include "netadr.h"
#include "vgui_schememanager.h"
#include "pm_shared.h"
#include "pm_defs.h"
#include <string.h>
#include "hud_servers.h"
#include "vgui_int.h"
int developer_level;
int g_iXashEngineBuildNumber;
BOOL g_fRenderInitialized = FALSE;
BOOL g_fRenderInterfaceValid = FALSE;
BOOL g_fXashEngine = FALSE;
cl_enginefunc_t gEngfuncs;
render_api_t gRenderfuncs;
CHud gHUD;
TeamFortressViewport *gViewPort = NULL;
void InitInput( void );
void ShutdownInput( void );
void EV_HookEvents( void );
void IN_Commands( void );
/*
==========================
Initialize
Called when the DLL is first loaded.
==========================
*/
extern "C"
{
int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion );
int DLLEXPORT HUD_VidInit( void );
void DLLEXPORT HUD_Init( void );
void DLLEXPORT HUD_Shutdown( void );
int DLLEXPORT HUD_Redraw( float flTime, int intermission );
int DLLEXPORT HUD_UpdateClientData( client_data_t *cdata, float flTime );
void DLLEXPORT HUD_Reset ( void );
void DLLEXPORT HUD_PlayerMove( struct playermove_s *ppmove, int server );
void DLLEXPORT HUD_PlayerMoveInit( struct playermove_s *ppmove );
char DLLEXPORT HUD_PlayerMoveTexture( char *name );
int DLLEXPORT HUD_ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size );
void DLLEXPORT HUD_PostRunCmd( local_state_t *from, local_state_t *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int seed );
int DLLEXPORT HUD_GetHullBounds( int hullnumber, float *mins, float *maxs );
void DLLEXPORT HUD_Frame( double time );
void DLLEXPORT HUD_VoiceStatus(int entindex, qboolean bTalking);
void DLLEXPORT HUD_DirectorMessage( int iSize, void *pbuf );
void DLLEXPORT HUD_ClipMoveToEntity( physent_t *pe, const float *start, float *mins, float *maxs, const float *end, pmtrace_t *tr );
}
/*
================================
HUD_GetHullBounds
Engine calls this to enumerate player collision hulls, for prediction. Return 0 if the hullnumber doesn't exist.
================================
*/
int DLLEXPORT HUD_GetHullBounds( int hullnumber, float *mins, float *maxs )
{
int iret = 0;
switch ( hullnumber )
{
case 0: // Normal player
mins = Vector(-16, -16, -36);
maxs = Vector(16, 16, 36);
iret = 1;
break;
case 1: // Crouched player
mins = Vector(-16, -16, -18 );
maxs = Vector(16, 16, 18 );
iret = 1;
break;
case 2: // Point based hull
mins = Vector( 0, 0, 0 );
maxs = Vector( 0, 0, 0 );
iret = 1;
break;
}
return iret;
}
/*
================================
HUD_ConnectionlessPacket
Return 1 if the packet is valid. Set response_buffer_size if you want to send a response packet. Incoming, it holds the max
size of the response_buffer, so you must zero it out if you choose not to respond.
================================
*/
int DLLEXPORT HUD_ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size )
{
// Parse stuff from args
int max_buffer_size = *response_buffer_size;
// Zero it out since we aren't going to respond.
// If we wanted to response, we'd write data into response_buffer
*response_buffer_size = 0;
// Since we don't listen for anything here, just respond that it's a bogus message
// If we didn't reject the message, we'd return 1 for success instead.
return 0;
}
void DLLEXPORT HUD_PlayerMoveInit( struct playermove_s *ppmove )
{
PM_Init( ppmove );
}
char DLLEXPORT HUD_PlayerMoveTexture( char *name )
{
return (char)0;
}
void DLLEXPORT HUD_PlayerMove( struct playermove_s *ppmove, int server )
{
PM_Move( ppmove, server );
}
int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion )
{
gEngfuncs = *pEnginefuncs;
if( iVersion != CLDLL_INTERFACE_VERSION )
return 0;
memcpy( &gEngfuncs, pEnginefuncs, sizeof( cl_enginefunc_t ));
// get developer level
developer_level = (int)CVAR_GET_FLOAT( "developer" );
if( CVAR_GET_POINTER( "host_clientloaded" ) != NULL )
g_fXashEngine = TRUE;
g_iXashEngineBuildNumber = (int)CVAR_GET_FLOAT( "build" ); // 0 for old builds or GoldSrc
if( g_iXashEngineBuildNumber <= 0 )
g_iXashEngineBuildNumber = (int)CVAR_GET_FLOAT( "buildnum" );
EV_HookEvents();
return 1;
}
/*
==========================
HUD_VidInit
Called when the game initializes
and whenever the vid_mode is changed
so the HUD can reinitialize itself.
==========================
*/
int DLLEXPORT HUD_VidInit( void )
{
gHUD.VidInit();
VGui_Startup();
if( g_fXashEngine && g_fRenderInitialized )
R_VidInit();
return 1;
}
/*
==========================
HUD_Init
Called whenever the client connects
to a server. Reinitializes all
the hud variables.
==========================
*/
void DLLEXPORT HUD_Init( void )
{
InitInput();
if( g_fXashEngine && g_fRenderInitialized )
GL_Init();
gHUD.Init();
Scheme_Init();
}
void DLLEXPORT HUD_Shutdown( void )
{
ShutdownInput();
if( g_fXashEngine && g_fRenderInitialized )
GL_Shutdown();
}
/*
==========================
HUD_Redraw
called every screen frame to
redraw the HUD.
===========================
*/
int DLLEXPORT HUD_Redraw( float time, int intermission )
{
return gHUD.Redraw( time, intermission );
}
/*
==========================
HUD_UpdateClientData
called every time shared client
dll/engine data gets changed,
and gives the cdll a chance
to modify the data.
returns 1 if anything has been changed, 0 otherwise.
==========================
*/
int DLLEXPORT HUD_UpdateClientData(client_data_t *pcldata, float flTime )
{
IN_Commands();
return gHUD.UpdateClientData(pcldata, flTime );
}
/*
==========================
HUD_Reset
Called at start and end of demos to restore to "non"HUD state.
==========================
*/
void DLLEXPORT HUD_Reset( void )
{
gHUD.VidInit();
}
/*
==========================
HUD_Frame
Called by engine every frame that client .dll is loaded
==========================
*/
void DLLEXPORT HUD_Frame( double time )
{
ServersThink( time );
GetClientVoiceMgr()->Frame(time);
}
/*
==========================
HUD_VoiceStatus
Called when a player starts or stops talking.
==========================
*/
void DLLEXPORT HUD_VoiceStatus( int entindex, qboolean bTalking )
{
GetClientVoiceMgr()->UpdateSpeakerStatus( entindex, bTalking );
}
/*
==========================
HUD_DirectorEvent
Called when a director event message was received
==========================
*/
void DLLEXPORT HUD_DirectorMessage( int iSize, void *pbuf )
{
gHUD.m_Spectator.DirectorMessage( iSize, pbuf );
}
void DLLEXPORT HUD_PostRunCmd( local_state_t *from, local_state_t *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int seed )
{
to->client.fov = 0;//g_lastFOV; buz
}
/*
==========================
HUD_ClipMoveToEntity
This called only for non-local clients (multiplayer)
==========================
*/
void DLLEXPORT HUD_ClipMoveToEntity( physent_t *pe, const float *start, float *mins, float *maxs, const float *end, pmtrace_t *tr )
{
// convert physent_t to cl_entity_t
cl_entity_t *pTouch = gEngfuncs.GetEntityByIndex( pe->info );
trace_t trace;
if( !pTouch )
{
// removed entity?
tr->allsolid = false;
return;
}
// make trace default
memset( &trace, 0, sizeof( trace ));
trace.allsolid = true;
trace.fraction = 1.0f;
trace.endpos = end;
Physic_SweepTest( pTouch, start, mins, maxs, end, &trace );
// convert trace_t into pmtrace_t
memcpy( tr, &trace, 48 );
tr->surf = trace.surf;
if( trace.ent != NULL && PM_GetPlayerMove( ))
tr->ent = pe - PM_GetPlayerMove()->physents;
else tr->ent = -1;
}

929
cl_dll/cl_dll.dsp Normal file
View File

@ -0,0 +1,929 @@
# Microsoft Developer Studio Project File - Name="cl_dll" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=cl_dll - Win32 Release
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "cl_dll.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "cl_dll.mak" CFG="cl_dll - Win32 Release"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "cl_dll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "cl_dll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""$/GoldSrc/cl_dll", HGEBAAAA"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "cl_dll - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "..\temp\client\!release"
# PROP Intermediate_Dir "..\temp\client\!release"
# PROP Ignore_Export_Lib 1
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\utils\vgui\include" /I "..\engine" /I "..\common" /I "..\pm_shared" /I ".\render" /I ".\\" /I "..\game_shared" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "CLIENT_DLL" /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# ADD LINK32 msvcrt.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib winmm.lib ../utils/vgui/lib/win32_vc6/vgui.lib wsock32.lib glu32.lib /nologo /subsystem:windows /dll /pdb:none /machine:I386 /nodefaultlib:"libc.lib" /out:"..\temp\client\!release\client.dll"
# SUBTRACT LINK32 /map /debug
# Begin Custom Build
TargetDir=\Paranoia2\src_main\temp\client\!release
InputPath=\Paranoia2\src_main\temp\client\!release\client.dll
SOURCE="$(InputPath)"
"D:\Paranoia2\base\bin\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
copy $(TargetDir)\client.dll "D:\Paranoia2\base\bin\client.dll"
# End Custom Build
!ELSEIF "$(CFG)" == "cl_dll - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "cl_dll___Win32_Debug"
# PROP BASE Intermediate_Dir "cl_dll___Win32_Debug"
# PROP BASE Ignore_Export_Lib 0
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "..\temp\client\!debug"
# PROP Intermediate_Dir "..\temp\client\!debug"
# PROP Ignore_Export_Lib 1
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /Zi /O2 /I "..\utils\vgui\include" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\dlls" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "CLIENT_DLL" /Fr /YX /FD /c
# ADD CPP /nologo /MDd /W3 /Gi /GX /ZI /Od /I "..\utils\vgui\include" /I "..\engine" /I "..\common" /I "..\pm_shared" /I ".\render" /I ".\\" /I "..\game_shared" /D "WIN32" /D "DEBUG" /D "_DEBUG" /D "_WINDOWS" /D "CLIENT_DLL" /FAs /FR /FD /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /D "DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "_DEBUG" /d "DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib winmm.lib ../utils/vgui/lib/win32_vc6/vgui.lib wsock32.lib opengl32.lib cg.lib cgGL.lib /nologo /subsystem:windows /dll /map /debug /machine:I386 /out:".\Release\client.dll"
# ADD LINK32 msvcrtd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib winmm.lib ../utils/vgui/lib/win32_vc6/vgui.lib wsock32.lib /nologo /subsystem:windows /dll /incremental:yes /debug /machine:I386 /nodefaultlib:"libcd.lib" /out:"..\temp\client\!debug\client.dll"
# SUBTRACT LINK32 /map
# Begin Custom Build
TargetDir=\Paranoia2\src_main\temp\client\!debug
InputPath=\Paranoia2\src_main\temp\client\!debug\client.dll
SOURCE="$(InputPath)"
"D:\Paranoia2\base\bin\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
copy $(TargetDir)\client.dll "D:\Paranoia2\base\bin\client.dll"
# End Custom Build
!ENDIF
# Begin Target
# Name "cl_dll - Win32 Release"
# Name "cl_dll - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
# Begin Group "hl"
# PROP Default_Filter "*.CPP"
# Begin Source File
SOURCE=..\game_shared\bone_setup.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\common.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_cubemaps.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_deferred.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_dlight.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_framebuffer.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_frustum.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_grass.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_lightmap.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_occlusion.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_primitive.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_scene.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_shader.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_shadowmap.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_slight.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_studio_draw.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_studio_init.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_studiodecal_new.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_studiovbo.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_subview.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_world_new.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\ikcontext.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\jigglebones.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\material.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\mathlib.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\matrix.cpp
# End Source File
# Begin Source File
SOURCE=..\pm_shared\meshdesc.cpp
# End Source File
# Begin Source File
SOURCE=..\pm_shared\pm_shared.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\procbones.cpp
# End Source File
# Begin Source File
SOURCE=.\stamina.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\stringlib.cpp
# End Source File
# Begin Source File
SOURCE=..\pm_shared\trace.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_checkbutton2.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_grid.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_helpers.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_listbox.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_loadtga.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_scrollbar2.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_slider2.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\voice_banmgr.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\voice_status.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\voice_vgui_tweakdlg.cpp
# End Source File
# End Group
# Begin Group "render"
# PROP Default_Filter "*.CPP"
# Begin Source File
SOURCE=.\render\gl_aurora.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_backend.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_cull.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_debug.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_decals.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_export.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_movie.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_postprocess.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_rmain.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_rmisc.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_rpart.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_rsurf.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_shadows.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_sky.cpp
# End Source File
# Begin Source File
SOURCE=.\render\gl_sprite.cpp
# End Source File
# Begin Source File
SOURCE=.\render\rain.cpp
# End Source File
# Begin Source File
SOURCE=.\render\tri.cpp
# End Source File
# Begin Source File
SOURCE=.\render\view.cpp
# End Source File
# End Group
# Begin Source File
SOURCE=.\ammo.cpp
# End Source File
# Begin Source File
SOURCE=.\ammo_secondary.cpp
# End Source File
# Begin Source File
SOURCE=.\ammohistory.cpp
# End Source File
# Begin Source File
SOURCE=.\battery.cpp
# End Source File
# Begin Source File
SOURCE=.\cdll_int.cpp
# End Source File
# Begin Source File
SOURCE=.\death.cpp
# End Source File
# Begin Source File
SOURCE=.\demo.cpp
# End Source File
# Begin Source File
SOURCE=.\entity.cpp
# End Source File
# Begin Source File
SOURCE=.\ev_common.cpp
# End Source File
# Begin Source File
SOURCE=.\ev_files.cpp
# End Source File
# Begin Source File
SOURCE=.\ev_hldm.cpp
# End Source File
# Begin Source File
SOURCE=.\events.cpp
# End Source File
# Begin Source File
SOURCE=.\flashlight.cpp
# End Source File
# Begin Source File
SOURCE=.\geiger.cpp
# End Source File
# Begin Source File
SOURCE=.\health.cpp
# End Source File
# Begin Source File
SOURCE=.\hud.cpp
# End Source File
# Begin Source File
SOURCE=.\hud_msg.cpp
# End Source File
# Begin Source File
SOURCE=.\hud_redraw.cpp
# End Source File
# Begin Source File
SOURCE=.\hud_servers.cpp
# End Source File
# Begin Source File
SOURCE=.\hud_spectator.cpp
# End Source File
# Begin Source File
SOURCE=.\hud_update.cpp
# End Source File
# Begin Source File
SOURCE=.\in_camera.cpp
# End Source File
# Begin Source File
SOURCE=.\input.cpp
# End Source File
# Begin Source File
SOURCE=.\inputw32.cpp
# End Source File
# Begin Source File
SOURCE=.\lensflare.cpp
# End Source File
# Begin Source File
SOURCE=.\menu.cpp
# End Source File
# Begin Source File
SOURCE=.\message.cpp
# End Source File
# Begin Source File
SOURCE=.\parsemsg.cpp
# End Source File
# Begin Source File
SOURCE=.\saytext.cpp
# End Source File
# Begin Source File
SOURCE=.\status_icons.cpp
# End Source File
# Begin Source File
SOURCE=.\statusbar.cpp
# End Source File
# Begin Source File
SOURCE=.\text_message.cpp
# End Source File
# Begin Source File
SOURCE=.\train.cpp
# End Source File
# Begin Source File
SOURCE=.\util.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_ClassMenu.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_ConsolePanel.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_ControlConfigPanel.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_CustomObjects.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_gamma.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_hud.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_int.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_MOTDWindow.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_paranoiatext.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_radio.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_SchemeManager.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_ScorePanel.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_ServerBrowser.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_SpectatorPanel.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_subtitles.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_tabpanel.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_TeamFortressViewport.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_teammenu.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_tips.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
# Begin Source File
SOURCE=.\ammo.h
# End Source File
# Begin Source File
SOURCE=.\ammohistory.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\bitvec.h
# End Source File
# Begin Source File
SOURCE=.\camera.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\cdll_dll.h
# End Source File
# Begin Source File
SOURCE=.\cl_dll.h
# End Source File
# Begin Source File
SOURCE=.\cl_util.h
# End Source File
# Begin Source File
SOURCE=..\pm_shared\clipfile.h
# End Source File
# Begin Source File
SOURCE=.\com_weapons.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\cubemap.h
# End Source File
# Begin Source File
SOURCE=.\custom_alloc.h
# End Source File
# Begin Source File
SOURCE=.\demo.h
# End Source File
# Begin Source File
SOURCE=.\enginecallback.h
# End Source File
# Begin Source File
SOURCE=.\ev_hldm.h
# End Source File
# Begin Source File
SOURCE=.\eventscripts.h
# End Source File
# Begin Source File
SOURCE=.\fmod_errors.h
# End Source File
# Begin Source File
SOURCE=.\getfont.h
# End Source File
# Begin Source File
SOURCE=.\render\gl_aurora.h
# End Source File
# Begin Source File
SOURCE=.\render\gl_decals.h
# End Source File
# Begin Source File
SOURCE=.\render\gl_export.h
# End Source File
# Begin Source File
SOURCE=.\render\gl_framebuffer.h
# End Source File
# Begin Source File
SOURCE=.\render\gl_frustum.h
# End Source File
# Begin Source File
SOURCE=.\render\gl_grass.h
# End Source File
# Begin Source File
SOURCE=.\render\gl_local.h
# End Source File
# Begin Source File
SOURCE=.\render\gl_occlusion.h
# End Source File
# Begin Source File
SOURCE=.\render\gl_rpart.h
# End Source File
# Begin Source File
SOURCE=.\render\gl_shader.h
# End Source File
# Begin Source File
SOURCE=.\render\gl_sprite.h
# End Source File
# Begin Source File
SOURCE=.\render\gl_studio.h
# End Source File
# Begin Source File
SOURCE=.\health.h
# End Source File
# Begin Source File
SOURCE=.\hud.h
# End Source File
# Begin Source File
SOURCE=.\hud_iface.h
# End Source File
# Begin Source File
SOURCE=.\hud_servers.h
# End Source File
# Begin Source File
SOURCE=.\hud_servers_priv.h
# End Source File
# Begin Source File
SOURCE=.\hud_spectator.h
# End Source File
# Begin Source File
SOURCE=.\in_defs.h
# End Source File
# Begin Source File
SOURCE=.\kbutton.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\material.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\matrix.h
# End Source File
# Begin Source File
SOURCE=..\pm_shared\meshdesc.h
# End Source File
# Begin Source File
SOURCE=.\overview.h
# End Source File
# Begin Source File
SOURCE=.\parsemsg.h
# End Source File
# Begin Source File
SOURCE=..\pm_shared\pm_debug.h
# End Source File
# Begin Source File
SOURCE=.\render\rain.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\stringlib.h
# End Source File
# Begin Source File
SOURCE=.\render\texture.h
# End Source File
# Begin Source File
SOURCE=.\tf_defs.h
# End Source File
# Begin Source File
SOURCE=..\pm_shared\trace.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\tri_stripper.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\utlarray.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\utlblockmemory.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\utllinkedlist.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\utlmemory.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\vector.h
# End Source File
# Begin Source File
SOURCE=.\render\vertex_fmt.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_checkbutton2.h
# End Source File
# Begin Source File
SOURCE=.\vgui_ConsolePanel.h
# End Source File
# Begin Source File
SOURCE=.\vgui_ControlConfigPanel.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_defaultinputsignal.h
# End Source File
# Begin Source File
SOURCE=.\vgui_gamma.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_grid.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_helpers.h
# End Source File
# Begin Source File
SOURCE=.\vgui_hud.h
# End Source File
# Begin Source File
SOURCE=.\vgui_int.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_listbox.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_loadtga.h
# End Source File
# Begin Source File
SOURCE=.\vgui_paranoiatext.h
# End Source File
# Begin Source File
SOURCE=.\vgui_pickup.h
# End Source File
# Begin Source File
SOURCE=.\vgui_radio.h
# End Source File
# Begin Source File
SOURCE=.\vgui_SchemeManager.h
# End Source File
# Begin Source File
SOURCE=.\vgui_ScorePanel.h
# End Source File
# Begin Source File
SOURCE=.\vgui_screenmsg.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_scrollbar2.h
# End Source File
# Begin Source File
SOURCE=.\vgui_ServerBrowser.h
# End Source File
# Begin Source File
SOURCE=.\vgui_shadowtext.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_slider2.h
# End Source File
# Begin Source File
SOURCE=.\vgui_SpectatorPanel.h
# End Source File
# Begin Source File
SOURCE=.\vgui_subtitles.h
# End Source File
# Begin Source File
SOURCE=.\vgui_tabpanel.h
# End Source File
# Begin Source File
SOURCE=.\vgui_TeamFortressViewport.h
# End Source File
# Begin Source File
SOURCE=.\vgui_tips.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\voice_banmgr.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\voice_common.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\voice_gamemgr.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\voice_status.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\voice_vgui_tweakdlg.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

49
cl_dll/cl_dll.h Normal file
View File

@ -0,0 +1,49 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// cl_dll.h
//
// 4-23-98 JOHN
//
// This DLL is linked by the client when they first initialize.
// This DLL is responsible for the following tasks:
// - Loading the HUD graphics upon initialization
// - Drawing the HUD graphics every frame
// - Handling the custum HUD-update packets
//
typedef unsigned char byte;
typedef unsigned short word;
typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf);
#include <vector.h>
#define EXPORT _declspec( dllexport )
#include "../engine/cdll_int.h"
#include "cdll_dll.h"
extern cl_enginefunc_t gEngfuncs;
#define CONPRINT (gEngfuncs.Con_Printf) //LRC - I can't live without printf!
//
// gl_export.cpp
//
bool GL_Init( void );
void GL_MapChanged( void );
void GL_Shutdown( void );
bool GL_Support( int r_ext );
void R_VidInit( void );

319
cl_dll/cl_util.h Normal file
View File

@ -0,0 +1,319 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// cl_util.h
//
#include "cvardef.h"
#define EXPORT _declspec( dllexport )
#define DLLEXPORT __declspec( dllexport )
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
extern int developer_level;
extern int r_currentMessageNum;
extern int g_iXashEngineBuildNumber;
extern BOOL g_fRenderInitialized;
extern BOOL g_fRenderInterfaceValid;
extern BOOL g_fXashEngine;
enum
{
DEV_NONE = 0,
DEV_NORMAL,
DEV_EXTENDED
};
typedef HMODULE dllhandle_t;
typedef struct dllfunc_s
{
const char *name;
void **func;
} dllfunc_t;
// misc cvars
extern cvar_t *r_test; // just cvar for testify new effects
extern cvar_t *r_stencilbits;
extern cvar_t *r_drawentities;
extern cvar_t *gl_extensions;
extern cvar_t *cv_dynamiclight;
extern cvar_t *r_detailtextures;
extern cvar_t *r_lighting_ambient;
extern cvar_t *r_lighting_modulate;
extern cvar_t *r_lightstyle_lerping;
extern cvar_t *r_lighting_extended;
extern cvar_t *r_occlusion_culling;
extern cvar_t *r_show_lightprobes;
extern cvar_t *r_show_cubemaps;
extern cvar_t *r_show_viewleaf;
extern cvar_t *cv_crosshair;
extern cvar_t *r_shadows;
extern cvar_t *r_fullbright;
extern cvar_t *r_draw_beams;
extern cvar_t *r_overview;
extern cvar_t *r_novis;
extern cvar_t *r_nocull;
extern cvar_t *r_lockpvs;
extern cvar_t *r_dof;
extern cvar_t *r_dof_hold_time;
extern cvar_t *r_dof_change_time;
extern cvar_t *r_dof_focal_length;
extern cvar_t *r_dof_fstop;
extern cvar_t *r_dof_debug;
extern cvar_t *r_allow_mirrors;
extern cvar_t *cv_renderer;
extern cvar_t *cv_brdf;
extern cvar_t *cv_bump;
extern cvar_t *cv_specular;
extern cvar_t *cv_parallax;
extern cvar_t *cv_decals;
extern cvar_t *cv_realtime_puddles;
extern cvar_t *cv_shadow_offset;
extern cvar_t *cv_cubemaps;
extern cvar_t *cv_deferred;
extern cvar_t *cv_deferred_full;
extern cvar_t *cv_deferred_maxlights;
extern cvar_t *cv_deferred_tracebmodels;
extern cvar_t *cv_cube_lod_bias;
extern cvar_t *cv_gamma;
extern cvar_t *cv_brightness;
extern cvar_t *cv_water;
extern cvar_t *cv_decalsdebug;
extern cvar_t *cv_show_tbn;
extern cvar_t *cv_nosort;
extern cvar_t *r_lightmap;
extern cvar_t *r_speeds;
extern cvar_t *r_decals;
extern cvar_t *r_studio_decals;
extern cvar_t *r_hand;
extern cvar_t *r_sunshadows;
extern cvar_t *r_sun_allowed;
extern cvar_t *r_shadow_split_weight;
extern cvar_t *r_wireframe;
extern cvar_t *r_lightstyles;
extern cvar_t *r_polyoffset;
extern cvar_t *r_dynamic;
extern cvar_t *r_finish;
extern cvar_t *r_clear;
extern cvar_t *r_grass;
extern cvar_t *r_grass_alpha;
extern cvar_t *r_grass_lighting;
extern cvar_t *r_grass_shadows;
extern cvar_t *r_grass_fade_start;
extern cvar_t *r_grass_fade_dist;
extern cvar_t *r_scissor_glass_debug;
extern cvar_t *r_scissor_light_debug;
extern cvar_t *r_showlightmaps;
extern cvar_t *r_recursion_depth;
extern cvar_t *r_shadowmap_size;
extern cvar_t *r_pssm_show_split;
extern cvar_t *v_sunshafts;
extern cvar_t *v_glows;
extern "C" void DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity );
// Macros to hook function calls into the HUD object
#define HOOK_MESSAGE(x) gEngfuncs.pfnHookUserMsg(#x, __MsgFunc_##x );
#define DECLARE_MESSAGE(y, x) int __MsgFunc_##x(const char *pszName, int iSize, void *pbuf) \
{ \
return gHUD.##y.MsgFunc_##x(pszName, iSize, pbuf ); \
}
#define HOOK_COMMAND(x, y) gEngfuncs.pfnAddCommand( x, __CmdFunc_##y );
#define DECLARE_COMMAND(y, x) void __CmdFunc_##x( void ) \
{ \
gHUD.##y.UserCmd_##x( ); \
}
#define SPR_Set (*gEngfuncs.pfnSPR_Set)
#define SPR_Frames (*gEngfuncs.pfnSPR_Frames)
client_sprite_t *SPR2_GetList( char *psz, int *piCount ); // new version
// SPR_Draw draws a the current sprite as solid
#define SPR_Draw (*gEngfuncs.pfnSPR_Draw)
// SPR_DrawHoles draws the current sprites, with color index255 not drawn (transparent)
#define SPR_DrawHoles (*gEngfuncs.pfnSPR_DrawHoles)
// SPR_DrawAdditive adds the sprites RGB values to the background (additive transulency)
#define SPR_DrawAdditive (*gEngfuncs.pfnSPR_DrawAdditive)
// SPR_EnableScissor sets a clipping rect for HUD sprites. (0,0) is the top-left hand corner of the screen.
#define SPR_EnableScissor (*gEngfuncs.pfnSPR_EnableScissor)
// SPR_DisableScissor disables the clipping rect
#define SPR_DisableScissor (*gEngfuncs.pfnSPR_DisableScissor)
//
#define FillRGBA (*gEngfuncs.pfnFillRGBA)
// ScreenHeight returns the height of the screen, in pixels
#define ScreenHeight (gHUD.m_scrinfo.iHeight)
// ScreenWidth returns the width of the screen, in pixels
#define ScreenWidth (gHUD.m_scrinfo.iWidth)
// Use this to set any co-ords in 640x480 space
#define XRES(x) ((int)(float(x) * ((float)ScreenWidth / 640.0f) + 0.5f))
#define YRES(y) ((int)(float(y) * ((float)ScreenHeight / 480.0f) + 0.5f))
// use this to project world coordinates to screen coordinates
#define XPROJECT(x) ( (1.0f+(x))*ScreenWidth*0.5f )
#define YPROJECT(y) ( (1.0f-(y))*ScreenHeight*0.5f )
#define GetScreenInfo (*gEngfuncs.pfnGetScreenInfo)
#define ServerCmd (*gEngfuncs.pfnServerCmd)
#define ClientCmd (*gEngfuncs.pfnClientCmd)
#define SetCrosshair (*gEngfuncs.pfnSetCrosshair)
#define AngleVectors (*gEngfuncs.pfnAngleVectors)
inline int ConsoleStringLen( const char *string )
{
int _width, _height;
GetConsoleStringSize( string, &_width, &_height );
return _width;
}
// returns the players name of entity no.
#define GetPlayerInfo (*gEngfuncs.pfnGetPlayerInfo)
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define fabs(x) ((x) > 0 ? (x) : 0 - (x))
void ScaleColors( int &r, int &g, int &b, int a );
#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
#define VectorSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];}
#define VectorAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];}
#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2])
inline void VectorClear(float *a) { a[0]=0.0;a[1]=0.0;a[2]=0.0;}
float Length(const float *v);
void VectorMA (const float *veca, float scale, const float *vecb, float *vecc);
void VectorScale (const float *in, float scale, float *out);
float VectorNormalize (float *v);
extern vec3_t vec3_origin;
extern struct ref_params_s *g_pViewParams;
// disable 'possible loss of data converting float to int' warning message
#pragma warning( disable: 4244 )
// disable 'truncation from 'const double' to 'float' warning message
#pragma warning( disable: 4305 )
inline void UnpackRGB(int &r, int &g, int &b, unsigned long ulRGB)\
{\
r = (ulRGB & 0xFF0000) >>16;\
g = (ulRGB & 0xFF00) >> 8;\
b = ulRGB & 0xFF;\
}
inline unsigned int PackRGBA( int r, int g, int b, int a )
{
r = bound( 0, r, 255 );
g = bound( 0, g, 255 );
b = bound( 0, b, 255 );
a = bound( 0, a, 255 );
return ((a)<<24|(r)<<16|(g)<<8|(b));
}
inline void UnpackRGBA( int &r, int &g, int &b, int &a, unsigned int ulRGBA )
{
a = (ulRGBA & 0xFF000000) >> 24;
r = (ulRGBA & 0xFF0000) >> 16;
g = (ulRGBA & 0xFF00) >> 8;
b = (ulRGBA & 0xFF) >> 0;
}
float PackColor( const color24 &color );
color24 UnpackColor( float pack );
HSPRITE LoadSprite(const char *pszName);
#define CHECKVISBIT( vis, b ) ((b) >= 0 ? (byte)((vis)[(b) >> 3] & (1 << ((b) & 7))) : (byte)false )
#define SETVISBIT( vis, b )( void ) ((b) >= 0 ? (byte)((vis)[(b) >> 3] |= (1 << ((b) & 7))) : (byte)false )
#define CLEARVISBIT( vis, b )( void ) ((b) >= 0 ? (byte)((vis)[(b) >> 3] &= ~(1 << ((b) & 7))) : (byte)false )
typedef struct leaflist_s
{
int count;
int maxcount;
bool overflowed;
short *list;
Vector mins, maxs;
struct mnode_s *headnode; // for overflows where each leaf can't be stored individually
} leaflist_t;
struct mleaf_s *Mod_PointInLeaf( const Vector &p, struct mnode_s *node );
byte *Mod_LeafPVS( struct mleaf_s *leaf, struct model_s *model );
byte *Mod_GetCurrentVis( void );
bool Mod_BoxVisible( const Vector &mins, const Vector &maxs, const byte *visbits );
bool Mod_CheckEntityPVS( cl_entity_t *ent );
bool Mod_CheckTempEntityPVS( struct tempent_s *pTemp );
bool Mod_CheckEntityLeafPVS( const Vector &absmin, const Vector &absmax, struct mleaf_s *leaf );
bool Mod_CheckBoxVisible( const Vector &absmin, const Vector &absmax );
void Mod_GetFrames( int modelIndex, int &numFrames );
struct model_s *Mod_Handle( int modelIndex );
bool Mod_PointInSolid( const Vector &p );
int Mod_GetType( int modelIndex );
extern void ParseRain( void );
extern int CL_IsDead( void );
void SetDLightVis( struct mworldlight_s *wl, int leafnum );
void MergeDLightVis( struct mworldlight_s *wl, int leafnum );
bool UTIL_IsPlayer( int idx );
bool UTIL_IsLocal( int idx );
void UTIL_WeaponAnimation( int iAnim, float framerate );
void UTIL_StudioDecal( const char *pDecalName, struct pmtrace_s *pTrace, const Vector &vecSrc );
bool R_ScissorForAABB( const Vector &absmin, const Vector &absmax, float *x, float *y, float *w, float *h );
bool R_AABBToScreen( const Vector &absmin, const Vector &absmax, Vector2D &scrmin, Vector2D &scrmax, wrect_t *rect = NULL );
bool R_ScissorForFrustum( class CFrustum *frustum, float *x, float *y, float *w, float *h );
void R_DrawScissorRectangle( float x, float y, float w, float h );
int WorldToScreen( const Vector &world, Vector &screen );
void R_TransformWorldToDevice( const Vector &world, Vector &ndc );
void R_TransformDeviceToScreen( const Vector &ndc, Vector &screen );
float ComputePixelWidthOfSphere( const Vector& vecOrigin, float flRadius );
bool R_SkyIsVisible( void );
bool R_ClipPolygon( int numPoints, Vector *points, const struct mplane_s *plane, int *numClipped, Vector *clipped );
void R_SplitPolygon( int numPoints, Vector *points, const struct mplane_s *plane, int *numFront, Vector *front, int *numBack, Vector *back );
// dll managment
bool Sys_LoadLibrary( const char *dllname, dllhandle_t *handle, const dllfunc_t *fcts = NULL );
void *Sys_GetProcAddress( dllhandle_t handle, const char *name );
void Sys_FreeLibrary( dllhandle_t *handle );
bool Sys_RemoveFile( const char *path );
void UTIL_CreateAurora( cl_entity_t *ent, const char *file, int attachment, float lifetime = 0.0f );
void UTIL_RemoveAurora( cl_entity_t *ent );
extern void AngleMatrix (const float *angles, float (*matrix)[4] );
extern void VectorTransform (const float *in1, float in2[3][4], float *out);
extern void SetPoint( float x, float y, float z, float (*matrix)[4]);
extern void CreateDecal( const Vector &p, const Vector &n, float ang, const char *sz, int flags = 0, int eIdx = 0, int mIdx = 0, bool source = true );
extern void CreateDecal( struct pmtrace_s *tr, const char *name, float angle, bool visent = false );
extern void Physic_SweepTest( struct cl_entity_s *pTouch, const Vector &start, const Vector &mins, const Vector &maxs, const Vector &end, trace_t *tr );
extern void BuildGammaTable( void );
extern float TextureToLinear( int c );
extern int LinearToTexture( float f );
extern void GL_GpuMemUsage_f( void );

108
cl_dll/custom_alloc.h Normal file
View File

@ -0,0 +1,108 @@
/************************************
simple memory allocator
by BUzer
************************************/
template <class T>
class MemBlock
{
typedef struct chunk_s {
int next;
T data;
} chunk_t;
public:
MemBlock(int numElements)
{
// ýëåìåíò 0 èñïîëüçóåòñÿ â êà÷åñòâå íà÷àëà ñïèñêà çàíÿòûõ ÿ÷ååê
m_iArraySize = numElements + 1;
m_pArray = new chunk_t[m_iArraySize];
if (!m_pArray)
{
m_iArraySize = 1;
m_iFirstFree = m_iArraySize;
return;
}
Clear();
}
~MemBlock()
{
delete[] m_pArray;
m_pArray = NULL;
}
void Clear( void )
{
if (m_iArraySize > 1)
{
m_pArray[0].next = 0; // åñëè îí ññûëàåòñÿ ñàì íà ñåáÿ, çíà÷èò ñïèñîê çàíÿòûõ ïóñò
m_iFirstFree = 1;
for (int i = 1; i < m_iArraySize; ++i)
m_pArray[i].next = i + 1;
}
}
T* Allocate( void )
{
if (m_iFirstFree != m_iArraySize)
{
int savedFirstFree = m_pArray[m_iFirstFree].next;
m_pArray[m_iFirstFree].next = m_pArray[0].next; // äîáàâëÿåì ñâîáîäíóþ ÿ÷åéêó â
m_pArray[0].next = m_iFirstFree; // ñïèñîê çàíÿòûõ
m_iFirstFree = savedFirstFree; // èñêëþ÷àåì ÿ÷åéêó èç ñïèñêà ñâîáîäíûõ
return &(m_pArray[m_pArray[0].next].data);
}
else
return NULL;
}
bool IsClear( void )
{
return m_pArray[0].next ? false : true;
}
bool StartPass( void )
{
m_iCurrent = 0; // íà÷èíàåì îáõîä ñ íóëåâîãî ýëåìåíòà
if (m_iArraySize > 1)
return true;
else
return false;
}
T* GetCurrent( void )
{
int retindex = m_pArray[m_iCurrent].next;
if (!retindex)
return NULL;
return &(m_pArray[retindex].data);
}
void MoveNext( void )
{
m_iCurrent = m_pArray[m_iCurrent].next;
}
void DeleteCurrent( void )
{
int delindex = m_pArray[m_iCurrent].next;
m_pArray[m_iCurrent].next = m_pArray[delindex].next; // âûáðàñûâàåì ýëåìåíò èç öåïè çàíÿòûõ
m_pArray[delindex].next = m_iFirstFree;
m_iFirstFree = delindex; // âêëþ÷àåì ýëåìåíò â íà÷àëî öåïè ñâîáîäíûõ
}
private:
chunk_t *m_pArray;
int m_iArraySize;
int m_iCurrent; // äëÿ ïðîõîæäåíèÿ ÷åðåç ìàññèâ
int m_iFirstFree; // íà÷àëî ñïèñêà ñâîáîäíûõ ýëåìåíòîâ
};

297
cl_dll/death.cpp Normal file
View File

@ -0,0 +1,297 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// death notice
//
#include "hud.h"
#include "cl_util.h"
#include "parsemsg.h"
#include <string.h>
#include <stdio.h>
#include "vgui_TeamFortressViewport.h"
DECLARE_MESSAGE( m_DeathNotice, DeathMsg );
struct DeathNoticeItem {
char szKiller[MAX_PLAYER_NAME_LENGTH*2];
char szVictim[MAX_PLAYER_NAME_LENGTH*2];
int iId; // the index number of the associated sprite
int iSuicide;
int iTeamKill;
int iNonPlayerKill;
float flDisplayTime;
float *KillerColor;
float *VictimColor;
};
#define MAX_DEATHNOTICES 4
static int DEATHNOTICE_DISPLAY_TIME = 6;
#define DEATHNOTICE_TOP 32
DeathNoticeItem rgDeathNoticeList[ MAX_DEATHNOTICES + 1 ];
float g_ColorBlue[3] = { 0.6, 0.8, 1.0 };
float g_ColorRed[3] = { 1.0, 0.25, 0.25 };
float g_ColorGreen[3] = { 0.6, 1.0, 0.6 };
float g_ColorYellow[3] = { 1.0, 0.7, 0.0 };
float g_ColorGrey[3] = { 0.8, 0.8, 0.8 };
float *GetClientColor( int clientIndex )
{
switch ( g_PlayerExtraInfo[clientIndex].teamnumber )
{
case 1: return g_ColorBlue;
case 2: return g_ColorRed;
case 3: return g_ColorYellow;
case 4: return g_ColorGreen;
case 0: return g_ColorYellow;
default : return g_ColorGrey;
}
return NULL;
}
int CHudDeathNotice :: Init( void )
{
gHUD.AddHudElem( this );
HOOK_MESSAGE( DeathMsg );
CVAR_REGISTER( "hud_deathnotice_time", "6", 0 );
return 1;
}
void CHudDeathNotice :: InitHUDData( void )
{
memset( rgDeathNoticeList, 0, sizeof(rgDeathNoticeList) );
}
int CHudDeathNotice :: VidInit( void )
{
m_HUD_d_skull = gHUD.GetSpriteIndex( "d_skull" );
return 1;
}
int CHudDeathNotice :: Draw( float flTime )
{
int x, y, r, g, b;
for ( int i = 0; i < MAX_DEATHNOTICES; i++ )
{
if ( rgDeathNoticeList[i].iId == 0 )
break; // we've gone through them all
if ( rgDeathNoticeList[i].flDisplayTime < flTime )
{ // display time has expired
// remove the current item from the list
memmove( &rgDeathNoticeList[i], &rgDeathNoticeList[i+1], sizeof(DeathNoticeItem) * (MAX_DEATHNOTICES - i) );
i--; // continue on the next item; stop the counter getting incremented
continue;
}
rgDeathNoticeList[i].flDisplayTime = min( rgDeathNoticeList[i].flDisplayTime, gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME );
// Only draw if the viewport will let me
if ( gViewPort && gViewPort->AllowedToPrintText() )
{
// Draw the death notice
y = YRES(DEATHNOTICE_TOP) + 2 + (20 * i); //!!!
int id = (rgDeathNoticeList[i].iId == -1) ? m_HUD_d_skull : rgDeathNoticeList[i].iId;
x = ScreenWidth - ConsoleStringLen(rgDeathNoticeList[i].szVictim) - (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left);
if ( !rgDeathNoticeList[i].iSuicide )
{
x -= (5 + ConsoleStringLen( rgDeathNoticeList[i].szKiller ) );
// Draw killers name
if ( rgDeathNoticeList[i].KillerColor )
gEngfuncs.pfnDrawSetTextColor( rgDeathNoticeList[i].KillerColor[0], rgDeathNoticeList[i].KillerColor[1], rgDeathNoticeList[i].KillerColor[2] );
x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller );
}
r = 255; g = 80; b = 0;
if ( rgDeathNoticeList[i].iTeamKill )
{
r = 10; g = 240; b = 10; // display it in sickly green
}
// Draw death weapon
SPR_Set( gHUD.GetSprite(id), r, g, b );
SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(id) );
x += (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left);
// Draw victims name (if it was a player that was killed)
if (rgDeathNoticeList[i].iNonPlayerKill == FALSE)
{
if ( rgDeathNoticeList[i].VictimColor )
gEngfuncs.pfnDrawSetTextColor( rgDeathNoticeList[i].VictimColor[0], rgDeathNoticeList[i].VictimColor[1], rgDeathNoticeList[i].VictimColor[2] );
x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim );
}
}
}
return 1;
}
// This message handler may be better off elsewhere
int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf )
{
m_iFlags |= HUD_ACTIVE;
BEGIN_READ( pbuf, iSize );
int killer = READ_BYTE();
int victim = READ_BYTE();
char killedwith[32];
strcpy( killedwith, "d_" );
strncat( killedwith, READ_STRING(), 32 );
if (gViewPort)
gViewPort->DeathMsg( killer, victim );
gHUD.m_Spectator.DeathMessage(victim);
for ( int i = 0; i < MAX_DEATHNOTICES; i++ )
{
if ( rgDeathNoticeList[i].iId == 0 )
break;
}
if ( i == MAX_DEATHNOTICES )
{ // move the rest of the list forward to make room for this item
memmove( rgDeathNoticeList, rgDeathNoticeList+1, sizeof(DeathNoticeItem) * MAX_DEATHNOTICES );
i = MAX_DEATHNOTICES - 1;
}
if (gViewPort)
gViewPort->GetAllPlayersInfo();
// Get the Killer's name
char *killer_name = g_PlayerInfoList[ killer ].name;
if ( !killer_name )
{
killer_name = "";
rgDeathNoticeList[i].szKiller[0] = 0;
}
else
{
rgDeathNoticeList[i].KillerColor = GetClientColor( killer );
strncpy( rgDeathNoticeList[i].szKiller, killer_name, MAX_PLAYER_NAME_LENGTH );
rgDeathNoticeList[i].szKiller[MAX_PLAYER_NAME_LENGTH-1] = 0;
}
// Get the Victim's name
char *victim_name = NULL;
// If victim is -1, the killer killed a specific, non-player object (like a sentrygun)
if ( ((char)victim) != -1 )
victim_name = g_PlayerInfoList[ victim ].name;
if ( !victim_name )
{
victim_name = "";
rgDeathNoticeList[i].szVictim[0] = 0;
}
else
{
rgDeathNoticeList[i].VictimColor = GetClientColor( victim );
strncpy( rgDeathNoticeList[i].szVictim, victim_name, MAX_PLAYER_NAME_LENGTH );
rgDeathNoticeList[i].szVictim[MAX_PLAYER_NAME_LENGTH-1] = 0;
}
// Is it a non-player object kill?
if ( ((char)victim) == -1 )
{
rgDeathNoticeList[i].iNonPlayerKill = TRUE;
// Store the object's name in the Victim slot (skip the d_ bit)
strcpy( rgDeathNoticeList[i].szVictim, killedwith+2 );
}
else
{
if ( killer == victim || killer == 0 )
rgDeathNoticeList[i].iSuicide = TRUE;
if ( !strcmp( killedwith, "d_teammate" ) )
rgDeathNoticeList[i].iTeamKill = TRUE;
}
// Find the sprite in the list
int spr = gHUD.GetSpriteIndex( killedwith );
rgDeathNoticeList[i].iId = spr;
DEATHNOTICE_DISPLAY_TIME = CVAR_GET_FLOAT( "hud_deathnotice_time" );
rgDeathNoticeList[i].flDisplayTime = gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME;
if (rgDeathNoticeList[i].iNonPlayerKill)
{
ConsolePrint( rgDeathNoticeList[i].szKiller );
ConsolePrint( " killed a " );
ConsolePrint( rgDeathNoticeList[i].szVictim );
ConsolePrint( "\n" );
}
else
{
// record the death notice in the console
if ( rgDeathNoticeList[i].iSuicide )
{
ConsolePrint( rgDeathNoticeList[i].szVictim );
if ( !strcmp( killedwith, "d_world" ) )
{
ConsolePrint( " died" );
}
else
{
ConsolePrint( " killed self" );
}
}
else if ( rgDeathNoticeList[i].iTeamKill )
{
ConsolePrint( rgDeathNoticeList[i].szKiller );
ConsolePrint( " killed his teammate " );
ConsolePrint( rgDeathNoticeList[i].szVictim );
}
else
{
ConsolePrint( rgDeathNoticeList[i].szKiller );
ConsolePrint( " killed " );
ConsolePrint( rgDeathNoticeList[i].szVictim );
}
if ( killedwith && *killedwith && (*killedwith > 13 ) && strcmp( killedwith, "d_world" ) && !rgDeathNoticeList[i].iTeamKill )
{
ConsolePrint( " with " );
ConsolePrint( killedwith+2 ); // skip over the "d_" part
}
ConsolePrint( "\n" );
}
return 1;
}

103
cl_dll/demo.cpp Normal file
View File

@ -0,0 +1,103 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#include "hud.h"
#include "cl_util.h"
#include "demo.h"
#include "demo_api.h"
#include <memory.h>
#define DLLEXPORT __declspec( dllexport )
int g_demosniper = 0;
int g_demosniperdamage = 0;
float g_demosniperorg[3];
float g_demosniperangles[3];
float g_demozoom;
// FIXME: There should be buffer helper functions to avoid all of the *(int *)& crap.
extern "C"
{
void DLLEXPORT Demo_ReadBuffer( int size, unsigned char *buffer );
}
/*
=====================
Demo_WriteBuffer
Write some data to the demo stream
=====================
*/
void Demo_WriteBuffer( int type, int size, unsigned char *buffer )
{
int pos = 0;
unsigned char buf[ 32 * 1024 ];
*( int * )&buf[pos] = type;
pos+=sizeof( int );
memcpy( &buf[pos], buffer, size );
// Write full buffer out
gEngfuncs.pDemoAPI->WriteBuffer( size + sizeof( int ), buf );
}
/*
=====================
Demo_ReadBuffer
Engine wants us to parse some data from the demo stream
=====================
*/
void DLLEXPORT Demo_ReadBuffer( int size, unsigned char *buffer )
{
int type;
int i = 0;
type = *( int * )buffer;
i += sizeof( int );
switch ( type )
{
case TYPE_SNIPERDOT:
g_demosniper = *(int * )&buffer[ i ];
i += sizeof( int );
if ( g_demosniper )
{
g_demosniperdamage = *( int * )&buffer[ i ];
i += sizeof( int );
g_demosniperangles[ 0 ] = *(float *)&buffer[i];
i += sizeof( float );
g_demosniperangles[ 1 ] = *(float *)&buffer[i];
i += sizeof( float );
g_demosniperangles[ 2 ] = *(float *)&buffer[i];
i += sizeof( float );
g_demosniperorg[ 0 ] = *(float *)&buffer[i];
i += sizeof( float );
g_demosniperorg[ 1 ] = *(float *)&buffer[i];
i += sizeof( float );
g_demosniperorg[ 2 ] = *(float *)&buffer[i];
i += sizeof( float );
}
break;
case TYPE_ZOOM:
g_demozoom = *(float * )&buffer[ i ];
i += sizeof( float );
break;
default:
gEngfuncs.Con_DPrintf( "Unknown demo buffer type, skipping.\n" );
break;
}
}

27
cl_dll/demo.h Normal file
View File

@ -0,0 +1,27 @@
//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#if !defined( DEMOH )
#define DEMOH
#pragma once
// Types of demo messages we can write/parse
enum
{
TYPE_SNIPERDOT = 0,
TYPE_ZOOM
};
void Demo_WriteBuffer( int type, int size, unsigned char *buffer );
extern int g_demosniper;
extern int g_demosniperdamage;
extern float g_demosniperorg[3];
extern float g_demosniperangles[3];
extern float g_demozoom;
#endif

173
cl_dll/enginecallback.h Normal file
View File

@ -0,0 +1,173 @@
/*
enginecallback.h - actual engine callbacks
Copyright (C) 2011 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef ENGINECALLBACK_H
#define ENGINECALLBACK_H
extern cl_enginefunc_t gEngfuncs;
extern render_api_t gRenderfuncs;
#define GET_CLIENT_TIME (*gEngfuncs.GetClientTime)
#define GET_CLIENT_OLDTIME (*gEngfuncs.GetClientOldTime)
#define CVAR_REGISTER (*gEngfuncs.pfnRegisterVariable)
#define CVAR_GET_FLOAT (*gEngfuncs.pfnGetCvarFloat)
#define CVAR_GET_STRING (*gEngfuncs.pfnGetCvarString)
#define CVAR_SET_FLOAT (*gEngfuncs.Cvar_SetValue)
//#define CVAR_SET_STRING (*gEngfuncs.pfnCVarSetString) // not implemented
#define CVAR_GET_POINTER (*gEngfuncs.pfnGetCvarPointer)
#define ADD_COMMAND (*gEngfuncs.pfnAddCommand)
#define CMD_ARGC (*gEngfuncs.Cmd_Argc)
#define CMD_ARGV (*gEngfuncs.Cmd_Argv)
#define Msg (*gEngfuncs.Con_Printf)
#define GET_LOCAL_PLAYER (*gEngfuncs.GetLocalPlayer)
#define GET_VIEWMODEL (*gEngfuncs.GetViewModel)
#define GET_ENTITY (*gEngfuncs.GetEntityByIndex)
#define POINT_CONTENTS( p ) (*gEngfuncs.PM_PointContents)( p, NULL )
#define WATER_ENTITY (*gEngfuncs.PM_WaterEntity)
#define RANDOM_LONG (*gEngfuncs.pfnRandomLong)
#define RANDOM_FLOAT (*gEngfuncs.pfnRandomFloat)
#define GetScreenInfo (*gEngfuncs.pfnGetScreenInfo)
#define ServerCmd (*gEngfuncs.pfnServerCmd)
#define ClientCmd (*gEngfuncs.pfnClientCmd)
#define SetCrosshair (*gEngfuncs.pfnSetCrosshair)
#define AngleVectors (*gEngfuncs.pfnAngleVectors)
#define GetPlayerInfo (*gEngfuncs.pfnGetPlayerInfo)
#define SPR_Load (*gEngfuncs.pfnSPR_Load)
#define SPR_Set (*gEngfuncs.pfnSPR_Set)
#define SPR_Frames (*gEngfuncs.pfnSPR_Frames)
#define SPR_Draw (*gEngfuncs.pfnSPR_Draw)
#define SPR_DrawHoles (*gEngfuncs.pfnSPR_DrawHoles)
#define SPR_DrawAdditive (*gEngfuncs.pfnSPR_DrawAdditive)
#define SPR_EnableScissor (*gEngfuncs.pfnSPR_EnableScissor)
#define SPR_DisableScissor (*gEngfuncs.pfnSPR_DisableScissor)
#define FillRGBA (*gEngfuncs.pfnFillRGBA)
#define SPR_Height (*gEngfuncs.pfnSPR_Height)
#define SPR_Width (*gEngfuncs.pfnSPR_Width)
#define SPR_GetList (*gEngfuncs.pfnSPR_GetList)
#define SPR_LoadEx (*gRenderfuncs.SPR_LoadExt)
#define ConsolePrint (*gEngfuncs.pfnConsolePrint)
#define CenterPrint (*gEngfuncs.pfnCenterPrint)
#define TextMessageGet (*gEngfuncs.pfnTextMessageGet)
#define TextMessageDrawChar (*gEngfuncs.pfnDrawCharacter)
#define DrawConsoleString (*gEngfuncs.pfnDrawConsoleString)
#define GetConsoleStringSize (*gEngfuncs.pfnDrawConsoleStringLen)
#define DrawSetTextColor (*gEngfuncs.pfnDrawSetTextColor)
#define LOAD_FILE( x, y ) (*gEngfuncs.COM_LoadFile)( x, 5, y )
#define FREE_FILE (*gEngfuncs.COM_FreeFile)
#define SAVE_FILE (*gRenderfuncs.pfnSaveFile)
#define Sys_DoubleTime (*gRenderfuncs.pfnTime)
// sound functions (we can't use macroses - this names is collide with standard windows methods)
inline void PlaySound( char *szSound, float vol ) { gEngfuncs.pfnPlaySoundByName( szSound, vol ); }
inline void PlaySound( int iSound, float vol ) { gEngfuncs.pfnPlaySoundByIndex( iSound, vol ); }
// render api callbacks
#define RENDER_GET_PARM (*gRenderfuncs.RenderGetParm)
#define SET_CURRENT_ENTITY (*gRenderfuncs.R_SetCurrentEntity)
#define SET_CURRENT_MODEL (*gRenderfuncs.R_SetCurrentModel)
#define ENGINE_SET_PVS (*gRenderfuncs.R_FatPVS)
#define HOST_ERROR (*gRenderfuncs.Host_Error)
#define GET_LIGHTSTYLE (*gRenderfuncs.GetLightStyle)
#define GET_DYNAMIC_LIGHT (*gRenderfuncs.GetDynamicLight)
#define GET_ENTITY_LIGHT (*gRenderfuncs.GetEntityLight)
#define TEXTURE_TO_TEXGAMMA (*gRenderfuncs.LightToTexGamma)
#define GET_FRAMETIME (*gRenderfuncs.GetFrameTime)
#define DRAW_SINGLE_DECAL (*gRenderfuncs.DrawSingleDecal)
#define DECAL_SETUP_VERTS (*gRenderfuncs.R_DecalSetupVerts)
#define GET_DETAIL_SCALE (*gRenderfuncs.GetDetailScaleForTexture)
#define GET_EXTRA_PARAMS (*gRenderfuncs.GetExtraParmsForTexture)
#define CREATE_TEXTURE (*gRenderfuncs.GL_CreateTexture)
#define FIND_TEXTURE (*gRenderfuncs.GL_FindTexture)
#define FREE_TEXTURE (*gRenderfuncs.GL_FreeTexture)
#define CREATE_TEXTURE_ARRAY (*gRenderfuncs.GL_CreateTextureArray)
#define STORE_EFRAGS (*gRenderfuncs.R_StoreEfrags)
#define INIT_BEAMCHAINS (*gRenderfuncs.GetBeamChains)
#define DRAW_PARTICLES (*gRenderfuncs.GL_DrawParticles)
#define SET_ENGINE_WORLDVIEW_MATRIX (*gRenderfuncs.GL_SetWorldviewProjectionMatrix)
#define GET_FOG_PARAMS (*gRenderfuncs.GetExtraParmsForTexture)
#define GET_TEXTURE_NAME (*gRenderfuncs.GL_TextureName)
#define GET_TEXTURE_DATA (*gRenderfuncs.GL_TextureData)
#define COMPARE_FILE_TIME (*gRenderfuncs.COM_CompareFileTime)
#define REMOVE_BSP_DECALS (*gRenderfuncs.R_EntityRemoveDecals)
#define STUDIO_GET_TEXTURE (*gRenderfuncs.StudioGetTexture)
#define GET_OVERVIEW_PARMS (*gRenderfuncs.GetOverviewParms)
#define FS_SEARCH (*gRenderfuncs.pfnGetFilesList)
#define ENV_SHOT (*gRenderfuncs.EnvShot)
#define LOAD_TEXTURE (*gRenderfuncs.GL_LoadTexture)
#define LOAD_TEXTURE_ARRAY (*gRenderfuncs.GL_LoadTextureArray)
// AVIKit interface
#define OPEN_CINEMATIC (*gRenderfuncs.AVI_LoadVideo)
#define FREE_CINEMATIC (*gRenderfuncs.AVI_FreeVideo)
#define CIN_IS_ACTIVE (*gRenderfuncs.AVI_IsActive)
#define CIN_GET_VIDEO_INFO (*gRenderfuncs.AVI_GetVideoInfo)
#define CIN_GET_FRAME_NUMBER (*gRenderfuncs.AVI_GetVideoFrameNumber)
#define CIN_GET_FRAMEDATA (*gRenderfuncs.AVI_GetVideoFrame)
#define CIN_UPLOAD_FRAME (*gRenderfuncs.AVI_UploadRawFrame)
#define CIN_UPDATE_SOUND (*gRenderfuncs.AVI_StreamSound)
// glcommands
#define GL_BindTexture (*gRenderfuncs.GL_Bind)
#define GL_SelectTexture (*gRenderfuncs.GL_SelectTexture)
#define GL_TexGen (*gRenderfuncs.GL_TexGen)
#define GL_LoadTextureMatrix (*gRenderfuncs.GL_LoadTextureMatrix)
#define GL_LoadIdentityTexMatrix (*gRenderfuncs.GL_TexMatrixIdentity)
#define GL_CleanUpTextureUnits (*gRenderfuncs.GL_CleanUpTextureUnits)
#define GL_TexCoordArrayMode (*gRenderfuncs.GL_TexCoordArrayMode)
#define GL_TextureTarget (*gRenderfuncs.GL_TextureTarget)
#define GL_UpdateTexSize (*gRenderfuncs.GL_UpdateTexSize)
#define RANDOM_SEED (*gRenderfuncs.SetRandomSeed)
#define MUSIC_FADE_VOLUME (*gRenderfuncs.S_FadeMusicVolume)
#define GL_GetProcAddress (*gRenderfuncs.GL_GetProcAddress)
#define MODEL_HANDLE (*gRenderfuncs.pfnGetModel)
// built-in memory manager
#define Mem_Alloc( x ) (*gRenderfuncs.pfnMemAlloc)( x, __FILE__, __LINE__ )
#define Mem_Free( x ) (*gRenderfuncs.pfnMemFree)( x, __FILE__, __LINE__ )
#define _Mem_Alloc (*gRenderfuncs.pfnMemAlloc)
#define _Mem_Free (*gRenderfuncs.pfnMemFree)
#define ASSERT( exp ) if(!( exp )) HOST_ERROR( "assert failed at %s:%i\n", __FILE__, __LINE__ )
#define IMAGE_EXISTS( path ) ( FILE_EXISTS( va( "%s.tga", path )) || FILE_EXISTS( va( "%s.dds", path )))
extern void ALERT( ALERT_TYPE level, char *szFmt, ... );
inline bool FILE_EXISTS( const char *filename )
{
int iCompare;
// verify file exists
// g-cont. idea! use COMPARE_FILE_TIME instead of COM_LoadFile
if( COMPARE_FILE_TIME( filename, filename, &iCompare ))
return true;
return false;
}
#define FILE_CRC32 (*gRenderfuncs.pfnFileBufferCRC32)
#define GET_MAX_CLIENTS (*gEngfuncs.GetMaxClients)
#endif//ENGINECALLBACK_H

937
cl_dll/entity.cpp Normal file
View File

@ -0,0 +1,937 @@
//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
// Client side entity management functions
#include <memory.h>
#include "hud.h"
#include "cl_util.h"
#include "const.h"
#include "entity_types.h"
#include "r_efx.h"
#include "event_api.h"
#include "pm_defs.h"
#include "pmtrace.h"
#include "pm_shared.h"
#include "eventscripts.h" // buz
#include "gl_local.h"
#include "gl_studio.h"
#define DLLEXPORT __declspec( dllexport )
void Game_AddObjects( void );
extern vec3_t v_origin;
extern vec3_t g_vSpread;
extern int g_iGunMode;
int g_iAlive = 1;
int g_flashlight; // buz
int r_currentMessageNum = 0;
int GlowFilterEntities ( int type, struct cl_entity_s *ent, const char *modelname ); // buz
extern "C"
{
int DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname );
void DLLEXPORT HUD_CreateEntities( void );
void DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity );
void DLLEXPORT HUD_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client );
void DLLEXPORT HUD_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src );
void DLLEXPORT HUD_TxferPredictionData ( struct entity_state_s *ps, const struct entity_state_s *pps, struct clientdata_s *pcd, const struct clientdata_s *ppcd, struct weapon_data_s *wd, const struct weapon_data_s *pwd );
void DLLEXPORT HUD_TempEntUpdate( double frametime, double client_time, double cl_gravity, struct tempent_s **ppTempEntFree, struct tempent_s **ppTempEntActive, int ( *Callback_AddVisibleEntity )( struct cl_entity_s *pEntity ), void ( *Callback_TempEntPlaySound )( struct tempent_s *pTemp, float damp ) );
struct cl_entity_s DLLEXPORT *HUD_GetUserEntity( int index );
}
/*
========================
HUD_AddEntity
Return 0 to filter entity from visible list for rendering
========================
*/
int DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname )
{
if( ent->curstate.rendermode == kRenderTransAlpha && ent->model && ent->model->type == mod_brush )
{
// fix invisible grates on fallback renderer
ent->curstate.renderamt = 255;
}
if( g_fXashEngine && g_fRenderInitialized )
{
// use engine renderer
if( cv_renderer->value == 0 )
return 1;
if( type == ET_BEAM )
return 1; // let the engine draw beams
R_AddEntity( ent, type );
return 0;
}
// each frame every entity passes this function, so the overview hooks it to filter the overview entities
// in spectator mode:
// each frame every entity passes this function, so the overview hooks
// it to filter the overview entities
if ( g_iUser1 )
{
gHUD.m_Spectator.AddOverviewEntity( type, ent, modelname );
if ( ( g_iUser1 == OBS_IN_EYE || gHUD.m_Spectator.m_pip->value == INSET_IN_EYE ) &&
ent->index == g_iUser2 )
return 0; // don't draw the player we are following in eye
}
return 1;
}
/*
=========================
HUD_TxferLocalOverrides
The server sends us our origin with extra precision as part of the clientdata structure, not during the normal
playerstate update in entity_state_t. In order for these overrides to eventually get to the appropriate playerstate
structure, we need to copy them into the state structure at this point.
=========================
*/
void DLLEXPORT HUD_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client )
{
state->origin = client->origin;
state->velocity = client->velocity;
gHUD.m_iViewModelIndex = client->viewmodel;
// Spectator
state->iuser1 = client->iuser1;
state->iuser2 = client->iuser2;
// Duck prevention
state->iuser3 = client->iuser3;
// Fire prevention
state->iuser4 = client->iuser4;
// always have valid PVS message
r_currentMessageNum = state->messagenum;
// IMPORTANT: this data doesn't present in entity_state_t
// but only in clientdata_t for local player (gun params, spectator mode etc)
g_iUser1 = client->iuser1;
g_iUser2 = client->iuser2;
g_iUser3 = client->iuser3;
// buz
g_vSpread = client->vuser1;
g_iGunMode = client->iuser4;
}
/*
=========================
HUD_ProcessPlayerState
We have received entity_state_t for this player over the network. We need to copy appropriate fields to the
playerstate structure
=========================
*/
void DLLEXPORT HUD_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src )
{
// Copy in network data
dst->origin = src->origin;
dst->angles = src->angles;
dst->velocity = src->velocity;
dst->basevelocity = src->basevelocity;
dst->frame = src->frame;
dst->modelindex = src->modelindex;
dst->skin = src->skin;
dst->effects = src->effects;
dst->weaponmodel = src->weaponmodel;
dst->movetype = src->movetype;
dst->sequence = src->sequence;
dst->animtime = src->animtime;
dst->solid = src->solid;
dst->rendermode = src->rendermode;
dst->renderamt = src->renderamt;
dst->rendercolor.r = src->rendercolor.r;
dst->rendercolor.g = src->rendercolor.g;
dst->rendercolor.b = src->rendercolor.b;
dst->renderfx = src->renderfx;
dst->framerate = src->framerate;
dst->body = src->body;
dst->friction = src->friction;
dst->gravity = src->gravity;
dst->gaitsequence = src->gaitsequence;
dst->usehull = src->usehull;
dst->playerclass = src->playerclass;
dst->team = src->team;
dst->colormap = src->colormap;
dst->fuser1 = src->fuser1;
dst->fuser2 = src->fuser2;
dst->fuser3 = src->fuser3;
dst->fuser4 = src->fuser4;
dst->vuser1 = src->vuser1;
dst->vuser2 = src->vuser2;
dst->vuser3 = src->vuser3;
dst->vuser4 = src->vuser4;
memcpy( &dst->controller[0], &src->controller[0], 4 * sizeof( byte ));
memcpy( &dst->blending[0], &src->blending[0], 2 * sizeof( byte ));
// Save off some data so other areas of the Client DLL can get to it
cl_entity_t *player = gEngfuncs.GetLocalPlayer(); // Get the local player's index
if ( dst->number == player->index )
{
g_iPlayerClass = dst->playerclass;
g_iTeamNumber = dst->team;
}
// buz: get flashlight status
if (dst->effects & EF_DIMLIGHT)
g_flashlight = 1;
else g_flashlight = 0;
}
/*
=========================
HUD_TxferPredictionData
Because we can predict an arbitrary number of frames before the server responds with an update, we need to be able to copy client side prediction data in
from the state that the server ack'd receiving, which can be anywhere along the predicted frame path ( i.e., we could predict 20 frames into the future and the server ack's
up through 10 of those frames, so we need to copy persistent client-side only state from the 10th predicted frame to the slot the server
update is occupying.
=========================
*/
void DLLEXPORT HUD_TxferPredictionData ( struct entity_state_s *ps, const struct entity_state_s *pps, struct clientdata_s *pcd, const struct clientdata_s *ppcd, struct weapon_data_s *wd, const struct weapon_data_s *pwd )
{
ps->oldbuttons = pps->oldbuttons;
ps->flFallVelocity = pps->flFallVelocity;
ps->iStepLeft = pps->iStepLeft;
ps->playerclass = pps->playerclass;
pcd->viewmodel = ppcd->viewmodel;
pcd->m_iId = ppcd->m_iId;
pcd->ammo_shells = ppcd->ammo_shells;
pcd->ammo_nails = ppcd->ammo_nails;
pcd->ammo_cells = ppcd->ammo_cells;
pcd->ammo_rockets = ppcd->ammo_rockets;
pcd->m_flNextAttack = ppcd->m_flNextAttack;
pcd->fov = ppcd->fov;
pcd->weaponanim = ppcd->weaponanim;
pcd->tfstate = ppcd->tfstate;
pcd->maxspeed = ppcd->maxspeed;
pcd->deadflag = ppcd->deadflag;
// Spectating or not dead == get control over view angles.
g_iAlive = ( ppcd->iuser1 || ( pcd->deadflag == DEAD_NO ) ) ? 1 : 0;
// Spectator
pcd->iuser1 = ppcd->iuser1;
pcd->iuser2 = ppcd->iuser2;
// Duck prevention
pcd->iuser3 = ppcd->iuser3;
if ( gEngfuncs.IsSpectateOnly() )
{
// in specator mode we tell the engine who we want to spectate and how
// iuser3 is not used for duck prevention (since the spectator can't duck at all)
pcd->iuser1 = g_iUser1; // observer mode
pcd->iuser2 = g_iUser2; // first target
pcd->iuser3 = g_iUser3; // second target
}
// Fire prevention
pcd->iuser4 = ppcd->iuser4;
pcd->fuser1 = ppcd->fuser1;
pcd->fuser2 = ppcd->fuser2;
pcd->fuser3 = ppcd->fuser3;
pcd->fuser4 = ppcd->fuser4;
pcd->vuser1 = ppcd->vuser1;
pcd->vuser2 = ppcd->vuser2;
pcd->vuser3 = ppcd->vuser3;
pcd->vuser4 = ppcd->vuser4;
memcpy( wd, pwd, 32 * sizeof( weapon_data_t ) );
}
/*
=========================
HUD_CreateEntities
Gives us a chance to add additional entities to the render this frame
=========================
*/
void DLLEXPORT HUD_CreateEntities( void )
{
// e.g., create a persistent cl_entity_t somewhere.
// Load an appropriate model into it ( gEngfuncs.CL_LoadModel )
// Call gEngfuncs.CL_CreateVisibleEntity to add it to the visedicts list
GetClientVoiceMgr()->CreateEntities();
// used to draw legs
HUD_AddEntity( ET_PLAYER, GET_LOCAL_PLAYER(), GET_LOCAL_PLAYER()->model->name );
}
void DlightFlash( const Vector &origin, int index )
{
dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight( index );
dl->origin = origin;
dl->radius = 128;
dl->color.r = 180;
dl->color.g = 160;
dl->color.b = 120;
dl->die = GET_CLIENT_TIME() + 0.06f;
CDynLight *pl = CL_AllocDlight( index );
R_SetupLightParams( pl, origin, g_vecZero, 128.0f, 0.0f, LIGHT_OMNI, DLF_NOSHADOWS );
pl->color = Vector( 0.7f, 0.6f, 0.5f );
pl->die = GET_CLIENT_TIME() + 0.06f;
}
/*
==============
CL_MuzzleFlash
Do muzzleflash
==============
*/
void HUD_MuzzleFlash( const cl_entity_t *e, const Vector &pos, const Vector &fwd, int type, float mul )
{
TEMPENTITY *pTemp;
int body, modelIndex, frameCount;
Vector flash_angles;
int flags = 0;
float scale;
if( RP_NORMALPASS( ))
{
if( e == gEngfuncs.GetViewModel( ))
flags |= EF_NOREFLECT|EF_NODEPTHTEST;
else if( e->player && RP_LOCALCLIENT( e ))
flags |= EF_REFLECTONLY;
}
else
{
if( e->player && RP_LOCALCLIENT( e ))
flags |= EF_REFLECTONLY;
}
body = bound( 0, type % 5, 4 );
scale = (type / 5) * 0.2f;
if( scale == 0.0f ) scale = 0.5f;
modelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/m_flash1.mdl");
if( !modelIndex ) return;
Mod_GetFrames( modelIndex, frameCount );
if( body > ( frameCount - 1 ))
body = frameCount - 1;
// must set position for right culling on render
if( !( pTemp = gEngfuncs.pEfxAPI->CL_TempEntAllocHigh((float *)&pos, Mod_Handle( modelIndex ))))
return;
VectorAngles( -fwd, flash_angles );
scale *= mul;
pTemp->entity.curstate.rendermode = kRenderGlow;
pTemp->entity.curstate.renderamt = 255;
pTemp->entity.curstate.framerate = 10;
pTemp->entity.curstate.renderfx = 0;
pTemp->entity.angles = flash_angles;
pTemp->die = tr.time + 0.015f; // die at next frame
pTemp->entity.curstate.body = body;
// pTemp->flags |= FTENT_MDLANIMATE|FTENT_MDLANIMATELOOP;
pTemp->entity.angles[2] = RANDOM_LONG( 0, 359 );
pTemp->entity.curstate.scale = scale;
pTemp->frameMax = frameCount - 1;
gEngfuncs.CL_CreateVisibleEntity( ET_TEMPENTITY, &pTemp->entity );
pTemp->entity.curstate.effects |= EF_FULLBRIGHT|flags; // CL_CreateVisibleEntity clears 'effect' field, so we need add it here
}
/*
=========================
HUD_StudioEvent
The entity's studio model description indicated an event was
fired during this frame, handle the event by it's tag ( e.g., muzzleflash, sound )
=========================
*/
void DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity )
{
float rnd2 = gEngfuncs.pfnRandomFloat( -0.03, 0.03 );
Vector pos, dir;
float mul = 2.0f;
int shell;
// ALERT( at_console, "Play event: %i, options %s, framecount %i\n", event->event, event->options, tr.realframecount );
if( entity == GET_VIEWMODEL( ))
mul = 8.0f;
switch( event->event )
{
case 5001:
R_StudioAttachmentPosDir( entity, 0, &pos, &dir );
HUD_MuzzleFlash( entity, pos, dir, atoi( event->options), mul );
DlightFlash((float *)&entity->attachment[0], entity->index );
EV_GunSmoke( entity->attachment[0] );
break;
case 5007:
EV_GunSmoke( entity->attachment[0] );
break;
case 5008:
EV_GunSmoke( entity->attachment[1] );
break;
case 5009: // custom shell ejection
shell = gEngfuncs.pEventAPI->EV_FindModelIndex( event->options );
R_StudioAttachmentPosDir( entity, 2, &pos, &dir );
EV_EjectBrass( pos, dir, 0, shell, TE_BOUNCE_SHELL );
break;
case 5010: // custom shell ejection, no velocity
shell = gEngfuncs.pEventAPI->EV_FindModelIndex( event->options );
R_StudioAttachmentPosDir( entity, 2, &pos, &dir );
EV_EjectBrass( pos, (float *)&g_vecZero, 0, shell, TE_BOUNCE_SHELL );
break;
case 5011:
R_StudioAttachmentPosDir( entity, 1, &pos, &dir );
HUD_MuzzleFlash( entity, pos, dir, atoi( event->options), mul );
DlightFlash((float *)&entity->attachment[1], entity->index );
EV_GunSmoke( entity->attachment[1] );
break;
case 5021:
R_StudioAttachmentPosDir( entity, 2, &pos, &dir );
HUD_MuzzleFlash( entity, pos, dir, atoi( event->options), mul );
DlightFlash((float *)&entity->attachment[2], entity->index );
EV_GunSmoke( entity->attachment[2] );
break;
case 5031:
R_StudioAttachmentPosDir( entity, 3, &pos, &dir );
HUD_MuzzleFlash( entity, pos, dir, atoi( event->options), mul );
DlightFlash((float *)&entity->attachment[3], entity->index );
EV_GunSmoke( entity->attachment[3] );
break;
case 5002:
gEngfuncs.pEfxAPI->R_SparkEffect( (float *)&entity->attachment[0], atoi( event->options), -100, 100 );
break;
// Client side sound
case 5004:
gEngfuncs.pfnPlaySoundByNameAtLocation( (char *)event->options, 1.0, (float *)&entity->attachment[0] );
break;
case 5005: // buz: left foot step (attach 3)
{
int contents = gEngfuncs.PM_PointContents( (float *)&entity->attachment[3], NULL );
if (contents == CONTENTS_WATER) // leg is in the water
{
int waterEntity = gEngfuncs.PM_WaterEntity( (float *)&entity->attachment[3] );
if ( waterEntity > 0 ) // water should be func_water entity
{
cl_entity_t *pwater = gEngfuncs.GetEntityByIndex( waterEntity );
if ( pwater && ( pwater->model != NULL ) )
{
if ((pwater->curstate.maxs[2] - entity->attachment[3][2]) < 16)
{
vec3_t vecNull(0, 0, 0);
vec3_t vecSrc((float *)&entity->attachment[3]);
vecSrc.z += 25;
int iPuff = gEngfuncs.pEventAPI->EV_FindModelIndex("sprites/wsplash_x.spr");
TEMPENTITY *wp = gEngfuncs.pEfxAPI->R_TempSprite(vecSrc, vecNull, 0.5, iPuff, kRenderTransAdd, kRenderFxNone, 1, 5, FTENT_SPRANIMATE);
wp->entity.curstate.framerate = 20;
//wp->entity.curstate.rendercolor.r = entity->cvFloorColor.r;
//wp->entity.curstate.rendercolor.g = entity->cvFloorColor.g;
//wp->entity.curstate.rendercolor.b = entity->cvFloorColor.b;
}
}
}
}
break;
}
case 5015: // buz: right foot step (attach 2)
{
int contents = gEngfuncs.PM_PointContents( (float *)&entity->attachment[2], NULL );
if (contents == CONTENTS_WATER) // leg is in the water
{
int waterEntity = gEngfuncs.PM_WaterEntity( (float *)&entity->attachment[2] );
if ( waterEntity > 0 ) // water should be func_water entity
{
cl_entity_t *pwater = gEngfuncs.GetEntityByIndex( waterEntity );
if ( pwater && ( pwater->model != NULL ) )
{
if ((pwater->curstate.maxs[2] - entity->attachment[2][2]) < 16)
{
vec3_t vecNull(0, 0, 0);
vec3_t vecSrc((float *)&entity->attachment[2]);
vecSrc.z += 25;
int iPuff = gEngfuncs.pEventAPI->EV_FindModelIndex("sprites/wsplash_x.spr");
TEMPENTITY *wp = gEngfuncs.pEfxAPI->R_TempSprite(vecSrc, vecNull, 0.5, iPuff, kRenderTransAdd, kRenderFxNone, 1, 5, FTENT_SPRANIMATE);
wp->entity.curstate.framerate = 20;
//wp->entity.curstate.rendercolor.r = entity->cvFloorColor.r;
//wp->entity.curstate.rendercolor.g = entity->cvFloorColor.g;
//wp->entity.curstate.rendercolor.b = entity->cvFloorColor.b;
}
}
}
}
break;
}
case 5006: // buz: shell at 2nd attachment flying to 3rd
{
int shell = gEngfuncs.pEventAPI->EV_FindModelIndex ("models/shell.mdl");
vec3_t VecDir = entity->attachment[2] - entity->attachment[1];
VecDir = VecDir * 10;
EV_EjectBrass ( (float *)&entity->attachment[1], VecDir, 0, shell, TE_BOUNCE_SHELL );
break;
}
case 5040:
// make aurora for origin
UTIL_CreateAurora((cl_entity_t *)entity, event->options, 0, 0.0f );
break;
case 5041:
// make aurora for attachment #1
UTIL_CreateAurora((cl_entity_t *)entity, event->options, 1, 0.0f );
break;
case 5042:
// make aurora for attachment #2
UTIL_CreateAurora((cl_entity_t *)entity, event->options, 2, 0.0f );
break;
case 5043:
// make aurora for attachment #3
UTIL_CreateAurora((cl_entity_t *)entity, event->options, 3, 0.0f );
break;
case 5044:
// make aurora for attachment #4
UTIL_CreateAurora((cl_entity_t *)entity, event->options, 4, 0.0f );
break;
default:
break;
}
}
/*
=================
CL_UpdateTEnts
Simulation and cleanup of temporary entities
=================
*/
void DLLEXPORT HUD_TempEntUpdate (
double frametime, // Simulation time
double client_time, // Absolute time on client
double cl_gravity, // True gravity on client
TEMPENTITY **ppTempEntFree, // List of freed temporary ents
TEMPENTITY **ppTempEntActive, // List
int (*Callback_AddVisibleEntity)( cl_entity_t *pEntity ),
void (*Callback_TempEntPlaySound)( TEMPENTITY *pTemp, float damp ) )
{
static int gTempEntFrame = 0;
TEMPENTITY *pTemp, *pnext, *pprev;
float freq, gravity, gravitySlow, life, fastFreq;
// Nothing to simulate
if( !*ppTempEntActive ) return;
// in order to have tents collide with players, we have to run the player prediction code so
// that the client has the player list. We run this code once when we detect any COLLIDEALL
// tent, then set this BOOL to true so the code doesn't get run again if there's more than
// one COLLIDEALL ent for this update. (often are).
gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true );
// Store off the old count
gEngfuncs.pEventAPI->EV_PushPMStates();
// Now add in all of the players.
gEngfuncs.pEventAPI->EV_SetSolidPlayers ( -1 );
// !!!BUGBUG -- This needs to be time based
gTempEntFrame = (gTempEntFrame+1) & 31;
pTemp = *ppTempEntActive;
// !!! Don't simulate while paused.... This is sort of a hack, revisit.
if( frametime <= 0 )
{
while( pTemp )
{
if( !(pTemp->flags & FTENT_NOMODEL ))
{
Callback_AddVisibleEntity( &pTemp->entity );
}
pTemp = pTemp->next;
}
goto finish;
}
pprev = NULL;
freq = client_time * 0.01;
fastFreq = client_time * 5.5;
gravity = -frametime * cl_gravity;
gravitySlow = gravity * 0.5;
while ( pTemp )
{
int active = 1;
life = pTemp->die - client_time;
pnext = pTemp->next;
if( life < 0 )
{
if ( pTemp->flags & FTENT_FADEOUT )
{
if (pTemp->entity.curstate.rendermode == kRenderNormal)
pTemp->entity.curstate.rendermode = kRenderTransTexture;
pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt * ( 1 + life * pTemp->fadeSpeed );
if ( pTemp->entity.curstate.renderamt <= 0 )
active = 0;
}
else active = 0;
}
if( !active ) // Kill it
{
pTemp->next = *ppTempEntFree;
*ppTempEntFree = pTemp;
if( !pprev ) // deleting at head of list
*ppTempEntActive = pnext;
else
pprev->next = pnext;
}
else
{
pprev = pTemp;
VectorCopy( pTemp->entity.origin, pTemp->entity.prevstate.origin );
if ( pTemp->flags & FTENT_SPARKSHOWER )
{
// Adjust speed if it's time
// Scale is next think time
if ( client_time > pTemp->entity.baseline.scale )
{
// Show Sparks
gEngfuncs.pEfxAPI->R_SparkEffect( pTemp->entity.origin, 8, -200, 200 );
// Reduce life
pTemp->entity.baseline.framerate -= 0.1;
if ( pTemp->entity.baseline.framerate <= 0.0 )
{
pTemp->die = client_time;
}
else
{
// So it will die no matter what
pTemp->die = client_time + 0.5;
// Next think
pTemp->entity.baseline.scale = client_time + 0.1;
}
}
}
else if ( pTemp->flags & FTENT_PLYRATTACHMENT )
{
cl_entity_t *pClient;
pClient = gEngfuncs.GetEntityByIndex( pTemp->clientIndex );
VectorAdd( pClient->origin, pTemp->tentOffset, pTemp->entity.origin );
}
else if ( pTemp->flags & FTENT_SINEWAVE )
{
pTemp->x += pTemp->entity.baseline.origin[0] * frametime;
pTemp->y += pTemp->entity.baseline.origin[1] * frametime;
pTemp->entity.origin[0] = pTemp->x + sin( pTemp->entity.baseline.origin[2] + client_time * pTemp->entity.prevstate.frame ) * (10*pTemp->entity.curstate.framerate);
pTemp->entity.origin[1] = pTemp->y + sin( pTemp->entity.baseline.origin[2] + fastFreq + 0.7 ) * (8*pTemp->entity.curstate.framerate);
pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime;
}
else if ( pTemp->flags & FTENT_SPIRAL )
{
float s, c;
s = sin( pTemp->entity.baseline.origin[2] + fastFreq );
c = cos( pTemp->entity.baseline.origin[2] + fastFreq );
pTemp->entity.origin[0] += pTemp->entity.baseline.origin[0] * frametime + 8 * sin( client_time * 20 + (int)pTemp );
pTemp->entity.origin[1] += pTemp->entity.baseline.origin[1] * frametime + 4 * sin( client_time * 30 + (int)pTemp );
pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime;
}
else
{
for ( int i = 0; i < 3; i++ )
pTemp->entity.origin[i] += pTemp->entity.baseline.origin[i] * frametime;
}
if ( pTemp->flags & FTENT_SPRANIMATE )
{
pTemp->entity.curstate.frame += frametime * pTemp->entity.curstate.framerate;
if ( pTemp->entity.curstate.frame >= pTemp->frameMax )
{
pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame);
if ( !(pTemp->flags & FTENT_SPRANIMATELOOP) )
{
// this animating sprite isn't set to loop, so destroy it.
pTemp->die = client_time;
pTemp = pnext;
continue;
}
}
}
else if ( pTemp->flags & FTENT_MDLANIMATE )
{
pTemp->entity.curstate.body += frametime * pTemp->entity.curstate.framerate;
if ( pTemp->entity.curstate.body >= pTemp->frameMax )
{
pTemp->entity.curstate.body = pTemp->frameMax;
if( !( pTemp->flags & FTENT_MDLANIMATELOOP ))
{
// this animating sprite isn't set to loop, so destroy it.
pTemp->die = client_time;
pTemp = pnext;
continue;
}
}
}
else if ( pTemp->flags & FTENT_SPRCYCLE )
{
pTemp->entity.curstate.frame += frametime * 10;
if ( pTemp->entity.curstate.frame >= pTemp->frameMax )
{
pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame);
}
}
// Experiment
#if 0
if ( pTemp->flags & FTENT_SCALE )
pTemp->entity.curstate.framerate += 20.0 * (frametime / pTemp->entity.curstate.framerate);
#endif
if ( pTemp->flags & FTENT_ROTATE )
{
pTemp->entity.angles[0] += pTemp->entity.baseline.angles[0] * frametime;
pTemp->entity.angles[1] += pTemp->entity.baseline.angles[1] * frametime;
pTemp->entity.angles[2] += pTemp->entity.baseline.angles[2] * frametime;
VectorCopy( pTemp->entity.angles, pTemp->entity.latched.prevangles );
}
if ( pTemp->flags & (FTENT_COLLIDEALL | FTENT_COLLIDEWORLD) )
{
vec3_t traceNormal;
float traceFraction = 1;
if ( pTemp->flags & FTENT_COLLIDEALL )
{
pmtrace_t pmtrace;
physent_t *pe;
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX, -1, &pmtrace );
if ( pmtrace.fraction != 1 )
{
pe = gEngfuncs.pEventAPI->EV_GetPhysent( pmtrace.ent );
if ( !pmtrace.ent || ( pe->info != pTemp->clientIndex ) )
{
traceFraction = pmtrace.fraction;
VectorCopy( pmtrace.plane.normal, traceNormal );
if ( pTemp->hitcallback )
{
(*pTemp->hitcallback)( pTemp, &pmtrace );
}
}
}
}
else if ( pTemp->flags & FTENT_COLLIDEWORLD )
{
pmtrace_t pmtrace;
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX | PM_WORLD_ONLY, -1, &pmtrace );
if ( pmtrace.fraction != 1 )
{
traceFraction = pmtrace.fraction;
VectorCopy( pmtrace.plane.normal, traceNormal );
if ( pTemp->flags & FTENT_SPARKSHOWER )
{
// Chop spark speeds a bit more
//
VectorScale( pTemp->entity.baseline.origin, 0.6, pTemp->entity.baseline.origin );
if ( Length( pTemp->entity.baseline.origin ) < 10 )
{
pTemp->entity.baseline.framerate = 0.0;
}
}
if ( pTemp->hitcallback )
{
(*pTemp->hitcallback)( pTemp, &pmtrace );
}
}
}
if ( traceFraction != 1 ) // Decent collision now, and damping works
{
float proj, damp;
// Place at contact point
VectorMA( pTemp->entity.prevstate.origin, traceFraction*frametime, pTemp->entity.baseline.origin, pTemp->entity.origin );
// Damp velocity
damp = pTemp->bounceFactor;
if ( pTemp->flags & (FTENT_GRAVITY|FTENT_SLOWGRAVITY) )
{
damp *= 0.5;
if ( traceNormal[2] > 0.9 ) // Hit floor?
{
if ( pTemp->entity.baseline.origin[2] <= 0 && pTemp->entity.baseline.origin[2] >= gravity*3 )
{
damp = 0; // Stop
pTemp->flags &= ~(FTENT_ROTATE|FTENT_GRAVITY|FTENT_SLOWGRAVITY|FTENT_COLLIDEWORLD|FTENT_SMOKETRAIL);
pTemp->entity.angles[0] = 0;
pTemp->entity.angles[2] = 0;
}
}
}
if (pTemp->hitSound)
{
Callback_TempEntPlaySound(pTemp, damp);
}
if (pTemp->flags & FTENT_COLLIDEKILL)
{
// die on impact
pTemp->flags &= ~FTENT_FADEOUT;
pTemp->die = client_time;
}
else
{
// Reflect velocity
if ( damp != 0 )
{
proj = DotProduct( pTemp->entity.baseline.origin, traceNormal );
VectorMA( pTemp->entity.baseline.origin, -proj*2, traceNormal, pTemp->entity.baseline.origin );
// Reflect rotation (fake)
pTemp->entity.angles[1] = -pTemp->entity.angles[1];
}
if ( damp != 1 )
{
VectorScale( pTemp->entity.baseline.origin, damp, pTemp->entity.baseline.origin );
VectorScale( pTemp->entity.angles, 0.9, pTemp->entity.angles );
}
}
}
}
if ( (pTemp->flags & FTENT_FLICKER) && gTempEntFrame == pTemp->entity.curstate.effects )
{
dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight (0);
VectorCopy (pTemp->entity.origin, dl->origin);
dl->radius = 60;
dl->color.r = 255;
dl->color.g = 120;
dl->color.b = 0;
dl->die = client_time + 0.01;
}
if ( pTemp->flags & FTENT_SMOKETRAIL )
{
gEngfuncs.pEfxAPI->R_RocketTrail (pTemp->entity.prevstate.origin, pTemp->entity.origin, 1);
}
if ( pTemp->flags & FTENT_GRAVITY )
pTemp->entity.baseline.origin[2] += gravity;
else if ( pTemp->flags & FTENT_SLOWGRAVITY )
pTemp->entity.baseline.origin[2] += gravitySlow;
if ( pTemp->flags & FTENT_CLIENTCUSTOM )
{
if ( pTemp->callback )
{
( *pTemp->callback )( pTemp, frametime, client_time );
}
}
// Cull to PVS (not frustum cull, just PVS)
if ( !(pTemp->flags & FTENT_NOMODEL ) )
{
if( g_fRenderInitialized )
{
Callback_AddVisibleEntity( &pTemp->entity );
}
else
{
if ( !Callback_AddVisibleEntity( &pTemp->entity ) )
{
if ( !(pTemp->flags & FTENT_PERSIST) )
{
pTemp->die = client_time; // If we can't draw it this frame, just dump it.
pTemp->flags &= ~FTENT_FADEOUT; // Don't fade out, just die
}
}
}
}
}
pTemp = pnext;
}
finish:
// Restore state info
gEngfuncs.pEventAPI->EV_PopPMStates();
}
/*
=================
HUD_GetUserEntity
If you specify negative numbers for beam start and end point entities, then
the engine will call back into this function requesting a pointer to a cl_entity_t
object that describes the entity to attach the beam onto.
Indices must start at 1, not zero.
=================
*/
cl_entity_t DLLEXPORT *HUD_GetUserEntity( int index )
{
return NULL;
}

205
cl_dll/ev_common.cpp Normal file
View File

@ -0,0 +1,205 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
// shared event functions
#include "hud.h"
#include "cl_util.h"
#include "const.h"
#include "entity_state.h"
#include "cl_entity.h"
#include "r_efx.h"
#include "eventscripts.h"
#include "event_api.h"
#include "pm_shared.h"
#define IS_FIRSTPERSON_SPEC ( g_iUser1 == OBS_IN_EYE || (g_iUser1 && (gHUD.m_Spectator.m_pip->value == INSET_IN_EYE)) )
/*
=================
GetEntity
Return's the requested cl_entity_t
=================
*/
struct cl_entity_s *GetEntity( int idx )
{
return gEngfuncs.GetEntityByIndex( idx );
}
/*
=================
GetViewEntity
Return's the current weapon/view model
=================
*/
struct cl_entity_s *GetViewEntity( void )
{
return gEngfuncs.GetViewModel();
}
/*
=================
EV_CreateTracer
Creates a tracer effect
=================
*/
void EV_CreateTracer( float *start, float *end )
{
gEngfuncs.pEfxAPI->R_TracerEffect( start, end );
}
/*
=================
EV_IsPlayer
Is the entity's index in the player range?
=================
*/
qboolean EV_IsPlayer( int idx )
{
if ( idx >= 1 && idx <= gEngfuncs.GetMaxClients() )
return true;
return false;
}
/*
=================
EV_IsLocal
Is the entity == the local player
=================
*/
qboolean EV_IsLocal( int idx )
{
// check if we are in some way in first person spec mode
if ( IS_FIRSTPERSON_SPEC )
return (g_iUser2 == idx);
else
return gEngfuncs.pEventAPI->EV_IsLocal( idx - 1 ) ? true : false;
}
/*
=================
EV_GetGunPosition
Figure out the height of the gun
=================
*/
void EV_GetGunPosition( event_args_t *args, float *pos, float *origin )
{
int idx;
vec3_t view_ofs;
idx = args->entindex;
VectorClear( view_ofs );
view_ofs[2] = DEFAULT_VIEWHEIGHT;
if ( EV_IsPlayer( idx ) )
{
// in spec mode use entity viewheigh, not own
if ( EV_IsLocal( idx ) && !IS_FIRSTPERSON_SPEC )
{
// Grab predicted result for local player
gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs );
}
else if ( args->ducking == 1 )
{
view_ofs[2] = VEC_DUCK_VIEW;
}
}
VectorAdd( origin, view_ofs, pos );
}
/*
=================
EV_EjectBrass
Bullet shell casings
=================
*/
void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype )
{
Vector endpos = Vector( 0.0f, rotation, 0.0f );
gEngfuncs.pEfxAPI->R_TempModel( origin, velocity, endpos, RANDOM_FLOAT( 1.5f, 3.0f ), model, soundtype );
}
/*
=================
EV_GetDefaultShellInfo
Determine where to eject shells from
=================
*/
void EV_GetDefaultShellInfo( event_args_t *args, float *origin, float *velocity, float *ShellVelocity, float *ShellOrigin, float *forward, float *right, float *up, float forwardScale, float upScale, float rightScale )
{
int i;
vec3_t view_ofs;
float fR, fU;
int idx;
idx = args->entindex;
VectorClear( view_ofs );
view_ofs[2] = DEFAULT_VIEWHEIGHT;
if ( EV_IsPlayer( idx ) )
{
if ( EV_IsLocal( idx ) )
{
gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs );
}
else if ( args->ducking == 1 )
{
view_ofs[2] = VEC_DUCK_VIEW;
}
}
// fR = gEngfuncs.pfnRandomFloat( 50, 70 );
// fU = gEngfuncs.pfnRandomFloat( 100, 150 );
fR = gEngfuncs.pfnRandomFloat( 80, 120 );
fU = gEngfuncs.pfnRandomFloat( 10, 30 ); // buz
for ( i = 0; i < 3; i++ )
{
ShellVelocity[i] = velocity[i] + right[i] * fR + up[i] * fU + forward[i] * 25;
ShellOrigin[i] = origin[i] + view_ofs[i] + up[i] * upScale + forward[i] * forwardScale + right[i] * rightScale;
}
}
/*
=================
EV_MuzzleFlash
Flag weapon/view model for muzzle flash
=================
*/
void EV_MuzzleFlash( void )
{
// Add muzzle flash to current weapon model
cl_entity_t *ent = GetViewEntity();
if ( !ent )
{
return;
}
// Or in the muzzle flash
ent->curstate.effects |= EF_MUZZLEFLASH;
}

44
cl_dll/ev_files.cpp Normal file
View File

@ -0,0 +1,44 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#include "../hud.h"
#include "../cl_util.h"
#include "event_api.h"
extern "C"
{
void EV_FireGeneric( struct event_args_s *args );
void EV_TrainPitchAdjust( struct event_args_s *args );
void EV_SmokePuff( struct event_args_s *args );
}
/*
======================
Game_HookEvents
Associate script file name with callback functions. Callback's must be extern "C" so
the engine doesn't get confused about name mangling stuff. Note that the format is
always the same. Of course, a clever mod team could actually embed parameters, behavior
into the actual .sc files and create a .sc file parser and hook their functionality through
that.. i.e., a scripting system.
That was what we were going to do, but we ran out of time...oh well.
======================
*/
void Game_HookEvents( void )
{
gEngfuncs.pfnHookEvent( "evTrainSound", EV_TrainPitchAdjust );
gEngfuncs.pfnHookEvent( "evSmokePuff", EV_SmokePuff );
gEngfuncs.pfnHookEvent( "evFireGeneric", EV_FireGeneric );
}

418
cl_dll/ev_hldm.cpp Normal file
View File

@ -0,0 +1,418 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#include "hud.h"
#include "cl_util.h"
#include "const.h"
#include "entity_state.h"
#include "cl_entity.h"
#include "entity_types.h"
#include "usercmd.h"
#include "pm_defs.h"
#include "eventscripts.h"
#include "ev_hldm.h"
#include "r_efx.h"
#include "event_api.h"
#include "event_args.h"
#include "in_defs.h"
#include "gl_rpart.h"
#include <string.h>
#include "material.h"
#include "r_studioint.h"
#include "com_model.h"
#include "studio.h"
extern engine_studio_api_t IEngineStudio;
static int tracerCount[ 32 ];
void V_PunchAxis( int axis, float punch );
void VectorAngles( const float *forward, float *angles );
extern cvar_t *cl_lw;
extern "C"
{
void EV_FireGeneric( struct event_args_s *args );
void EV_TrainPitchAdjust( struct event_args_s *args );
void EV_SmokePuff( struct event_args_s *args );
}
// play a strike sound based on the texture that was hit by the attack traceline. VecSrc/VecEnd are the
// original traceline endpoints used by the attacker, iBulletType is the type of bullet that hit the texture.
// returns volume of strike instrument (crowbar) to play
void EV_HLDM_PlayTextureSound( pmtrace_t *ptr, const Vector &vecSrc, const Vector &vecEnd )
{
// hit the world, try to play sound based on texture material type
char *rgsz[MAX_MAT_SOUNDS];
float fattn = ATTN_NORM;
int cnt = 0;
physent_t *pe = gEngfuncs.pEventAPI->EV_GetPhysent( ptr->ent );
matdef_t *pMat = NULL;
if( pe )
{
if( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP )
pMat = COM_MatDefFromSurface( gEngfuncs.pEventAPI->EV_TraceSurface( ptr->ent, (float *)&vecSrc, (float *)&vecEnd ), ptr->endpos );
else if( pe->solid == SOLID_CUSTOM && ptr->surf )
pMat = ptr->surf->effects;
if( !pMat ) return;
// fire effects
for( cnt = 0; pMat->impact_parts[cnt] != NULL; cnt++ )
g_pParticles.CreateEffect( pMat->impact_parts[cnt], ptr->endpos, ptr->plane.normal );
// count sounds
for( cnt = 0; pMat->impact_sounds[cnt] != NULL; cnt++ )
rgsz[cnt] = (char *)pMat->impact_sounds[cnt];
}
if( !cnt ) return;
gEngfuncs.pEventAPI->EV_PlaySound( 0, ptr->endpos, CHAN_STATIC, rgsz[RANDOM_LONG( 0, cnt - 1 )], 0.9, fattn, 0, 96 + RANDOM_LONG( 0, 0xf ));
}
void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, const Vector &vecSrc, const Vector &vecEnd )
{
if( pTrace->inwater ) return;
int iRand = RANDOM_LONG( 0, 0x7FFF );
if( iRand < ( 0x7fff / 2 )) // not every bullet makes a sound.
{
switch( iRand % 5)
{
case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 2: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric3.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 3: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric4.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
case 4: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric5.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break;
}
}
physent_t *pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent );
matdef_t *pMat = NULL;
if( pe )
{
if( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP )
{
pMat = COM_MatDefFromSurface( gEngfuncs.pEventAPI->EV_TraceSurface( pTrace->ent, (float *)&vecSrc, (float *)&vecEnd ), pTrace->endpos );
if ( pMat ) CreateDecal( pTrace, pMat->impact_decal, RANDOM_FLOAT( 0.0f, 360.0f ));
}
else if( pe->solid == SOLID_CUSTOM && pTrace->surf )
{
pMat = pTrace->surf->effects;
if ( pMat ) UTIL_StudioDecal( pMat->impact_decal, pTrace, vecSrc );
}
}
}
/*
================
FireBullets
Go to the trouble of combining multiple pellets into a single damage call.
================
*/
void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY )
{
int i;
pmtrace_t tr;
int iShot;
for ( iShot = 1; iShot <= cShots; iShot++ )
{
Vector vecDir, vecEnd;
float x, y, z;
// We randomize for the Shotgun.
if ( iBulletType == BULLET_BUCKSHOT )
{
do {
x = RANDOM_FLOAT( -0.5f, 0.5f ) + RANDOM_FLOAT( -0.5f, 0.5f );
y = RANDOM_FLOAT( -0.5f, 0.5f ) + RANDOM_FLOAT( -0.5f, 0.5f );
z = x * x + y * y;
} while( z > 1.0f );
for ( i = 0 ; i < 3; i++ )
{
vecDir[i] = vecDirShooting[i] + x * flSpreadX * right[i] + y * flSpreadY * up[i];
vecEnd[i] = vecSrc[i] + flDistance * vecDir[i];
}
}
else
{
// but other guns already have their spread randomized in the synched spread.
for ( i = 0 ; i < 3; i++ )
{
vecDir[i] = vecDirShooting[i] + flSpreadX * right[i] + flSpreadY * up[i];
vecEnd[i] = vecSrc[i] + flDistance * vecDir[i];
}
}
gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true );
// Store off the old count
gEngfuncs.pEventAPI->EV_PushPMStates();
// Now add in all of the players.
gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 );
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, 0, -1, &tr );
// do damage, paint decals
if ( tr.fraction != 1.0 && !tr.inwater ) // buz: dont smoke and particle if shoot in sky
{
EV_HLDM_PlayTextureSound( &tr, vecSrc, vecEnd );
EV_HLDM_GunshotDecalTrace( &tr, vecSrc, vecEnd );
}
gEngfuncs.pEventAPI->EV_PopPMStates();
}
}
//======================
// WEAPON GENERIC START
//======================
void EV_FireGeneric( struct event_args_s *args )
{
int idx;
Vector origin;
Vector angles;
Vector velocity;
Vector ShellVelocity;
Vector ShellOrigin;
Vector vecSrc, vecAiming;
Vector up, right, forward;
float flSpread = 0.01;
idx = args->entindex;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
AngleVectors( angles, forward, right, up );
int shell = args->bparam1; // brass shell
EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 );
if( EV_IsLocal( idx ))
{
// add muzzle flash to current weapon model
EV_MuzzleFlash();
UTIL_WeaponAnimation(( args->iparam1 & 0xFFF ), 1.0f ); // FIXME: how to send framerate?
V_PunchAxis( 0, RANDOM_FLOAT( ((float)args->iparam2 / 255.0f ) * -3.0f, 0.0f ));
cl_entity_t *ent = GetViewEntity();
if( ent ) ShellOrigin = ent->attachment[1];
}
int numShots = ((args->iparam1 >> 12) & 0xF);
int soundType = TE_BOUNCE_SHELL;
int bulletType = BULLET_NORMAL;
float flDist = 8192.0f;
// shotgun case
if( numShots > 1 )
{
bulletType = BULLET_BUCKSHOT;
soundType = TE_BOUNCE_SHOTSHELL;
flDist = 2048.0f;
}
EV_EjectBrass( ShellOrigin, ShellVelocity , RANDOM_FLOAT( -angles[YAW], angles[YAW] ), shell, soundType );
if( args->bparam2 )
{
const char *fireSound = gEngfuncs.pEventAPI->EV_SoundForIndex( args->bparam2 );
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, fireSound, 1, ATTN_NORM, 0, 94 + RANDOM_LONG( 0, 0xf ));
}
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
EV_HLDM_FireBullets( idx, forward, right, up, numShots, vecSrc, vecAiming, flDist, bulletType, 2, &tracerCount[idx-1], args->fparam1, args->fparam2 );
}
//======================
// WEAPON GENERIC END
//======================
#define SND_CHANGE_PITCH (1<<7) // duplicated in protocol.h change sound pitch
void EV_TrainPitchAdjust( event_args_t *args )
{
int idx;
Vector origin;
unsigned short us_params;
int noise;
float m_flVolume;
int pitch;
int stop;
char sz[ 256 ];
idx = args->entindex;
VectorCopy( args->origin, origin );
us_params = (unsigned short)args->iparam1;
stop = args->bparam1;
m_flVolume = (float)(us_params & 0x003f)/40.0;
noise = (int)(((us_params) >> 12 ) & 0x0007);
pitch = (int)( 10.0 * (float)( ( us_params >> 6 ) & 0x003f ) );
switch ( noise )
{
case 1: strcpy( sz, "plats/ttrain1.wav"); break;
case 2: strcpy( sz, "plats/ttrain2.wav"); break;
case 3: strcpy( sz, "plats/ttrain3.wav"); break;
case 4: strcpy( sz, "plats/ttrain4.wav"); break;
case 5: strcpy( sz, "plats/ttrain6.wav"); break;
case 6: strcpy( sz, "plats/ttrain7.wav"); break;
default:
// no sound
strcpy( sz, "" );
return;
}
if ( stop )
{
gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, sz );
}
else
{
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, sz, m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, pitch );
}
}
int EV_TFC_IsAllyTeam( int iTeam1, int iTeam2 )
{
return 0;
}
// buz: smokepuff event - for invoke puffs from server, when monsters firing, etc..
void EV_SmokePuff( struct event_args_s *args )
{
VectorNormalize(args->angles); // there is surface normal actually
g_pParticles.BulletParticles( args->origin, args->angles );
}
void EV_GunSmoke( const Vector &pos )
{
g_pParticles.GunSmoke( pos, 2 );
}
void EV_ExplodeSmoke( const Vector &pos )
{
g_pParticles.SmokeParticles( pos, 10 );
}
void EV_HLDM_WaterSplash( float x, float y, float z, float ScaleSplash1, float ScaleSplash2 )
{
int iWaterSplash = gEngfuncs.pEventAPI->EV_FindModelIndex ("sprites/splash1.spr");
TEMPENTITY *pTemp = gEngfuncs.pEfxAPI->R_TempSprite( Vector( x, y, z + 15 ),
Vector( 0, 0, 0 ),
/*ScaleSplash1*/0.2, iWaterSplash, kRenderTransAdd, kRenderFxNone, 1.0, 0.5, FTENT_SPRANIMATE | FTENT_FADEOUT | FTENT_COLLIDEKILL );
if(pTemp)
{
pTemp->fadeSpeed = 90.0;
pTemp->entity.curstate.framerate = 70.0;
pTemp->entity.curstate.renderamt = 155;
pTemp->entity.curstate.rendercolor.r = 255;
pTemp->entity.curstate.rendercolor.g = 255;
pTemp->entity.curstate.rendercolor.b = 255;
}
iWaterSplash = gEngfuncs.pEventAPI->EV_FindModelIndex ("sprites/splash2.spr");
pTemp = gEngfuncs.pEfxAPI->R_TempSprite( Vector( x, y, z ),
Vector( 0, 0, 0 ),
/*ScaleSplash2*/0.08, iWaterSplash, kRenderTransAdd, kRenderFxNone, 1.0, 0.5, FTENT_SPRANIMATE | FTENT_FADEOUT | FTENT_COLLIDEKILL );
if(pTemp)
{
pTemp->fadeSpeed = 60.0;
pTemp->entity.curstate.framerate = 60.0;
pTemp->entity.curstate.renderamt = 150;
pTemp->entity.curstate.rendercolor.r = 255;
pTemp->entity.curstate.rendercolor.g = 255;
pTemp->entity.curstate.rendercolor.b = 255;
pTemp->entity.angles = Vector( 90, 0, 0 );
}
}
void EV_HLDM_NewExplode( float x, float y, float z, float ScaleExplode1 )
{
float rnd = gEngfuncs.pfnRandomFloat( -0.03, 0.03 );
int iNewExplode = gEngfuncs.pEventAPI->EV_FindModelIndex ("sprites/dexplo.spr");
TEMPENTITY *pTemp = gEngfuncs.pEfxAPI->R_TempSprite( Vector( x, y, z + 15 ), Vector( 0, 0, 0 ),
ScaleExplode1, iNewExplode, kRenderTransAdd, kRenderFxNone, 1.0, 0.5, FTENT_SPRANIMATE | FTENT_FADEOUT );
if( pTemp )
{
pTemp->fadeSpeed = 90.0;
pTemp->entity.curstate.framerate = 37.0;
pTemp->entity.curstate.renderamt = 155;
pTemp->entity.curstate.rendercolor.r = 255;
pTemp->entity.curstate.rendercolor.g = 255;
pTemp->entity.curstate.rendercolor.b = 255;
}
iNewExplode = gEngfuncs.pEventAPI->EV_FindModelIndex ("sprites/fexplo.spr");
pTemp = gEngfuncs.pEfxAPI->R_TempSprite( Vector( x, y, z + 15), Vector( 0, 0, 0 ),
ScaleExplode1, iNewExplode, kRenderTransAdd, kRenderFxNone, 1.0, 0.5, FTENT_SPRANIMATE | FTENT_FADEOUT );
if( pTemp )
{
pTemp->fadeSpeed = 100.0;
pTemp->entity.curstate.framerate = 35.0;
pTemp->entity.curstate.renderamt = 150;
pTemp->entity.curstate.rendercolor.r = 255;
pTemp->entity.curstate.rendercolor.g = 255;
pTemp->entity.curstate.rendercolor.b = 255;
pTemp->entity.angles = Vector( 90, 0, 0 );
}
iNewExplode = gEngfuncs.pEventAPI->EV_FindModelIndex ("sprites/smokeball.spr");
pTemp = gEngfuncs.pEfxAPI->R_TempSprite( Vector( x, y, z + 16), Vector( 0, 0, 0 ),
ScaleExplode1, iNewExplode, kRenderTransAdd, kRenderFxNone, 1.0, 0.5, FTENT_SPRANIMATE | FTENT_FADEOUT );
if( pTemp )
{
pTemp->fadeSpeed = 50.0;
pTemp->entity.curstate.framerate = 22.0;
pTemp->entity.curstate.renderamt = 120;
pTemp->entity.curstate.rendercolor.r = 255;
pTemp->entity.curstate.rendercolor.g = 255;
pTemp->entity.curstate.rendercolor.b = 255;
pTemp->entity.angles = Vector( 90, 0, 0 );
}
EV_ExplodeSmoke( Vector( x, y, z + 4.0f ));
}

17
cl_dll/ev_hldm.h Normal file
View File

@ -0,0 +1,17 @@
//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#if !defined ( EV_HLDMH )
#define EV_HLDMH
#include <bullets.h>
void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, const Vector &vecSrc, const Vector &vecEnd );
int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount );
void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY );
#endif // EV_HLDMH

23
cl_dll/events.cpp Normal file
View File

@ -0,0 +1,23 @@
//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#include "hud.h"
#include "cl_util.h"
void Game_HookEvents( void );
/*
===================
EV_HookEvents
See if game specific code wants to hook any events.
===================
*/
void EV_HookEvents( void )
{
Game_HookEvents();
}

74
cl_dll/eventscripts.h Normal file
View File

@ -0,0 +1,74 @@
//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
// eventscripts.h
#if !defined ( EVENTSCRIPTSH )
#define EVENTSCRIPTSH
// defaults for clientinfo messages
#define DEFAULT_VIEWHEIGHT 28
#define VEC_DUCK_VIEW 12
#define FTENT_FADEOUT 0x00000080
#define DMG_GENERIC 0 // generic damage was done
#define DMG_CRUSH (1 << 0) // crushed by falling or moving object
#define DMG_BULLET (1 << 1) // shot
#define DMG_SLASH (1 << 2) // cut, clawed, stabbed
#define DMG_BURN (1 << 3) // heat burned
#define DMG_FREEZE (1 << 4) // frozen
#define DMG_FALL (1 << 5) // fell too far
#define DMG_BLAST (1 << 6) // explosive blast damage
#define DMG_CLUB (1 << 7) // crowbar, punch, headbutt
#define DMG_SHOCK (1 << 8) // electric shock
#define DMG_SONIC (1 << 9) // sound pulse shockwave
#define DMG_ENERGYBEAM (1 << 10) // laser or other high energy beam
#define DMG_NEVERGIB (1 << 12) // with this bit OR'd in, no damage type will be able to gib victims upon death
#define DMG_ALWAYSGIB (1 << 13) // with this bit OR'd in, any damage type can be made to gib victims upon death.
// time-based damage
//mask off TF-specific stuff too
#define DMG_TIMEBASED (~(0xff003fff)) // mask for time-based damage
#define DMG_DROWN (1 << 14) // Drowning
#define DMG_FIRSTTIMEBASED DMG_DROWN
#define DMG_PARALYZE (1 << 15) // slows affected creature down
#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad
#define DMG_POISON (1 << 17) // blood poisioning
#define DMG_RADIATION (1 << 18) // radiation exposure
#define DMG_DROWNRECOVER (1 << 19) // drowning recovery
#define DMG_ACID (1 << 20) // toxic chemicals or acid burns
#define DMG_SLOWBURN (1 << 21) // in an oven
#define DMG_SLOWFREEZE (1 << 22) // in a subzero freezer
#define DMG_MORTAR (1 << 23) // Hit by air raid (done to distinguish grenade from mortar)
//TF ADDITIONS
#define DMG_IGNITE (1 << 24) // Players hit by this begin to burn
#define DMG_RADIUS_MAX (1 << 25) // Radius damage with this flag doesn't decrease over distance
#define DMG_RADIUS_QUAKE (1 << 26) // Radius damage is done like Quake. 1/2 damage at 1/2 radius.
#define DMG_IGNOREARMOR (1 << 27) // Damage ignores target's armor
#define DMG_AIMED (1 << 28) // Does Hit location damage
#define DMG_WALLPIERCING (1 << 29) // Blast Damages ents through walls
#define DMG_CALTROP (1<<30)
#define DMG_HALLUC (1<<31)
// Some of these are HL/TFC specific?
void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype );
void EV_GetGunPosition( struct event_args_s *args, float *pos, float *origin );
void EV_GetDefaultShellInfo( struct event_args_s *args, float *origin, float *velocity, float *ShellVelocity, float *ShellOrigin, float *forward, float *right, float *up, float forwardScale, float upScale, float rightScale );
qboolean EV_IsLocal( int idx );
qboolean EV_IsPlayer( int idx );
void EV_CreateTracer( float *start, float *end );
struct cl_entity_s *GetEntity( int idx );
struct cl_entity_s *GetViewEntity( void );
void EV_GunSmoke( const Vector &pos );
void EV_MuzzleFlash( void );
#endif // EVENTSCRIPTSH

151
cl_dll/flashlight.cpp Normal file
View File

@ -0,0 +1,151 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// flashlight.cpp
//
// implementation of CHudFlashlight class
//
#include "hud.h"
#include "cl_util.h"
#include "parsemsg.h"
#include <string.h>
#include <stdio.h>
DECLARE_MESSAGE(m_Flash, FlashBat)
DECLARE_MESSAGE(m_Flash, Flashlight)
#define BAT_NAME "sprites/%d_Flashlight.spr"
int CHudFlashlight::Init(void)
{
m_fFade = 0;
m_fOn = 0;
HOOK_MESSAGE(Flashlight);
HOOK_MESSAGE(FlashBat);
m_iFlags |= HUD_ACTIVE;
gHUD.AddHudElem(this);
return 1;
};
void CHudFlashlight::Reset(void)
{
m_fFade = 0;
m_fOn = 0;
}
int CHudFlashlight::VidInit(void)
{
int HUD_flash_empty = gHUD.GetSpriteIndex( "flash_empty" );
int HUD_flash_full = gHUD.GetSpriteIndex( "flash_full" );
int HUD_flash_beam = gHUD.GetSpriteIndex( "flash_beam" );
m_hSprite1 = gHUD.GetSprite(HUD_flash_empty);
m_hSprite2 = gHUD.GetSprite(HUD_flash_full);
m_hBeam = gHUD.GetSprite(HUD_flash_beam);
m_prc1 = &gHUD.GetSpriteRect(HUD_flash_empty);
m_prc2 = &gHUD.GetSpriteRect(HUD_flash_full);
m_prcBeam = &gHUD.GetSpriteRect(HUD_flash_beam);
m_iWidth = m_prc2->right - m_prc2->left;
return 1;
};
int CHudFlashlight:: MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
int x = READ_BYTE();
m_iBat = x;
m_flBat = ((float)x)/100.0;
return 1;
}
int CHudFlashlight:: MsgFunc_Flashlight(const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
m_fOn = READ_BYTE();
int x = READ_BYTE();
m_iBat = x;
m_flBat = ((float)x)/100.0;
return 1;
}
int CHudFlashlight::Draw(float flTime)
{
return 1; // buz: no flashlight
if ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_FLASHLIGHT | HIDEHUD_ALL ) )
return 1;
int r, g, b, x, y, a;
wrect_t rc;
if (!FBitSet( gHUD.m_iHideHUDDisplay, ITEM_SUIT ))
return 1;
if (m_fOn)
a = 225;
else
a = MIN_ALPHA;
if (m_flBat < 0.20)
UnpackRGB(r,g,b, RGB_REDISH);
else
UnpackRGB(r,g,b, gHUD.m_iHUDColor);
ScaleColors(r, g, b, a);
y = (m_prc1->bottom - m_prc2->top)/2;
x = ScreenWidth - m_iWidth - m_iWidth/2 ;
// Draw the flashlight casing
SPR_Set(m_hSprite1, r, g, b );
SPR_DrawAdditive( 0, x, y, m_prc1);
if ( m_fOn )
{ // draw the flashlight beam
x = ScreenWidth - m_iWidth/2;
SPR_Set( m_hBeam, r, g, b );
SPR_DrawAdditive( 0, x, y, m_prcBeam );
}
// draw the flashlight energy level
x = ScreenWidth - m_iWidth - m_iWidth/2 ;
int iOffset = m_iWidth * (1.0 - m_flBat);
if (iOffset < m_iWidth)
{
rc = *m_prc2;
rc.left += iOffset;
SPR_Set(m_hSprite2, r, g, b );
SPR_DrawAdditive( 0, x + iOffset, y, &rc);
}
return 1;
}

184
cl_dll/geiger.cpp Normal file
View File

@ -0,0 +1,184 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// Geiger.cpp
//
// implementation of CHudAmmo class
//
#include "hud.h"
#include "cl_util.h"
#include <string.h>
#include <time.h>
#include <stdio.h>
#include "parsemsg.h"
DECLARE_MESSAGE(m_Geiger, Geiger )
int CHudGeiger::Init(void)
{
HOOK_MESSAGE( Geiger );
m_iGeigerRange = 0;
m_iFlags = 0;
gHUD.AddHudElem(this);
srand( (unsigned)time( NULL ) );
return 1;
};
int CHudGeiger::VidInit(void)
{
return 1;
};
int CHudGeiger::MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf)
{
BEGIN_READ( pbuf, iSize );
// update geiger data
m_iGeigerRange = READ_BYTE();
m_iGeigerRange = m_iGeigerRange << 2;
m_iFlags |= HUD_ACTIVE;
return 1;
}
int CHudGeiger::Draw (float flTime)
{
int pct;
float flvol;
int rg[3];
int i;
if (m_iGeigerRange < 1000 && m_iGeigerRange > 0)
{
// peicewise linear is better than continuous formula for this
if (m_iGeigerRange > 800)
{
pct = 0; //Con_Printf ( "range > 800\n");
}
else if (m_iGeigerRange > 600)
{
pct = 2;
flvol = 0.4; //Con_Printf ( "range > 600\n");
rg[0] = 1;
rg[1] = 1;
i = 2;
}
else if (m_iGeigerRange > 500)
{
pct = 4;
flvol = 0.5; //Con_Printf ( "range > 500\n");
rg[0] = 1;
rg[1] = 2;
i = 2;
}
else if (m_iGeigerRange > 400)
{
pct = 8;
flvol = 0.6; //Con_Printf ( "range > 400\n");
rg[0] = 1;
rg[1] = 2;
rg[2] = 3;
i = 3;
}
else if (m_iGeigerRange > 300)
{
pct = 8;
flvol = 0.7; //Con_Printf ( "range > 300\n");
rg[0] = 2;
rg[1] = 3;
rg[2] = 4;
i = 3;
}
else if (m_iGeigerRange > 200)
{
pct = 28;
flvol = 0.78; //Con_Printf ( "range > 200\n");
rg[0] = 2;
rg[1] = 3;
rg[2] = 4;
i = 3;
}
else if (m_iGeigerRange > 150)
{
pct = 40;
flvol = 0.80; //Con_Printf ( "range > 150\n");
rg[0] = 3;
rg[1] = 4;
rg[2] = 5;
i = 3;
}
else if (m_iGeigerRange > 100)
{
pct = 60;
flvol = 0.85; //Con_Printf ( "range > 100\n");
rg[0] = 3;
rg[1] = 4;
rg[2] = 5;
i = 3;
}
else if (m_iGeigerRange > 75)
{
pct = 80;
flvol = 0.9; //Con_Printf ( "range > 75\n");
//gflGeigerDelay = cl.time + GEIGERDELAY * 0.75;
rg[0] = 4;
rg[1] = 5;
rg[2] = 6;
i = 3;
}
else if (m_iGeigerRange > 50)
{
pct = 90;
flvol = 0.95; //Con_Printf ( "range > 50\n");
rg[0] = 5;
rg[1] = 6;
i = 2;
}
else
{
pct = 95;
flvol = 1.0; //Con_Printf ( "range < 50\n");
rg[0] = 5;
rg[1] = 6;
i = 2;
}
flvol = (flvol * ((rand() & 127)) / 255) + 0.25; // UTIL_RandomFloat(0.25, 0.5);
if ((rand() & 127) < pct || (rand() & 127) < pct)
{
//S_StartDynamicSound (-1, 0, rgsfx[rand() % i], r_origin, flvol, 1.0, 0, 100);
char sz[256];
int j = rand() & 1;
if (i > 2)
j += rand() & 1;
sprintf(sz, "player/geiger%d.wav", j + 1);
PlaySound(sz, flvol);
}
}
return 1;
}

11
cl_dll/getfont.h Normal file
View File

@ -0,0 +1,11 @@
// ============================
// getfont - function, returning font pointer from text message
// written by BUzer
// ============================
#ifndef _GETFONT_H
#define _GETFONT_H
Font* FontFromMessage(const char* &ptext);
#endif // _GETFONT_H

508
cl_dll/health.cpp Normal file
View File

@ -0,0 +1,508 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// Health.cpp
//
// implementation of CHudHealth class
//
#include "STDIO.H"
#include "STDLIB.H"
#include "MATH.H"
#include "hud.h"
#include "cl_util.h"
#include "parsemsg.h"
#include <string.h>
#include "vgui_TeamFortressViewport.h" // buz
#include "vgui_hud.h" // buz
DECLARE_MESSAGE(m_Health, Health )
DECLARE_MESSAGE(m_Health, Damage )
#define PAIN_NAME "sprites/%d_pain.spr"
#define DAMAGE_NAME "sprites/%d_dmg.spr"
int giDmgHeight, giDmgWidth;
int giDmgFlags[NUM_DMG_TYPES] =
{
DMG_POISON,
DMG_ACID,
DMG_FREEZE|DMG_SLOWFREEZE,
DMG_DROWN,
DMG_BURN|DMG_SLOWBURN,
DMG_NERVEGAS,
DMG_RADIATION,
DMG_SHOCK,
DMG_CALTROP,
DMG_TRANQ,
DMG_CONCUSS,
DMG_HALLUC
};
int CHudHealth::Init(void)
{
HOOK_MESSAGE(Health);
HOOK_MESSAGE(Damage);
m_iHealth = 100;
m_fFade = 0;
m_iFlags = 0;
m_bitsDamage = 0;
m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0;
giDmgHeight = 0;
giDmgWidth = 0;
memset(m_dmg, 0, sizeof(DAMAGE_IMAGE) * NUM_DMG_TYPES);
gHUD.AddHudElem(this);
return 1;
}
void CHudHealth::Reset( void )
{
// make sure the pain compass is cleared when the player respawns
m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0;
// force all the flashing damage icons to expire
m_bitsDamage = 0;
for ( int i = 0; i < NUM_DMG_TYPES; i++ )
{
m_dmg[i].fExpire = 0;
}
}
int CHudHealth::VidInit(void)
{
m_hSprite = 0;
// m_hDecoration = gHUD.GetSpriteIndex( "health_decoration" ); // buz
m_HUD_dmg_bio = gHUD.GetSpriteIndex( "dmg_bio" ) + 1;
m_HUD_cross = gHUD.GetSpriteIndex( "cross" );
giDmgHeight = gHUD.GetSpriteRect(m_HUD_dmg_bio).right - gHUD.GetSpriteRect(m_HUD_dmg_bio).left;
giDmgWidth = gHUD.GetSpriteRect(m_HUD_dmg_bio).bottom - gHUD.GetSpriteRect(m_HUD_dmg_bio).top;
return 1;
}
int CHudHealth:: MsgFunc_Health(const char *pszName, int iSize, void *pbuf )
{
// TODO: update local health data
BEGIN_READ( pbuf, iSize );
int x = READ_BYTE();
m_iFlags |= HUD_ACTIVE;
// Only update the fade if we've changed health
if (x != m_iHealth)
{
m_fFade = FADE_TIME;
m_iHealth = x;
}
gViewPort->m_pHud2->UpdateHealth(x); // buz
return 1;
}
int CHudHealth:: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
int armor = READ_BYTE(); // armor
int damageTaken = READ_BYTE(); // health
long bitsDamage = READ_LONG(); // damage bits
Vector vecFrom;
for ( int i = 0 ; i < 3 ; i++)
vecFrom[i] = READ_COORD();
UpdateTiles(gHUD.m_flTime, bitsDamage);
// Actually took damage?
if( damageTaken > 0 || armor > 0)
{
CalcDamageDirection( vecFrom );
}
return 1;
}
// Returns back a color from the
// Green <-> Yellow <-> Red ramp
void CHudHealth::GetPainColor( int &r, int &g, int &b )
{
int iHealth = m_iHealth;
if (iHealth > 25)
iHealth -= 25;
else if ( iHealth < 0 )
iHealth = 0;
#if 0
g = iHealth * 255 / 100;
r = 255 - g;
b = 0;
#else
if (m_iHealth > 25)
{
UnpackRGB(r,g,b, gHUD.m_iHUDColor);
}
else
{
r = 250;
g = 0;
b = 0;
}
#endif
}
int CHudHealth::Draw(float flTime)
{
// gEngfuncs.Con_Printf("drawing health. decindex is %d\n", m_hDecoration);
if ( (gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH) || gEngfuncs.IsSpectateOnly() )
return 1;
if ( !m_hSprite )
m_hSprite = LoadSprite(PAIN_NAME);
#if (0) // buz: dont draw health!
int r, g, b;
int a = 0, x, y;
int HealthWidth;
// Has health changed? Flash the health # // buz - comment from here
if (m_fFade)
{
m_fFade -= (gHUD.m_flTimeDelta * 20);
if (m_fFade <= 0)
{
a = MIN_ALPHA;
m_fFade = 0;
}
// Fade the health number back to dim
a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128;
}
else
a = MIN_ALPHA;
// If health is getting low, make it bright red
if (m_iHealth <= 15)
a = 255;
GetPainColor( r, g, b );
ScaleColors(r, g, b, a ); // buz - to here
// r = 255; g = 255; b = 255; //buz
// Only draw health if we have the suit.
if (FBitSet( gHUD.m_iHideHUDDisplay, ITEM_SUIT ))
{
// buz: draw decoration
// SPR_Set(gHUD.GetSprite(m_hDecoration), 255, 255, 255 );
// SPR_DrawHoles(0, 0, ScreenHeight - (gHUD.GetSpriteRect(m_hDecoration).bottom - gHUD.GetSpriteRect(m_hDecoration).top), &gHUD.GetSpriteRect(m_hDecoration));
// buz- comment from here
HealthWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left;
int CrossWidth = gHUD.GetSpriteRect(m_HUD_cross).right - gHUD.GetSpriteRect(m_HUD_cross).left;
y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2;
x = CrossWidth /2;
SPR_Set(gHUD.GetSprite(m_HUD_cross), r, g, b);
SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_cross));
x = CrossWidth + HealthWidth / 2;
x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iHealth, r, g, b);
x += HealthWidth/2;
int iHeight = gHUD.m_iFontHeight;
int iWidth = HealthWidth/10;
UnpackRGB(r,g,b, gHUD.m_iHUDColor); //LRC
//LRC FillRGBA(x, y, iWidth, iHeight, 255, 160, 0, a);
FillRGBA(x, y, iWidth, iHeight, r, g, b, a); //LRC buz - to here
/* if (ScreenWidth < 640)
{
x = 57;
y = ScreenHeight - 15;
}
else
{
x = 112;
y = ScreenHeight - 29;
}*/ // buz
// gEngfuncs.Con_Printf("Health amount: %d\n", m_iHealth);
// x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iHealth, r, g, b);
}
#endif // buz
DrawDamage(flTime);
return DrawPain(flTime);
}
void CHudHealth::CalcDamageDirection(Vector vecFrom)
{
Vector forward, right, up;
float side, front;
Vector vecOrigin, vecAngles;
if (!vecFrom[0] && !vecFrom[1] && !vecFrom[2])
{
m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0;
return;
}
memcpy(vecOrigin, gHUD.m_vecOrigin, sizeof(Vector));
memcpy(vecAngles, gHUD.m_vecAngles, sizeof(Vector));
VectorSubtract (vecFrom, vecOrigin, vecFrom);
float flDistToTarget = vecFrom.Length();
vecFrom = vecFrom.Normalize();
AngleVectors (vecAngles, forward, right, up);
front = DotProduct (vecFrom, right);
side = DotProduct (vecFrom, forward);
if (flDistToTarget <= 50)
{
m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 1;
}
else
{
if (side > 0)
{
if (side > 0.3)
m_fAttackFront = max(m_fAttackFront, side);
}
else
{
float f = fabs(side);
if (f > 0.3)
m_fAttackRear = max(m_fAttackRear, f);
}
if (front > 0)
{
if (front > 0.3)
m_fAttackRight = max(m_fAttackRight, front);
}
else
{
float f = fabs(front);
if (f > 0.3)
m_fAttackLeft = max(m_fAttackLeft, f);
}
}
}
int CHudHealth::DrawPain(float flTime)
{
if (!(m_fAttackFront || m_fAttackRear || m_fAttackLeft || m_fAttackRight))
return 1;
int r, g, b;
int x, y, a, shade;
// TODO: get the shift value of the health
a = 255; // max brightness until then
float fFade = gHUD.m_flTimeDelta * 2;
// SPR_Draw top
if (m_fAttackFront > 0.4)
{
GetPainColor(r,g,b);
shade = a * max( m_fAttackFront, 0.5 );
ScaleColors(r, g, b, shade);
SPR_Set(m_hSprite, r, g, b );
x = ScreenWidth/2 - SPR_Width(m_hSprite, 0)/2;
y = ScreenHeight/2 - SPR_Height(m_hSprite,0) * 3;
SPR_DrawAdditive(0, x, y, NULL);
m_fAttackFront = max( 0, m_fAttackFront - fFade );
} else
m_fAttackFront = 0;
if (m_fAttackRight > 0.4)
{
GetPainColor(r,g,b);
shade = a * max( m_fAttackRight, 0.5 );
ScaleColors(r, g, b, shade);
SPR_Set(m_hSprite, r, g, b );
x = ScreenWidth/2 + SPR_Width(m_hSprite, 1) * 2;
y = ScreenHeight/2 - SPR_Height(m_hSprite,1)/2;
SPR_DrawAdditive(1, x, y, NULL);
m_fAttackRight = max( 0, m_fAttackRight - fFade );
} else
m_fAttackRight = 0;
if (m_fAttackRear > 0.4)
{
GetPainColor(r,g,b);
shade = a * max( m_fAttackRear, 0.5 );
ScaleColors(r, g, b, shade);
SPR_Set(m_hSprite, r, g, b );
x = ScreenWidth/2 - SPR_Width(m_hSprite, 2)/2;
y = ScreenHeight/2 + SPR_Height(m_hSprite,2) * 2;
SPR_DrawAdditive(2, x, y, NULL);
m_fAttackRear = max( 0, m_fAttackRear - fFade );
} else
m_fAttackRear = 0;
if (m_fAttackLeft > 0.4)
{
GetPainColor(r,g,b);
shade = a * max( m_fAttackLeft, 0.5 );
ScaleColors(r, g, b, shade);
SPR_Set(m_hSprite, r, g, b );
x = ScreenWidth/2 - SPR_Width(m_hSprite, 3) * 3;
y = ScreenHeight/2 - SPR_Height(m_hSprite,3)/2;
SPR_DrawAdditive(3, x, y, NULL);
m_fAttackLeft = max( 0, m_fAttackLeft - fFade );
} else
m_fAttackLeft = 0;
return 1;
}
int CHudHealth::DrawDamage(float flTime)
{
int r, g, b, a;
DAMAGE_IMAGE *pdmg;
if (!m_bitsDamage)
return 1;
UnpackRGB(r,g,b, gHUD.m_iHUDColor);
a = (int)( fabs(sin(flTime*2)) * 256.0);
ScaleColors(r, g, b, a);
// Draw all the items
for (int i = 0; i < NUM_DMG_TYPES; i++)
{
if (m_bitsDamage & giDmgFlags[i])
{
pdmg = &m_dmg[i];
HSPRITE hCurrent = gHUD.GetSprite( m_HUD_dmg_bio + i );
if( !hCurrent ) continue; // sprite was missed
SPR_Set( hCurrent, r, g, b );
SPR_DrawAdditive(0, pdmg->x, pdmg->y, &gHUD.GetSpriteRect(m_HUD_dmg_bio + i));
}
}
// check for bits that should be expired
for ( i = 0; i < NUM_DMG_TYPES; i++ )
{
DAMAGE_IMAGE *pdmg = &m_dmg[i];
if ( m_bitsDamage & giDmgFlags[i] )
{
pdmg->fExpire = min( flTime + DMG_IMAGE_LIFE, pdmg->fExpire );
if ( pdmg->fExpire <= flTime // when the time has expired
&& a < 40 ) // and the flash is at the low point of the cycle
{
pdmg->fExpire = 0;
int y = pdmg->y;
pdmg->x = pdmg->y = 0;
// move everyone above down
for (int j = 0; j < NUM_DMG_TYPES; j++)
{
pdmg = &m_dmg[j];
if ((pdmg->y) && (pdmg->y < y))
pdmg->y += giDmgHeight;
}
m_bitsDamage &= ~giDmgFlags[i]; // clear the bits
}
}
}
return 1;
}
void CHudHealth::UpdateTiles(float flTime, long bitsDamage)
{
DAMAGE_IMAGE *pdmg;
// Which types are new?
long bitsOn = ~m_bitsDamage & bitsDamage;
for (int i = 0; i < NUM_DMG_TYPES; i++)
{
pdmg = &m_dmg[i];
// Is this one already on?
if (m_bitsDamage & giDmgFlags[i])
{
pdmg->fExpire = flTime + DMG_IMAGE_LIFE; // extend the duration
if (!pdmg->fBaseline)
pdmg->fBaseline = flTime;
}
// Are we just turning it on?
if (bitsOn & giDmgFlags[i])
{
// put this one at the bottom
pdmg->x = giDmgWidth/8;
pdmg->y = ScreenHeight - giDmgHeight * 2;
pdmg->fExpire=flTime + DMG_IMAGE_LIFE;
// move everyone else up
for (int j = 0; j < NUM_DMG_TYPES; j++)
{
if (j == i)
continue;
pdmg = &m_dmg[j];
if (pdmg->y)
pdmg->y -= giDmgHeight;
}
pdmg = &m_dmg[i];
}
}
// damage bits are only turned on here; they are turned off when the draw time has expired (in DrawDamage())
m_bitsDamage |= bitsDamage;
}

128
cl_dll/health.h Normal file
View File

@ -0,0 +1,128 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#define DMG_IMAGE_LIFE 2 // seconds that image is up
#define DMG_IMAGE_POISON 0
#define DMG_IMAGE_ACID 1
#define DMG_IMAGE_COLD 2
#define DMG_IMAGE_DROWN 3
#define DMG_IMAGE_BURN 4
#define DMG_IMAGE_NERVE 5
#define DMG_IMAGE_RAD 6
#define DMG_IMAGE_SHOCK 7
//tf defines
#define DMG_IMAGE_CALTROP 8
#define DMG_IMAGE_TRANQ 9
#define DMG_IMAGE_CONCUSS 10
#define DMG_IMAGE_HALLUC 11
#define NUM_DMG_TYPES 12
// instant damage
#define DMG_GENERIC 0 // generic damage was done
#define DMG_CRUSH (1 << 0) // crushed by falling or moving object
#define DMG_BULLET (1 << 1) // shot
#define DMG_SLASH (1 << 2) // cut, clawed, stabbed
#define DMG_BURN (1 << 3) // heat burned
#define DMG_FREEZE (1 << 4) // frozen
#define DMG_FALL (1 << 5) // fell too far
#define DMG_BLAST (1 << 6) // explosive blast damage
#define DMG_CLUB (1 << 7) // crowbar, punch, headbutt
#define DMG_SHOCK (1 << 8) // electric shock
#define DMG_SONIC (1 << 9) // sound pulse shockwave
#define DMG_ENERGYBEAM (1 << 10) // laser or other high energy beam
#define DMG_NEVERGIB (1 << 12) // with this bit OR'd in, no damage type will be able to gib victims upon death
#define DMG_ALWAYSGIB (1 << 13) // with this bit OR'd in, any damage type can be made to gib victims upon death.
// time-based damage
//mask off TF-specific stuff too
#define DMG_TIMEBASED (~(0xff003fff)) // mask for time-based damage
#define DMG_DROWN (1 << 14) // Drowning
#define DMG_FIRSTTIMEBASED DMG_DROWN
#define DMG_PARALYZE (1 << 15) // slows affected creature down
#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad
#define DMG_POISON (1 << 17) // blood poisioning
#define DMG_RADIATION (1 << 18) // radiation exposure
#define DMG_DROWNRECOVER (1 << 19) // drowning recovery
#define DMG_ACID (1 << 20) // toxic chemicals or acid burns
#define DMG_SLOWBURN (1 << 21) // in an oven
#define DMG_SLOWFREEZE (1 << 22) // in a subzero freezer
#define DMG_MORTAR (1 << 23) // Hit by air raid (done to distinguish grenade from mortar)
//TF ADDITIONS
#define DMG_IGNITE (1 << 24) // Players hit by this begin to burn
#define DMG_RADIUS_MAX (1 << 25) // Radius damage with this flag doesn't decrease over distance
#define DMG_RADIUS_QUAKE (1 << 26) // Radius damage is done like Quake. 1/2 damage at 1/2 radius.
#define DMG_IGNOREARMOR (1 << 27) // Damage ignores target's armor
#define DMG_AIMED (1 << 28) // Does Hit location damage
#define DMG_WALLPIERCING (1 << 29) // Blast Damages ents through walls
#define DMG_CALTROP (1<<30)
#define DMG_HALLUC (1<<31)
// TF Healing Additions for TakeHealth
#define DMG_IGNORE_MAXHEALTH DMG_IGNITE
// TF Redefines since we never use the originals
#define DMG_NAIL DMG_SLASH
#define DMG_NOT_SELF DMG_FREEZE
#define DMG_TRANQ DMG_MORTAR
#define DMG_CONCUSS DMG_SONIC
typedef struct
{
float fExpire;
float fBaseline;
int x, y;
} DAMAGE_IMAGE;
//
//-----------------------------------------------------
//
class CHudHealth: public CHudBase
{
public:
virtual int Init( void );
virtual int VidInit( void );
virtual int Draw(float fTime);
virtual void Reset( void );
int MsgFunc_Health(const char *pszName, int iSize, void *pbuf);
int MsgFunc_Damage(const char *pszName, int iSize, void *pbuf);
int m_iHealth;
int m_HUD_dmg_bio;
int m_HUD_cross;
float m_fAttackFront, m_fAttackRear, m_fAttackLeft, m_fAttackRight;
void GetPainColor( int &r, int &g, int &b );
float m_fFade;
private:
HSPRITE m_hSprite;
HSPRITE m_hDamage;
int m_hDecoration; // buz
DAMAGE_IMAGE m_dmg[NUM_DMG_TYPES];
int m_bitsDamage;
int DrawPain(float fTime);
int DrawDamage(float fTime);
void CalcDamageDirection(vec3_t vecFrom);
void UpdateTiles(float fTime, long bits);
};

889
cl_dll/hud.cpp Normal file
View File

@ -0,0 +1,889 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// hud.cpp
//
// implementation of CHud class
//
//LRC - define to help track what calls are made on changelevel, save/restore, etc
#define ENGINE_DEBUG
#include "hud.h"
#include "cl_util.h"
#include <stringlib.h>
#include <stdio.h>
#include "parsemsg.h"
#include "hud_servers.h"
#include "vgui_int.h"
#include "vgui_TeamFortressViewport.h"
#include "vgui_subtitles.h" // buz
#include "vgui_radio.h" // buz
#include "vgui_hud.h" // buz
#include "vgui_tabpanel.h" // buz
#include "studio.h"
#include "demo.h"
#include "demo_api.h"
#include "vgui_scorepanel.h"
#include "gl_local.h" // buz
#include "r_studioint.h"
cvar_t *cl_rollspeed;
cvar_t *cl_rollangle;
class CHLVoiceStatusHelper : public IVoiceStatusHelper
{
public:
virtual void GetPlayerTextColor(int entindex, int color[3])
{
color[0] = color[1] = color[2] = 255;
if( entindex >= 0 && entindex < sizeof(g_PlayerExtraInfo)/sizeof(g_PlayerExtraInfo[0]) )
{
int iTeam = g_PlayerExtraInfo[entindex].teamnumber;
if ( iTeam < 0 )
{
iTeam = 0;
}
iTeam = iTeam % iNumberOfTeamColors;
color[0] = iTeamColors[iTeam][0];
color[1] = iTeamColors[iTeam][1];
color[2] = iTeamColors[iTeam][2];
}
}
virtual void UpdateCursorState()
{
gViewPort->UpdateCursorState();
}
virtual int GetAckIconHeight()
{
return ScreenHeight - gHUD.m_iFontHeight*3 - 6;
}
virtual bool CanShowSpeakerLabels()
{
if( gViewPort && gViewPort->m_pScoreBoard )
return !gViewPort->m_pScoreBoard->isVisible();
else
return false;
}
};
static CHLVoiceStatusHelper g_VoiceStatusHelper;
extern client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount);
extern cvar_t *sensitivity;
cvar_t *cl_lw = NULL;
void ShutdownInput (void);
//DECLARE_MESSAGE(m_Logo, Logo)
int __MsgFunc_Logo(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_Logo(pszName, iSize, pbuf );
}
//DECLARE_MESSAGE(m_Logo, Logo)
//LRC
int __MsgFunc_HUDColor(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_HUDColor(pszName, iSize, pbuf );
}
//LRC
int __MsgFunc_SetFog(const char *pszName, int iSize, void *pbuf)
{
gHUD.MsgFunc_SetFog( pszName, iSize, pbuf );
return 1;
}
//LRC
int __MsgFunc_KeyedDLight(const char *pszName, int iSize, void *pbuf)
{
gHUD.MsgFunc_KeyedDLight( pszName, iSize, pbuf );
return 1;
}
//LRC
int __MsgFunc_SetSky(const char *pszName, int iSize, void *pbuf)
{
gHUD.MsgFunc_SetSky( pszName, iSize, pbuf );
return 1;
}
int __MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf)
{
#ifdef ENGINE_DEBUG
// CONPRINT("## ResetHUD\n");
#endif
return gHUD.MsgFunc_ResetHUD(pszName, iSize, pbuf );
}
int __MsgFunc_InitHUD(const char *pszName, int iSize, void *pbuf)
{
#ifdef ENGINE_DEBUG
// CONPRINT("## InitHUD\n");
#endif
gHUD.MsgFunc_InitHUD( pszName, iSize, pbuf );
return 1;
}
int __MsgFunc_ViewMode(const char *pszName, int iSize, void *pbuf)
{
gHUD.MsgFunc_ViewMode( pszName, iSize, pbuf );
return 1;
}
int __MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_SetFOV( pszName, iSize, pbuf );
}
int __MsgFunc_Concuss(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_Concuss( pszName, iSize, pbuf );
}
int __MsgFunc_GameMode( const char *pszName, int iSize, void *pbuf )
{
return gHUD.MsgFunc_GameMode( pszName, iSize, pbuf );
}
int __MsgFunc_WaterSplash( const char *pszName, int iSize, void *pbuf )
{
gHUD.MsgFunc_WaterSplash( pszName, iSize, pbuf );
return 1;
}
int __MsgFunc_NewExplode( const char *pszName, int iSize, void *pbuf )
{
gHUD.MsgFunc_NewExplode( pszName, iSize, pbuf );
return 1;
}
// buz
int __MsgFunc_GasMask(const char *pszName, int iSize, void *pbuf )
{
return gHUD.MsgFunc_GasMask( pszName, iSize, pbuf );
}
// buz
int __MsgFunc_SpecTank(const char *pszName, int iSize, void *pbuf )
{
return gHUD.MsgFunc_SpecTank( pszName, iSize, pbuf );
}
int __MsgFunc_HeadShield(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_HeadShield( pszName, iSize, pbuf );
}
int __MsgFunc_Particle(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_Particle( pszName, iSize, pbuf );
}
int __MsgFunc_DelParticle(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_DelParticle( pszName, iSize, pbuf );
}
int __MsgFunc_WeaponAnim(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_WeaponAnim( pszName, iSize, pbuf );
}
int __MsgFunc_WeaponBody(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_WeaponBody( pszName, iSize, pbuf );
}
int __MsgFunc_WeaponSkin(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_WeaponSkin( pszName, iSize, pbuf );
}
int __MsgFunc_SkyMarker(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_SkyMarker( pszName, iSize, pbuf );
}
int __MsgFunc_WorldMarker(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_WorldMarker( pszName, iSize, pbuf );
}
int __MsgFunc_CustomDecal(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_CustomDecal( pszName, iSize, pbuf );
}
int __MsgFunc_StudioDecal(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_StudioDecal( pszName, iSize, pbuf );
}
int __MsgFunc_PartEffect(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_PartEffect( pszName, iSize, pbuf );
}
int __MsgFunc_LevelTime(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_LevelTime( pszName, iSize, pbuf );
}
int __MsgFunc_BlurEffect(const char *pszName, int iSize, void *pbuf)
{
gHUD.MsgFunc_BlurEffect( pszName, iSize, pbuf );
return 1;
}
// TFFree Command Menu
void __CmdFunc_OpenCommandMenu(void)
{
if ( gViewPort )
{
gViewPort->ShowCommandMenu( gViewPort->m_StandardMenu );
}
}
// TFC "special" command
void __CmdFunc_InputPlayerSpecial(void)
{
if ( gViewPort )
{
gViewPort->InputPlayerSpecial();
}
}
void __CmdFunc_CloseCommandMenu(void)
{
if ( gViewPort )
{
gViewPort->InputSignalHideCommandMenu();
}
}
void __CmdFunc_ForceCloseCommandMenu( void )
{
if ( gViewPort )
{
gViewPort->HideCommandMenu();
}
}
void __CmdFunc_ToggleServerBrowser( void )
{
if ( gViewPort )
{
gViewPort->ToggleServerBrowser();
}
}
// TFFree Command Menu Message Handlers
int __MsgFunc_ValClass(const char *pszName, int iSize, void *pbuf)
{
if (gViewPort)
return gViewPort->MsgFunc_ValClass( pszName, iSize, pbuf );
return 0;
}
int __MsgFunc_TeamNames(const char *pszName, int iSize, void *pbuf)
{
if (gViewPort)
return gViewPort->MsgFunc_TeamNames( pszName, iSize, pbuf );
return 0;
}
int __MsgFunc_Feign(const char *pszName, int iSize, void *pbuf)
{
if (gViewPort)
return gViewPort->MsgFunc_Feign( pszName, iSize, pbuf );
return 0;
}
int __MsgFunc_Detpack(const char *pszName, int iSize, void *pbuf)
{
if (gViewPort)
return gViewPort->MsgFunc_Detpack( pszName, iSize, pbuf );
return 0;
}
int __MsgFunc_VGUIMenu(const char *pszName, int iSize, void *pbuf)
{
if (gViewPort)
return gViewPort->MsgFunc_VGUIMenu( pszName, iSize, pbuf );
return 0;
}
int __MsgFunc_MOTD(const char *pszName, int iSize, void *pbuf)
{
if (gViewPort)
return gViewPort->MsgFunc_MOTD( pszName, iSize, pbuf );
return 0;
}
int __MsgFunc_BuildSt(const char *pszName, int iSize, void *pbuf)
{
if (gViewPort)
return gViewPort->MsgFunc_BuildSt( pszName, iSize, pbuf );
return 0;
}
int __MsgFunc_RandomPC(const char *pszName, int iSize, void *pbuf)
{
if (gViewPort)
return gViewPort->MsgFunc_RandomPC( pszName, iSize, pbuf );
return 0;
}
int __MsgFunc_ServerName(const char *pszName, int iSize, void *pbuf)
{
if (gViewPort)
return gViewPort->MsgFunc_ServerName( pszName, iSize, pbuf );
return 0;
}
int __MsgFunc_ScoreInfo(const char *pszName, int iSize, void *pbuf)
{
if (gViewPort)
return gViewPort->MsgFunc_ScoreInfo( pszName, iSize, pbuf );
return 0;
}
int __MsgFunc_TeamScore(const char *pszName, int iSize, void *pbuf)
{
if (gViewPort)
return gViewPort->MsgFunc_TeamScore( pszName, iSize, pbuf );
return 0;
}
int __MsgFunc_TeamInfo(const char *pszName, int iSize, void *pbuf)
{
if (gViewPort)
return gViewPort->MsgFunc_TeamInfo( pszName, iSize, pbuf );
return 0;
}
int __MsgFunc_Spectator(const char *pszName, int iSize, void *pbuf)
{
if (gViewPort)
return gViewPort->MsgFunc_Spectator( pszName, iSize, pbuf );
return 0;
}
int __MsgFunc_AllowSpec(const char *pszName, int iSize, void *pbuf)
{
if (gViewPort)
return gViewPort->MsgFunc_AllowSpec( pszName, iSize, pbuf );
return 0;
}
int __MsgFunc_MusicFade(const char *pszName, int iSize, void *pbuf )
{
return gHUD.MsgFunc_MusicFade( pszName, iSize, pbuf );
}
// buz
int __MsgFunc_TextWindow(const char *pszName, int iSize, void *pbuf)
{
if (gViewPort)
return gViewPort->MsgFunc_ShowTextWindow( pszName, iSize, pbuf );
return 0;
}
// buz
int __MsgFunc_RainData(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_RainData( pszName, iSize, pbuf );
}
int MsgCustomDlight(const char *pszName, int iSize, void *pbuf)
{
BEGIN_READ( pbuf, iSize );
vec3_t pos;
pos.x = READ_COORD();
pos.y = READ_COORD();
pos.z = READ_COORD();
float radius = (float)READ_BYTE() * 10;
float life = (float)READ_BYTE() / 10;
float decay = (float)READ_BYTE() * 10;
CDynLight *dl = CL_AllocDlight (0);
R_SetupLightParams( dl, pos, g_vecZero, radius, 0.0f, LIGHT_OMNI );
dl->color = Vector( 0.7f, 0.6f, 0.5f );
dl->die = GET_CLIENT_TIME() + life;
dl->decay = decay;
return 1;
}
// debug command
// usage: makelight [R G B] [radius] [life]\n" );
void MakeLight( void )
{
CDynLight *dl = CL_AllocDlight( 0 );
if( CMD_ARGC() >= 4 )
{
dl->color[0] = Q_atof(CMD_ARGV( 1 ));
dl->color[1] = Q_atof(CMD_ARGV( 2 ));
dl->color[2] = Q_atof(CMD_ARGV( 3 ));
}
else
{
dl->color = Vector( 0.7f, 0.6f, 0.5f );
}
float radius;
if( CMD_ARGC() >= 5 )
radius = Q_atof(CMD_ARGV( 4 ));
else radius = 128.0f;
R_SetupLightParams( dl, GetVieworg(), g_vecZero, radius, 0.0f, LIGHT_OMNI );
if( CMD_ARGC() >= 6 )
dl->die = GET_CLIENT_TIME() + Q_atof(CMD_ARGV( 5 ));
else dl->die = GET_CLIENT_TIME() + 30.0f;
}
void GammaGraphInit();
void CanUseInit( void ); // Wargon: Èêîíêà þçà.
// This is called every time the DLL is loaded
void CHud :: Init( void )
{
static cl_entity_t head_shield;
GammaGraphInit();
RadioIconInit(); // buz
Hud2Init(); // buz
SubtitleInit(); // buz
TabPanelInit(); // buz
CanUseInit(); // Wargon: Èêîíêà þçà.
// pointer to headshield entity
m_pHeadShieldEnt = &head_shield;
HOOK_MESSAGE( Logo );
HOOK_MESSAGE( ResetHUD );
HOOK_MESSAGE( GameMode );
HOOK_MESSAGE( InitHUD );
HOOK_MESSAGE( ViewMode );
HOOK_MESSAGE( SetFOV );
HOOK_MESSAGE( Concuss );
HOOK_MESSAGE( HUDColor ); //LRC
HOOK_MESSAGE( SetFog ); //LRC
HOOK_MESSAGE( KeyedDLight ); //LRC
HOOK_MESSAGE( SetSky ); //LRC
HOOK_MESSAGE( GasMask ); //buz
HOOK_MESSAGE( SpecTank ); //buz
HOOK_MESSAGE( TextWindow ); // buz
HOOK_MESSAGE( RainData );// buz
HOOK_MESSAGE( Particle );// buz
HOOK_MESSAGE( DelParticle );// buz
gEngfuncs.pfnHookUserMsg( "mydlight", MsgCustomDlight );
// TFFree CommandMenu
HOOK_COMMAND( "+commandmenu", OpenCommandMenu );
HOOK_COMMAND( "-commandmenu", CloseCommandMenu );
HOOK_COMMAND( "ForceCloseCommandMenu", ForceCloseCommandMenu );
HOOK_COMMAND( "special", InputPlayerSpecial );
HOOK_COMMAND( "togglebrowser", ToggleServerBrowser );
gEngfuncs.pfnAddCommand( "makelight", MakeLight );
HOOK_MESSAGE( ValClass );
HOOK_MESSAGE( TeamNames );
HOOK_MESSAGE( Feign );
HOOK_MESSAGE( Detpack );
HOOK_MESSAGE( MOTD );
HOOK_MESSAGE( BuildSt );
HOOK_MESSAGE( RandomPC );
HOOK_MESSAGE( ServerName );
HOOK_MESSAGE( ScoreInfo );
HOOK_MESSAGE( TeamScore );
HOOK_MESSAGE( TeamInfo );
HOOK_MESSAGE( Spectator );
HOOK_MESSAGE( AllowSpec );
HOOK_MESSAGE( WaterSplash );
HOOK_MESSAGE( NewExplode );
HOOK_MESSAGE( HeadShield );
HOOK_MESSAGE( WeaponAnim );
HOOK_MESSAGE( WeaponBody );
HOOK_MESSAGE( WeaponSkin );
HOOK_MESSAGE( SkyMarker );
HOOK_MESSAGE( WorldMarker );
HOOK_MESSAGE( StudioDecal );
HOOK_MESSAGE( CustomDecal );
HOOK_MESSAGE( PartEffect );
HOOK_MESSAGE( LevelTime );
HOOK_MESSAGE( BlurEffect );
// VGUI Menus
HOOK_MESSAGE( VGUIMenu );
m_pZoomSpeed = gEngfuncs.pfnRegisterVariable( "cl_zoomspeed","100", 0 );
CVAR_REGISTER( "hud_classautokill", "1", FCVAR_ARCHIVE | FCVAR_USERINFO ); // controls whether or not to suicide immediately on TF class switch
CVAR_REGISTER( "hud_takesshots", "0", FCVAR_ARCHIVE );// controls whether or not to automatically take screenshots at the end of a round
HOOK_MESSAGE( MusicFade );
m_iLogo = 0;
m_iFOV = 90; // buz - make 90, not 0
m_iHUDColor = 0x00FFA000; //255,160,0 -- LRC
CVAR_REGISTER( "zoom_sensitivity_ratio", "1.2", 0 );
default_fov = CVAR_REGISTER( "default_fov", "75", FCVAR_ARCHIVE );// buz: turn off
m_pCvarStealMouse = CVAR_REGISTER( "hud_capturemouse", "1", FCVAR_ARCHIVE );
m_pCvarDraw = CVAR_REGISTER( "hud_draw", "1", FCVAR_ARCHIVE );
cl_lw = gEngfuncs.pfnGetCvarPointer( "cl_lw" );
cl_rollangle = gEngfuncs.pfnRegisterVariable ( "cl_rollangle", "0.65", FCVAR_CLIENTDLL|FCVAR_ARCHIVE );
cl_rollspeed = gEngfuncs.pfnRegisterVariable ( "cl_rollspeed", "300", FCVAR_CLIENTDLL|FCVAR_ARCHIVE );
m_pSpriteList = NULL;
// Clear any old HUD list
if ( m_pHudList )
{
HUDLIST *pList;
while ( m_pHudList )
{
pList = m_pHudList;
m_pHudList = m_pHudList->pNext;
free( pList );
}
m_pHudList = NULL;
}
// In case we get messages before the first update -- time will be valid
m_flTime = 1.0;
m_Ammo.Init();
m_HudStamina.Init();
m_Health.Init();
m_SayText.Init();
m_Spectator.Init();
m_Geiger.Init();
m_Train.Init();
m_Battery.Init();
m_Flash.Init();
m_Message.Init();
m_StatusBar.Init();
m_DeathNotice.Init();
m_AmmoSecondary.Init();
m_TextMessage.Init();
m_StatusIcons.Init();
m_Lensflare.Init();
GetClientVoiceMgr()->Init(&g_VoiceStatusHelper, (vgui::Panel**)&gViewPort);
m_Menu.Init();
ServersInit();
MsgFunc_ResetHUD(0, 0, NULL );
}
// CHud destructor
// cleans up memory allocated for m_rg* arrays
CHud :: ~CHud()
{
delete [] m_rghSprites;
delete [] m_rgrcRects;
delete [] m_rgszSpriteNames;
if ( m_pHudList )
{
HUDLIST *pList;
while ( m_pHudList )
{
pList = m_pHudList;
m_pHudList = m_pHudList->pNext;
free( pList );
}
m_pHudList = NULL;
}
ServersShutdown();
}
// GetSpriteIndex()
// searches through the sprite list loaded from hud.txt for a name matching SpriteName
// returns an index into the gHUD.m_rghSprites[] array
// returns 0 if sprite not found
int CHud :: GetSpriteIndex( const char *SpriteName )
{
// look through the loaded sprite name list for SpriteName
for ( int i = 0; i < m_iSpriteCount; i++ )
{
if ( strncmp( SpriteName, m_rgszSpriteNames + (i * MAX_SPRITE_NAME_LENGTH), MAX_SPRITE_NAME_LENGTH ) == 0 )
return i;
}
return -1; // invalid sprite
}
void CHud :: VidInit( void )
{
m_flDeadTime = 0; // buz
m_SpecTank_on = 0; // buz
memset( m_pHeadShieldEnt, 0, sizeof(cl_entity_t));
m_pHeadShieldEnt->modelhandle = INVALID_HANDLE;
m_pHeadShieldEnt->curstate.framerate = 1.0f;
m_iHeadShieldState = SHIELD_OFF;
m_flHeadShieldSwitchTime = 0.0f;
CVAR_SET_FLOAT( "hud_draw", 1.0f );
m_flFOV = -1; // buz
m_scrinfo.iSize = sizeof(m_scrinfo);
GetScreenInfo(&m_scrinfo);
// ----------
// Load Sprites
// ---------
// m_hsprFont = LoadSprite("sprites/%d_font.spr");
m_hsprLogo = 0;
m_hsprCursor = 0;
if (ScreenWidth < 640)
m_iRes = 320;
else
m_iRes = 640;
// Only load this once
if ( !m_pSpriteList )
{
// we need to load the hud.txt, and all sprites within
m_pSpriteList = SPR_GetList("scripts/weapons/hud.txt", &m_iSpriteCountAllRes);
if (m_pSpriteList)
{
// count the number of sprites of the appropriate res
m_iSpriteCount = 0;
client_sprite_t *p = m_pSpriteList;
for ( int j = 0; j < m_iSpriteCountAllRes; j++ )
{
if ( p->iRes == m_iRes )
m_iSpriteCount++;
p++;
}
// allocated memory for sprite handle arrays
m_rghSprites = new HSPRITE[m_iSpriteCount];
m_rgrcRects = new wrect_t[m_iSpriteCount];
m_rgszSpriteNames = new char[m_iSpriteCount * MAX_SPRITE_NAME_LENGTH];
p = m_pSpriteList;
int index = 0;
for ( j = 0; j < m_iSpriteCountAllRes; j++ )
{
if ( p->iRes == m_iRes )
{
char sz[256];
sprintf(sz, "sprites/%s.spr", p->szSprite);
m_rghSprites[index] = SPR_Load(sz);
m_rgrcRects[index] = p->rc;
strncpy( &m_rgszSpriteNames[index * MAX_SPRITE_NAME_LENGTH], p->szName, MAX_SPRITE_NAME_LENGTH );
index++;
}
p++;
}
}
}
else
{
// we have already have loaded the sprite reference from hud.txt, but
// we need to make sure all the sprites have been loaded (we've gone through a transition, or loaded a save game)
client_sprite_t *p = m_pSpriteList;
int index = 0;
for ( int j = 0; j < m_iSpriteCountAllRes; j++ )
{
if ( p->iRes == m_iRes )
{
char sz[256];
sprintf( sz, "sprites/%s.spr", p->szSprite );
m_rghSprites[index] = SPR_Load(sz);
index++;
}
p++;
}
}
// assumption: number_1, number_2, etc, are all listed and loaded sequentially
m_HUD_number_0 = GetSpriteIndex( "number_0" );
m_iFontHeight = m_rgrcRects[m_HUD_number_0].bottom - m_rgrcRects[m_HUD_number_0].top;
m_Ammo.VidInit();
m_HudStamina.VidInit();
m_Health.VidInit();
m_Spectator.VidInit();
m_Geiger.VidInit();
m_Train.VidInit();
m_Battery.VidInit();
m_Flash.VidInit();
m_Message.VidInit();
m_StatusBar.VidInit();
m_DeathNotice.VidInit();
m_SayText.VidInit();
m_Menu.VidInit();
m_AmmoSecondary.VidInit();
m_TextMessage.VidInit();
m_StatusIcons.VidInit();
m_Lensflare.VidInit();
GetClientVoiceMgr()->VidInit();
}
int CHud::MsgFunc_Logo(const char *pszName, int iSize, void *pbuf)
{
BEGIN_READ( pbuf, iSize );
// update Train data
m_iLogo = READ_BYTE();
return 1;
}
//LRC
int CHud::MsgFunc_HUDColor(const char *pszName, int iSize, void *pbuf)
{
BEGIN_READ( pbuf, iSize );
m_iHUDColor = READ_LONG();
return 1;
}
//float g_lastFOV = 0.0; buz
/*
=================
HUD_IsGame
=================
*/
int HUD_IsGame( const char *game )
{
const char *gamedir;
char gd[ 1024 ];
gamedir = gEngfuncs.pfnGetGameDirectory();
if ( gamedir && gamedir[0] )
{
COM_FileBase( gamedir, gd );
if ( !stricmp( gd, game ) )
return 1;
}
return 0;
}
/*
=====================
HUD_GetFOV
Returns last FOV
=====================
*/
#if 0 // buz
float HUD_GetFOV( void )
{
if ( gEngfuncs.pDemoAPI->IsRecording() )
{
// Write it
int i = 0;
unsigned char buf[ 100 ];
// Active
*( float * )&buf[ i ] = g_lastFOV;
i += sizeof( float );
Demo_WriteBuffer( TYPE_ZOOM, i, buf );
}
if ( gEngfuncs.pDemoAPI->IsPlayingback() )
{
g_lastFOV = g_demozoom;
}
return g_lastFOV;
}
#endif
int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf)
{
BEGIN_READ( pbuf, iSize );
int newfov = READ_BYTE();
return 1;
}
void CHud::AddHudElem(CHudBase *phudelem)
{
HUDLIST *pdl, *ptemp;
//phudelem->Think();
if (!phudelem)
return;
pdl = (HUDLIST *)malloc(sizeof(HUDLIST));
if (!pdl)
return;
memset(pdl, 0, sizeof(HUDLIST));
pdl->p = phudelem;
if (!m_pHudList)
{
m_pHudList = pdl;
return;
}
ptemp = m_pHudList;
while (ptemp->pNext)
ptemp = ptemp->pNext;
ptemp->pNext = pdl;
}
float CHud::GetSensitivity( void )
{
return m_flMouseSensitivity;
}

832
cl_dll/hud.h Normal file
View File

@ -0,0 +1,832 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// hud.h
//
// class CHud declaration
//
// CHud handles the message, calculation, and drawing the HUD
//
#pragma warning (disable:4018)
#define DO_TIMING
#define FOG_LIMIT 30000
#define RGB_YELLOWISH 0x00FFA000 //255,160,0
#define RGB_REDISH 0x00FF1010 //255,160,0
#define RGB_GREENISH 0x0000A000 //0,160,0
#include "wrect.h"
#include "windows.h"
#include "cl_dll.h"
#include "render_api.h"
#include "enginecallback.h"
#include "ammo.h"
#include "mathlib.h"
#include "timing.h"
#define DHN_DRAWZERO 1
#define DHN_2DIGITS 2
#define DHN_3DIGITS 4
#define MIN_ALPHA 170
// headshield states
#define SHIELD_ON 0
#define SHIELD_OFF 1
#define SHIELD_TURNING_ON 2
#define SHIELD_TURNING_OFF 3
// headshield anims
#define SHIELDANIM_IDLE 0
#define SHIELDANIM_DRAW 1
#define SHIELDANIM_HOLSTER 2
#define HUDELEM_ACTIVE 1
typedef struct {
int x, y;
} POSITION;
enum
{
MAX_PLAYERS = 64,
MAX_TEAMS = 64,
MAX_TEAM_NAME = 16,
};
typedef struct {
unsigned char r,g,b,a;
} RGBA;
typedef struct cvar_s cvar_t;
#define HUD_ACTIVE 1
#define HUD_INTERMISSION 2
#define MAX_PLAYER_NAME_LENGTH 32
#define MAX_MOTD_LENGTH 1536
//
//-----------------------------------------------------
//
class CHudBase
{
public:
POSITION m_pos;
int m_type;
int m_iFlags; // active, moving,
virtual ~CHudBase() {}
virtual int Init( void ) {return 0;}
virtual int VidInit( void ) {return 0;}
virtual int Draw(float flTime) {return 0;}
virtual void Think(void) {return;}
virtual void Reset(void) {return;}
virtual void InitHUDData( void ) {} // called every time a server is connected to
};
struct HUDLIST {
CHudBase *p;
HUDLIST *pNext;
};
//
//-----------------------------------------------------
//
#include "..\game_shared\voice_status.h"
#include "hud_spectator.h"
//
//-----------------------------------------------------
//
class CHudAmmo: public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw(float flTime);
void Think(void);
void Reset(void);
void UpdateCrosshair(); // buz
int DrawWList(float flTime);
int MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf);
int MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf);
int MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf);
int MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf );
int MsgFunc_WeapPickup( const char *pszName, int iSize, void *pbuf );
int MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf );
int MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf );
void SlotInput( int iSlot );
void _cdecl UserCmd_Slot1( void );
void _cdecl UserCmd_Slot2( void );
void _cdecl UserCmd_Slot3( void );
void _cdecl UserCmd_Slot4( void );
void _cdecl UserCmd_Slot5( void );
void _cdecl UserCmd_Slot6( void );
void _cdecl UserCmd_Slot7( void );
void _cdecl UserCmd_Slot8( void );
void _cdecl UserCmd_Slot9( void );
void _cdecl UserCmd_Slot10( void );
void _cdecl UserCmd_Close( void );
void _cdecl UserCmd_NextWeapon( void );
void _cdecl UserCmd_PrevWeapon( void );
void LoadMenuSettings( void );
// buz: these variables loaded from file menu_settings.txt
int m_menuSizeX;
int m_menuSizeY;
float m_menuScale;
float m_menuMinAlpha;
float m_menuAddAlpha;
float m_menuSpeed;
int m_menuRenderMode;
int m_menuOfsX;
int m_menuOfsY;
int m_menuSpaceX;
int m_menuSpaceY;
int m_menuNumberSizeX;
int m_menuNumberSizeY;
//private:
float m_fFade;
RGBA m_rgba;
WEAPON *m_pWeapon;
int m_HUD_bucket0;
int m_HUD_selection;
int m_mach; // buz
};
//
//-----------------------------------------------------
//
class CHudAmmoSecondary: public CHudBase
{
public:
int Init( void );
int VidInit( void );
void Reset( void );
int Draw(float flTime);
int MsgFunc_SecAmmoVal( const char *pszName, int iSize, void *pbuf );
int MsgFunc_SecAmmoIcon( const char *pszName, int iSize, void *pbuf );
private:
enum {
MAX_SEC_AMMO_VALUES = 4
};
int m_HUD_ammoicon; // sprite indices
int m_iAmmoAmounts[MAX_SEC_AMMO_VALUES];
float m_fFade;
};
#include "health.h"
#define FADE_TIME 100
//
//-----------------------------------------------------
//
class CHudGeiger: public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw(float flTime);
int MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf);
private:
int m_iGeigerRange;
};
//
//-----------------------------------------------------
//
class CHudTrain: public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw(float flTime);
int MsgFunc_Train(const char *pszName, int iSize, void *pbuf);
private:
HSPRITE m_hSprite;
int m_iPos;
};
//
//-----------------------------------------------------
//
class CHudLensflare: public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw(float flTime);
int DrawFlare( const Vector &forward, const Vector &lightdir, const Vector &lightorg );
private:
float flPlayerBlend;
float flPlayerBlend2;
float flPlayerBlend3;
float flPlayerBlend4;
float flPlayerBlend5;
float flPlayerBlend6;
float Screenmx;
float Screenmy;
float multi[10];
int scale[10];
int red[10];
int green[10];
int blue[10];
char text[10];
float Lensx[10];
float Lensy[10];
float Suncoordx;
float Suncoordy;
float Sundistx;
float Sundisty;
cvar_t *m_pCvarDraw;
};
//
//-----------------------------------------------------
//
// REMOVED: Vgui has replaced this.
//
/*
class CHudMOTD : public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw( float flTime );
void Reset( void );
int MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf );
protected:
static int MOTD_DISPLAY_TIME;
char m_szMOTD[ MAX_MOTD_LENGTH ];
float m_flActiveRemaining;
int m_iLines;
};
*/
//
//-----------------------------------------------------
//
class CHudStatusBar : public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw( float flTime );
void Reset( void );
void ParseStatusString( int line_num );
int MsgFunc_StatusText( const char *pszName, int iSize, void *pbuf );
int MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf );
protected:
enum {
MAX_STATUSTEXT_LENGTH = 128,
MAX_STATUSBAR_VALUES = 8,
MAX_STATUSBAR_LINES = 2,
};
char m_szStatusText[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // a text string describing how the status bar is to be drawn
char m_szStatusBar[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // the constructed bar that is drawn
int m_iStatusValues[MAX_STATUSBAR_VALUES]; // an array of values for use in the status bar
int m_bReparseString; // set to TRUE whenever the m_szStatusBar needs to be recalculated
// an array of colors...one color for each line
float *m_pflNameColors[MAX_STATUSBAR_LINES];
};
//
//-----------------------------------------------------
//
// REMOVED: Vgui has replaced this.
//
/*
class CHudScoreboard: public CHudBase
{
public:
int Init( void );
void InitHUDData( void );
int VidInit( void );
int Draw( float flTime );
int DrawPlayers( int xoffset, float listslot, int nameoffset = 0, char *team = NULL ); // returns the ypos where it finishes drawing
void UserCmd_ShowScores( void );
void UserCmd_HideScores( void );
int MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf );
int MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf );
int MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf );
void DeathMsg( int killer, int victim );
int m_iNumTeams;
int m_iLastKilledBy;
int m_fLastKillTime;
int m_iPlayerNum;
int m_iShowscoresHeld;
void GetAllPlayersInfo( void );
private:
struct cvar_s *cl_showpacketloss;
};
*/
struct extra_player_info_t
{
short frags;
short deaths;
short playerclass;
short teamnumber;
char teamname[MAX_TEAM_NAME];
};
struct team_info_t
{
char name[MAX_TEAM_NAME];
short frags;
short deaths;
short ping;
short packetloss;
short ownteam;
short players;
int already_drawn;
int scores_overriden;
int teamnumber;
};
extern hud_player_info_t g_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine
extern extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client dll
extern team_info_t g_TeamInfo[MAX_TEAMS+1];
extern int g_IsSpectator[MAX_PLAYERS+1];
//
//-----------------------------------------------------
//
class CHudDeathNotice : public CHudBase
{
public:
int Init( void );
void InitHUDData( void );
int VidInit( void );
int Draw( float flTime );
int MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf );
private:
int m_HUD_d_skull; // sprite index of skull icon
};
//
//-----------------------------------------------------
//
class CHudMenu : public CHudBase
{
public:
int Init( void );
void InitHUDData( void );
int VidInit( void );
void Reset( void );
int Draw( float flTime );
int MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf );
void SelectMenuItem( int menu_item );
int m_fMenuDisplayed;
int m_bitsValidSlots;
float m_flShutoffTime;
int m_fWaitingForMore;
};
//
//-----------------------------------------------------
//
class CHudSayText : public CHudBase
{
public:
int Init( void );
void InitHUDData( void );
int VidInit( void );
int Draw( float flTime );
int MsgFunc_SayText( const char *pszName, int iSize, void *pbuf );
void SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex = -1 );
void EnsureTextFitsInOneLineAndWrapIfHaveTo( int line );
friend class CHudSpectator;
private:
struct cvar_s * m_HUD_saytext;
struct cvar_s * m_HUD_saytext_time;
};
//
//-----------------------------------------------------
//
class CHudBattery: public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw(float flTime);
int MsgFunc_Battery(const char *pszName, int iSize, void *pbuf );
private:
HSPRITE m_hSprite1;
HSPRITE m_hSprite2;
wrect_t *m_prc1;
wrect_t *m_prc2;
int m_iBat;
float m_fFade;
int m_iHeight; // width of the battery innards
};
class CHudStamina: public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw(float flTime);
int MsgFunc_Stamina(const char *pszName, int iSize, void *pbuf );
private:
HSPRITE m_hSprite1;
HSPRITE m_hSprite2;
wrect_t *m_prc1;
wrect_t *m_prc2;
int m_iStam;
float m_fFade;
int m_iHeight;
};
//
//-----------------------------------------------------
//
class CHudFlashlight: public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw(float flTime);
void Reset( void );
int MsgFunc_Flashlight(const char *pszName, int iSize, void *pbuf );
int MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf );
private:
HSPRITE m_hSprite1;
HSPRITE m_hSprite2;
HSPRITE m_hBeam;
wrect_t *m_prc1;
wrect_t *m_prc2;
wrect_t *m_prcBeam;
float m_flBat;
int m_iBat;
int m_fOn;
float m_fFade;
int m_iWidth; // width of the battery innards
};
//
//-----------------------------------------------------
//
const int maxHUDMessages = 16;
struct message_parms_t
{
client_textmessage_t *pMessage;
float time;
int x, y;
int totalWidth, totalHeight;
int width;
int lines;
int lineLength;
int length;
int r, g, b;
int text;
int fadeBlend;
float charTime;
float fadeTime;
};
//
//-----------------------------------------------------
//
class CHudTextMessage: public CHudBase
{
public:
int Init( void );
static char *LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size );
static char *BufferedLocaliseTextString( const char *msg );
char *LookupString( const char *msg_name, int *msg_dest = NULL );
int MsgFunc_TextMsg(const char *pszName, int iSize, void *pbuf);
};
//
//-----------------------------------------------------
//
class CHudMessage: public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw(float flTime);
int MsgFunc_HudText(const char *pszName, int iSize, void *pbuf);
int MsgFunc_GameTitle(const char *pszName, int iSize, void *pbuf);
float FadeBlend( float fadein, float fadeout, float hold, float localTime );
int XPosition( float x, int width, int lineWidth );
int YPosition( float y, int height );
void MessageAdd( const char *pName, float time );
void MessageAdd(client_textmessage_t * newMessage );
void MessageDrawScan( client_textmessage_t *pMessage, float time );
void MessageScanStart( void );
void MessageScanNextChar( void );
void Reset( void );
private:
client_textmessage_t *m_pMessages[maxHUDMessages];
float m_startTime[maxHUDMessages];
message_parms_t m_parms;
float m_gameTitleTime;
client_textmessage_t *m_pGameTitle;
int m_HUD_title_life;
int m_HUD_title_half;
};
//
//-----------------------------------------------------
//
#define MAX_SPRITE_NAME_LENGTH 24
class CHudStatusIcons: public CHudBase
{
public:
int Init( void );
int VidInit( void );
void Reset( void );
int Draw(float flTime);
int MsgFunc_StatusIcon(const char *pszName, int iSize, void *pbuf);
enum {
MAX_ICONSPRITENAME_LENGTH = MAX_SPRITE_NAME_LENGTH,
MAX_ICONSPRITES = 4,
};
//had to make these public so CHud could access them (to enable concussion icon)
//could use a friend declaration instead...
void EnableIcon( char *pszIconName, unsigned char red, unsigned char green, unsigned char blue );
void DisableIcon( char *pszIconName );
private:
typedef struct
{
char szSpriteName[MAX_ICONSPRITENAME_LENGTH];
HSPRITE spr;
wrect_t rc;
unsigned char r, g, b;
} icon_sprite_t;
icon_sprite_t m_IconList[MAX_ICONSPRITES];
};
//
//-----------------------------------------------------
//
//LRC - for the moment, skymode has only two settings
#define SKY_OFF 0
#define SKY_ON 1
class CHud
{
private:
HUDLIST *m_pHudList;
int m_iLogo;
client_sprite_t *m_pSpriteList;
int m_iSpriteCount;
int m_iSpriteCountAllRes;
float m_flMouseSensitivity;
int m_iConcussionEffect;
public:
HSPRITE m_hsprCursor;
HSPRITE m_hsprLogo; // buz: make public
float m_flTime; // the current client time
float m_fOldTime; // the time at which the HUD was last redrawn
double m_flTimeDelta; // the difference between flTime and fOldTime
Vector m_vecOrigin;
Vector m_vecAngles;
int m_iKeyBits;
int m_iHideHUDDisplay;
int m_iFOV;
float m_flFOV; // buz - that's my FOV!
int m_Teamplay;
int m_iRes;
cvar_t *m_pCvarStealMouse;
cvar_t *m_pCvarDraw;
cvar_t *m_pZoomSpeed; // buz
cl_entity_t *m_pHeadShieldEnt;
int m_iHeadShieldState;
float m_flHeadShieldSwitchTime;
int m_iViewModelIndex;
Vector m_vecSkyPos; //LRC
int m_iSkyMode; //LRC
// buz: spec tank variables;
int m_SpecTank_on;
Vector m_SpecTank_point;
float m_SpecTank_defYaw;
float m_SpecTank_coneHor;
float m_SpecTank_coneVer;
float m_SpecTank_distFwd;
float m_SpecTank_distUp;
int m_SpecTank_Ammo;
float m_flBlurAmount;
// buz: die time
float m_flDeadTime;
float m_flLevelTime;
int m_iFontHeight;
int DrawHudNumber(int x, int y, int iFlags, int iNumber, int r, int g, int b );
int DrawHudString(int x, int y, int iMaxX, char *szString, int r, int g, int b );
int DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b );
int DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b );
int GetNumWidth(int iNumber, int iFlags);
int m_iHUDColor; //LRC
private:
// the memory for these arrays are allocated in the first call to CHud::VidInit(), when the hud.txt and associated sprites are loaded.
// freed in ~CHud()
HSPRITE *m_rghSprites; /*[HUD_SPRITE_COUNT]*/ // the sprites loaded from hud.txt
wrect_t *m_rgrcRects; /*[HUD_SPRITE_COUNT]*/
char *m_rgszSpriteNames; /*[HUD_SPRITE_COUNT][MAX_SPRITE_NAME_LENGTH]*/
struct cvar_s *default_fov; // buz: turn off
public:
HSPRITE GetSprite( int index )
{
return (index < 0) ? 0 : m_rghSprites[index];
}
wrect_t& GetSpriteRect( int index )
{
return m_rgrcRects[index];
}
int GetSpriteIndex( const char *SpriteName ); // gets a sprite index, for use in the m_rghSprites[] array
CHudAmmo m_Ammo;
CHudStamina m_HudStamina;
CHudHealth m_Health;
CHudSpectator m_Spectator;
CHudGeiger m_Geiger;
CHudBattery m_Battery;
CHudTrain m_Train;
CHudFlashlight m_Flash;
CHudMessage m_Message;
CHudStatusBar m_StatusBar;
CHudDeathNotice m_DeathNotice;
CHudSayText m_SayText;
CHudMenu m_Menu;
CHudAmmoSecondary m_AmmoSecondary;
CHudTextMessage m_TextMessage;
CHudStatusIcons m_StatusIcons;
CHudLensflare m_Lensflare;
void Init( void );
void VidInit( void );
void Think(void);
int Redraw( float flTime, int intermission );
int UpdateClientData( client_data_t *cdata, float time );
CHud() : m_iSpriteCount(0), m_pHudList(NULL) {}
~CHud(); // destructor, frees allocated memory
// user messages
int _cdecl MsgFunc_Damage(const char *pszName, int iSize, void *pbuf );
int _cdecl MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf );
int _cdecl MsgFunc_Logo(const char *pszName, int iSize, void *pbuf);
int _cdecl MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf);
void _cdecl MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf );
void _cdecl MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf );
int _cdecl MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf);
int _cdecl MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf );
int _cdecl MsgFunc_BlurEffect( const char *pszName, int iSize, void *pbuf );
int _cdecl MsgFunc_HUDColor(const char *pszName, int iSize, void *pbuf); //LRC
void _cdecl MsgFunc_SetFog( const char *pszName, int iSize, void *pbuf ); //LRC
void _cdecl MsgFunc_KeyedDLight( const char *pszName, int iSize, void *pbuf ); //LRC
void _cdecl MsgFunc_SetSky( const char *pszName, int iSize, void *pbuf ); //LRC
int _cdecl MsgFunc_GasMask( const char *pszName, int iSize, void *pbuf ); // buz
int _cdecl MsgFunc_SpecTank( const char *pszName, int iSize, void *pbuf ); // buz
int _cdecl MsgFunc_MusicFade( const char *pszName, int iSize, void *pbuf );
int _cdecl MsgFunc_RainData( const char *pszName, int iSize, void *pbuf ); // buz
int _cdecl MsgFunc_WaterSplash( const char *pszName, int iSize, void *pbuf );
int _cdecl MsgFunc_NewExplode( const char *pszName, int iSize, void *pbuf );
int _cdecl MsgFunc_HeadShield( const char *pszName, int iSize, void *pbuf );
int _cdecl MsgFunc_Particle( const char *pszName, int iSize, void *pbuf );
int _cdecl MsgFunc_DelParticle( const char *pszName, int iSize, void *pbuf );
// viewmodel messages
int _cdecl MsgFunc_WeaponAnim( const char *pszName, int iSize, void *pbuf );
int _cdecl MsgFunc_WeaponBody( const char *pszName, int iSize, void *pbuf );
int _cdecl MsgFunc_WeaponSkin( const char *pszName, int iSize, void *pbuf );
// sky messages
int _cdecl MsgFunc_SkyMarker( const char *pszName, int iSize, void *pbuf );
int _cdecl MsgFunc_WorldMarker( const char *pszName, int iSize, void *pbuf );
// decal messages
int _cdecl MsgFunc_CustomDecal( const char *pszName, int iSize, void *pbuf );
int _cdecl MsgFunc_StudioDecal( const char *pszName, int iSize, void *pbuf );
// effect messages
int _cdecl MsgFunc_PartEffect(const char *pszName, int iSize, void *pbuf);
int _cdecl MsgFunc_LevelTime(const char *pszName, int iSize, void *pbuf);
// Screen information
SCREENINFO m_scrinfo;
int m_iWeaponBits;
int m_fPlayerDead;
int m_iIntermission;
// sprite indexes
int m_HUD_number_0;
void AddHudElem(CHudBase *p);
float GetSensitivity();
};
class TeamFortressViewport;
extern CHud gHUD;
extern TeamFortressViewport *gViewPort;
extern int g_iPlayerClass;
extern int g_iTeamNumber;
extern int g_iUser1;
extern int g_iUser2;
extern int g_iUser3;

18
cl_dll/hud_iface.h Normal file
View File

@ -0,0 +1,18 @@
//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#if !defined( HUD_IFACEH )
#define HUD_IFACEH
#pragma once
#define EXPORT _declspec( dllexport )
#define _DLLEXPORT __declspec( dllexport )
#include "../engine/cdll_int.h"
extern cl_enginefunc_t gEngfuncs;
#endif

613
cl_dll/hud_msg.cpp Normal file
View File

@ -0,0 +1,613 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// hud_msg.cpp
//
#include "hud.h"
#include "cl_util.h"
#include "parsemsg.h"
#include "r_efx.h"
#include "studio.h"
#include "gl_local.h"
#include "gl_studio.h"
#include "stringlib.h"
#include "gl_rpart.h"
//LRC - the fogging fog
float g_fFogColor[3];
float g_fStartDist;
float g_fEndDist;
//int g_iFinalStartDist; //for fading
int g_iFinalEndDist; //for fading
float g_fFadeDuration; //negative = fading out
extern engine_studio_api_t IEngineStudio;
extern float v_idlescale;
extern int g_iGunMode;
#define MAX_CLIENTS 32
void EV_HLDM_WaterSplash( float x, float y, float z, float ScaleSplash1, float ScaleSplash2 );
int CHud :: MsgFunc_WaterSplash( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
float X, Y, Z, ScaleSplash1, ScaleSplash2;
X = READ_COORD();
Y = READ_COORD();
Z = READ_COORD();
ScaleSplash1 = READ_COORD();
ScaleSplash2 = READ_COORD();
EV_HLDM_WaterSplash( X, Y, Z, ScaleSplash1, ScaleSplash2 );
return 1;
}
void EV_HLDM_NewExplode( float x, float y, float z, float ScaleExplode1 );
int CHud :: MsgFunc_NewExplode( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
float X, Y, Z, ScaleExplode1;
X = READ_COORD();
Y = READ_COORD();
Z = READ_COORD();
ScaleExplode1 = READ_COORD();
EV_HLDM_NewExplode( X, Y, Z, ScaleExplode1 );
return 1;
}
/// USER-DEFINED SERVER MESSAGE HANDLERS
int CHud :: MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf )
{
// clear all hud data
HUDLIST *pList = m_pHudList;
while ( pList )
{
if ( pList->p )
pList->p->Reset();
pList = pList->pNext;
}
// reset sensitivity
m_flMouseSensitivity = 0;
// reset concussion effect
m_iConcussionEffect = 0;
m_flLevelTime = -1.0f;
//LRC - reset fog
m_flBlurAmount = 0;
g_fStartDist = 0;
g_fEndDist = 0;
g_iGunMode = 0;
return 1;
}
void CAM_ToFirstPerson(void);
void CHud :: MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf )
{
CAM_ToFirstPerson();
}
void CHud :: MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf )
{
m_flLevelTime = -1.0f;
//LRC - clear the fog
g_fStartDist = 0;
g_fEndDist = 0;
m_iSkyMode = SKY_OFF; //LRC
// prepare all hud data
HUDLIST *pList = m_pHudList;
while (pList)
{
if ( pList->p )
pList->p->InitHUDData();
pList = pList->pNext;
}
g_iGunMode = 0;
}
//LRC
void CHud :: MsgFunc_SetFog( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
for ( int i = 0; i < 3; i++ )
g_fFogColor[ i ] = READ_BYTE();
g_fFadeDuration = READ_SHORT();
g_fStartDist = READ_SHORT();
if (g_fFadeDuration > 0)
{
// // fading in
// g_fStartDist = READ_SHORT();
g_iFinalEndDist = READ_SHORT();
// g_fStartDist = FOG_LIMIT;
g_fEndDist = FOG_LIMIT;
}
else if (g_fFadeDuration < 0)
{
// // fading out
// g_iFinalStartDist =
g_iFinalEndDist = g_fEndDist = READ_SHORT();
}
else
{
// g_fStartDist = READ_SHORT();
g_fEndDist = READ_SHORT();
}
}
//LRC
void CHud :: MsgFunc_KeyedDLight( const char *pszName, int iSize, void *pbuf )
{
// CONPRINT("MSG:KeyedDLight");
BEGIN_READ( pbuf, iSize );
// as-yet unused:
// float decay; // drop this each second
// float minlight; // don't add when contributing less
// qboolean dark; // subtracts light instead of adding (doesn't seem to do anything?)
int iKey = READ_BYTE();
dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight( iKey );
int bActive = READ_BYTE();
if (!bActive)
{
// die instantly
dl->die = gEngfuncs.GetClientTime();
}
else
{
// never die
dl->die = gEngfuncs.GetClientTime() + 1E6;
dl->origin[0] = READ_COORD();
dl->origin[1] = READ_COORD();
dl->origin[2] = READ_COORD();
dl->radius = READ_BYTE();
dl->color.r = READ_BYTE();
dl->color.g = READ_BYTE();
dl->color.b = READ_BYTE();
}
}
//LRC
void CHud :: MsgFunc_SetSky( const char *pszName, int iSize, void *pbuf )
{
// CONPRINT("MSG:SetSky");
BEGIN_READ( pbuf, iSize );
m_iSkyMode = READ_BYTE();
m_vecSkyPos.x = READ_COORD();
m_vecSkyPos.y = READ_COORD();
m_vecSkyPos.z = READ_COORD();
}
int CHud :: MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
m_Teamplay = READ_BYTE();
return 1;
}
int CHud :: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf )
{
int armor, blood;
Vector from;
int i;
float count;
BEGIN_READ( pbuf, iSize );
armor = READ_BYTE();
blood = READ_BYTE();
for (i=0 ; i<3 ; i++)
from[i] = READ_COORD();
count = (blood * 0.5) + (armor * 0.5);
if (count < 10)
count = 10;
// TODO: kick viewangles, show damage visually
return 1;
}
int CHud :: MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
m_iConcussionEffect = READ_BYTE();
if (m_iConcussionEffect)
this->m_StatusIcons.EnableIcon("dmg_concuss",255,160,0);
else
this->m_StatusIcons.DisableIcon("dmg_concuss");
return 1;
}
// buz: gasmask message
int CHud :: MsgFunc_GasMask( const char *pszName, int iSize, void *pbuf )
{
studiohdr_t *pStudioHeader;
mstudioseqdesc_t *pseq;
BEGIN_READ( pbuf, iSize );
gHUD.m_pHeadShieldEnt->model = IEngineStudio.Mod_ForName( "models/v_gasmask.mdl", true );
if( g_fRenderInitialized && RENDER_GET_PARM( PARM_WIDESCREEN, 0 ))
gHUD.m_pHeadShieldEnt->curstate.fuser2 = 4.2f; // offset
else gHUD.m_pHeadShieldEnt->curstate.fuser2 = 4.8f; // offset
// 0 is OFF; 1 is ON; 2 is fast switch to ON
switch( READ_BYTE( ))
{
case 0:
m_iHeadShieldState = SHIELD_TURNING_OFF;
m_pHeadShieldEnt->curstate.animtime = gEngfuncs.GetClientTime();
m_pHeadShieldEnt->curstate.sequence = SHIELDANIM_HOLSTER;
// get animation length in seconds
pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata( gHUD.m_pHeadShieldEnt->model );
pseq = (mstudioseqdesc_t *)((byte *)pStudioHeader + pStudioHeader->seqindex) + SHIELDANIM_HOLSTER;
m_flHeadShieldSwitchTime = gEngfuncs.GetClientTime() + (pseq->numframes / pseq->fps);
break;
case 1:
m_iHeadShieldState = SHIELD_TURNING_ON;
m_pHeadShieldEnt->curstate.animtime = gEngfuncs.GetClientTime();
m_pHeadShieldEnt->curstate.sequence = SHIELDANIM_DRAW;
// get animation length in seconds
pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata( gHUD.m_pHeadShieldEnt->model );
pseq = (mstudioseqdesc_t *)((byte *)pStudioHeader + pStudioHeader->seqindex) + SHIELDANIM_DRAW;
m_flHeadShieldSwitchTime = gEngfuncs.GetClientTime() + (pseq->numframes / pseq->fps);
break;
case 2:
m_iHeadShieldState = SHIELD_ON;
m_pHeadShieldEnt->curstate.animtime = gEngfuncs.GetClientTime();
m_pHeadShieldEnt->curstate.sequence = SHIELDANIM_IDLE;
}
return 1;
}
int CHud::MsgFunc_HeadShield( const char *pszName, int iSize, void *pbuf )
{
studiohdr_t *pStudioHeader;
mstudioseqdesc_t *pseq;
BEGIN_READ( pbuf, iSize );
gHUD.m_pHeadShieldEnt->model = IEngineStudio.Mod_ForName( "models/v_headshield.mdl", true );
if( g_fRenderInitialized && RENDER_GET_PARM( PARM_WIDESCREEN, 0 ))
gHUD.m_pHeadShieldEnt->curstate.fuser2 = 5.0f; // offset
else gHUD.m_pHeadShieldEnt->curstate.fuser2 = 16.0f; // offset
// 0 is OFF; 1 is ON; 2 is fast switch to ON
switch( READ_BYTE( ))
{
case 0:
m_iHeadShieldState = SHIELD_TURNING_OFF;
m_pHeadShieldEnt->curstate.animtime = gEngfuncs.GetClientTime();
m_pHeadShieldEnt->curstate.sequence = SHIELDANIM_HOLSTER;
// get animation length in seconds
pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata( gHUD.m_pHeadShieldEnt->model );
pseq = (mstudioseqdesc_t *)((byte *)pStudioHeader + pStudioHeader->seqindex) + SHIELDANIM_HOLSTER;
m_flHeadShieldSwitchTime = gEngfuncs.GetClientTime() + (pseq->numframes / pseq->fps);
break;
case 1:
m_iHeadShieldState = SHIELD_TURNING_ON;
m_pHeadShieldEnt->curstate.animtime = gEngfuncs.GetClientTime();
m_pHeadShieldEnt->curstate.sequence = SHIELDANIM_DRAW;
// get animation length in seconds
pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata( gHUD.m_pHeadShieldEnt->model );
pseq = (mstudioseqdesc_t *)((byte *)pStudioHeader + pStudioHeader->seqindex) + SHIELDANIM_DRAW;
m_flHeadShieldSwitchTime = gEngfuncs.GetClientTime() + (pseq->numframes / pseq->fps);
break;
case 2:
m_iHeadShieldState = SHIELD_ON;
m_pHeadShieldEnt->curstate.animtime = gEngfuncs.GetClientTime();
m_pHeadShieldEnt->curstate.sequence = SHIELDANIM_IDLE;
}
return 1;
}
// buz: special tank message
int CHud :: MsgFunc_SpecTank( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
m_SpecTank_on = READ_BYTE();
if (m_SpecTank_on == 0) // turn off
return 1;
else if (m_SpecTank_on == 2) // only ammo update
{
m_SpecTank_Ammo = READ_LONG();
m_Ammo.m_fFade = 200.0f;
}
else // turn on
{
m_SpecTank_point.x = READ_COORD();
m_SpecTank_point.y = READ_COORD();
m_SpecTank_point.z = READ_COORD();
m_SpecTank_defYaw = READ_COORD();
m_SpecTank_coneHor = READ_COORD();
m_SpecTank_coneVer = READ_COORD();
m_SpecTank_distFwd = READ_COORD();
m_SpecTank_distUp = READ_COORD();
m_SpecTank_Ammo = READ_LONG();
}
return 1;
}
int CHud :: MsgFunc_MusicFade( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
MUSIC_FADE_VOLUME( (float)READ_SHORT() / 100.0f );
return 1;
}
int CHud :: MsgFunc_Particle( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
int entindex = READ_SHORT();
char *sz = READ_STRING();
int attachment = READ_BYTE();
UTIL_CreateAurora( GET_ENTITY( entindex ), sz, attachment );
return 1;
}
int CHud :: MsgFunc_DelParticle( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
int entindex = READ_SHORT();
UTIL_RemoveAurora( GET_ENTITY( entindex ));
return 1;
}
int CHud :: MsgFunc_RainData( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
ParseRain();
return 1;
}
int CHud :: MsgFunc_WeaponAnim( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
int sequence = READ_BYTE();
float framerate = READ_BYTE() * 0.125f;
UTIL_WeaponAnimation( sequence, framerate );
return 1;
}
int CHud :: MsgFunc_WeaponBody( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
GET_VIEWMODEL()->curstate.body = READ_BYTE();
return 1;
}
int CHud :: MsgFunc_WeaponSkin( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
GET_VIEWMODEL()->curstate.skin = READ_BYTE();
return 1;
}
// 3d skybox
int CHud :: MsgFunc_SkyMarker( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
tr.sky_origin.x = READ_COORD();
tr.sky_origin.y = READ_COORD();
tr.sky_origin.z = READ_COORD();
return 1;
}
// 3d skybox
int CHud :: MsgFunc_WorldMarker( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
tr.sky_world_origin.x = READ_COORD();
tr.sky_world_origin.y = READ_COORD();
tr.sky_world_origin.z = READ_COORD();
tr.sky_speed = READ_COORD();
Msg( "sky_speed: %g\n", tr.sky_speed );
return 1;
}
int CHud :: MsgFunc_CustomDecal( const char *pszName, int iSize, void *pbuf )
{
char name[80];
BEGIN_READ( pbuf, iSize );
Vector pos, normal;
pos.x = READ_COORD();
pos.y = READ_COORD();
pos.z = READ_COORD();
normal.x = READ_COORD() / 8192.0f;
normal.y = READ_COORD() / 8192.0f;
normal.z = READ_COORD() / 8192.0f;
int entityIndex = READ_SHORT();
int modelIndex = READ_SHORT();
Q_strncpy( name, READ_STRING(), sizeof( name ));
int flags = READ_BYTE();
float angle = READ_ANGLE();
CreateDecal( pos, normal, angle, name, flags, entityIndex, modelIndex );
return 1;
}
int CHud :: MsgFunc_StudioDecal( const char *pszName, int iSize, void *pbuf )
{
Vector vecEnd, vecNormal, vecScale = g_vecZero;
char name[80];
BEGIN_READ( pbuf, iSize );
vecEnd.x = READ_COORD();
vecEnd.y = READ_COORD();
vecEnd.z = READ_COORD();
vecNormal.x = READ_COORD() * 0.001f;
vecNormal.y = READ_COORD() * 0.001f;
vecNormal.z = READ_COORD() * 0.001f;
int entityIndex = READ_SHORT();
int modelIndex = READ_SHORT();
Q_strncpy( name, READ_STRING(), sizeof( name ));
int flags = READ_BYTE();
modelstate_t state;
state.sequence = READ_SHORT();
state.frame = READ_SHORT();
state.blending[0] = READ_BYTE();
state.blending[1] = READ_BYTE();
state.controller[0] = READ_BYTE();
state.controller[1] = READ_BYTE();
state.controller[2] = READ_BYTE();
state.controller[3] = READ_BYTE();
state.body = READ_BYTE();
state.skin = READ_BYTE();
int cacheID = READ_SHORT();
if( REMAIN_BYTES( ))
{
vecScale.x = READ_COORD() * 0.001f;
vecScale.y = READ_COORD() * 0.001f;
vecScale.z = READ_COORD() * 0.001f;
}
cl_entity_t *ent = GET_ENTITY( entityIndex );
if( !ent )
{
// something very bad happens...
ALERT( at_error, "StudioDecal: ent == NULL\n" );
return 1;
}
g_StudioRenderer.PushEntityState( ent );
g_StudioRenderer.ModelStateToEntity( ent, &state );
// restore model in case decalmessage was delivered early than delta-update
if( !ent->model && modelIndex != 0 )
ent->model = IEngineStudio.GetModelByIndex( modelIndex );
if( cacheID )
{
// tell the code about vertex lighting
SetBits( ent->curstate.iuser1, CF_STATIC_ENTITY );
ent->curstate.colormap = cacheID;
}
if( !RENDER_GET_PARM( PARM_CLIENT_ACTIVE, 0 ) && FBitSet( ent->curstate.iuser1, CF_STATIC_ENTITY ))
ent->curstate.startpos = vecScale; // restore scale here
if( !ent->model || ent->model->type != mod_studio )
return 1;
g_StudioRenderer.StudioDecalShoot( vecNormal, vecEnd, name, ent, flags, &state );
g_StudioRenderer.PopEntityState( ent );
return 1;
}
int CHud :: MsgFunc_PartEffect( const char *pszName, int iSize, void *pbuf )
{
char name[80];
BEGIN_READ( pbuf, iSize );
Vector pos, normal;
pos.x = READ_COORD();
pos.y = READ_COORD();
pos.z = READ_COORD();
normal.x = READ_COORD() / 8192.0f;
normal.y = READ_COORD() / 8192.0f;
normal.z = READ_COORD() / 8192.0f;
Q_strncpy( name, READ_STRING(), sizeof( name ));
g_pParticles.CreateEffect( name, pos, normal );
return 1;
}
int CHud :: MsgFunc_LevelTime( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
m_flLevelTime = READ_FLOAT();
return 1;
}
int CHud :: MsgFunc_BlurEffect( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
m_flBlurAmount = (float)READ_SHORT() / 10000.0f;
v_idlescale = m_flBlurAmount * 100.0f;
// reset blur on a next level
if( !RENDER_GET_PARM( PARM_CLIENT_ACTIVE, 0 ))
{
m_flBlurAmount = 0.0f;
v_idlescale = 0.0f;
}
return 1;
}

521
cl_dll/hud_redraw.cpp Normal file
View File

@ -0,0 +1,521 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// hud_redraw.cpp
//
#include <math.h>
#include "hud.h"
#include "cl_util.h"
#include "vgui_TeamFortressViewport.h"
#include "vgui_hud.h"
#include "triangleapi.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
#endif
// buz: for IsHardware check
#include "r_studioint.h"
#include "com_model.h"
extern engine_studio_api_t IEngineStudio;
#include "vgui_TeamFortressViewport.h"
#include "vgui_paranoiatext.h"// buz
#include "gl_local.h"
#include "gl_decals.h"
#define MAX_LOGO_FRAMES 56
// buz: spread value
vec3_t g_vSpread;
int g_iGunMode = 0;
void DrawBlurTest(float frametime); // buz
extern int g_iVisibleMouse;
//float HUD_GetFOV( void ); buz
extern cvar_t *sensitivity;
// Think
void CHud::Think(void)
{
// buz: calc dead time
if (gHUD.m_Health.m_iHealth <= 0 && !m_flDeadTime)
{
m_flDeadTime = gEngfuncs.GetClientTime();
}
// Wargon: Èñïðàâëåíèå áàãà ýôôåêòà grayscale, îñòàâàâøåãîñÿ ïîñëå çàãðóçêè èç ìåðòâîãî ñîñòîÿíèÿ.
if (gHUD.m_Health.m_iHealth > 0)
{
m_flDeadTime = 0;
}
float targetFOV;
HUDLIST *pList = m_pHudList;
static float lasttime = 0;
while (pList)
{
if (pList->p->m_iFlags & HUD_ACTIVE)
pList->p->Think();
pList = pList->pNext;
}
if( g_iGunMode == 3 )
targetFOV = 30;
else if( g_iGunMode == 2 )
targetFOV = 60;
else targetFOV = default_fov->value;
static float lastFixedFov = 0;
if( m_flFOV < 0 )
{
m_flFOV = targetFOV;
lasttime = gEngfuncs.GetClientTime();
lastFixedFov = m_flFOV;
}
else
{
float curtime = gEngfuncs.GetClientTime();
float mod = targetFOV - m_flFOV;
if( mod < 0 ) mod *= -1;
if( mod < 30 ) mod = 30;
if( g_iGunMode == 3 || lastFixedFov == 30 )
mod *= 2; // õàêàìè õàëôà ïîëíèòñÿ (c)
mod /= 30;
if( m_flFOV < targetFOV )
{
m_flFOV += (curtime - lasttime) * m_pZoomSpeed->value * mod;
if( m_flFOV > targetFOV )
{
m_flFOV = targetFOV;
lastFixedFov = m_flFOV;
}
}
else if( m_flFOV > targetFOV )
{
m_flFOV -= (curtime - lasttime) * m_pZoomSpeed->value * mod;
if( m_flFOV < targetFOV )
{
m_flFOV = targetFOV;
lastFixedFov = m_flFOV;
}
}
lasttime = curtime;
}
m_iFOV = m_flFOV;
// Set a new sensitivity
if ( m_iFOV == default_fov->value )// buz: turn off
{
// reset to saved sensitivity
m_flMouseSensitivity = 0;
}
else
{
// set a new sensitivity that is proportional to the change from the FOV default
m_flMouseSensitivity = sensitivity->value * (m_flFOV / (float)90) * CVAR_GET_FLOAT("zoom_sensitivity_ratio");
}
}
//LRC - fog fading values
extern float g_fFadeDuration;
extern float g_fStartDist;
extern float g_fEndDist;
//extern int g_iFinalStartDist;
extern int g_iFinalEndDist;
void OrthoScope(void); // buz
void OrthoVGUI(void); // buz
extern vec3_t g_CrosshairAngle; // buz
#define CROSS_LENGTH 18.0f
// Redraw
// step through the local data, placing the appropriate graphics & text as appropriate
// returns 1 if they've changed, 0 otherwise
int CHud :: Redraw( float flTime, int intermission )
{
m_fOldTime = m_flTime; // save time of previous redraw
m_flTime = flTime;
m_flTimeDelta = (double)m_flTime - m_fOldTime;
static m_flShotTime = 0;
#if 0
// g-cont. disabled for users request
if( g_fRenderInitialized )
DrawBlurTest( m_flTimeDelta );
#endif
//LRC - handle fog fading effects. (is this the right place for it?)
if (g_fFadeDuration)
{
// Nicer might be to use some kind of logarithmic fade-in?
double fFraction = m_flTimeDelta/g_fFadeDuration;
// g_fStartDist -= (FOG_LIMIT - g_iFinalStartDist)*fFraction;
g_fEndDist -= (FOG_LIMIT - g_iFinalEndDist)*fFraction;
// CONPRINT("FogFading: %f - %f, frac %f, time %f, final %d\n", g_fStartDist, g_fEndDist, fFraction, flTime, g_iFinalEndDist);
// cap it
// if (g_fStartDist > FOG_LIMIT) g_fStartDist = FOG_LIMIT;
if (g_fEndDist > FOG_LIMIT) g_fEndDist = FOG_LIMIT;
// if (g_fStartDist < g_iFinalStartDist) g_fStartDist = g_iFinalStartDist;
if (g_fEndDist < g_iFinalEndDist) g_fEndDist = g_iFinalEndDist;
}
// Clock was reset, reset delta
if ( m_flTimeDelta < 0 )
m_flTimeDelta = 0;
if (g_iGunMode == 3) // buz: special sniper scope
{
if (IEngineStudio.IsHardware())
OrthoScope();
}
if (!IEngineStudio.IsHardware() && m_iHeadShieldState != 1 )
DrawHudString(XRES(10), YRES(350), XRES(600), "Using Head Shield", 180, 180, 180);
if( r_stats.debug_surface != NULL )
gEngfuncs.pfnDrawCharacter( XRES( 320 ), YRES( 240 ), '+', 128, 255, 92 );
OrthoVGUI(); // buz: panels background
// Bring up the scoreboard during intermission
if (gViewPort)
{
if ( m_iIntermission && !intermission )
{
// Have to do this here so the scoreboard goes away
m_iIntermission = intermission;
gViewPort->HideCommandMenu();
gViewPort->HideScoreBoard();
// gViewPort->UpdateSpectatorPanel();
}
else if ( !m_iIntermission && intermission )
{
m_iIntermission = intermission;
gViewPort->HideCommandMenu();
gViewPort->HideVGUIMenu();
gViewPort->ShowScoreBoard();
// gViewPort->UpdateSpectatorPanel();
// Take a screenshot if the client's got the cvar set
if ( CVAR_GET_FLOAT( "hud_takesshots" ) != 0 )
m_flShotTime = flTime + 1.0; // Take a screenshot in a second
}
}
if (m_flShotTime && m_flShotTime < flTime)
{
gEngfuncs.pfnClientCmd("snapshot\n");
m_flShotTime = 0;
}
m_iIntermission = intermission;
// if no redrawing is necessary
// return 0;
if ( m_pCvarDraw->value )
{
HUDLIST *pList = m_pHudList;
while (pList)
{
if ( !intermission )
{
if ( (pList->p->m_iFlags & HUD_ACTIVE) && !(m_iHideHUDDisplay & HIDEHUD_ALL) )
pList->p->Draw(flTime);
}
else
{ // it's an intermission, so only draw hud elements that are set to draw during intermissions
if ( pList->p->m_iFlags & HUD_INTERMISSION )
pList->p->Draw( flTime );
}
pList = pList->pNext;
}
}
// buz: draw crosshair
// Wargon: Ïðèöåë ðèñóåòñÿ òîëüêî åñëè hud_draw = 1.
if(( g_vSpread[0] && g_iGunMode == 1 && m_SpecTank_on == 0 ) && gHUD.m_pCvarDraw->value && cv_crosshair->value )
{
if( gViewPort && gViewPort->m_pParanoiaText && gViewPort->m_pParanoiaText->isVisible( ))
return 1;
int barsize = XRES(g_iGunMode == 1 ? 9 : 6);
int hW = ScreenWidth / 2;
int hH = ScreenHeight / 2;
float mod = (1/(tan(M_PI/180*(m_iFOV/2))));
int dir = ((g_vSpread[0] * hW) / 500) * mod;
// gEngfuncs.Con_Printf("mod is %f, %d\n", mod, m_iFOV);
if (g_CrosshairAngle[0] != 0 || g_CrosshairAngle[1] != 0)
{
// adjust for autoaim
hW -= g_CrosshairAngle[1] * (ScreenWidth / m_iFOV);
hH -= g_CrosshairAngle[0] * (ScreenWidth / m_iFOV);
}
// g_vSpread[2] - is redish [0..500]
// gEngfuncs.Con_Printf("received spread: %f\n", g_vSpread[2]);
int c = 255 - (g_vSpread[2] * 0.5);
if( cv_crosshair->value > 1.0f )
{
// old Paranoia-style crosshair
FillRGBA(hW - dir - barsize, hH, barsize, 1, 255, c, c, 200);
FillRGBA(hW + dir, hH, barsize, 1, 255, c, c, 200);
FillRGBA(hW, hH - dir - barsize, 1, barsize, 255, c, c, 200);
FillRGBA(hW, hH + dir, 1, barsize, 255, c, c, 200);
}
else
{
// new crysis-style crosshair
float flColor = 255.0f - (g_vSpread[2] * 0.5f);
flColor = bound( 0.0f, flColor * (1.0f / 255.0f), 1.0f );
GL_TextureTarget( GL_NONE );
gEngfuncs.pTriAPI->RenderMode( kRenderTransColor );
gEngfuncs.pTriAPI->Color4f( 1.0f, flColor, flColor, 0.8f );
gEngfuncs.pTriAPI->Begin( TRI_LINES );
gEngfuncs.pTriAPI->Vertex3f( hW, hH - dir, 0.0f );
gEngfuncs.pTriAPI->Vertex3f( hW, hH - ( CROSS_LENGTH * 1.2f ) - dir, 0.0f );
gEngfuncs.pTriAPI->End();
gEngfuncs.pTriAPI->Begin( TRI_LINES );
gEngfuncs.pTriAPI->Vertex3f( hW + dir, hH + dir, 0.0f );
gEngfuncs.pTriAPI->Vertex3f( hW + CROSS_LENGTH + dir, hH + CROSS_LENGTH + dir, 0.0f );
gEngfuncs.pTriAPI->End();
gEngfuncs.pTriAPI->Begin( TRI_LINES );
gEngfuncs.pTriAPI->Vertex3f( hW - dir, hH + dir, 0.0f );
gEngfuncs.pTriAPI->Vertex3f( hW - CROSS_LENGTH - dir, hH + CROSS_LENGTH + dir, 0.0f );
gEngfuncs.pTriAPI->End();
GL_TextureTarget( GL_TEXTURE_2D );
}
}
return 1;
}
void ScaleColors( int &r, int &g, int &b, int a )
{
float x = (float)a / 255;
r = (int)(r * x);
g = (int)(g * x);
b = (int)(b * x);
}
int CHud :: DrawHudString(int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b )
{
// draw the string until we hit the null character or a newline character
for ( ; *szIt != 0 && *szIt != '\n'; szIt++ )
{
int next = xpos + gHUD.m_scrinfo.charWidths[ *szIt ]; // variable-width fonts look cool
if ( next > iMaxX )
return xpos;
TextMessageDrawChar( xpos, ypos, *szIt, r, g, b );
xpos = next;
}
return xpos;
}
int CHud :: DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b )
{
char szString[32];
sprintf( szString, "%d", iNumber );
return DrawHudStringReverse( xpos, ypos, iMinX, szString, r, g, b );
}
// draws a string from right to left (right-aligned)
int CHud :: DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b )
{
// find the end of the string
for ( char *szIt = szString; *szIt != 0; szIt++ )
{ // we should count the length?
}
// iterate throug the string in reverse
for ( szIt--; szIt != (szString-1); szIt-- )
{
int next = xpos - gHUD.m_scrinfo.charWidths[ *szIt ]; // variable-width fonts look cool
if ( next < iMinX )
return xpos;
xpos = next;
TextMessageDrawChar( xpos, ypos, *szIt, r, g, b );
}
return xpos;
}
int CHud :: DrawHudNumber( int x, int y, int iFlags, int iNumber, int r, int g, int b)
{
int iWidth = GetSpriteRect(m_HUD_number_0).right - GetSpriteRect(m_HUD_number_0).left;
int k;
if (iNumber > 0)
{
// SPR_Draw 100's
if (iNumber >= 100)
{
k = iNumber/100;
SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b );
SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k));
x += iWidth;
}
else if (iFlags & (DHN_3DIGITS))
{
//SPR_DrawAdditive( 0, x, y, &rc );
x += iWidth;
}
// SPR_Draw 10's
if (iNumber >= 10)
{
k = (iNumber % 100)/10;
SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b );
SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k));
x += iWidth;
}
else if (iFlags & (DHN_3DIGITS | DHN_2DIGITS))
{
//SPR_DrawAdditive( 0, x, y, &rc );
x += iWidth;
}
// SPR_Draw ones
k = iNumber % 10;
SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b );
SPR_DrawAdditive(0, x, y, &GetSpriteRect(m_HUD_number_0 + k));
x += iWidth;
}
else if (iFlags & DHN_DRAWZERO)
{
SPR_Set(GetSprite(m_HUD_number_0), r, g, b );
// SPR_Draw 100's
if (iFlags & (DHN_3DIGITS))
{
//SPR_DrawAdditive( 0, x, y, &rc );
x += iWidth;
}
if (iFlags & (DHN_3DIGITS | DHN_2DIGITS))
{
//SPR_DrawAdditive( 0, x, y, &rc );
x += iWidth;
}
// SPR_Draw ones
SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0));
x += iWidth;
}
return x;
}
int CHud::GetNumWidth( int iNumber, int iFlags )
{
if (iFlags & (DHN_3DIGITS))
return 3;
if (iFlags & (DHN_2DIGITS))
return 2;
if (iNumber <= 0)
{
if (iFlags & (DHN_DRAWZERO))
return 1;
else
return 0;
}
if (iNumber < 10)
return 1;
if (iNumber < 100)
return 2;
return 3;
}
// buz
void DrawBlurTest( float frametime )
{
static int blurstate = false;
if( gHUD.m_flBlurAmount > 0.0f && frametime )
{
if( !g_fRenderInitialized )
{
ALERT( at_error, "GL effects are not allowed\n" );
gHUD.m_flBlurAmount = 0.0f;
return;
}
GLint val_r, val_g, val_b;
pglGetIntegerv( GL_ACCUM_RED_BITS, &val_r );
pglGetIntegerv( GL_ACCUM_GREEN_BITS, &val_g );
pglGetIntegerv( GL_ACCUM_BLUE_BITS, &val_b );
if( !val_r || !val_g || !val_b )
{
ALERT( at_error, "Accumulation buffer is not present\n" );
gHUD.m_flBlurAmount = 0.0f;
return;
}
if( !blurstate )
{
// load entire screen first time
pglAccum( GL_LOAD, 1.0f );
}
else
{
float blur = ( 51.0f - ( gHUD.m_flBlurAmount * 50.0f ));
blur = bound( 0.0f, blur * frametime, 1.0f );
pglReadBuffer( GL_BACK );
pglAccum( GL_MULT, 1.0f - blur ); // scale contents of accumulation buffer
pglAccum( GL_ACCUM, blur ); // add screen contents
pglAccum( GL_RETURN, 1 ); // read result back
}
blurstate = true;
}
else
{
blurstate = false;
}
}

1230
cl_dll/hud_servers.cpp Normal file

File diff suppressed because it is too large Load Diff

41
cl_dll/hud_servers.h Normal file
View File

@ -0,0 +1,41 @@
//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#if !defined( HUD_SERVERSH )
#define HUD_SERVERSH
#pragma once
#define NET_CALLBACK /* */
// Dispatchers
void NET_CALLBACK ListResponse( struct net_response_s *response );
void NET_CALLBACK ServerResponse( struct net_response_s *response );
void NET_CALLBACK PingResponse( struct net_response_s *response );
void NET_CALLBACK RulesResponse( struct net_response_s *response );
void NET_CALLBACK PlayersResponse( struct net_response_s *response );
void ServersInit( void );
void ServersShutdown( void );
void ServersThink( double time );
void ServersCancel( void );
// Get list and get server info from each
void ServersList( void );
// Query for IP / IPX LAN servers
void BroadcastServersList( int clearpending );
void ServerPing( int server );
void ServerRules( int server );
void ServerPlayers( int server );
int ServersGetCount( void );
const char *ServersGetInfo( int server );
int ServersIsQuerying( void );
void SortServers( const char *fieldname );
#endif // HUD_SERVERSH

98
cl_dll/hud_servers_priv.h Normal file
View File

@ -0,0 +1,98 @@
//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#if !defined( HUD_SERVERS_PRIVH )
#define HUD_SERVERS_PRIVH
#pragma once
#include "netadr.h"
class CHudServers
{
public:
typedef struct request_s
{
struct request_s *next;
netadr_t remote_address;
int context;
} request_t;
typedef struct server_s
{
struct server_s *next;
netadr_t remote_address;
char *info;
int ping;
} server_t;
CHudServers();
~CHudServers();
void Think( double time );
void QueryThink( void );
int isQuerying( void );
int LoadMasterAddresses( int maxservers, int *count, netadr_t *padr );
void RequestList( void );
void RequestBroadcastList( int clearpending );
void ServerPing( int server );
void ServerRules( int server );
void ServerPlayers( int server );
void CancelRequest( void );
int CompareServers( server_t *p1, server_t *p2 );
void ClearServerList( server_t **ppList );
void ClearRequestList( request_t **ppList );
void AddServer( server_t **ppList, server_t *p );
void RemoveServerFromList( request_t **ppList, request_t *item );
request_t *FindRequest( int context, request_t *pList );
int ServerListSize( void );
char *GetServerInfo( int server );
int GetServerCount( void );
void SortServers( const char *fieldname );
void ListResponse( struct net_response_s *response );
void ServerResponse( struct net_response_s *response );
void PingResponse( struct net_response_s *response );
void RulesResponse( struct net_response_s *response );
void PlayersResponse( struct net_response_s *response );
private:
server_t *GetServer( int server );
//
char m_szToken[ 1024 ];
int m_nRequesting;
int m_nDone;
double m_dStarted;
request_t *m_pServerList;
request_t *m_pActiveList;
server_t *m_pServers;
int m_nServerCount;
int m_nActiveQueries;
int m_nQuerying;
double m_fElapsed;
request_t *m_pPingRequest;
request_t *m_pRulesRequest;
request_t *m_pPlayersRequest;
};
#endif // HUD_SERVERS_PRIVH

1626
cl_dll/hud_spectator.cpp Normal file

File diff suppressed because it is too large Load Diff

132
cl_dll/hud_spectator.h Normal file
View File

@ -0,0 +1,132 @@
//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#ifndef SPECTATOR_H
#define SPECTATOR_H
#pragma once
#include "cl_entity.h"
#define INSET_OFF 0
#define INSET_CHASE_FREE 1
#define INSET_IN_EYE 2
#define INSET_MAP_FREE 3
#define INSET_MAP_CHASE 4
#define MAX_SPEC_HUD_MESSAGES 8
#define OVERVIEW_TILE_SIZE 128 // don't change this
#define OVERVIEW_MAX_LAYERS 1
//-----------------------------------------------------------------------------
// Purpose: Handles the drawing of the spectator stuff (camera & top-down map and all the things on it )
//-----------------------------------------------------------------------------
typedef struct overviewInfo_s {
char map[64]; // cl.levelname or empty
vec3_t origin; // center of map
float zoom; // zoom of map images
int layers; // how may layers do we have
float layersHeights[OVERVIEW_MAX_LAYERS];
char layersImages[OVERVIEW_MAX_LAYERS][255];
qboolean rotated; // are map images rotated (90 degrees) ?
int insetWindowX;
int insetWindowY;
int insetWindowHeight;
int insetWindowWidth;
} overviewInfo_t;
typedef struct overviewEntity_s {
HSPRITE hSprite;
struct cl_entity_s * entity;
double killTime;
} overviewEntity_t;
#define MAX_OVERVIEW_ENTITIES 128
class CHudSpectator : public CHudBase
{
public:
void Reset();
int ToggleInset(bool allowOff);
void CheckSettings();
void InitHUDData( void );
bool AddOverviewEntityToList( HSPRITE sprite, cl_entity_t * ent, double killTime);
void DeathMessage(int victim);
bool AddOverviewEntity( int type, struct cl_entity_s *ent, const char *modelname );
void CheckOverviewEntities();
void DrawOverview();
void DrawOverviewEntities();
void GetMapPosition( float * returnvec );
void DrawOverviewLayer();
void LoadMapSprites();
bool ParseOverviewFile();
bool IsActivePlayer(cl_entity_t * ent);
void SetModes(int iMainMode, int iInsetMode);
void HandleButtonsDown(int ButtonPressed);
void HandleButtonsUp(int ButtonPressed);
void FindNextPlayer( bool bReverse );
void DirectorMessage( int iSize, void *pbuf );
void SetSpectatorStartPosition();
int Init();
int VidInit();
int Draw(float flTime);
int m_iDrawCycle;
client_textmessage_t m_HUDMessages[MAX_SPEC_HUD_MESSAGES];
char m_HUDMessageText[MAX_SPEC_HUD_MESSAGES][128];
int m_lastHudMessage;
overviewInfo_t m_OverviewData;
overviewEntity_t m_OverviewEntities[MAX_OVERVIEW_ENTITIES];
int m_iObserverFlags;
int m_iSpectatorNumber;
float m_mapZoom; // zoom the user currently uses
vec3_t m_mapOrigin; // origin where user rotates around
cvar_t * m_drawnames;
cvar_t * m_drawcone;
cvar_t * m_drawstatus;
cvar_t * m_autoDirector;
cvar_t * m_pip;
qboolean m_chatEnabled;
vec3_t m_cameraOrigin; // a help camera
vec3_t m_cameraAngles; // and it's angles
private:
vec3_t m_vPlayerPos[MAX_PLAYERS];
HSPRITE m_hsprPlayerBlue;
HSPRITE m_hsprPlayerRed;
HSPRITE m_hsprPlayer;
HSPRITE m_hsprCamera;
HSPRITE m_hsprPlayerDead;
HSPRITE m_hsprViewcone;
HSPRITE m_hsprUnkownMap;
HSPRITE m_hsprBeam;
HSPRITE m_hCrosshair;
wrect_t m_crosshairRect;
struct model_s * m_MapSprite; // each layer image is saved in one sprite, where each tile is a sprite frame
float m_flNextObserverInput;
float m_zoomDelta;
float m_moveDelta;
int m_lastPrimaryObject;
int m_lastSecondaryObject;
};
#endif // SPECTATOR_H

54
cl_dll/hud_update.cpp Normal file
View File

@ -0,0 +1,54 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// hud_update.cpp
//
#include <math.h>
#include "hud.h"
#include "cl_util.h"
#include <stdlib.h>
#include <memory.h>
int CL_ButtonBits( int );
void CL_ResetButtonBits( int bits );
extern float v_idlescale;
float in_fov;
extern void HUD_SetCmdBits( int bits );
int CHud::UpdateClientData(client_data_t *cdata, float time)
{
memcpy(m_vecOrigin, cdata->origin, sizeof(vec3_t));
memcpy(m_vecAngles, cdata->viewangles, sizeof(vec3_t));
m_iKeyBits = CL_ButtonBits( 0 );
m_iWeaponBits = cdata->iWeaponBits;
in_fov = cdata->fov;
Think();
cdata->fov = m_flFOV;//m_iFOV; buz
// v_idlescale = m_iConcussionEffect;
CL_ResetButtonBits( m_iKeyBits );
// return 1 if in anything in the client_data struct has been changed, 0 otherwise
return 1;
}

621
cl_dll/in_camera.cpp Normal file
View File

@ -0,0 +1,621 @@
//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#include "hud.h"
#include "cl_util.h"
#include "camera.h"
#include "kbutton.h"
#include "cvardef.h"
#include "usercmd.h"
#include "const.h"
#include "camera.h"
#include "in_defs.h"
#include "gl_local.h"
#include "windows.h"
float CL_KeyState (kbutton_t *key);
extern "C"
{
void DLLEXPORT CAM_Think( void );
int DLLEXPORT CL_IsThirdPerson( void );
void DLLEXPORT CL_CameraOffset( float *ofs );
}
extern cl_enginefunc_t gEngfuncs;
//-------------------------------------------------- Constants
#define CAM_DIST_DELTA 1.0
#define CAM_ANGLE_DELTA 2.5
#define CAM_ANGLE_SPEED 2.5
#define CAM_MIN_DIST 30.0
#define CAM_ANGLE_MOVE .5
#define MAX_ANGLE_DIFF 10.0
#define PITCH_MAX 90.0
#define PITCH_MIN 0
#define YAW_MAX 135.0
#define YAW_MIN -135.0
enum ECAM_Command
{
CAM_COMMAND_NONE = 0,
CAM_COMMAND_TOTHIRDPERSON = 1,
CAM_COMMAND_TOFIRSTPERSON = 2
};
//-------------------------------------------------- Global Variables
cvar_t *cam_command;
cvar_t *cam_snapto;
cvar_t *cam_idealyaw;
cvar_t *cam_idealpitch;
cvar_t *cam_idealdist;
cvar_t *cam_contain;
cvar_t *c_maxpitch;
cvar_t *c_minpitch;
cvar_t *c_maxyaw;
cvar_t *c_minyaw;
cvar_t *c_maxdistance;
cvar_t *c_mindistance;
// pitch, yaw, dist
vec3_t cam_ofs;
// In third person
int cam_thirdperson;
int cam_mousemove; //true if we are moving the cam with the mouse, False if not
int iMouseInUse=0;
int cam_distancemove;
extern int mouse_x, mouse_y; //used to determine what the current x and y values are
int cam_old_mouse_x, cam_old_mouse_y; //holds the last ticks mouse movement
POINT cam_mouse;
//-------------------------------------------------- Local Variables
static kbutton_t cam_pitchup, cam_pitchdown, cam_yawleft, cam_yawright;
static kbutton_t cam_in, cam_out, cam_move;
//-------------------------------------------------- Prototypes
void CAM_ToThirdPerson(void);
void CAM_ToFirstPerson(void);
void CAM_StartDistance(void);
void CAM_EndDistance(void);
//-------------------------------------------------- Local Functions
float MoveToward( float cur, float goal, float maxspeed )
{
if( cur != goal )
{
if( abs( cur - goal ) > 180.0 )
{
if( cur < goal )
cur += 360.0;
else
cur -= 360.0;
}
if( cur < goal )
{
if( cur < goal - 1.0 )
cur += ( goal - cur ) / 4.0;
else
cur = goal;
}
else
{
if( cur > goal + 1.0 )
cur -= ( cur - goal ) / 4.0;
else
cur = goal;
}
}
// bring cur back into range
if( cur < 0 )
cur += 360.0;
else if( cur >= 360 )
cur -= 360;
return cur;
}
//-------------------------------------------------- Gobal Functions
typedef struct
{
vec3_t boxmins, boxmaxs;// enclose the test object along entire move
float *mins, *maxs; // size of the moving object
vec3_t mins2, maxs2; // size when clipping against mosnters
float *start, *end;
trace_t trace;
int type;
edict_t *passedict;
qboolean monsterclip;
} moveclip_t;
extern trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
void DLLEXPORT CAM_Think( void )
{
vec3_t origin;
vec3_t ext, pnt, camForward, camRight, camUp;
moveclip_t clip;
float dist;
vec3_t camAngles;
float flSensitivity;
#ifdef LATER
int i;
#endif
vec3_t viewangles;
switch( (int) cam_command->value )
{
case CAM_COMMAND_TOTHIRDPERSON:
CAM_ToThirdPerson();
break;
case CAM_COMMAND_TOFIRSTPERSON:
CAM_ToFirstPerson();
break;
case CAM_COMMAND_NONE:
default:
break;
}
if( !cam_thirdperson )
return;
#ifdef LATER
if ( cam_contain->value )
{
gEngfuncs.GetClientOrigin( origin );
ext[0] = ext[1] = ext[2] = 0.0;
}
#endif
camAngles[ PITCH ] = cam_idealpitch->value;
camAngles[ YAW ] = cam_idealyaw->value;
dist = cam_idealdist->value;
//
//movement of the camera with the mouse
//
if (cam_mousemove)
{
//get windows cursor position
GetCursorPos (&cam_mouse);
//check for X delta values and adjust accordingly
//eventually adjust YAW based on amount of movement
//don't do any movement of the cam using YAW/PITCH if we are zooming in/out the camera
if (!cam_distancemove)
{
//keep the camera within certain limits around the player (ie avoid certain bad viewing angles)
if (cam_mouse.x>gEngfuncs.GetWindowCenterX())
{
//if ((camAngles[YAW]>=225.0)||(camAngles[YAW]<135.0))
if (camAngles[YAW]<c_maxyaw->value)
{
camAngles[ YAW ] += (CAM_ANGLE_MOVE)*((cam_mouse.x-gEngfuncs.GetWindowCenterX())/2);
}
if (camAngles[YAW]>c_maxyaw->value)
{
camAngles[YAW]=c_maxyaw->value;
}
}
else if (cam_mouse.x<gEngfuncs.GetWindowCenterX())
{
//if ((camAngles[YAW]<=135.0)||(camAngles[YAW]>225.0))
if (camAngles[YAW]>c_minyaw->value)
{
camAngles[ YAW ] -= (CAM_ANGLE_MOVE)* ((gEngfuncs.GetWindowCenterX()-cam_mouse.x)/2);
}
if (camAngles[YAW]<c_minyaw->value)
{
camAngles[YAW]=c_minyaw->value;
}
}
//check for y delta values and adjust accordingly
//eventually adjust PITCH based on amount of movement
//also make sure camera is within bounds
if (cam_mouse.y>gEngfuncs.GetWindowCenterY())
{
if(camAngles[PITCH]<c_maxpitch->value)
{
camAngles[PITCH] +=(CAM_ANGLE_MOVE)* ((cam_mouse.y-gEngfuncs.GetWindowCenterY())/2);
}
if (camAngles[PITCH]>c_maxpitch->value)
{
camAngles[PITCH]=c_maxpitch->value;
}
}
else if (cam_mouse.y<gEngfuncs.GetWindowCenterY())
{
if (camAngles[PITCH]>c_minpitch->value)
{
camAngles[PITCH] -= (CAM_ANGLE_MOVE)*((gEngfuncs.GetWindowCenterY()-cam_mouse.y)/2);
}
if (camAngles[PITCH]<c_minpitch->value)
{
camAngles[PITCH]=c_minpitch->value;
}
}
//set old mouse coordinates to current mouse coordinates
//since we are done with the mouse
if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 )
{
cam_old_mouse_x=cam_mouse.x*flSensitivity;
cam_old_mouse_y=cam_mouse.y*flSensitivity;
}
else
{
cam_old_mouse_x=cam_mouse.x;
cam_old_mouse_y=cam_mouse.y;
}
SetCursorPos (gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY());
}
}
//Nathan code here
if( CL_KeyState( &cam_pitchup ) )
camAngles[ PITCH ] += CAM_ANGLE_DELTA;
else if( CL_KeyState( &cam_pitchdown ) )
camAngles[ PITCH ] -= CAM_ANGLE_DELTA;
if( CL_KeyState( &cam_yawleft ) )
camAngles[ YAW ] -= CAM_ANGLE_DELTA;
else if( CL_KeyState( &cam_yawright ) )
camAngles[ YAW ] += CAM_ANGLE_DELTA;
if( CL_KeyState( &cam_in ) )
{
dist -= CAM_DIST_DELTA;
if( dist < CAM_MIN_DIST )
{
// If we go back into first person, reset the angle
camAngles[ PITCH ] = 0;
camAngles[ YAW ] = 0;
dist = CAM_MIN_DIST;
}
}
else if( CL_KeyState( &cam_out ) )
dist += CAM_DIST_DELTA;
if (cam_distancemove)
{
if (cam_mouse.y>gEngfuncs.GetWindowCenterY())
{
if(dist<c_maxdistance->value)
{
dist +=CAM_DIST_DELTA * ((cam_mouse.y-gEngfuncs.GetWindowCenterY())/2);
}
if (dist>c_maxdistance->value)
{
dist=c_maxdistance->value;
}
}
else if (cam_mouse.y<gEngfuncs.GetWindowCenterY())
{
if (dist>c_mindistance->value)
{
dist -= (CAM_DIST_DELTA)*((gEngfuncs.GetWindowCenterY()-cam_mouse.y)/2);
}
if (dist<c_mindistance->value)
{
dist=c_mindistance->value;
}
}
//set old mouse coordinates to current mouse coordinates
//since we are done with the mouse
cam_old_mouse_x=cam_mouse.x*gHUD.GetSensitivity();
cam_old_mouse_y=cam_mouse.y*gHUD.GetSensitivity();
SetCursorPos (gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY());
}
#ifdef LATER
if( cam_contain->value )
{
// check new ideal
VectorCopy( origin, pnt );
AngleVectors( camAngles, camForward, camRight, camUp );
for (i=0 ; i<3 ; i++)
pnt[i] += -dist*camForward[i];
// check line from r_refdef.vieworg to pnt
memset ( &clip, 0, sizeof ( moveclip_t ) );
clip.trace = SV_ClipMoveToEntity( sv.edicts, r_refdef.vieworg, ext, ext, pnt );
if( clip.trace.fraction == 1.0 )
{
// update ideal
cam_idealpitch->value = camAngles[ PITCH ];
cam_idealyaw->value = camAngles[ YAW ];
cam_idealdist->value = dist;
}
}
else
#endif
{
// update ideal
cam_idealpitch->value = camAngles[ PITCH ];
cam_idealyaw->value = camAngles[ YAW ];
cam_idealdist->value = dist;
}
// Move towards ideal
VectorCopy( cam_ofs, camAngles );
gEngfuncs.GetViewAngles( (float *)viewangles );
if( cam_snapto->value )
{
camAngles[ YAW ] = cam_idealyaw->value + viewangles[ YAW ];
camAngles[ PITCH ] = cam_idealpitch->value + viewangles[ PITCH ];
camAngles[ 2 ] = cam_idealdist->value;
}
else
{
if( camAngles[ YAW ] - viewangles[ YAW ] != cam_idealyaw->value )
camAngles[ YAW ] = MoveToward( camAngles[ YAW ], cam_idealyaw->value + viewangles[ YAW ], CAM_ANGLE_SPEED );
if( camAngles[ PITCH ] - viewangles[ PITCH ] != cam_idealpitch->value )
camAngles[ PITCH ] = MoveToward( camAngles[ PITCH ], cam_idealpitch->value + viewangles[ PITCH ], CAM_ANGLE_SPEED );
if( abs( camAngles[ 2 ] - cam_idealdist->value ) < 2.0 )
camAngles[ 2 ] = cam_idealdist->value;
else
camAngles[ 2 ] += ( cam_idealdist->value - camAngles[ 2 ] ) / 4.0;
}
#ifdef LATER
if( cam_contain->value )
{
// Test new position
dist = camAngles[ ROLL ];
camAngles[ ROLL ] = 0;
VectorCopy( origin, pnt );
AngleVectors( camAngles, camForward, camRight, camUp );
for (i=0 ; i<3 ; i++)
pnt[i] += -dist*camForward[i];
// check line from r_refdef.vieworg to pnt
memset ( &clip, 0, sizeof ( moveclip_t ) );
ext[0] = ext[1] = ext[2] = 0.0;
clip.trace = SV_ClipMoveToEntity( sv.edicts, r_refdef.vieworg, ext, ext, pnt );
if( clip.trace.fraction != 1.0 )
return;
}
#endif
cam_ofs[ 0 ] = camAngles[ 0 ];
cam_ofs[ 1 ] = camAngles[ 1 ];
cam_ofs[ 2 ] = dist;
}
extern void KeyDown (kbutton_t *b); // HACK
extern void KeyUp (kbutton_t *b); // HACK
void CAM_PitchUpDown(void) { KeyDown( &cam_pitchup ); }
void CAM_PitchUpUp(void) { KeyUp( &cam_pitchup ); }
void CAM_PitchDownDown(void) { KeyDown( &cam_pitchdown ); }
void CAM_PitchDownUp(void) { KeyUp( &cam_pitchdown ); }
void CAM_YawLeftDown(void) { KeyDown( &cam_yawleft ); }
void CAM_YawLeftUp(void) { KeyUp( &cam_yawleft ); }
void CAM_YawRightDown(void) { KeyDown( &cam_yawright ); }
void CAM_YawRightUp(void) { KeyUp( &cam_yawright ); }
void CAM_InDown(void) { KeyDown( &cam_in ); }
void CAM_InUp(void) { KeyUp( &cam_in ); }
void CAM_OutDown(void) { KeyDown( &cam_out ); }
void CAM_OutUp(void) { KeyUp( &cam_out ); }
void CAM_ToThirdPerson(void)
{
vec3_t viewangles;
#if !defined( _DEBUG )
if ( gEngfuncs.GetMaxClients() > 1 )
{
// no thirdperson in multiplayer.
return;
}
#endif
gEngfuncs.GetViewAngles( (float *)viewangles );
if( !cam_thirdperson )
{
cam_thirdperson = 1;
cam_ofs[ YAW ] = viewangles[ YAW ];
cam_ofs[ PITCH ] = viewangles[ PITCH ];
cam_ofs[ 2 ] = CAM_MIN_DIST;
}
gEngfuncs.Cvar_SetValue( "cam_command", 0 );
}
void CAM_ToFirstPerson(void)
{
cam_thirdperson = 0;
gEngfuncs.Cvar_SetValue( "cam_command", 0 );
}
void CAM_ToggleSnapto( void )
{
cam_snapto->value = !cam_snapto->value;
}
void CAM_Init( void )
{
gEngfuncs.pfnAddCommand( "+campitchup", CAM_PitchUpDown );
gEngfuncs.pfnAddCommand( "-campitchup", CAM_PitchUpUp );
gEngfuncs.pfnAddCommand( "+campitchdown", CAM_PitchDownDown );
gEngfuncs.pfnAddCommand( "-campitchdown", CAM_PitchDownUp );
gEngfuncs.pfnAddCommand( "+camyawleft", CAM_YawLeftDown );
gEngfuncs.pfnAddCommand( "-camyawleft", CAM_YawLeftUp );
gEngfuncs.pfnAddCommand( "+camyawright", CAM_YawRightDown );
gEngfuncs.pfnAddCommand( "-camyawright", CAM_YawRightUp );
gEngfuncs.pfnAddCommand( "+camin", CAM_InDown );
gEngfuncs.pfnAddCommand( "-camin", CAM_InUp );
gEngfuncs.pfnAddCommand( "+camout", CAM_OutDown );
gEngfuncs.pfnAddCommand( "-camout", CAM_OutUp );
gEngfuncs.pfnAddCommand( "thirdperson", CAM_ToThirdPerson );
gEngfuncs.pfnAddCommand( "firstperson", CAM_ToFirstPerson );
gEngfuncs.pfnAddCommand( "+cammousemove",CAM_StartMouseMove);
gEngfuncs.pfnAddCommand( "-cammousemove",CAM_EndMouseMove);
gEngfuncs.pfnAddCommand( "+camdistance", CAM_StartDistance );
gEngfuncs.pfnAddCommand( "-camdistance", CAM_EndDistance );
gEngfuncs.pfnAddCommand( "snapto", CAM_ToggleSnapto );
cam_command = gEngfuncs.pfnRegisterVariable ( "cam_command", "0", 0 ); // tells camera to go to thirdperson
cam_snapto = gEngfuncs.pfnRegisterVariable ( "cam_snapto", "0", 0 ); // snap to thirdperson view
cam_idealyaw = gEngfuncs.pfnRegisterVariable ( "cam_idealyaw", "90", 0 ); // thirdperson yaw
cam_idealpitch = gEngfuncs.pfnRegisterVariable ( "cam_idealpitch", "0", 0 ); // thirperson pitch
cam_idealdist = gEngfuncs.pfnRegisterVariable ( "cam_idealdist", "64", 0 ); // thirdperson distance
cam_contain = gEngfuncs.pfnRegisterVariable ( "cam_contain", "0", 0 ); // contain camera to world
c_maxpitch = gEngfuncs.pfnRegisterVariable ( "c_maxpitch", "90.0", 0 );
c_minpitch = gEngfuncs.pfnRegisterVariable ( "c_minpitch", "0.0", 0 );
c_maxyaw = gEngfuncs.pfnRegisterVariable ( "c_maxyaw", "135.0", 0 );
c_minyaw = gEngfuncs.pfnRegisterVariable ( "c_minyaw", "-135.0", 0 );
c_maxdistance = gEngfuncs.pfnRegisterVariable ( "c_maxdistance", "200.0", 0 );
c_mindistance = gEngfuncs.pfnRegisterVariable ( "c_mindistance", "30.0", 0 );
}
void CAM_ClearStates( void )
{
vec3_t viewangles;
gEngfuncs.GetViewAngles( (float *)viewangles );
cam_pitchup.state = 0;
cam_pitchdown.state = 0;
cam_yawleft.state = 0;
cam_yawright.state = 0;
cam_in.state = 0;
cam_out.state = 0;
cam_thirdperson = 0;
cam_command->value = 0;
cam_mousemove=0;
cam_snapto->value = 0;
cam_distancemove = 0;
cam_ofs[ 0 ] = 0.0;
cam_ofs[ 1 ] = 0.0;
cam_ofs[ 2 ] = CAM_MIN_DIST;
cam_idealpitch->value = viewangles[ PITCH ];
cam_idealyaw->value = viewangles[ YAW ];
cam_idealdist->value = CAM_MIN_DIST;
}
void CAM_StartMouseMove(void)
{
float flSensitivity;
//only move the cam with mouse if we are in third person.
if (cam_thirdperson)
{
//set appropriate flags and initialize the old mouse position
//variables for mouse camera movement
if (!cam_mousemove)
{
cam_mousemove=1;
iMouseInUse=1;
GetCursorPos (&cam_mouse);
if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 )
{
cam_old_mouse_x=cam_mouse.x*flSensitivity;
cam_old_mouse_y=cam_mouse.y*flSensitivity;
}
else
{
cam_old_mouse_x=cam_mouse.x;
cam_old_mouse_y=cam_mouse.y;
}
}
}
//we are not in 3rd person view..therefore do not allow camera movement
else
{
cam_mousemove=0;
iMouseInUse=0;
}
}
//the key has been released for camera movement
//tell the engine that mouse camera movement is off
void CAM_EndMouseMove(void)
{
cam_mousemove=0;
iMouseInUse=0;
}
//----------------------------------------------------------
//routines to start the process of moving the cam in or out
//using the mouse
//----------------------------------------------------------
void CAM_StartDistance(void)
{
//only move the cam with mouse if we are in third person.
if (cam_thirdperson)
{
//set appropriate flags and initialize the old mouse position
//variables for mouse camera movement
if (!cam_distancemove)
{
cam_distancemove=1;
cam_mousemove=1;
iMouseInUse=1;
GetCursorPos (&cam_mouse);
cam_old_mouse_x=cam_mouse.x*gHUD.GetSensitivity();
cam_old_mouse_y=cam_mouse.y*gHUD.GetSensitivity();
}
}
//we are not in 3rd person view..therefore do not allow camera movement
else
{
cam_distancemove=0;
cam_mousemove=0;
iMouseInUse=0;
}
}
//the key has been released for camera movement
//tell the engine that mouse camera movement is off
void CAM_EndDistance(void)
{
cam_distancemove=0;
cam_mousemove=0;
iMouseInUse=0;
}
int DLLEXPORT CL_IsThirdPerson( void )
{
return (cam_thirdperson ? 1 : 0) || (g_iUser1 && (g_iUser2 == gEngfuncs.GetLocalPlayer()->index) );
}
void DLLEXPORT CL_CameraOffset( float *ofs )
{
VectorCopy( cam_ofs, ofs );
}

24
cl_dll/in_defs.h Normal file
View File

@ -0,0 +1,24 @@
//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#if !defined( IN_DEFSH )
#define IN_DEFSH
#pragma once
// up / down
#define PITCH 0
// left / right
#define YAW 1
// fall over
#define ROLL 2
#define DLLEXPORT __declspec( dllexport )
void V_StartPitchDrift( void );
void V_StopPitchDrift( void );
#endif

1051
cl_dll/input.cpp Normal file

File diff suppressed because it is too large Load Diff

963
cl_dll/inputw32.cpp Normal file
View File

@ -0,0 +1,963 @@
//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
// in_win.c -- windows 95 mouse and joystick code
// 02/21/97 JCB Added extended DirectInput code to support external controllers.
#include "hud.h"
#include "cl_util.h"
#include "camera.h"
#include "kbutton.h"
#include "cvardef.h"
#include "usercmd.h"
#include "const.h"
#include "camera.h"
#include "in_defs.h"
#include "../engine/keydefs.h"
#include "windows.h"
#define MOUSE_BUTTON_COUNT 5
// Set this to 1 to show mouse cursor. Experimental
int g_iVisibleMouse = 0;
extern "C"
{
void DLLEXPORT IN_ActivateMouse( void );
void DLLEXPORT IN_DeactivateMouse( void );
void DLLEXPORT IN_MouseEvent (int mstate);
void DLLEXPORT IN_Accumulate (void);
void DLLEXPORT IN_ClearStates (void);
}
extern cl_enginefunc_t gEngfuncs;
extern int iMouseInUse;
extern kbutton_t in_strafe;
extern kbutton_t in_mlook;
extern kbutton_t in_speed;
extern kbutton_t in_jlook;
extern cvar_t *m_pitch;
extern cvar_t *m_yaw;
extern cvar_t *m_forward;
extern cvar_t *m_side;
extern cvar_t *lookstrafe;
extern cvar_t *lookspring;
extern cvar_t *cl_pitchdown;
extern cvar_t *cl_pitchup;
extern cvar_t *cl_yawspeed;
extern cvar_t *cl_sidespeed;
extern cvar_t *cl_forwardspeed;
extern cvar_t *cl_pitchspeed;
extern cvar_t *cl_movespeedkey;
// mouse variables
cvar_t *m_filter;
cvar_t *sensitivity;
int CL_IsDead( void ); // buz
int mouse_buttons;
int mouse_oldbuttonstate;
POINT current_pos;
int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum;
static int restore_spi;
static int originalmouseparms[3], newmouseparms[3] = {0, 0, 1};
static int mouseactive;
int mouseinitialized;
static int mouseparmsvalid;
static int mouseshowtoggle = 1;
// joystick defines and variables
// where should defines be moved?
#define JOY_ABSOLUTE_AXIS 0x00000000 // control like a joystick
#define JOY_RELATIVE_AXIS 0x00000010 // control like a mouse, spinner, trackball
#define JOY_MAX_AXES 6 // X, Y, Z, R, U, V
#define JOY_AXIS_X 0
#define JOY_AXIS_Y 1
#define JOY_AXIS_Z 2
#define JOY_AXIS_R 3
#define JOY_AXIS_U 4
#define JOY_AXIS_V 5
enum _ControlList
{
AxisNada = 0,
AxisForward,
AxisLook,
AxisSide,
AxisTurn
};
DWORD dwAxisFlags[JOY_MAX_AXES] =
{
JOY_RETURNX,
JOY_RETURNY,
JOY_RETURNZ,
JOY_RETURNR,
JOY_RETURNU,
JOY_RETURNV
};
DWORD dwAxisMap[ JOY_MAX_AXES ];
DWORD dwControlMap[ JOY_MAX_AXES ];
PDWORD pdwRawValue[ JOY_MAX_AXES ];
// none of these cvars are saved over a session
// this means that advanced controller configuration needs to be executed
// each time. this avoids any problems with getting back to a default usage
// or when changing from one controller to another. this way at least something
// works.
cvar_t *in_joystick;
cvar_t *joy_name;
cvar_t *joy_advanced;
cvar_t *joy_advaxisx;
cvar_t *joy_advaxisy;
cvar_t *joy_advaxisz;
cvar_t *joy_advaxisr;
cvar_t *joy_advaxisu;
cvar_t *joy_advaxisv;
cvar_t *joy_forwardthreshold;
cvar_t *joy_sidethreshold;
cvar_t *joy_pitchthreshold;
cvar_t *joy_yawthreshold;
cvar_t *joy_forwardsensitivity;
cvar_t *joy_sidesensitivity;
cvar_t *joy_pitchsensitivity;
cvar_t *joy_yawsensitivity;
cvar_t *joy_wwhack1;
cvar_t *joy_wwhack2;
int joy_avail, joy_advancedinit, joy_haspov;
DWORD joy_oldbuttonstate, joy_oldpovstate;
int joy_id;
DWORD joy_flags;
DWORD joy_numbuttons;
static JOYINFOEX ji;
/*
===========
Force_CenterView_f
===========
*/
void Force_CenterView_f (void)
{
vec3_t viewangles;
if (!iMouseInUse)
{
gEngfuncs.GetViewAngles( (float *)viewangles );
viewangles[PITCH] = 0;
gEngfuncs.SetViewAngles( (float *)viewangles );
}
}
/*
===========
IN_ActivateMouse
===========
*/
void DLLEXPORT IN_ActivateMouse (void)
{
if (mouseinitialized)
{
if (mouseparmsvalid)
restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0);
mouseactive = 1;
}
}
/*
===========
IN_DeactivateMouse
===========
*/
void DLLEXPORT IN_DeactivateMouse (void)
{
if (mouseinitialized)
{
if (restore_spi)
SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0);
mouseactive = 0;
}
}
/*
===========
IN_StartupMouse
===========
*/
void IN_StartupMouse (void)
{
if ( gEngfuncs.CheckParm ("-nomouse", NULL ) )
return;
mouseinitialized = 1;
mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0);
if (mouseparmsvalid)
{
if ( gEngfuncs.CheckParm ("-noforcemspd", NULL ) )
newmouseparms[2] = originalmouseparms[2];
if ( gEngfuncs.CheckParm ("-noforcemaccel", NULL ) )
{
newmouseparms[0] = originalmouseparms[0];
newmouseparms[1] = originalmouseparms[1];
}
if ( gEngfuncs.CheckParm ("-noforcemparms", NULL ) )
{
newmouseparms[0] = originalmouseparms[0];
newmouseparms[1] = originalmouseparms[1];
newmouseparms[2] = originalmouseparms[2];
}
}
mouse_buttons = MOUSE_BUTTON_COUNT;
}
/*
===========
IN_Shutdown
===========
*/
void IN_Shutdown (void)
{
IN_DeactivateMouse ();
}
/*
===========
IN_GetMousePos
Ask for mouse position from engine
===========
*/
void IN_GetMousePos( int *mx, int *my )
{
gEngfuncs.GetMousePosition( mx, my );
}
/*
===========
IN_ResetMouse
FIXME: Call through to engine?
===========
*/
void IN_ResetMouse( void )
{
SetCursorPos ( gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY() );
}
/*
===========
IN_MouseEvent
===========
*/
void DLLEXPORT IN_MouseEvent (int mstate)
{
int i;
if ( iMouseInUse || g_iVisibleMouse )
return;
// perform button actions
for (i=0 ; i<mouse_buttons ; i++)
{
if ( (mstate & (1<<i)) &&
!(mouse_oldbuttonstate & (1<<i)) )
{
gEngfuncs.Key_Event (K_MOUSE1 + i, 1);
}
if ( !(mstate & (1<<i)) &&
(mouse_oldbuttonstate & (1<<i)) )
{
gEngfuncs.Key_Event (K_MOUSE1 + i, 0);
}
}
mouse_oldbuttonstate = mstate;
}
/*
===========
IN_MouseMove
===========
*/
void IN_MouseMove ( float frametime, usercmd_t *cmd)
{
int mx, my;
vec3_t viewangles;
gEngfuncs.GetViewAngles( (float *)viewangles );
if ( in_mlook.state & 1)
{
V_StopPitchDrift ();
}
//jjb - this disbles normal mouse control if the user is trying to
// move the camera, or if the mouse cursor is visible or if we're in intermission
if ( !iMouseInUse && !g_iVisibleMouse && !gHUD.m_iIntermission )
{
GetCursorPos (&current_pos);
mx = current_pos.x - gEngfuncs.GetWindowCenterX() + mx_accum;
my = current_pos.y - gEngfuncs.GetWindowCenterY() + my_accum;
mx_accum = 0;
my_accum = 0;
if (m_filter->value)
{
mouse_x = (mx + old_mouse_x) * 0.5;
mouse_y = (my + old_mouse_y) * 0.5;
}
else
{
mouse_x = mx;
mouse_y = my;
}
old_mouse_x = mx;
old_mouse_y = my;
if ( gHUD.GetSensitivity() != 0 )
{
mouse_x *= gHUD.GetSensitivity();
mouse_y *= gHUD.GetSensitivity();
}
else
{
mouse_x *= sensitivity->value;
mouse_y *= sensitivity->value;
}
// buz: slower turning when in sniper mode
if (gHUD.m_iFOV < 90)
{
mouse_x *= 0.5;
mouse_y *= 0.5;
}
// buz: remove turning if DEAD!
if (CL_IsDead())
{
mouse_x = 0;
mouse_y = 0;
// CONPRINT("DEAD!\n");
}
// add mouse X/Y movement to cmd
if ( (in_strafe.state & 1) || (lookstrafe->value && (in_mlook.state & 1) ))
cmd->sidemove += m_side->value * mouse_x;
else
viewangles[YAW] -= m_yaw->value * mouse_x;
if ( (in_mlook.state & 1) && !(in_strafe.state & 1))
{
viewangles[PITCH] += m_pitch->value * mouse_y;
if (viewangles[PITCH] > cl_pitchdown->value)
viewangles[PITCH] = cl_pitchdown->value;
if (viewangles[PITCH] < -cl_pitchup->value)
viewangles[PITCH] = -cl_pitchup->value;
}
else
{
if ((in_strafe.state & 1) && gEngfuncs.IsNoClipping() )
{
cmd->upmove -= m_forward->value * mouse_y;
}
else
{
cmd->forwardmove -= m_forward->value * mouse_y;
}
}
// if the mouse has moved, force it to the center, so there's room to move
if ( mx || my )
{
IN_ResetMouse();
}
}
gEngfuncs.SetViewAngles( (float *)viewangles );
/*
//#define TRACE_TEST
#if defined( TRACE_TEST )
{
int mx, my;
void V_Move( int mx, int my );
IN_GetMousePos( &mx, &my );
V_Move( mx, my );
}
#endif
*/
}
/*
===========
IN_Accumulate
===========
*/
void DLLEXPORT IN_Accumulate (void)
{
//only accumulate mouse if we are not moving the camera with the mouse
if ( !iMouseInUse && !g_iVisibleMouse )
{
if (mouseactive)
{
GetCursorPos (&current_pos);
mx_accum += current_pos.x - gEngfuncs.GetWindowCenterX();
my_accum += current_pos.y - gEngfuncs.GetWindowCenterY();
// force the mouse to the center, so there's room to move
IN_ResetMouse();
}
}
}
/*
===================
IN_ClearStates
===================
*/
void DLLEXPORT IN_ClearStates (void)
{
if ( !mouseactive )
return;
mx_accum = 0;
my_accum = 0;
mouse_oldbuttonstate = 0;
}
/*
===============
IN_StartupJoystick
===============
*/
void IN_StartupJoystick (void)
{
int numdevs;
JOYCAPS jc;
MMRESULT mmr;
// assume no joystick
joy_avail = 0;
// abort startup if user requests no joystick
if ( gEngfuncs.CheckParm ("-nojoy", NULL ) )
return;
// verify joystick driver is present
if ((numdevs = joyGetNumDevs ()) == 0)
{
gEngfuncs.Con_DPrintf ("joystick not found -- driver not present\n\n");
return;
}
// cycle through the joystick ids for the first valid one
for (joy_id=0 ; joy_id<numdevs ; joy_id++)
{
memset (&ji, 0, sizeof(ji));
ji.dwSize = sizeof(ji);
ji.dwFlags = JOY_RETURNCENTERED;
if ((mmr = joyGetPosEx (joy_id, &ji)) == JOYERR_NOERROR)
break;
}
// abort startup if we didn't find a valid joystick
if (mmr != JOYERR_NOERROR)
{
gEngfuncs.Con_DPrintf ("joystick not found -- no valid joysticks (%x)\n\n", mmr);
return;
}
// get the capabilities of the selected joystick
// abort startup if command fails
memset (&jc, 0, sizeof(jc));
if ((mmr = joyGetDevCaps (joy_id, &jc, sizeof(jc))) != JOYERR_NOERROR)
{
gEngfuncs.Con_DPrintf ("joystick not found -- invalid joystick capabilities (%x)\n\n", mmr);
return;
}
// save the joystick's number of buttons and POV status
joy_numbuttons = jc.wNumButtons;
joy_haspov = jc.wCaps & JOYCAPS_HASPOV;
// old button and POV states default to no buttons pressed
joy_oldbuttonstate = joy_oldpovstate = 0;
// mark the joystick as available and advanced initialization not completed
// this is needed as cvars are not available during initialization
gEngfuncs.Con_Printf ("joystick found\n\n", mmr);
joy_avail = 1;
joy_advancedinit = 0;
}
/*
===========
RawValuePointer
===========
*/
PDWORD RawValuePointer (int axis)
{
switch (axis)
{
case JOY_AXIS_X:
return &ji.dwXpos;
case JOY_AXIS_Y:
return &ji.dwYpos;
case JOY_AXIS_Z:
return &ji.dwZpos;
case JOY_AXIS_R:
return &ji.dwRpos;
case JOY_AXIS_U:
return &ji.dwUpos;
case JOY_AXIS_V:
return &ji.dwVpos;
}
// FIX: need to do some kind of error
return &ji.dwXpos;
}
/*
===========
Joy_AdvancedUpdate_f
===========
*/
void Joy_AdvancedUpdate_f (void)
{
// called once by IN_ReadJoystick and by user whenever an update is needed
// cvars are now available
int i;
DWORD dwTemp;
// initialize all the maps
for (i = 0; i < JOY_MAX_AXES; i++)
{
dwAxisMap[i] = AxisNada;
dwControlMap[i] = JOY_ABSOLUTE_AXIS;
pdwRawValue[i] = RawValuePointer(i);
}
if( joy_advanced->value == 0.0)
{
// default joystick initialization
// 2 axes only with joystick control
dwAxisMap[JOY_AXIS_X] = AxisTurn;
// dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS;
dwAxisMap[JOY_AXIS_Y] = AxisForward;
// dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS;
}
else
{
if ( strcmp ( joy_name->string, "joystick") != 0 )
{
// notify user of advanced controller
gEngfuncs.Con_Printf ("\n%s configured\n\n", joy_name->string);
}
// advanced initialization here
// data supplied by user via joy_axisn cvars
dwTemp = (DWORD) joy_advaxisx->value;
dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD) joy_advaxisy->value;
dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD) joy_advaxisz->value;
dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD) joy_advaxisr->value;
dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD) joy_advaxisu->value;
dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD) joy_advaxisv->value;
dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS;
}
// compute the axes to collect from DirectInput
joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV;
for (i = 0; i < JOY_MAX_AXES; i++)
{
if (dwAxisMap[i] != AxisNada)
{
joy_flags |= dwAxisFlags[i];
}
}
}
/*
===========
IN_Commands
===========
*/
void IN_Commands (void)
{
int i, key_index;
DWORD buttonstate, povstate;
if (!joy_avail)
{
return;
}
// loop through the joystick buttons
// key a joystick event or auxillary event for higher number buttons for each state change
buttonstate = ji.dwButtons;
for (i=0 ; i < (int)joy_numbuttons ; i++)
{
if ( (buttonstate & (1<<i)) && !(joy_oldbuttonstate & (1<<i)) )
{
key_index = (i < 4) ? K_JOY1 : K_AUX1;
gEngfuncs.Key_Event (key_index + i, 1);
}
if ( !(buttonstate & (1<<i)) && (joy_oldbuttonstate & (1<<i)) )
{
key_index = (i < 4) ? K_JOY1 : K_AUX1;
gEngfuncs.Key_Event (key_index + i, 0);
}
}
joy_oldbuttonstate = buttonstate;
if (joy_haspov)
{
// convert POV information into 4 bits of state information
// this avoids any potential problems related to moving from one
// direction to another without going through the center position
povstate = 0;
if(ji.dwPOV != JOY_POVCENTERED)
{
if (ji.dwPOV == JOY_POVFORWARD)
povstate |= 0x01;
if (ji.dwPOV == JOY_POVRIGHT)
povstate |= 0x02;
if (ji.dwPOV == JOY_POVBACKWARD)
povstate |= 0x04;
if (ji.dwPOV == JOY_POVLEFT)
povstate |= 0x08;
}
// determine which bits have changed and key an auxillary event for each change
for (i=0 ; i < 4 ; i++)
{
if ( (povstate & (1<<i)) && !(joy_oldpovstate & (1<<i)) )
{
gEngfuncs.Key_Event (K_AUX29 + i, 1);
}
if ( !(povstate & (1<<i)) && (joy_oldpovstate & (1<<i)) )
{
gEngfuncs.Key_Event (K_AUX29 + i, 0);
}
}
joy_oldpovstate = povstate;
}
}
/*
===============
IN_ReadJoystick
===============
*/
int IN_ReadJoystick (void)
{
memset (&ji, 0, sizeof(ji));
ji.dwSize = sizeof(ji);
ji.dwFlags = joy_flags;
if (joyGetPosEx (joy_id, &ji) == JOYERR_NOERROR)
{
// this is a hack -- there is a bug in the Logitech WingMan Warrior DirectInput Driver
// rather than having 32768 be the zero point, they have the zero point at 32668
// go figure -- anyway, now we get the full resolution out of the device
if (joy_wwhack1->value != 0.0)
{
ji.dwUpos += 100;
}
return 1;
}
else
{
// read error occurred
// turning off the joystick seems too harsh for 1 read error,\
// but what should be done?
// Con_Printf ("IN_ReadJoystick: no response\n");
// joy_avail = 0;
return 0;
}
}
/*
===========
IN_JoyMove
===========
*/
void IN_JoyMove ( float frametime, usercmd_t *cmd )
{
float speed, aspeed;
float fAxisValue, fTemp;
int i;
vec3_t viewangles;
gEngfuncs.GetViewAngles( (float *)viewangles );
// complete initialization if first time in
// this is needed as cvars are not available at initialization time
if( joy_advancedinit != 1 )
{
Joy_AdvancedUpdate_f();
joy_advancedinit = 1;
}
// verify joystick is available and that the user wants to use it
if (!joy_avail || !in_joystick->value)
{
return;
}
// collect the joystick data, if possible
if (IN_ReadJoystick () != 1)
{
return;
}
if (in_speed.state & 1)
speed = cl_movespeedkey->value;
else
speed = 1;
aspeed = speed * frametime;
// loop through the axes
for (i = 0; i < JOY_MAX_AXES; i++)
{
// get the floating point zero-centered, potentially-inverted data for the current axis
fAxisValue = (float) *pdwRawValue[i];
// move centerpoint to zero
fAxisValue -= 32768.0;
if (joy_wwhack2->value != 0.0)
{
if (dwAxisMap[i] == AxisTurn)
{
// this is a special formula for the Logitech WingMan Warrior
// y=ax^b; where a = 300 and b = 1.3
// also x values are in increments of 800 (so this is factored out)
// then bounds check result to level out excessively high spin rates
fTemp = 300.0 * pow(abs(fAxisValue) / 800.0, 1.3);
if (fTemp > 14000.0)
fTemp = 14000.0;
// restore direction information
fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp;
}
}
// convert range from -32768..32767 to -1..1
fAxisValue /= 32768.0;
switch (dwAxisMap[i])
{
case AxisForward:
if ((joy_advanced->value == 0.0) && (in_jlook.state & 1))
{
// user wants forward control to become look control
if (fabs(fAxisValue) > joy_pitchthreshold->value)
{
// if mouse invert is on, invert the joystick pitch value
// only absolute control support here (joy_advanced is 0)
if (m_pitch->value < 0.0)
{
viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value;
}
else
{
viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value;
}
V_StopPitchDrift();
}
else
{
// no pitch movement
// disable pitch return-to-center unless requested by user
// *** this code can be removed when the lookspring bug is fixed
// *** the bug always has the lookspring feature on
if(lookspring->value == 0.0)
{
V_StopPitchDrift();
}
}
}
else
{
// user wants forward control to be forward control
if (fabs(fAxisValue) > joy_forwardthreshold->value)
{
cmd->forwardmove += (fAxisValue * joy_forwardsensitivity->value) * speed * cl_forwardspeed->value;
}
}
break;
case AxisSide:
if (fabs(fAxisValue) > joy_sidethreshold->value)
{
cmd->sidemove += (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value;
}
break;
case AxisTurn:
if ((in_strafe.state & 1) || (lookstrafe->value && (in_jlook.state & 1)))
{
// user wants turn control to become side control
if (fabs(fAxisValue) > joy_sidethreshold->value)
{
cmd->sidemove -= (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value;
}
}
else
{
// user wants turn control to be turn control
if (fabs(fAxisValue) > joy_yawthreshold->value)
{
if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
{
viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * aspeed * cl_yawspeed->value;
}
else
{
viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * speed * 180.0;
}
}
}
break;
case AxisLook:
if (in_jlook.state & 1)
{
if (fabs(fAxisValue) > joy_pitchthreshold->value)
{
// pitch movement detected and pitch movement desired by user
if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
{
viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value;
}
else
{
viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * speed * 180.0;
}
V_StopPitchDrift();
}
else
{
// no pitch movement
// disable pitch return-to-center unless requested by user
// *** this code can be removed when the lookspring bug is fixed
// *** the bug always has the lookspring feature on
if( lookspring->value == 0.0 )
{
V_StopPitchDrift();
}
}
}
break;
default:
break;
}
}
// bounds check pitch
if (viewangles[PITCH] > cl_pitchdown->value)
viewangles[PITCH] = cl_pitchdown->value;
if (viewangles[PITCH] < -cl_pitchup->value)
viewangles[PITCH] = -cl_pitchup->value;
gEngfuncs.SetViewAngles( (float *)viewangles );
}
/*
===========
IN_Move
===========
*/
void IN_Move ( float frametime, usercmd_t *cmd)
{
if ( !iMouseInUse && mouseactive )
{
IN_MouseMove ( frametime, cmd);
}
IN_JoyMove ( frametime, cmd);
}
/*
===========
IN_Init
===========
*/
void IN_Init (void)
{
m_filter = gEngfuncs.pfnRegisterVariable ( "m_filter","0", FCVAR_ARCHIVE );
sensitivity = gEngfuncs.pfnRegisterVariable ( "sensitivity","3", FCVAR_ARCHIVE ); // user mouse sensitivity setting.
in_joystick = gEngfuncs.pfnRegisterVariable ( "joystick","0", FCVAR_ARCHIVE );
joy_name = gEngfuncs.pfnRegisterVariable ( "joyname", "joystick", 0 );
joy_advanced = gEngfuncs.pfnRegisterVariable ( "joyadvanced", "0", 0 );
joy_advaxisx = gEngfuncs.pfnRegisterVariable ( "joyadvaxisx", "0", 0 );
joy_advaxisy = gEngfuncs.pfnRegisterVariable ( "joyadvaxisy", "0", 0 );
joy_advaxisz = gEngfuncs.pfnRegisterVariable ( "joyadvaxisz", "0", 0 );
joy_advaxisr = gEngfuncs.pfnRegisterVariable ( "joyadvaxisr", "0", 0 );
joy_advaxisu = gEngfuncs.pfnRegisterVariable ( "joyadvaxisu", "0", 0 );
joy_advaxisv = gEngfuncs.pfnRegisterVariable ( "joyadvaxisv", "0", 0 );
joy_forwardthreshold = gEngfuncs.pfnRegisterVariable ( "joyforwardthreshold", "0.15", 0 );
joy_sidethreshold = gEngfuncs.pfnRegisterVariable ( "joysidethreshold", "0.15", 0 );
joy_pitchthreshold = gEngfuncs.pfnRegisterVariable ( "joypitchthreshold", "0.15", 0 );
joy_yawthreshold = gEngfuncs.pfnRegisterVariable ( "joyyawthreshold", "0.15", 0 );
joy_forwardsensitivity = gEngfuncs.pfnRegisterVariable ( "joyforwardsensitivity", "-1.0", 0 );
joy_sidesensitivity = gEngfuncs.pfnRegisterVariable ( "joysidesensitivity", "-1.0", 0 );
joy_pitchsensitivity = gEngfuncs.pfnRegisterVariable ( "joypitchsensitivity", "1.0", 0 );
joy_yawsensitivity = gEngfuncs.pfnRegisterVariable ( "joyyawsensitivity", "-1.0", 0 );
joy_wwhack1 = gEngfuncs.pfnRegisterVariable ( "joywwhack1", "0.0", 0 );
joy_wwhack2 = gEngfuncs.pfnRegisterVariable ( "joywwhack2", "0.0", 0 );
gEngfuncs.pfnAddCommand ("force_centerview", Force_CenterView_f);
gEngfuncs.pfnAddCommand ("joyadvancedupdate", Joy_AdvancedUpdate_f);
IN_StartupMouse ();
IN_StartupJoystick ();
}

18
cl_dll/kbutton.h Normal file
View File

@ -0,0 +1,18 @@
//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#if !defined( KBUTTONH )
#define KBUTTONH
#pragma once
typedef struct kbutton_s
{
int down[2]; // key nums holding it down
int state; // low bit is down state
} kbutton_t;
#endif // !KBUTTONH

364
cl_dll/lensflare.cpp Normal file
View File

@ -0,0 +1,364 @@
#include "hud.h"
#include "cl_util.h"
#include <string.h>
#include <stdio.h>
#include <time.h>
#include "parsemsg.h"
#include "vgui_TeamFortressViewport.h"
#include "triangleapi.h"
#include "ref_params.h"
#include "event_api.h"
#include "pm_defs.h"
#include "pm_movevars.h"
#include "gl_local.h"
int CHudLensflare :: Init( void )
{
m_iFlags |= HUD_ACTIVE;
m_pCvarDraw = CVAR_REGISTER( "cl_lensflare", "1", FCVAR_ARCHIVE );
gHUD.AddHudElem( this );
return 1;
}
int CHudLensflare :: VidInit( void )
{
text[0] = SPR_Load("sprites/lens/lens1.spr");
red[0] = green[0] = blue[0] = 1.0;
scale[0] = 45;
multi[0] = -0.45;
text[1] = SPR_Load("sprites/lens/lens2.spr");
red[1] = green[0] = blue[0] = 1.0;
scale[1] = 25;
multi[1] = 0.2;
text[2] = SPR_Load("sprites/lens/glow1.spr");
red[2] = 132/255;
green[2] = 1.0;
blue[2] = 153/255;
scale[2] = 35;
multi[2] = 0.3;
text[3] = SPR_Load("sprites/lens/glow2.spr");
red[3] = 1.0;
green[3] = 164/255;
blue[3] = 164/255;
scale[3] = 40;
multi[3] = 0.46;
text[4] = SPR_Load("sprites/lens/lens3.spr");
red[4] = 1.0;
green[4] = 164/255;
blue[4] = 164/255;
scale[4] = 52;
multi[4] = 0.5;
text[5] = SPR_Load("sprites/lens/lens2.spr");
red[5] = green[5] = blue[5] = 1.0;
scale[5] = 31;
multi[5] = 0.54;
text[6] = SPR_Load("sprites/lens/lens2.spr");
red[6] = 0.6;
green[6] = 1.0;
blue[6] = 0.6;
scale[6] = 26;
multi[6] = 0.64;
text[7] = SPR_Load("sprites/lens/glow1.spr");
red[7] = 0.5;
green[7] = 1.0;
blue[7] = 0.5;
scale[7] = 20;
multi[7] = 0.77;
text[8] = SPR_Load("sprites/lens/lens2.spr");
text[9] = SPR_Load("sprites/lens/lens1.spr");
flPlayerBlend = 0.0;
flPlayerBlend2 = 0.0;
return 1;
}
int CHudLensflare :: DrawFlare( const Vector &forward, const Vector &lightdir, const Vector &lightorg )
{
flPlayerBlend = max( DotProduct( forward, lightdir ) - 0.85, 0.0 ) * 6.8;
if( flPlayerBlend > 1.0 ) flPlayerBlend = 1.0;
flPlayerBlend4 = max( DotProduct( forward, lightdir ) - 0.90, 0.0 ) * 6.6;
if( flPlayerBlend4 > 1.0 ) flPlayerBlend4 = 1.0;
flPlayerBlend6 = max( DotProduct( forward, lightdir ) - 0.80, 0.0 ) * 6.7;
if( flPlayerBlend6 > 1.0 ) flPlayerBlend6 = 1.0;
flPlayerBlend2 = flPlayerBlend6 * 140.0 ;
flPlayerBlend3 = flPlayerBlend * 190.0 ;
flPlayerBlend5 = flPlayerBlend4 * 222.0 ;
Vector normal, point, screen;
if( cv_renderer->value ) R_WorldToScreen( lightorg, screen );
else gEngfuncs.pTriAPI->WorldToScreen( (float *)&lightorg, screen );
Suncoordx = XPROJECT( screen[0] );
Suncoordy = YPROJECT( screen[1] );
Screenmx = ScreenWidth / 2;
Screenmy = ScreenHeight / 2;
Sundistx = Screenmx - Suncoordx;
Sundisty = Screenmy - Suncoordy;
gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); //additive
gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *) gEngfuncs.GetSpritePointer(SPR_Load("sprites/lens/lensflare2.spr")) , 0);
gEngfuncs.pTriAPI->CullFace( TRI_NONE ); //no culling
gEngfuncs.pTriAPI->Color4f( 0.97f, 0.6f, 0.02f, 1.0f );
gEngfuncs.pTriAPI->Brightness( 0.3f );
gEngfuncs.pTriAPI->Begin(TRI_QUADS); //start our quad
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Suncoordx + 190, Suncoordy + 190, 0); //top left
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Suncoordx + 190, Suncoordy - 190, 0); //bottom left
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Suncoordx - 190, Suncoordy - 190, 0); //bottom right
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Suncoordx - 190, Suncoordy + 190, 0); //top right
gEngfuncs.pTriAPI->End(); //end our list of vertexes
gEngfuncs.pTriAPI->RenderMode(kRenderNormal);
gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); //additive
gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *) gEngfuncs.GetSpritePointer(SPR_Load("sprites/lens/glow2.spr")) , 0);
gEngfuncs.pTriAPI->CullFace( TRI_NONE ); //no culling
gEngfuncs.pTriAPI->Color4f(1.0, 1.0 , 1.0, flPlayerBlend3/255.0);
gEngfuncs.pTriAPI->Brightness(flPlayerBlend3/255.0);
gEngfuncs.pTriAPI->Begin(TRI_QUADS); //start our quad
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Suncoordx + 160, Suncoordy + 160, 0); //top left
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Suncoordx + 160, Suncoordy - 160, 0); //bottom left
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Suncoordx - 160, Suncoordy - 160, 0); //bottom right
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Suncoordx - 160, Suncoordy + 160, 0); //top right
gEngfuncs.pTriAPI->End(); //end our list of vertexes
gEngfuncs.pTriAPI->RenderMode(kRenderNormal);
gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); //additive
gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *) gEngfuncs.GetSpritePointer(SPR_Load("sprites/lens/glow3.spr")) , 0);
gEngfuncs.pTriAPI->CullFace( TRI_NONE ); //no culling
gEngfuncs.pTriAPI->Color4f(1.0, 1.0 , 1.0, flPlayerBlend5/255.0);
gEngfuncs.pTriAPI->Brightness(flPlayerBlend5/255.0);
gEngfuncs.pTriAPI->Begin(TRI_QUADS); //start our quad
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(0, 0, 0); //top left
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(0, ScreenHeight, 0); //bottom left
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(ScreenWidth, ScreenHeight, 0); //bottom right
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(ScreenWidth, 0, 0); //top right
gEngfuncs.pTriAPI->End(); //end our list of vertexes
gEngfuncs.pTriAPI->RenderMode(kRenderNormal);
int i = 1;
Lensx[i] = (Suncoordx + (Sundistx * multi[i]));
Lensy[i] = (Suncoordy + (Sundisty * multi[i]));
gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); //additive
gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *) gEngfuncs.GetSpritePointer(text[i]) , 0);
gEngfuncs.pTriAPI->CullFace( TRI_NONE ); //no culling
gEngfuncs.pTriAPI->Color4f(red[i], green[i] , green[i], flPlayerBlend2/255.0);
gEngfuncs.pTriAPI->Brightness(flPlayerBlend2/255.0);
gEngfuncs.pTriAPI->Begin(TRI_QUADS); //start our quad
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] + scale[i], Lensy[i] + scale[i], 0); //top left
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] + scale[i], Lensy[i] - scale[i], 0); //bottom left
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] - scale[i], Lensy[i] - scale[i], 0); //bottom right
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] - scale[i], Lensy[i] + scale[i], 0); //top right
gEngfuncs.pTriAPI->End(); //end our list of vertexes
gEngfuncs.pTriAPI->RenderMode(kRenderNormal);
i++;
Lensx[i] = (Suncoordx + (Sundistx * multi[i]));
Lensy[i] = (Suncoordy + (Sundisty * multi[i]));
gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); //additive
gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *) gEngfuncs.GetSpritePointer(text[i]) , 0);
gEngfuncs.pTriAPI->CullFace( TRI_NONE ); //no culling
gEngfuncs.pTriAPI->Color4f(red[i], green[i] , green[i], flPlayerBlend2/255.0);
gEngfuncs.pTriAPI->Brightness(flPlayerBlend2/255.0);
gEngfuncs.pTriAPI->Begin(TRI_QUADS); //start our quad
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] + scale[i], Lensy[i] + scale[i], 0); //top left
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] + scale[i], Lensy[i] - scale[i], 0); //bottom left
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] - scale[i], Lensy[i] - scale[i], 0); //bottom right
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] - scale[i], Lensy[i] + scale[i], 0); //top right
gEngfuncs.pTriAPI->End(); //end our list of vertexes
gEngfuncs.pTriAPI->RenderMode(kRenderNormal);
i++;
Lensx[i] = (Suncoordx + (Sundistx * multi[i]));
Lensy[i] = (Suncoordy + (Sundisty * multi[i]));
gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); //additive
gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *) gEngfuncs.GetSpritePointer(text[i]) , 0);
gEngfuncs.pTriAPI->CullFace( TRI_NONE ); //no culling
gEngfuncs.pTriAPI->Color4f(red[i], green[i] , green[i], flPlayerBlend2/255.0);
gEngfuncs.pTriAPI->Brightness(flPlayerBlend2/255.0);
gEngfuncs.pTriAPI->Begin(TRI_QUADS); //start our quad
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] + scale[i], Lensy[i] + scale[i], 0); //top left
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] + scale[i], Lensy[i] - scale[i], 0); //bottom left
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] - scale[i], Lensy[i] - scale[i], 0); //bottom right
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] - scale[i], Lensy[i] + scale[i], 0); //top right
gEngfuncs.pTriAPI->End(); //end our list of vertexes
gEngfuncs.pTriAPI->RenderMode(kRenderNormal);
i++;
Lensx[i] = (Suncoordx + (Sundistx * multi[i]));
Lensy[i] = (Suncoordy + (Sundisty * multi[i]));
gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); //additive
gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *) gEngfuncs.GetSpritePointer(text[i]) , 0);
gEngfuncs.pTriAPI->CullFace( TRI_NONE ); //no culling
gEngfuncs.pTriAPI->Color4f(red[i], green[i] , green[i], flPlayerBlend2/255.0);
gEngfuncs.pTriAPI->Brightness(flPlayerBlend2/255.0);
gEngfuncs.pTriAPI->Begin(TRI_QUADS); //start our quad
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] + scale[i], Lensy[i] + scale[i], 0); //top left
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] + scale[i], Lensy[i] - scale[i], 0); //bottom left
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] - scale[i], Lensy[i] - scale[i], 0); //bottom right
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] - scale[i], Lensy[i] + scale[i], 0); //top right
gEngfuncs.pTriAPI->End(); //end our list of vertexes
gEngfuncs.pTriAPI->RenderMode(kRenderNormal);
i++;
Lensx[i] = (Suncoordx + (Sundistx * multi[i]));
Lensy[i] = (Suncoordy + (Sundisty * multi[i]));
gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); //additive
gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *) gEngfuncs.GetSpritePointer(text[i]) , 0);
gEngfuncs.pTriAPI->CullFace( TRI_NONE ); //no culling
gEngfuncs.pTriAPI->Color4f(red[i], green[i] , green[i], flPlayerBlend2/255.0);
gEngfuncs.pTriAPI->Brightness(flPlayerBlend2/255.0);
gEngfuncs.pTriAPI->Begin(TRI_QUADS); //start our quad
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] + scale[i], Lensy[i] + scale[i], 0); //top left
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] + scale[i], Lensy[i] - scale[i], 0); //bottom left
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] - scale[i], Lensy[i] - scale[i], 0); //bottom right
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] - scale[i], Lensy[i] + scale[i], 0); //top right
gEngfuncs.pTriAPI->End(); //end our list of vertexes
gEngfuncs.pTriAPI->RenderMode(kRenderNormal);
i++;
Lensx[i] = (Suncoordx + (Sundistx * multi[i]));
Lensy[i] = (Suncoordy + (Sundisty * multi[i]));
gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); //additive
gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *) gEngfuncs.GetSpritePointer(text[i]) , 0);
gEngfuncs.pTriAPI->CullFace( TRI_NONE ); //no culling
gEngfuncs.pTriAPI->Color4f(red[i], green[i] , green[i], flPlayerBlend2/255.0);
gEngfuncs.pTriAPI->Brightness(flPlayerBlend2/255.0);
gEngfuncs.pTriAPI->Begin(TRI_QUADS); //start our quad
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] + scale[i], Lensy[i] + scale[i], 0); //top left
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] + scale[i], Lensy[i] - scale[i], 0); //bottom left
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] - scale[i], Lensy[i] - scale[i], 0); //bottom right
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] - scale[i], Lensy[i] + scale[i], 0); //top right
gEngfuncs.pTriAPI->End(); //end our list of vertexes
gEngfuncs.pTriAPI->RenderMode(kRenderNormal);
i++;
Lensx[i] = (Suncoordx + (Sundistx * multi[i]));
Lensy[i] = (Suncoordy + (Sundisty * multi[i]));
gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); //additive
gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *) gEngfuncs.GetSpritePointer(text[i]) , 0);
gEngfuncs.pTriAPI->CullFace( TRI_NONE ); //no culling
gEngfuncs.pTriAPI->Color4f(red[i], green[i] , green[i], flPlayerBlend2/255.0);
gEngfuncs.pTriAPI->Brightness(flPlayerBlend2/255.0);
gEngfuncs.pTriAPI->Begin(TRI_QUADS); //start our quad
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] + scale[i], Lensy[i] + scale[i], 0); //top left
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] + scale[i], Lensy[i] - scale[i], 0); //bottom left
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] - scale[i], Lensy[i] - scale[i], 0); //bottom right
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx[i] - scale[i], Lensy[i] + scale[i], 0); //top right
gEngfuncs.pTriAPI->End(); //end our list of vertexes
gEngfuncs.pTriAPI->RenderMode(kRenderNormal);
i++;
int scale1 = 32;
int Lensx1,Lensy1 = 0;
Lensx1 = (Suncoordx + (Sundistx * 0.88));
Lensy1 = (Suncoordy + (Sundisty * 0.88));
gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); //additive
gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *) gEngfuncs.GetSpritePointer(text[i]) , 0);
gEngfuncs.pTriAPI->CullFace( TRI_NONE ); //no culling
gEngfuncs.pTriAPI->Color4f(0.9, 0.9 , 0.9, flPlayerBlend2/255.0);
gEngfuncs.pTriAPI->Brightness(flPlayerBlend2/255.0);
gEngfuncs.pTriAPI->Begin(TRI_QUADS); //start our quad
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx1 + scale1, Lensy1 + scale1, 0); //top left
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx1 + scale1, Lensy1 - scale1, 0); //bottom left
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx1 - scale1, Lensy1 - scale1, 0); //bottom right
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx1 - scale1, Lensy1 + scale1, 0); //top right
gEngfuncs.pTriAPI->End(); //end our list of vertexes
gEngfuncs.pTriAPI->RenderMode(kRenderNormal);
i++;
scale1 = 140;
Lensx1 = (Suncoordx + (Sundistx * 1.1));
Lensy1 = (Suncoordy + (Sundisty * 1.1));
gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); //additive
gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *) gEngfuncs.GetSpritePointer(text[i]) , 0);
gEngfuncs.pTriAPI->CullFace( TRI_NONE ); //no culling
gEngfuncs.pTriAPI->Color4f(0.9, 0.9 , 0.9, flPlayerBlend2/255.0);
gEngfuncs.pTriAPI->Brightness(flPlayerBlend2/255.0);
gEngfuncs.pTriAPI->Begin(TRI_QUADS); //start our quad
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx1 + scale1, Lensy1 + scale1, 0); //top left
gEngfuncs.pTriAPI->TexCoord2f(0.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx1 + scale1, Lensy1 - scale1, 0); //bottom left
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 0.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx1 - scale1, Lensy1 - scale1, 0); //bottom right
gEngfuncs.pTriAPI->TexCoord2f(1.0f, 1.0f);gEngfuncs.pTriAPI->Vertex3f(Lensx1 - scale1, Lensy1 + scale1, 0); //top right
gEngfuncs.pTriAPI->End(); //end our list of vertexes
gEngfuncs.pTriAPI->RenderMode(kRenderNormal);
gEngfuncs.pTriAPI->CullFace( TRI_FRONT );
return 1;
}
int CHudLensflare :: Draw( float flTime )
{
Vector forward, sundir, suntarget;
pmtrace_t ptr;
if( m_pCvarDraw->value <= 0.0f )
return 0;
forward = g_pViewParams->forward;
// draw flares for dynlights
for( int i = 0; i < MAX_DLIGHTS; i++ )
{
CDynLight *pl = &tr.dlights[i];
if( pl->die < flTime || !pl->radius || !FBitSet( pl->flags, DLF_LENSFLARE ))
continue;
if( pl->type == LIGHT_SPOT )
sundir = pl->frustum.GetPlane( FRUSTUM_FAR )->normal;
else sundir = ( pl->origin - g_pViewParams->vieworg ).Normalize();
suntarget = pl->origin;
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( g_pViewParams->vieworg, suntarget, PM_GLASS_IGNORE, -1, &ptr );
if( DotProduct( forward, sundir ) >= 0.68f && !pl->frustum.CullSphere( GetVieworg(), 72.0f ) && ptr.fraction == 1.0f )
{
DrawFlare( forward, sundir, suntarget );
}
}
if( CVAR_TO_BOOL( v_sunshafts ))
return 1; // don't mixing sunshafts and lensflares because this looks ugly
if( !tr.fogEnabled )
{
Vector skyVec = tr.sky_normal;
if( skyVec == g_vecZero )
return 1; // no light_environment on a map
sundir = -skyVec.Normalize();
suntarget = tr.cached_vieworigin + sundir * 32768.0f;
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( tr.cached_vieworigin, suntarget, PM_GLASS_IGNORE, -1, &ptr );
if( DotProduct( forward, sundir ) >= 0.68f && R_SkyIsVisible() && gEngfuncs.PM_PointContents( ptr.endpos, null ) == CONTENTS_SKY )
{
DrawFlare( forward, sundir, suntarget );
}
}
return 1;
}

187
cl_dll/menu.cpp Normal file
View File

@ -0,0 +1,187 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// menu.cpp
//
// generic menu handler
//
#include "hud.h"
#include "cl_util.h"
#include "parsemsg.h"
#include <string.h>
#include <stdio.h>
#include "vgui_TeamFortressViewport.h"
#define MAX_MENU_STRING 512
char g_szMenuString[MAX_MENU_STRING];
char g_szPrelocalisedMenuString[MAX_MENU_STRING];
int KB_ConvertString( char *in, char **ppout );
DECLARE_MESSAGE( m_Menu, ShowMenu );
int CHudMenu :: Init( void )
{
gHUD.AddHudElem( this );
HOOK_MESSAGE( ShowMenu );
InitHUDData();
return 1;
}
void CHudMenu :: InitHUDData( void )
{
m_fMenuDisplayed = 0;
m_bitsValidSlots = 0;
Reset();
}
void CHudMenu :: Reset( void )
{
g_szPrelocalisedMenuString[0] = 0;
m_fWaitingForMore = FALSE;
}
int CHudMenu :: VidInit( void )
{
return 1;
}
int CHudMenu :: Draw( float flTime )
{
// check for if menu is set to disappear
if ( m_flShutoffTime > 0 )
{
if ( m_flShutoffTime <= gHUD.m_flTime )
{ // times up, shutoff
m_fMenuDisplayed = 0;
m_iFlags &= ~HUD_ACTIVE;
return 1;
}
}
// don't draw the menu if the scoreboard is being shown
if ( gViewPort && gViewPort->IsScoreBoardVisible() )
return 1;
// draw the menu, along the left-hand side of the screen
// count the number of newlines
int nlc = 0;
for ( int i = 0; i < MAX_MENU_STRING && g_szMenuString[i] != '\0'; i++ )
{
if ( g_szMenuString[i] == '\n' )
nlc++;
}
// center it
int y = (ScreenHeight/2) - ((nlc/2)*12) - 40; // make sure it is above the say text
int x = 20;
i = 0;
while ( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' )
{
gHUD.DrawHudString( x, y, 320, g_szMenuString + i, 255, 255, 255 );
y += 12;
while ( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' && g_szMenuString[i] != '\n' )
i++;
if ( g_szMenuString[i] == '\n' )
i++;
}
return 1;
}
// selects an item from the menu
void CHudMenu :: SelectMenuItem( int menu_item )
{
// if menu_item is in a valid slot, send a menuselect command to the server
if ( (menu_item > 0) && (m_bitsValidSlots & (1 << (menu_item-1))) )
{
char szbuf[32];
sprintf( szbuf, "menuselect %d\n", menu_item );
ClientCmd( szbuf );
// remove the menu
m_fMenuDisplayed = 0;
m_iFlags &= ~HUD_ACTIVE;
}
}
// Message handler for ShowMenu message
// takes four values:
// short: a bitfield of keys that are valid input
// char : the duration, in seconds, the menu should stay up. -1 means is stays until something is chosen.
// byte : a boolean, TRUE if there is more string yet to be received before displaying the menu, FALSE if it's the last string
// string: menu string to display
// if this message is never received, then scores will simply be the combined totals of the players.
int CHudMenu :: MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf )
{
char *temp = NULL;
BEGIN_READ( pbuf, iSize );
m_bitsValidSlots = READ_SHORT();
int DisplayTime = READ_CHAR();
int NeedMore = READ_BYTE();
if ( DisplayTime > 0 )
m_flShutoffTime = DisplayTime + gHUD.m_flTime;
else
m_flShutoffTime = -1;
if ( m_bitsValidSlots )
{
if ( !m_fWaitingForMore ) // this is the start of a new menu
{
strncpy( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING );
}
else
{ // append to the current menu string
strncat( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING - strlen(g_szPrelocalisedMenuString) );
}
g_szPrelocalisedMenuString[MAX_MENU_STRING-1] = 0; // ensure null termination (strncat/strncpy does not)
if ( !NeedMore )
{ // we have the whole string, so we can localise it now
strcpy( g_szMenuString, gHUD.m_TextMessage.BufferedLocaliseTextString( g_szPrelocalisedMenuString ) );
// Swap in characters
if ( KB_ConvertString( g_szMenuString, &temp ) )
{
strcpy( g_szMenuString, temp );
free( temp );
}
}
m_fMenuDisplayed = 1;
m_iFlags |= HUD_ACTIVE;
}
else
{
m_fMenuDisplayed = 0; // no valid slots means that the menu should be turned off
m_iFlags &= ~HUD_ACTIVE;
}
m_fWaitingForMore = NeedMore;
return 1;
}

539
cl_dll/message.cpp Normal file
View File

@ -0,0 +1,539 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// Message.cpp
//
// implementation of CHudMessage class
//
#include "hud.h"
#include "cl_util.h"
#include <string.h>
#include <stdio.h>
#include "parsemsg.h"
void SubtitleMessageAdd( client_textmessage_t *tempMessage ); // buz
void ShowTip( client_textmessage_t *tempMessage ); // buz
void VGuiAddScreenMessage( client_textmessage_t *msg ); // buz
void VGuiAddPickupMessage( client_textmessage_t *msg ); // buz
// Wargon: Ñêðîëëÿùèéñÿ òåêñò.
void VGuiAddScrollingMessage( client_textmessage_t *msg );
DECLARE_MESSAGE( m_Message, HudText )
DECLARE_MESSAGE( m_Message, GameTitle )
// 1 Global client_textmessage_t for custom messages that aren't in the titles.txt
client_textmessage_t g_pCustomMessage;
char *g_pCustomName = "Custom";
char g_pCustomText[1024];
int CHudMessage::Init(void)
{
HOOK_MESSAGE( HudText );
HOOK_MESSAGE( GameTitle );
gHUD.AddHudElem(this);
Reset();
return 1;
};
int CHudMessage::VidInit( void )
{
return 1;
};
void CHudMessage::Reset( void )
{
memset( m_pMessages, 0, sizeof( m_pMessages[0] ) * maxHUDMessages );
memset( m_startTime, 0, sizeof( m_startTime[0] ) * maxHUDMessages );
m_gameTitleTime = 0;
m_pGameTitle = NULL;
}
float CHudMessage::FadeBlend( float fadein, float fadeout, float hold, float localTime )
{
float fadeTime = fadein + hold;
float fadeBlend;
if ( localTime < 0 )
return 0;
if ( localTime < fadein )
{
fadeBlend = 1 - ((fadein - localTime) / fadein);
}
else if ( localTime > fadeTime )
{
if ( fadeout > 0 )
fadeBlend = 1 - ((localTime - fadeTime) / fadeout);
else
fadeBlend = 0;
}
else
fadeBlend = 1;
return fadeBlend;
}
int CHudMessage::XPosition( float x, int width, int totalWidth )
{
int xPos;
if ( x == -1 )
{
xPos = (ScreenWidth - width) / 2;
}
else
{
if ( x < 0 )
xPos = (1.0 + x) * ScreenWidth - totalWidth; // Alight right
else
xPos = x * ScreenWidth;
}
if ( xPos + width > ScreenWidth )
xPos = ScreenWidth - width;
else if ( xPos < 0 )
xPos = 0;
return xPos;
}
int CHudMessage::YPosition( float y, int height )
{
int yPos;
if ( y == -1 ) // Centered?
yPos = (ScreenHeight - height) * 0.5;
else
{
// Alight bottom?
if ( y < 0 )
yPos = (1.0 + y) * ScreenHeight - height; // Alight bottom
else // align top
yPos = y * ScreenHeight;
}
if ( yPos + height > ScreenHeight )
yPos = ScreenHeight - height;
else if ( yPos < 0 )
yPos = 0;
return yPos;
}
void CHudMessage::MessageScanNextChar( void )
{
int srcRed, srcGreen, srcBlue, destRed, destGreen, destBlue;
int blend;
srcRed = m_parms.pMessage->r1;
srcGreen = m_parms.pMessage->g1;
srcBlue = m_parms.pMessage->b1;
blend = 0; // Pure source
switch( m_parms.pMessage->effect )
{
// Fade-in / Fade-out
case 0:
case 1:
destRed = destGreen = destBlue = 0;
blend = m_parms.fadeBlend;
break;
case 2:
m_parms.charTime += m_parms.pMessage->fadein;
if ( m_parms.charTime > m_parms.time )
{
srcRed = srcGreen = srcBlue = 0;
blend = 0; // pure source
}
else
{
float deltaTime = m_parms.time - m_parms.charTime;
destRed = destGreen = destBlue = 0;
if ( m_parms.time > m_parms.fadeTime )
{
blend = m_parms.fadeBlend;
}
else if ( deltaTime > m_parms.pMessage->fxtime )
blend = 0; // pure dest
else
{
destRed = m_parms.pMessage->r2;
destGreen = m_parms.pMessage->g2;
destBlue = m_parms.pMessage->b2;
blend = 255 - (deltaTime * (1.0/m_parms.pMessage->fxtime) * 255.0 + 0.5);
}
}
break;
}
if ( blend > 255 )
blend = 255;
else if ( blend < 0 )
blend = 0;
m_parms.r = ((srcRed * (255-blend)) + (destRed * blend)) >> 8;
m_parms.g = ((srcGreen * (255-blend)) + (destGreen * blend)) >> 8;
m_parms.b = ((srcBlue * (255-blend)) + (destBlue * blend)) >> 8;
if ( m_parms.pMessage->effect == 1 && m_parms.charTime != 0 )
{
if ( m_parms.x >= 0 && m_parms.y >= 0 && (m_parms.x + gHUD.m_scrinfo.charWidths[ m_parms.text ]) <= ScreenWidth )
TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.pMessage->r2, m_parms.pMessage->g2, m_parms.pMessage->b2 );
}
}
void CHudMessage::MessageScanStart( void )
{
switch( m_parms.pMessage->effect )
{
// Fade-in / out with flicker
case 1:
case 0:
m_parms.fadeTime = m_parms.pMessage->fadein + m_parms.pMessage->holdtime;
if ( m_parms.time < m_parms.pMessage->fadein )
{
m_parms.fadeBlend = ((m_parms.pMessage->fadein - m_parms.time) * (1.0/m_parms.pMessage->fadein) * 255);
}
else if ( m_parms.time > m_parms.fadeTime )
{
if ( m_parms.pMessage->fadeout > 0 )
m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255);
else
m_parms.fadeBlend = 255; // Pure dest (off)
}
else
m_parms.fadeBlend = 0; // Pure source (on)
m_parms.charTime = 0;
if ( m_parms.pMessage->effect == 1 && (rand()%100) < 10 )
m_parms.charTime = 1;
break;
case 2:
m_parms.fadeTime = (m_parms.pMessage->fadein * m_parms.length) + m_parms.pMessage->holdtime;
if ( m_parms.time > m_parms.fadeTime && m_parms.pMessage->fadeout > 0 )
m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255);
else
m_parms.fadeBlend = 0;
break;
}
}
void CHudMessage::MessageDrawScan( client_textmessage_t *pMessage, float time )
{
int i, j, length, width;
const char *pText;
unsigned char line[80];
pText = pMessage->pMessage;
// Count lines
m_parms.lines = 1;
m_parms.time = time;
m_parms.pMessage = pMessage;
length = 0;
width = 0;
m_parms.totalWidth = 0;
while ( *pText )
{
if ( *pText == '\n' )
{
m_parms.lines++;
if ( width > m_parms.totalWidth )
m_parms.totalWidth = width;
width = 0;
}
else
width += gHUD.m_scrinfo.charWidths[*pText];
pText++;
length++;
}
m_parms.length = length;
m_parms.totalHeight = (m_parms.lines * gHUD.m_scrinfo.iCharHeight);
m_parms.y = YPosition( pMessage->y, m_parms.totalHeight );
pText = pMessage->pMessage;
m_parms.charTime = 0;
MessageScanStart();
for ( i = 0; i < m_parms.lines; i++ )
{
m_parms.lineLength = 0;
m_parms.width = 0;
while ( *pText && *pText != '\n' )
{
unsigned char c = *pText;
line[m_parms.lineLength] = c;
m_parms.width += gHUD.m_scrinfo.charWidths[c];
m_parms.lineLength++;
pText++;
}
pText++; // Skip LF
line[m_parms.lineLength] = 0;
m_parms.x = XPosition( pMessage->x, m_parms.width, m_parms.totalWidth );
for ( j = 0; j < m_parms.lineLength; j++ )
{
m_parms.text = line[j];
int next = m_parms.x + gHUD.m_scrinfo.charWidths[ m_parms.text ];
MessageScanNextChar();
if ( m_parms.x >= 0 && m_parms.y >= 0 && next <= ScreenWidth )
TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.r, m_parms.g, m_parms.b );
m_parms.x = next;
}
m_parms.y += gHUD.m_scrinfo.iCharHeight;
}
}
int CHudMessage::Draw( float fTime )
{
int i, drawn;
client_textmessage_t *pMessage;
float endTime;
drawn = 0;
// Fixup level transitions
for ( i = 0; i < maxHUDMessages; i++ )
{
// Assume m_parms.time contains last time
if ( m_pMessages[i] )
{
pMessage = m_pMessages[i];
if ( m_startTime[i] > gHUD.m_flTime )
m_startTime[i] = gHUD.m_flTime + m_parms.time - m_startTime[i] + 0.2; // Server takes 0.2 seconds to spawn, adjust for this
}
}
for ( i = 0; i < maxHUDMessages; i++ )
{
if ( m_pMessages[i] )
{
pMessage = m_pMessages[i];
// This is when the message is over
switch( pMessage->effect )
{
case 0:
case 1:
endTime = m_startTime[i] + pMessage->fadein + pMessage->fadeout + pMessage->holdtime;
break;
// Fade in is per character in scanning messages
case 2:
endTime = m_startTime[i] + (pMessage->fadein * strlen( pMessage->pMessage )) + pMessage->fadeout + pMessage->holdtime;
break;
}
if ( fTime <= endTime )
{
float messageTime = fTime - m_startTime[i];
// Draw the message
// effect 0 is fade in/fade out
// effect 1 is flickery credits
// effect 2 is write out (training room)
MessageDrawScan( pMessage, messageTime );
drawn++;
}
else
{
// The message is over
m_pMessages[i] = NULL;
}
}
}
// Remember the time -- to fix up level transitions
m_parms.time = gHUD.m_flTime;
// Don't call until we get another message
if ( !drawn )
m_iFlags &= ~HUD_ACTIVE;
return 1;
}
void CHudMessage::MessageAdd( const char *pName, float time )
{
int i,j;
client_textmessage_t *tempMessage;
for ( i = 0; i < maxHUDMessages; i++ )
{
if ( !m_pMessages[i] )
{
// Trim off a leading # if it's there
if ( pName[0] == '#' )
pName++;
tempMessage = TextMessageGet( pName );
// If we couldnt find it in the titles.txt, just create it
if ( !tempMessage )
{
// buz: !-messages are only sentences.txt
if (pName[0] == '!')
return;
g_pCustomMessage.effect = 2;
g_pCustomMessage.r1 = g_pCustomMessage.g1 = g_pCustomMessage.b1 = g_pCustomMessage.a1 = 100;
g_pCustomMessage.r2 = 240;
g_pCustomMessage.g2 = 110;
g_pCustomMessage.b2 = 0;
g_pCustomMessage.a2 = 0;
g_pCustomMessage.x = -1; // Centered
g_pCustomMessage.y = 0.7;
g_pCustomMessage.fadein = 0.01;
g_pCustomMessage.fadeout = 1.5;
g_pCustomMessage.fxtime = 0.25;
g_pCustomMessage.holdtime = 5;
g_pCustomMessage.pName = g_pCustomName;
strcpy( g_pCustomText, pName );
g_pCustomMessage.pMessage = g_pCustomText;
tempMessage = &g_pCustomMessage;
}
else if (tempMessage->effect == 3) // buz: link into subtitle system
{
SubtitleMessageAdd( tempMessage );
return;
}
else if (tempMessage->effect == 4) // buz: link into vgui screen messages system
{
VGuiAddScreenMessage( tempMessage );
return;
}
else if (tempMessage->effect == 5) // buz: link into vgui pickup messages system
{
VGuiAddPickupMessage( tempMessage );
return;
}
else if (tempMessage->effect == 6) // Wargon: Ñêðîëëÿùèéñÿ òåêñò.
{
VGuiAddScrollingMessage( tempMessage );
return;
}
else if (tempMessage->effect >= 20 && tempMessage->effect < 30) // buz: link into tips system
{
ShowTip( tempMessage );
return;
}
for ( j = 0; j < maxHUDMessages; j++ )
{
if ( m_pMessages[j] )
{
// is this message already in the list
if ( !strcmp( tempMessage->pMessage, m_pMessages[j]->pMessage ) )
{
return;
}
// get rid of any other messages in same location (only one displays at a time)
if ( fabs( tempMessage->y - m_pMessages[j]->y ) < 0.0001 )
{
if ( fabs( tempMessage->x - m_pMessages[j]->x ) < 0.0001 )
{
m_pMessages[j] = NULL;
}
}
}
}
m_pMessages[i] = tempMessage;
m_startTime[i] = time;
return;
}
}
}
int CHudMessage::MsgFunc_HudText( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
char *pString = READ_STRING();
MessageAdd( pString, gHUD.m_flTime );
// Remember the time -- to fix up level transitions
m_parms.time = gHUD.m_flTime;
// Turn on drawing
if ( !(m_iFlags & HUD_ACTIVE) )
m_iFlags |= HUD_ACTIVE;
return 1;
}
int CHudMessage::MsgFunc_GameTitle( const char *pszName, int iSize, void *pbuf )
{
m_pGameTitle = TextMessageGet( "GAMETITLE" );
if ( m_pGameTitle != NULL )
{
m_gameTitleTime = gHUD.m_flTime;
// Turn on drawing
if ( !(m_iFlags & HUD_ACTIVE) )
m_iFlags |= HUD_ACTIVE;
}
return 1;
}
void CHudMessage::MessageAdd(client_textmessage_t * newMessage )
{
m_parms.time = gHUD.m_flTime;
// Turn on drawing
if ( !(m_iFlags & HUD_ACTIVE) )
m_iFlags |= HUD_ACTIVE;
for ( int i = 0; i < maxHUDMessages; i++ )
{
if ( !m_pMessages[i] )
{
m_pMessages[i] = newMessage;
m_startTime[i] = gHUD.m_flTime;
return;
}
}
}

31
cl_dll/overview.h Normal file
View File

@ -0,0 +1,31 @@
//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#ifndef OVERVIEW_H
#define OVERVIEW_H
#pragma once
//-----------------------------------------------------------------------------
// Purpose: Handles the drawing of the top-down map and all the things on it
//-----------------------------------------------------------------------------
class CHudOverview : public CHudBase
{
public:
int Init();
int VidInit();
int Draw(float flTime);
void InitHUDData( void );
private:
HSPRITE m_hsprPlayer;
HSPRITE m_hsprViewcone;
};
#endif // OVERVIEW_H

178
cl_dll/parsemsg.cpp Normal file
View File

@ -0,0 +1,178 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// parsemsg.cpp
//
#include "hud.h"
#include "cl_util.h"
#include "const.h"
#include "com_model.h"
#include "gl_local.h"
typedef unsigned char byte;
#define true 1
static byte *gpBuf;
static int giSize;
static int giRead;
static int giBadRead;
void BEGIN_READ( void *buf, int size )
{
giRead = 0;
giBadRead = 0;
giSize = size;
gpBuf = (byte*)buf;
}
int READ_CHAR( void )
{
int c;
if (giRead + 1 > giSize)
{
giBadRead = true;
return -1;
}
c = (signed char)gpBuf[giRead];
giRead++;
return c;
}
int READ_BYTE( void )
{
int c;
if (giRead+1 > giSize)
{
giBadRead = true;
return -1;
}
c = (unsigned char)gpBuf[giRead];
giRead++;
return c;
}
int READ_SHORT( void )
{
int c;
if (giRead+2 > giSize)
{
giBadRead = true;
return -1;
}
c = (short)( gpBuf[giRead] + ( gpBuf[giRead+1] << 8 ) );
giRead += 2;
return c;
}
int READ_WORD( void )
{
return READ_SHORT();
}
int READ_LONG( void )
{
int c;
if (giRead+4 > giSize)
{
giBadRead = true;
return -1;
}
c = gpBuf[giRead] + (gpBuf[giRead + 1] << 8) + (gpBuf[giRead + 2] << 16) + (gpBuf[giRead + 3] << 24);
giRead += 4;
return c;
}
float READ_FLOAT( void )
{
union
{
byte b[4];
float f;
int l;
} dat;
dat.b[0] = gpBuf[giRead];
dat.b[1] = gpBuf[giRead+1];
dat.b[2] = gpBuf[giRead+2];
dat.b[3] = gpBuf[giRead+3];
giRead += 4;
// dat.l = LittleLong (dat.l);
return dat.f;
}
char* READ_STRING( void )
{
static char string[2048];
int l,c;
string[0] = 0;
l = 0;
do
{
if ( giRead+1 > giSize )
break; // no more characters
c = READ_CHAR();
if (c == 0) break;
string[l] = c;
l++;
} while (l < sizeof(string)-1);
string[l] = 0;
return string;
}
float READ_COORD( void )
{
// g-cont. we loose precision here but keep old size of coord variable!
if( g_fRenderInitialized && RENDER_GET_PARM( PARM_FEATURES, 0 ) & ENGINE_WRITE_LARGE_COORD )
return (float)(READ_SHORT() * 1.0f);
return (float)(READ_SHORT() * (1.0f / 8.0f));
}
float READ_ANGLE( void )
{
return (float)(READ_CHAR() * (360.0/256));
}
float READ_HIRESANGLE( void )
{
return (float)(READ_SHORT() * (360.0/65536));
}
BOOL REMAIN_BYTES( void )
{
return giRead < giSize;
}

38
cl_dll/parsemsg.h Normal file
View File

@ -0,0 +1,38 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. 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
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// parsemsg.h
//
void BEGIN_READ( void *buf, int size );
int READ_CHAR( void );
int READ_BYTE( void );
int READ_SHORT( void );
int READ_WORD( void );
int READ_LONG( void );
float READ_FLOAT( void );
char* READ_STRING( void );
float READ_COORD( void );
float READ_ANGLE( void );
float READ_HIRESANGLE( void );
BOOL REMAIN_BYTES( void );

88
cl_dll/render/cl_dlight.h Normal file
View File

@ -0,0 +1,88 @@
/*
cl_dlight.h - dynamic lighting description
this code written for Paranoia 2: Savior modification
Copyright (C) 2014 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef CL_DLIGHT_H
#define CL_DLIGHT_H
#define NUM_SHADOW_SPLITS 3 // four splits
#define MAX_SHADOWMAPS (NUM_SHADOW_SPLITS + 1)
// dlight flags
#define DLF_NOSHADOWS BIT( 0 )
#define DLF_NOBUMP BIT( 1 )
#define DLF_LENSFLARE BIT( 2 )
#define DLF_CULLED BIT( 3 ) // light culled by scissor
#define DLF_ASPECT3X4 BIT( 4 )
#define DLF_ASPECT4X3 BIT( 5 )
#define DLF_FLIPTEXTURE BIT( 6 )
class CDynLight
{
public:
Vector origin;
Vector angles;
float radius;
Vector color; // ignored for spotlights, they have a texture
float die; // stop lighting after this time
float decay; // drop this each second
int key;
int type; // light type
bool update; // light needs update
matrix4x4 viewMatrix;
matrix4x4 projectionMatrix; // light projection matrix
matrix4x4 modelviewMatrix; // light modelview
matrix4x4 lightviewProjMatrix; // lightview projection
matrix4x4 textureMatrix[MAX_SHADOWMAPS]; // result texture matrix
matrix4x4 shadowMatrix[MAX_SHADOWMAPS]; // result texture matrix
GLfloat gl_shadowMatrix[MAX_SHADOWMAPS][16]; // cached matrices
Vector mins, maxs; // local bounds
Vector absmin, absmax; // world bounds
CFrustum frustum; // normal frustum
CFrustum splitFrustum[MAX_SHADOWMAPS];
// scissor data
float x, y, w, h;
// spotlight specific:
int spotlightTexture; // spotlights only
int shadowTexture[MAX_SHADOWMAPS]; // shadowmap for this light
int cinTexturenum; // not gltexturenum!
int lastframe; // cinematic lastframe
int flags;
float fov;
bool Expired( void )
{
if( die < GET_CLIENT_TIME( ))
return true;
if( radius <= 0.0f )
return true;
return false;
}
bool Active( void )
{
if( Expired( ))
return false;
if( FBitSet( flags, DLF_CULLED ))
return false;
return true;
}
};
#endif//CL_DLIGHT_H

1170
cl_dll/render/gl_aurora.cpp Normal file

File diff suppressed because it is too large Load Diff

211
cl_dll/render/gl_aurora.h Normal file
View File

@ -0,0 +1,211 @@
/*
r_particle.h - Laurie Cheers Aurora Particle System
First implementation of 02/08/02 November235
Copyright (C) 2011 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef GL_PARTICLE_H
#define GL_PARTICLE_H
class CParticleType;
class CParticleSystem;
#include "randomrange.h"
struct CParticle
{
CParticle *nextpart;
CParticle *m_pOverlay; // for making multi-layered particles
CParticleType *pType;
Vector origin;
Vector velocity;
Vector accel;
Vector m_vecWind;
cl_entity_t *m_pEntity; // if not null, this particle is tied to the given entity
float m_fRed;
float m_fGreen;
float m_fBlue;
float m_fRedStep;
float m_fGreenStep;
float m_fBlueStep;
float m_fAlpha;
float m_fAlphaStep;
float frame;
float m_fFrameStep;
float m_fAngle;
float m_fAngleStep;
float m_fSize;
float m_fSizeStep;
float m_fDrag;
float age;
float age_death;
float age_spray;
};
class CParticleType
{
public:
CParticleType( CParticleType *pNext = NULL );
// here is a particle system. Add a (set of) particles according to this type, and initialise their values.
CParticle *CreateParticle( CParticleSystem *pSys );
// initialise this particle. Does not define velocity or age.
void InitParticle( CParticle *pPart, CParticleSystem *pSys );
bool m_bIsDefined; // is this CParticleType just a placeholder?
int m_iRenderMode;
int m_iDrawCond;
RandomRange m_Bounce;
RandomRange m_BounceFriction;
bool m_bBouncing;
RandomRange m_Life;
RandomRange m_StartAlpha;
RandomRange m_EndAlpha;
RandomRange m_StartRed;
RandomRange m_EndRed;
RandomRange m_StartGreen;
RandomRange m_EndGreen;
RandomRange m_StartBlue;
RandomRange m_EndBlue;
RandomRange m_StartSize;
RandomRange m_SizeDelta;
RandomRange m_EndSize;
RandomRange m_StartFrame;
RandomRange m_EndFrame;
RandomRange m_FrameRate; // incompatible with EndFrame
bool m_bEndFrame;
RandomRange m_StartAngle;
RandomRange m_AngleDelta;
RandomRange m_SprayRate;
RandomRange m_SprayForce;
RandomRange m_SprayPitch;
RandomRange m_SprayYaw;
RandomRange m_SprayRoll;
CParticleType *m_pSprayType;
RandomRange m_Gravity;
RandomRange m_WindStrength;
RandomRange m_WindYaw;
HSPRITE m_hSprite;
CParticleType *m_pOverlayType;
RandomRange m_Drag;
CParticleType *m_pNext;
char m_szName[32];
};
typedef enum
{
AURORA_REMOVE = 0,
AURORA_INVISIBLE,
AURORA_DRAW,
} AURSTATE;
class CParticleSystem
{
public:
CParticleSystem( cl_entity_t *ent, const char *szFilename, int attachment = 0, float lifetime = 0.0f );
~CParticleSystem( void );
void AllocateParticles( int iParticles );
void CalculateDistance( void );
CParticleType *GetType( const char *szName );
CParticleType *AddPlaceholderType( const char *szName );
CParticleType *ParseType( char *&szFile );
cl_entity_t *GetEntity() { return m_pEntity; }
// General functions
AURSTATE UpdateSystem( float frametime ); // If this function returns false, the manager deletes the system
void DrawSystem( void );
CParticle *ActivateParticle( void ); // adds one of the free particles to the active list, and returns it for initialisation.
// MUST CHECK WHETHER THIS RESULT IS NULL!
// returns false if the particle has died
bool UpdateParticle( CParticle *part, float frametime );
void DrawParticle( CParticle *part, Vector &right, Vector &up );
// Utility functions that have to be public
bool ParticleIsVisible( CParticle* part );
void MarkForDeletion( void );
static float CosLookup( int angle ) { return angle < 0 ? c_fCosTable[angle+360] : c_fCosTable[angle]; }
static float SinLookup( int angle ) { return angle < -90 ? c_fCosTable[angle+450] : c_fCosTable[angle+90]; }
// Pointer to next system for linked list structure
CParticleSystem *m_pNextSystem;
CParticle *m_pActiveParticle;
float m_fViewerDist;
cl_entity_t *m_pEntity;
int m_iEntAttachment;
int m_iKillCondition;
int m_iLightingModel;
matrix3x3 entityMatrix;
int m_fHasProjectionLighting;
float m_fLifeTime; // for auto-removed particles
bool enable;
private:
static float c_fCosTable[360 + 90];
static bool c_bCosTableInit;
// the block of allocated particles
CParticle *m_pAllParticles;
// First particles in the linked list for the active particles and the dead particles
CParticle *m_pFreeParticle;
CParticle *m_pMainParticle; // the "source" particle.
CParticleType *m_pFirstType;
CParticleType *m_pMainType;
};
class CParticleSystemManager
{
public:
CParticleSystemManager( void );
~CParticleSystemManager( void );
void AddSystem( CParticleSystem* );
CParticleSystem *FindSystem( CParticleSystem *pFirstSystem, cl_entity_t *pEntity );
void MarkSystemForDeletion( CParticleSystem *pSys );
void UpdateSystems( void );
void ClearSystems( void );
void SortSystems( void );
private:
CParticleSystem *m_pFirstSystem;
};
extern CParticleSystemManager g_pParticleSystems; // buz
#endif//GL_PARTICLE_H

1055
cl_dll/render/gl_backend.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,228 @@
/*
gl_cubemaps.cpp - tools for cubemaps search & handling
Copyright (C) 2016 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "hud.h"
#include "cl_util.h"
#include "const.h"
#include "com_model.h"
#include "ref_params.h"
#include "gl_local.h"
#include "gl_decals.h"
#include <mathlib.h>
#include "gl_world.h"
/*
=================
CL_FindNearestCubeMap
find the nearest cubemap for a given point
=================
*/
void CL_FindNearestCubeMap( const Vector &pos, mcubemap_t **result )
{
if( !result ) return;
float maxDist = 99999.0f;
*result = NULL;
for( int i = 0; i < world->num_cubemaps; i++ )
{
mcubemap_t *check = &world->cubemaps[i];
float dist = VectorDistance( check->origin, pos );
if( dist < maxDist )
{
*result = check;
maxDist = dist;
}
}
if( !*result )
{
// this may happens if map
// doesn't have any cubemaps
*result = &world->defaultCubemap;
}
}
/*
=================
CL_FindNearestCubeMapForSurface
find the nearest cubemap on front of plane
=================
*/
void CL_FindNearestCubeMapForSurface( const Vector &pos, const msurface_t *surf, mcubemap_t **result )
{
if( !result ) return;
float maxDist = 99999.0f;
mplane_t plane;
*result = NULL;
plane = *surf->plane;
if( FBitSet( surf->flags, SURF_PLANEBACK ))
{
plane.normal = -plane.normal;
plane.dist = -plane.dist;
}
for( int i = 0; i < world->num_cubemaps; i++ )
{
mcubemap_t *check = &world->cubemaps[i];
float dist = VectorDistance( check->origin, pos );
if( dist < maxDist && PlaneDiff( check->origin, &plane ) >= 0.0f )
{
*result = check;
maxDist = dist;
}
}
if( *result ) return;
// fallback to default method
CL_FindNearestCubeMap( pos, result );
}
/*
=================
CL_FindTwoNearestCubeMap
find the two nearest cubemaps for a given point
=================
*/
void CL_FindTwoNearestCubeMap( const Vector &pos, mcubemap_t **result1, mcubemap_t **result2 )
{
if( !result1 || !result2 )
return;
float maxDist1 = 99999.0f;
float maxDist2 = 99999.0f;
*result1 = *result2 = NULL;
for( int i = 0; i < world->num_cubemaps; i++ )
{
mcubemap_t *check = &world->cubemaps[i];
float dist = VectorDistance( check->origin, pos );
if( dist < maxDist1 )
{
*result1 = check;
maxDist1 = dist;
}
else if( dist < maxDist2 && dist > maxDist1 )
{
*result2 = check;
maxDist2 = dist;
}
}
if( !*result1 )
{
// this may happens if map
// doesn't have any cubemaps
*result1 = &world->defaultCubemap;
}
if( !*result2 )
{
// this may happens if map
// doesn't have any cubemaps
*result2 = *result1;
}
}
/*
=================
CL_FindTwoNearestCubeMapForSurface
find the two nearest cubemaps on front of plane
=================
*/
void CL_FindTwoNearestCubeMapForSurface( const Vector &pos, const msurface_t *surf, mcubemap_t **result1, mcubemap_t **result2 )
{
if( !result1 || !result2 ) return;
float maxDist1 = 99999.0f;
float maxDist2 = 99999.0f;
mplane_t plane;
*result1 = NULL;
*result2 = NULL;
plane = *surf->plane;
if( FBitSet( surf->flags, SURF_PLANEBACK ))
{
plane.normal = -plane.normal;
plane.dist = -plane.dist;
}
for( int i = 0; i < world->num_cubemaps; i++ )
{
mcubemap_t *check = &world->cubemaps[i];
float dist = VectorDistance( check->origin, pos );
if( dist < maxDist1 && PlaneDiff( check->origin, &plane ) >= 0.0f )
{
*result1 = check;
maxDist1 = dist;
}
else if( dist < maxDist2 && dist > maxDist1 )
{
*result2 = check;
maxDist2 = dist;
}
}
if( *result1 )
{
if( !*result2 )
*result2 = *result1;
return;
}
// fallback to default method
CL_FindTwoNearestCubeMap( pos, result1, result2 );
}
/*
=================
CL_BuildCubemaps_f
force to rebuilds all the cubemaps
in the scene
=================
*/
void CL_BuildCubemaps_f( void )
{
mcubemap_t *m = &world->defaultCubemap;
FREE_TEXTURE( m->texture );
m->valid = m->texture = false;
for( int i = 0; i < world->num_cubemaps; i++ )
{
mcubemap_t *m = &world->cubemaps[i];
FREE_TEXTURE( m->texture );
m->valid = m->texture = false;
}
if( FBitSet( world->features, WORLD_HAS_SKYBOX ))
world->build_default_cubemap = true;
world->rebuilding_cubemaps = CMREBUILD_CHECKING;
world->loading_cubemaps = true;
}

253
cl_dll/render/gl_cull.cpp Normal file
View File

@ -0,0 +1,253 @@
/*
gl_cull.cpp - render culling routines
Copyright (C) 2011 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "hud.h"
#include "cl_util.h"
#include "gl_local.h"
#include "entity_types.h"
#include "mathlib.h"
#include "gl_world.h"
#include "gl_grass.h"
/*
=============
R_CullModel
=============
*/
bool R_CullModel( cl_entity_t *e, const Vector &absmin, const Vector &absmax )
{
if( e == GET_VIEWMODEL( ) || e == gHUD.m_pHeadShieldEnt )
{
if( RI->params & RP_NONVIEWERREF )
return true;
return false;
}
// don't reflect this entity in mirrors
if( FBitSet( e->curstate.effects, EF_NOREFLECT ) && FBitSet( RI->params, RP_MIRRORVIEW ))
return true;
// draw only in mirrors
if( FBitSet( e->curstate.effects, EF_REFLECTONLY ) && !FBitSet( RI->params, RP_MIRRORVIEW ))
return true;
// never draw playermodel for himself flashlight while shadowpass is active
if( FBitSet( RI->params, RP_SHADOWVIEW ) && RI->currentlight != NULL )
{
if( UTIL_IsLocal( e->index ) && RI->currentlight->key == FLASHLIGHT_KEY )
return true;
}
#if 0
// don't cull local player because we draw legs instead
if( RP_LOCALCLIENT( e ) && !FBitSet( RI->params, RP_THIRDPERSON ) && UTIL_IsLocal( RI->view.entity ))
{
// player can view himself from the portal camera
if( !FBitSet( RI->params, RP_MIRRORVIEW|RP_SHADOWVIEW ))
return true;
}
#endif
return R_CullBox( absmin, absmax );
}
/*
================
R_CullBrushModel
Cull brush model by bbox
================
*/
bool R_CullBrushModel( cl_entity_t *e )
{
gl_state_t *glm = GL_GetCache( e->hCachedMatrix );
model_t *clmodel = e->model;
Vector absmin, absmax;
if( !e || !e->model )
return true;
// skybox entity
if( e->curstate.renderfx == SKYBOX_ENTITY )
{
if( FBitSet( RI->params, RP_SHADOWVIEW ))
return true;
Vector trans = GetVieworg() - tr.sky_origin;
if( tr.sky_speed )
{
trans = trans - (GetVieworg() - tr.sky_world_origin) / tr.sky_speed;
Vector skypos = tr.sky_origin + (GetVieworg() - tr.sky_world_origin) / tr.sky_speed;
tr.modelorg = skypos - e->origin;
}
else tr.modelorg = tr.sky_origin - e->origin;
absmin = e->origin + trans + clmodel->mins;
absmax = e->origin + trans + clmodel->maxs;
}
else
{
if( e->angles != g_vecZero )
{
absmin = e->origin - clmodel->radius;
absmax = e->origin + clmodel->radius;
}
else
{
absmin = e->origin + clmodel->mins;
absmax = e->origin + clmodel->maxs;
}
tr.modelorg = glm->GetModelOrigin();
}
return R_CullModel( e, absmin, absmax );
}
static bool R_SunLightShadow( void )
{
if( RI->currentlight && RI->currentlight->type == LIGHT_DIRECTIONAL && FBitSet( RI->params, RP_SHADOWVIEW ))
return true;
return false;
}
/*
=================
R_AllowFacePlaneCulling
allow to culling backfaces
=================
*/
static bool R_AllowFacePlaneCulling( msurface_t *surf )
{
if( !glState.faceCull )
return false;
if( FBitSet( surf->flags, SURF_TWOSIDE ))
return false;
if( !FBitSet( RI->params, RP_SHADOWVIEW ) && RI->currentlight && RI->currentlight->type == LIGHT_DIRECTIONAL )
return false;
// don't cull transparent surfaces because we should be draw decals on them
if( FBitSet( surf->flags, SURF_HAS_DECALS ) && !R_OpaqueEntity( RI->currententity ))
return false;
return true;
}
/*
=================
R_CullSurface
cull invisible surfaces
=================
*/
int R_CullSurface( msurface_t *surf, const Vector &vieworg, CFrustum *frustum, int clipFlags )
{
cl_entity_t *e = RI->currententity;
if( !surf || !surf->texinfo || !surf->texinfo->texture )
return CULL_OTHER;
if( FBitSet( RI->params, RP_WATERPASS ) && R_WaterEntity( e->model ))
return CULL_OTHER; // don't render water from waterplane reflection
if( CVAR_TO_BOOL( r_nocull ))
return CULL_VISIBLE;
if( R_SunLightShadow( ))
return CULL_VISIBLE;
// because light or shadow passes required both sides for right self-shadowing
if( R_AllowFacePlaneCulling( surf ))
{
float dist;
// can use normal.z for world (optimisation)
if( FBitSet( RI->params, RP_DRAW_OVERVIEW ))
{
Vector orthonormal;
if( e == GET_ENTITY( 0 ) || R_StaticEntity( e ))
{
orthonormal.z = surf->plane->normal.z;
}
else
{
matrix4x4 m = matrix4x4( g_vecZero, e->angles );
orthonormal = m.VectorRotate( surf->plane->normal );
}
dist = orthonormal.z;
}
else dist = PlaneDiff( vieworg, surf->plane );
if( glState.faceCull == GL_FRONT || ( RI->params & RP_MIRRORVIEW ))
{
if( surf->flags & SURF_PLANEBACK )
{
if( dist >= -BACKFACE_EPSILON )
return CULL_BACKSIDE; // wrong side
}
else
{
if( dist <= BACKFACE_EPSILON )
return CULL_BACKSIDE; // wrong side
}
}
else if( glState.faceCull == GL_BACK )
{
if( surf->flags & SURF_PLANEBACK )
{
if( dist <= BACKFACE_EPSILON )
return CULL_BACKSIDE; // wrong side
}
else
{
if( dist >= -BACKFACE_EPSILON )
return CULL_BACKSIDE; // wrong side
}
}
}
if( frustum && frustum->CullBox( surf->info->mins, surf->info->maxs, clipFlags ))
return CULL_FRUSTUM;
return CULL_VISIBLE;
}
/*
================
R_CullNodeTopView
cull node by user rectangle (simple scissor)
================
*/
bool R_CullNodeTopView( mnode_t *node )
{
Vector2D delta, size;
Vector center, half, mins, maxs;
// build the node center and half-diagonal
mins = node->minmaxs, maxs = node->minmaxs + 3;
center = (mins + maxs) * 0.5f;
half = maxs - center;
// cull against the screen frustum or the appropriate area's frustum.
delta.x = center.x - world->orthocenter.x;
delta.y = center.y - world->orthocenter.y;
size.x = half.x + world->orthohalf.x;
size.y = half.y + world->orthohalf.y;
return ( fabs( delta.x ) > size.x ) || ( fabs( delta.y ) > size.y );
}

576
cl_dll/render/gl_debug.cpp Normal file
View File

@ -0,0 +1,576 @@
//
// written by BUzer for HL: Paranoia modification
//
// 2006
#include "hud.h"
#include "cl_util.h"
#include "const.h"
#include "com_model.h"
#include "r_studioint.h"
#include "ref_params.h"
#include "r_efx.h"
#include "event_api.h"
#include "pm_defs.h"
#include "pmtrace.h"
#include "triangleapi.h"
#include "gl_local.h"
#include "stringlib.h"
#include "gl_world.h"
#include "gl_shader.h"
#include "vertex_fmt.h"
void GL_GpuMemUsage_f( void )
{
GLint cur_avail_mem_kb = 0;
GLint total_mem_kb = 0;
if( glConfig.hardware_type == GLHW_NVIDIA )
{
pglGetIntegerv( GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX, &total_mem_kb );
pglGetIntegerv( GL_GPU_MEM_INFO_CURRENT_AVAILABLE_MEM_NVX, &cur_avail_mem_kb );
}
Msg( "TEX used memory %s\n", Q_memprint( RENDER_GET_PARM( PARM_TEX_MEMORY, 0 )));
Msg( "VBO used memory %s\n", Q_memprint( tr.total_vbo_memory ));
Msg( "GPU used memory %s\n", Q_memprint(( total_mem_kb - cur_avail_mem_kb ) * 1024 ));
}
void DBG_PrintVertexVBOSizes( void )
{
if( developer_level < at_aiconsole )
return;
ALERT( at_console, "sizeof( bvert_v0_gl21_t ) == %d bytes\n", sizeof( bvert_v0_gl21_t ));
ALERT( at_console, "sizeof( bvert_v0_gl30_t ) == %d bytes\n", sizeof( bvert_v0_gl30_t ));
ALERT( at_console, "sizeof( gvert_v0_gl21_t ) == %d bytes\n", sizeof( gvert_v0_gl21_t ));
ALERT( at_console, "sizeof( gvert_v0_gl30_t ) == %d bytes\n", sizeof( gvert_v0_gl30_t ));
ALERT( at_console, "sizeof( gvert_v1_gl21_t ) == %d bytes\n", sizeof( gvert_v1_gl21_t ));
ALERT( at_console, "sizeof( gvert_v1_gl30_t ) == %d bytes\n", sizeof( gvert_v1_gl30_t ));
ALERT( at_console, "sizeof( svert_v0_gl21_t ) == %d bytes\n", sizeof( svert_v0_gl21_t ));
ALERT( at_console, "sizeof( svert_v0_gl30_t ) == %d bytes\n", sizeof( svert_v0_gl30_t ));
ALERT( at_console, "sizeof( svert_v1_gl21_t ) == %d bytes\n", sizeof( svert_v1_gl21_t ));
ALERT( at_console, "sizeof( svert_v1_gl30_t ) == %d bytes\n", sizeof( svert_v1_gl30_t ));
ALERT( at_console, "sizeof( svert_v2_gl21_t ) == %d bytes\n", sizeof( svert_v2_gl21_t ));
ALERT( at_console, "sizeof( svert_v2_gl30_t ) == %d bytes\n", sizeof( svert_v2_gl30_t ));
ALERT( at_console, "sizeof( svert_v3_gl21_t ) == %d bytes\n", sizeof( svert_v3_gl21_t ));
ALERT( at_console, "sizeof( svert_v3_gl30_t ) == %d bytes\n", sizeof( svert_v3_gl30_t ));
ALERT( at_console, "sizeof( svert_v4_gl21_t ) == %d bytes\n", sizeof( svert_v4_gl21_t ));
ALERT( at_console, "sizeof( svert_v4_gl30_t ) == %d bytes\n", sizeof( svert_v4_gl30_t ));
ALERT( at_console, "sizeof( svert_v5_gl21_t ) == %d bytes\n", sizeof( svert_v5_gl21_t ));
ALERT( at_console, "sizeof( svert_v5_gl30_t ) == %d bytes\n", sizeof( svert_v5_gl30_t ));
ALERT( at_console, "sizeof( svert_v6_gl21_t ) == %d bytes\n", sizeof( svert_v6_gl21_t ));
ALERT( at_console, "sizeof( svert_v6_gl30_t ) == %d bytes\n", sizeof( svert_v6_gl30_t ));
ALERT( at_console, "sizeof( svert_v7_gl21_t ) == %d bytes\n", sizeof( svert_v7_gl21_t ));
ALERT( at_console, "sizeof( svert_v7_gl30_t ) == %d bytes\n", sizeof( svert_v7_gl30_t ));
ALERT( at_console, "sizeof( svert_v8_gl21_t ) == %d bytes\n", sizeof( svert_v8_gl21_t ));
ALERT( at_console, "sizeof( svert_v8_gl30_t ) == %d bytes\n", sizeof( svert_v8_gl30_t ));
}
// some simple helpers to draw a cube in the special way the ambient visualization wants
static float *CubeSide( const vec3_t pos, float size, int vert )
{
static vec3_t side;
VectorCopy( pos, side );
side[0] += (vert & 1) ? -size : size;
side[1] += (vert & 2) ? -size : size;
side[2] += (vert & 4) ? -size : size;
return side;
}
static void CubeFace( const vec3_t org, int v0, int v1, int v2, int v3, float size, const byte *color )
{
uint scale = tr.lightstyle[0];
uint unclamped[3];
int col[3];
unclamped[0] = TEXTURE_TO_TEXGAMMA( color[0] ) * scale;
unclamped[1] = TEXTURE_TO_TEXGAMMA( color[1] ) * scale;
unclamped[2] = TEXTURE_TO_TEXGAMMA( color[2] ) * scale;
col[0] = min((unclamped[0] >> 7), 255 );
col[1] = min((unclamped[1] >> 7), 255 );
col[2] = min((unclamped[2] >> 7), 255 );
// pglColor3ub( col[0], col[1], col[2] );
pglColor3ub( color[0], color[1], color[2] );
pglVertex3fv( CubeSide( org, size, v0 ));
pglVertex3fv( CubeSide( org, size, v1 ));
pglVertex3fv( CubeSide( org, size, v2 ));
pglVertex3fv( CubeSide( org, size, v3 ));
}
void R_RenderLightProbe( mlightprobe_t *probe )
{
float rad = 4.0f;
pglBegin( GL_QUADS );
CubeFace( probe->origin, 4, 6, 2, 0, rad, probe->cube.color[0] );
CubeFace( probe->origin, 7, 5, 1, 3, rad, probe->cube.color[1] );
CubeFace( probe->origin, 0, 1, 5, 4, rad, probe->cube.color[2] );
CubeFace( probe->origin, 3, 2, 6, 7, rad, probe->cube.color[3] );
CubeFace( probe->origin, 2, 3, 1, 0, rad, probe->cube.color[4] );
CubeFace( probe->origin, 4, 5, 7, 6, rad, probe->cube.color[5] );
pglEnd ();
}
void R_RenderCubemap( mcubemap_t *cube )
{
float rad = (float)cube->size * 0.1f;
byte color[3] = { 127, 127, 127 };
pglBegin( GL_QUADS );
CubeFace( cube->origin, 4, 6, 2, 0, rad, color );
CubeFace( cube->origin, 7, 5, 1, 3, rad, color );
CubeFace( cube->origin, 0, 1, 5, 4, rad, color );
CubeFace( cube->origin, 3, 2, 6, 7, rad, color );
CubeFace( cube->origin, 2, 3, 1, 0, rad, color );
CubeFace( cube->origin, 4, 5, 7, 6, rad, color );
pglEnd ();
}
void R_RenderLightProbeInternal( const Vector &origin, const Vector lightCube[] )
{
mlightprobe_t probe;
for( int i = 0; i < 6; i++ )
{
probe.cube.color[i][0] = lightCube[i].x * 255;
probe.cube.color[i][1] = lightCube[i].y * 255;
probe.cube.color[i][2] = lightCube[i].z * 255;
}
probe.origin = origin;
R_RenderLightProbe( &probe );
}
/*
===============
R_DrawAABB
===============
*/
static void R_DrawAABB( const Vector &absmin, const Vector &absmax, int contents )
{
vec3_t bbox[8];
int i;
// compute a full bounding box
for( i = 0; i < 8; i++ )
{
bbox[i][0] = ( i & 1 ) ? absmin[0] : absmax[0];
bbox[i][1] = ( i & 2 ) ? absmin[1] : absmax[1];
bbox[i][2] = ( i & 4 ) ? absmin[2] : absmax[2];
}
GL_BindTexture( GL_TEXTURE0, tr.whiteTexture );
pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
pglDisable( GL_DEPTH_TEST );
switch( contents )
{
case CONTENTS_EMPTY:
pglColor4f( 0.5f, 1.0f, 0.0f, 1.0f ); // green for empty
break;
case CONTENTS_SOLID:
pglColor4f( 1.0f, 0.0f, 0.0f, 1.0f ); // red for solid
break;
case CONTENTS_WATER:
pglColor4f( 0.0f, 0.5f, 1.0f, 1.0f ); // blue for water
break;
default:
pglColor4f( 0.5f, 0.5f, 0.5f, 1.0f ); // gray as default
break;
}
pglBegin( GL_LINES );
for( i = 0; i < 2; i += 1 )
{
pglVertex3fv( bbox[i+0] );
pglVertex3fv( bbox[i+2] );
pglVertex3fv( bbox[i+4] );
pglVertex3fv( bbox[i+6] );
pglVertex3fv( bbox[i+0] );
pglVertex3fv( bbox[i+4] );
pglVertex3fv( bbox[i+2] );
pglVertex3fv( bbox[i+6] );
pglVertex3fv( bbox[i*2+0] );
pglVertex3fv( bbox[i*2+1] );
pglVertex3fv( bbox[i*2+4] );
pglVertex3fv( bbox[i*2+5] );
}
pglEnd();
pglEnable( GL_DEPTH_TEST );
}
/*
===============
R_RenderVisibleLeafs
===============
*/
static void R_RenderVisibleLeafs( void )
{
mleaf_t *leaf;
int i;
// always skip the leaf 0, because is outside leaf
for( i = 1, leaf = &worldmodel->leafs[1]; i < worldmodel->numleafs + 1; i++, leaf++ )
{
mextraleaf_t *eleaf = LEAF_INFO( leaf, worldmodel );
if( CHECKVISBIT( RI->view.pvsarray, leaf->cluster ) && ( leaf->efrags || leaf->nummarksurfaces ))
{
R_DrawAABB( eleaf->mins, eleaf->maxs, CONTENTS_WATER );
R_DrawAABB( Vector( leaf->minmaxs ), Vector( leaf->minmaxs + 3 ), leaf->contents );
}
}
}
/*
=============
DrawViewLeaf
=============
*/
void DrawViewLeaf( void )
{
if( !CVAR_TO_BOOL( r_show_viewleaf ))
return;
GL_Blend( GL_FALSE );
R_RenderVisibleLeafs();
}
/*
=============
DrawLightProbes
=============
*/
void DrawLightProbes( void )
{
int i, j;
mlightprobe_t *probe;
mleaf_t *leaf;
mextraleaf_t *info;
if( !CVAR_TO_BOOL( r_show_lightprobes ))
return;
GL_Blend( GL_FALSE );
GL_BindTexture( GL_TEXTURE0, tr.whiteTexture );
pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
// draw the all visible probes
for( i = 1; i < world->numleafs; i++ )
{
leaf = (mleaf_t *)&worldmodel->leafs[i];
info = LEAF_INFO( leaf, worldmodel );
if( !CHECKVISBIT( RI->view.pvsarray, leaf->cluster ))
continue; // not visible from player
for( j = 0; j < info->num_lightprobes; j++ )
{
probe = info->ambient_light + j;
R_RenderLightProbe( probe );
}
}
pglColor3f( 1.0f, 1.0f, 1.0f );
}
/*
=============
DrawCubeMaps
=============
*/
void DrawCubeMaps( void )
{
mcubemap_t *cm;
if( !CVAR_TO_BOOL( r_show_cubemaps ))
return;
GL_Blend( GL_FALSE );
GL_BindTexture( GL_TEXTURE0, tr.whiteTexture );
pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
// draw the all cubemaps
for( int i = 0; i < world->num_cubemaps; i++ )
{
cm = &world->cubemaps[i];
R_RenderCubemap( cm );
}
pglColor3f( 1.0f, 1.0f, 1.0f );
}
void DBG_DrawBBox( const Vector &mins, const Vector &maxs )
{
Vector bbox[8];
int i;
for( i = 0; i < 8; i++ )
{
bbox[i][0] = ( i & 1 ) ? mins[0] : maxs[0];
bbox[i][1] = ( i & 2 ) ? mins[1] : maxs[1];
bbox[i][2] = ( i & 4 ) ? mins[2] : maxs[2];
}
pglColor4f( 1.0f, 0.0f, 1.0f, 1.0f ); // yellow bboxes for frustum
GL_BindTexture( GL_TEXTURE0, tr.whiteTexture );
pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
pglBegin( GL_LINES );
for( i = 0; i < 2; i += 1 )
{
pglVertex3fv( bbox[i+0] );
pglVertex3fv( bbox[i+2] );
pglVertex3fv( bbox[i+4] );
pglVertex3fv( bbox[i+6] );
pglVertex3fv( bbox[i+0] );
pglVertex3fv( bbox[i+4] );
pglVertex3fv( bbox[i+2] );
pglVertex3fv( bbox[i+6] );
pglVertex3fv( bbox[i*2+0] );
pglVertex3fv( bbox[i*2+1] );
pglVertex3fv( bbox[i*2+4] );
pglVertex3fv( bbox[i*2+5] );
}
pglEnd();
}
void DBG_DrawLightFrustum( void )
{
if( CVAR_TO_BOOL( r_scissor_light_debug ) && RP_NORMALPASS( ))
{
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
for( int i = 0; i < MAX_DLIGHTS; i++ )
{
CDynLight *pl = &tr.dlights[i];
if( !pl->Active( )) continue;
if( r_scissor_light_debug->value == 1.0f )
{
R_DrawScissorRectangle( pl->x, pl->y, pl->w, pl->h );
}
else if( r_scissor_light_debug->value == 2.0f )
{
if( pl->type == LIGHT_DIRECTIONAL )
{
for( int j = 0; j < NUM_SHADOW_SPLITS + 1; j++ )
pl->splitFrustum[j].DrawFrustumDebug();
}
else pl->frustum.DrawFrustumDebug();
}
else
{
DBG_DrawBBox( pl->absmin, pl->absmax );
}
}
}
}
void DBG_DrawGlassScissors( void )
{
if( CVAR_TO_BOOL( r_scissor_glass_debug ) && RP_NORMALPASS( ))
{
// debug scissor code
GL_BindShader( NULL );
// debug scissor code
for( int k = 0; k < RI->frame.trans_list.Count(); k++ )
{
CTransEntry *entry = &RI->frame.trans_list[k];
entry->RenderScissorDebug();
}
}
}
/*
================
DrawTangentSpaces
Draws vertex tangent spaces for debugging
================
*/
void DrawTangentSpaces( void )
{
float temp[3];
float vecLen = 4.0f;
if( !CVAR_TO_BOOL( cv_show_tbn ))
return;
GL_BindTexture( GL_TEXTURE0, tr.whiteTexture );
pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
pglDisable( GL_DEPTH_TEST );
GL_Blend( GL_FALSE );
pglBegin( GL_LINES );
for( int i = 0; i < worldmodel->nummodelsurfaces; i++ )
{
msurface_t *surf = &worldmodel->surfaces[i];
mextrasurf_t *esrf = surf->info;
if( FBitSet( surf->flags, SURF_DRAWTURB|SURF_DRAWSKY ))
continue;
bvert_t *mv = &world->vertexes[esrf->firstvertex];
for( int j = 0; j < esrf->numverts; j++, mv++ )
{
pglColor3f( 1.0f, 0.0f, 0.0f );
pglVertex3fv( mv->vertex );
VectorMA( mv->vertex, vecLen, Vector( mv->tangent ), temp );
pglVertex3fv( temp );
pglColor3f( 0.0f, 1.0f, 0.0f );
pglVertex3fv( mv->vertex );
VectorMA( mv->vertex, vecLen, Vector( mv->binormal ), temp );
pglVertex3fv( temp );
pglColor3f( 0.0f, 0.0f, 1.0f );
pglVertex3fv( mv->vertex );
VectorMA( mv->vertex, vecLen, Vector( mv->normal ), temp );
pglVertex3fv( temp );
}
}
pglEnd();
pglEnable( GL_DEPTH_TEST );
}
void DrawWireFrame( void )
{
int i;
if( !CVAR_TO_BOOL( r_wireframe ))
return;
pglEnable( GL_BLEND );
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
pglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
pglColor4f( 1.0f, 1.0f, 1.0f, 0.99f );
pglDisable( GL_DEPTH_TEST );
pglEnable( GL_LINE_SMOOTH );
GL_BindTexture( GL_TEXTURE0, tr.whiteTexture );
pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
pglEnable( GL_POLYGON_SMOOTH );
pglHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
pglHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
for( i = 0; i < RI->frame.solid_faces.Count(); i++ )
{
if( RI->frame.solid_faces[i].m_bDrawType != DRAWTYPE_SURFACE )
continue;
msurface_t *surf = RI->frame.solid_faces[i].m_pSurf;
mextrasurf_t *es = surf->info;
pglBegin( GL_POLYGON );
for( int j = 0; j < es->numverts; j++ )
{
bvert_t *v = &world->vertexes[es->firstvertex + j];
pglVertex3fv( v->vertex + Vector( v->normal ) * 0.1f );
}
pglEnd();
}
pglColor4f( 0.0f, 1.0f, 0.0f, 0.99f );
for( i = 0; i < RI->frame.trans_list.Count(); i++ )
{
if( RI->frame.trans_list[i].m_bDrawType != DRAWTYPE_SURFACE )
continue;
msurface_t *surf = RI->frame.trans_list[i].m_pSurf;
mextrasurf_t *es = surf->info;
pglBegin( GL_POLYGON );
for( int j = 0; j < es->numverts; j++ )
{
bvert_t *v = &world->vertexes[es->firstvertex + j];
pglVertex3fv( v->vertex + Vector( v->normal ) * 0.1f );
}
pglEnd();
}
pglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
pglDisable( GL_POLYGON_SMOOTH );
pglDisable( GL_LINE_SMOOTH );
pglEnable( GL_DEPTH_TEST );
pglDisable( GL_BLEND );
}
void DrawWirePoly( msurface_t *surf )
{
if( !surf ) return;
pglEnable( GL_BLEND );
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
pglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
pglColor4f( 0.5f, 1.0f, 0.36f, 0.99f );
pglLineWidth( 4.0f );
pglDisable( GL_DEPTH_TEST );
pglEnable( GL_LINE_SMOOTH );
pglEnable( GL_POLYGON_SMOOTH );
pglHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
pglHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
mextrasurf_t *es = surf->info;
pglBegin( GL_POLYGON );
for( int j = 0; j < es->numverts; j++ )
{
bvert_t *v = &world->vertexes[es->firstvertex + j];
pglVertex3fv( v->vertex + Vector( v->normal ) * 0.1f );
}
pglEnd();
pglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
pglDisable( GL_POLYGON_SMOOTH );
pglDisable( GL_LINE_SMOOTH );
pglEnable( GL_DEPTH_TEST );
pglDisable( GL_BLEND );
pglLineWidth( 1.0f );
}
void R_ShowLightMaps( void )
{
int index = 0;
if( !CVAR_TO_BOOL( r_showlightmaps ))
return;
index = r_showlightmaps->value - 1.0f;
if( tr.lightmaps[index].state == LM_FREE )
return;
GL_BindTexture( GL_TEXTURE0, tr.lightmaps[index].lightmap );
pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
GL_Setup2D();
pglBegin( GL_QUADS );
pglTexCoord2f( 0.0f, 0.0f );
pglVertex2f( 0.0f, 0.0f );
pglTexCoord2f( 1.0f, 0.0f );
pglVertex2f( glState.width, 0.0f );
pglTexCoord2f( 1.0f, 1.0f );
pglVertex2f( glState.width, glState.height );
pglTexCoord2f( 0.0f, 1.0f );
pglVertex2f( 0.0f, glState.height );
pglEnd();
GL_Setup3D();
}

1973
cl_dll/render/gl_decals.cpp Normal file

File diff suppressed because it is too large Load Diff

105
cl_dll/render/gl_decals.h Normal file
View File

@ -0,0 +1,105 @@
/*
gl_decals.h - decal project & rendering
this code written for Paranoia 2: Savior modification
Copyright (C) 2013 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef GL_DECALS_H
#define GL_DECALS_H
class DecalGroup;
class DecalGroupEntry
{
public:
char m_DecalName[64];
unsigned short gl_diffuse_id;
unsigned short gl_normalmap_id;
unsigned short gl_heightmap_id;
unsigned short gl_specular_id; // specular
int xsize, ysize;
matdesc_t *matdesc; // pointer to settings
float overlay;
bool opaque; // solid decal doesn't use blend
const DecalGroup *group; // get group name
bool m_init;
void PreloadTextures( void );
};
class DecalGroup
{
public:
DecalGroup( const char *name, int numelems, DecalGroupEntry *source );
~DecalGroup();
DecalGroupEntry *GetRandomDecal( void );
DecalGroup *GetNext( void ) { return pnext; }
const char *GetName( void ) { return m_chGroupName; }
const char *GetName( void ) const { return m_chGroupName; }
static DecalGroup *FindGroup( const char *name );
DecalGroupEntry *FindEntry( const char *name );
DecalGroupEntry *GetEntry( int num );
static DecalGroupEntry *GetEntry( const char *name, int flags );
private:
char m_chGroupName[16];
DecalGroupEntry *pEntryArray;
DecalGroup *pnext;
int size;
};
typedef struct dvert_s
{
Vector vertex; // position
Vector tangent; // tangent
Vector binormal; // binormal
Vector normal; // normal
float stcoord0[4]; // ST texture coords + Decal coords
float lmcoord0[4]; // LM texture coords for styles 0-1
float lmcoord1[4]; // LM texture coords for styles 2-3
byte styles[4]; // lightstyles
} dvert_t;
// decal entry
typedef struct brushdecal_s
{
// this part is goes to savelist
byte flags;
short entityIndex;
Vector position;
Vector impactPlaneNormal;
float angle; // goes into scale
const DecalGroupEntry *texinfo;
// verts & elems
dvert_t *verts; // pointer to cache array
word *elems; // pointer to index array
byte numVerts;
byte numElems;
// shader cache
shader_t forwardScene;
shader_t deferredScene;
mextrasurf_t *surface;
struct brushdecal_s *pnext; // linked list for each surface
model_t *model;
} brushdecal_t;
void DecalsInit( void );
void ClearDecals( void );
void DecalsShutdown( void );
void R_RenderDecalsSolidList( drawlist_t drawlist_type );
void R_RenderDecalsTransList( drawlist_t drawlist_type );
void R_RenderDecalsTransEntry( CTransEntry *entry, drawlist_t drawlist_type );
int SaveDecalList( decallist_t *pBaseList, int count );
#endif//GL_DECALS_H

View File

@ -0,0 +1,554 @@
/*
gl_deferred.cpp - deferred rendering
Copyright (C) 2018 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "hud.h"
#include "cl_util.h"
#include "gl_local.h"
#include "gl_shader.h"
#include "gl_world.h"
#include "gl_grass.h"
enum
{
SCENE_PASS = 0,
LIGHT_PASS,
};
enum
{
BILATERAL_PASS0 = 0,
BILATERAL_PASS1,
};
void GL_InitDefSceneFBO( void )
{
GLenum MRTBuffers[5] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_COLOR_ATTACHMENT3_EXT, GL_COLOR_ATTACHMENT4_EXT };
int albedo_buffer;
int normal_buffer;
int smooth_buffer;
int light0_buffer;
int light1_buffer;
int depth_buffer;
if( !GL_Support( R_FRAMEBUFFER_OBJECT ) || !GL_Support( R_DRAW_BUFFERS_EXT ))
return;
// Create and set up the framebuffer
tr.defscene_fbo = GL_AllocDrawbuffer( "*defscene", glState.width, glState.height, 1 );
// create textures
albedo_buffer = CREATE_TEXTURE( "*albedo_rt", glState.width, glState.height, NULL, TF_RT_COLOR|TF_HAS_ALPHA );
normal_buffer = CREATE_TEXTURE( "*normal_rt", glState.width, glState.height, NULL, TF_RT_NORMAL|TF_HAS_ALPHA );
smooth_buffer = CREATE_TEXTURE( "*smooth_rt", glState.width, glState.height, NULL, TF_RT_COLOR|TF_HAS_ALPHA );
light0_buffer = CREATE_TEXTURE( "*light0_rt", glState.width, glState.height, NULL, TF_RT_COLOR|TF_HAS_ALPHA );
light1_buffer = CREATE_TEXTURE( "*light1_rt", glState.width, glState.height, NULL, TF_RT_COLOR|TF_HAS_ALPHA );
depth_buffer = CREATE_TEXTURE( "*depth_rt", glState.width, glState.height, NULL, TF_RT_DEPTH );
GL_AttachColorTextureToFBO( tr.defscene_fbo, albedo_buffer, 0 );
GL_AttachColorTextureToFBO( tr.defscene_fbo, normal_buffer, 1 );
GL_AttachColorTextureToFBO( tr.defscene_fbo, smooth_buffer, 2 );
GL_AttachColorTextureToFBO( tr.defscene_fbo, light0_buffer, 3 );
GL_AttachColorTextureToFBO( tr.defscene_fbo, light1_buffer, 4 );
GL_AttachDepthTextureToFBO( tr.defscene_fbo, depth_buffer );
pglDrawBuffersARB( ARRAYSIZE( MRTBuffers ), MRTBuffers );
pglReadBuffer( GL_NONE );
// check the framebuffer status
GL_CheckFBOStatus( tr.defscene_fbo );
}
void GL_VidInitDefSceneFBO( void )
{
// resize attached textures
GL_ResizeDrawbuffer( tr.defscene_fbo, glState.width, glState.height, 1 );
GL_AttachColorTextureToFBO( tr.defscene_fbo, tr.defscene_fbo->colortarget[0], 0 );
GL_AttachColorTextureToFBO( tr.defscene_fbo, tr.defscene_fbo->colortarget[1], 1 );
GL_AttachColorTextureToFBO( tr.defscene_fbo, tr.defscene_fbo->colortarget[2], 2 );
GL_AttachColorTextureToFBO( tr.defscene_fbo, tr.defscene_fbo->colortarget[3], 3 );
GL_AttachColorTextureToFBO( tr.defscene_fbo, tr.defscene_fbo->colortarget[4], 4 );
GL_AttachDepthTextureToFBO( tr.defscene_fbo, tr.defscene_fbo->depthtarget );
}
void GL_InitDefLightFBO( void )
{
GLenum MRTBuffers[3] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT };
int normal_buffer;
int light0_buffer;
int light1_buffer;
int depth_buffer;
if( !GL_Support( R_FRAMEBUFFER_OBJECT ) || !GL_Support( R_DRAW_BUFFERS_EXT ))
return;
// Create and set up the framebuffer
tr.deflight_fbo = GL_AllocDrawbuffer( "*deflight", glState.defWidth, glState.defHeight, 1 );
// create textures
normal_buffer = CREATE_TEXTURE( "*normal_rs", glState.defWidth, glState.defHeight, NULL, TF_RT_NORMAL|TF_HAS_ALPHA );
light0_buffer = CREATE_TEXTURE( "*light0_rs", glState.defWidth, glState.defHeight, NULL, TF_RT_COLOR|TF_HAS_ALPHA );
light1_buffer = CREATE_TEXTURE( "*light1_rs", glState.defWidth, glState.defHeight, NULL, TF_RT_COLOR|TF_HAS_ALPHA );
depth_buffer = CREATE_TEXTURE( "*depth_rs", glState.defWidth, glState.defHeight, NULL, TF_RT_DEPTH );
GL_AttachColorTextureToFBO( tr.deflight_fbo, normal_buffer, 0 );
GL_AttachColorTextureToFBO( tr.deflight_fbo, light0_buffer, 1 );
GL_AttachColorTextureToFBO( tr.deflight_fbo, light1_buffer, 2 );
GL_AttachDepthTextureToFBO( tr.deflight_fbo, depth_buffer );
pglDrawBuffersARB( ARRAYSIZE( MRTBuffers ), MRTBuffers );
pglReadBuffer( GL_NONE );
// check the framebuffer status
GL_CheckFBOStatus( tr.deflight_fbo );
}
void GL_VidInitDefLightFBO( void )
{
// resize attached textures
GL_ResizeDrawbuffer( tr.deflight_fbo, glState.defWidth, glState.defHeight, 1 );
GL_AttachColorTextureToFBO( tr.deflight_fbo, tr.deflight_fbo->colortarget[0], 0 );
GL_AttachColorTextureToFBO( tr.deflight_fbo, tr.deflight_fbo->colortarget[1], 1 );
GL_AttachColorTextureToFBO( tr.deflight_fbo, tr.deflight_fbo->colortarget[2], 2 );
GL_AttachDepthTextureToFBO( tr.deflight_fbo, tr.deflight_fbo->depthtarget );
}
void GL_VidInitDrawBuffers( void )
{
if( tr.defscene_fbo == NULL )
GL_InitDefSceneFBO();
else GL_VidInitDefSceneFBO();
if( tr.deflight_fbo == NULL )
GL_InitDefLightFBO();
else GL_VidInitDefLightFBO();
// unbind the framebuffer
GL_BindDrawbuffer( NULL );
}
void GL_SetupGBuffer( void )
{
// bind geometry fullscreen buffer
if( FBitSet( RI->params, RP_DEFERREDSCENE ))
GL_BindDrawbuffer( tr.defscene_fbo );
// bind light-pass downscaled buffer
if( FBitSet( RI->params, RP_DEFERREDLIGHT ))
GL_BindDrawbuffer( tr.deflight_fbo );
R_Clear( ~0 );
}
void GL_ResetGBuffer( void )
{
GL_BindDrawbuffer( NULL );
}
void GL_DrawScreenSpaceQuad( const vec3_t normals[4] )
{
pglBegin( GL_QUADS );
pglTexCoord2f( 0.0f, 1.0f );
pglNormal3fv( normals[0] );
pglVertex2f( 0.0f, 0.0f );
pglTexCoord2f( 1.0f, 1.0f );
pglNormal3fv( normals[3] );
pglVertex2f( RI->view.port[2], 0.0f );
pglTexCoord2f( 1.0f, 0.0f );
pglNormal3fv( normals[2] );
pglVertex2f( RI->view.port[2], RI->view.port[3] );
pglTexCoord2f( 0.0f, 0.0f );
pglNormal3fv( normals[1] );
pglVertex2f( 0.0f, RI->view.port[3] );
pglEnd();
}
/*
=================
GL_Setup2D
=================
*/
void GL_SetupDeferred( void )
{
// set up full screen workspace
pglMatrixMode( GL_PROJECTION );
pglLoadIdentity();
pglOrtho( 0, RI->view.port[2], RI->view.port[3], 0, -99999, 99999 );
pglMatrixMode( GL_MODELVIEW );
pglLoadIdentity();
GL_AlphaTest( GL_FALSE );
GL_DepthMask( GL_FALSE );
pglDisable( GL_DEPTH_TEST ); // older dirvers has issues with this
if( RI->currentlight != NULL )
{
GL_Blend( GL_TRUE );
pglBlendFunc( GL_ONE, GL_ONE );
}
else
{
GL_Blend( GL_FALSE );
}
GL_Cull( GL_FRONT );
pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
pglViewport( 0, 0, RI->view.port[2], RI->view.port[3] );
}
static void GL_DrawDeferred( word hProgram, int pass )
{
if( hProgram <= 0 )
{
GL_BindShader( NULL );
return; // bad shader?
}
// prepare deferred pass
GL_SetupDeferred();
if( RI->currentshader != &glsl_programs[hProgram] )
{
// force to bind new shader
GL_BindShader( &glsl_programs[hProgram] );
}
glsl_program_t *shader = RI->currentshader;
CDynLight *pl = RI->currentlight; // may be NULL
Vector4D lightdir;
float *v;
// setup specified uniforms (and texture bindings)
for( int i = 0; i < shader->numUniforms; i++ )
{
uniform_t *u = &shader->uniforms[i];
switch( u->type )
{
case UT_COLORMAP:
u->SetValue( tr.defscene_fbo->colortarget[0] );
break;
case UT_NORMALMAP:
if( pass == LIGHT_PASS )
u->SetValue( tr.deflight_fbo->colortarget[0] );
else u->SetValue( tr.defscene_fbo->colortarget[1] );
break;
case UT_GLOSSMAP:
u->SetValue( tr.defscene_fbo->colortarget[2] );
break;
case UT_VISLIGHTMAP0:
if( pass == LIGHT_PASS )
u->SetValue( tr.deflight_fbo->colortarget[1] );
else u->SetValue( tr.defscene_fbo->colortarget[3] );
break;
case UT_VISLIGHTMAP1:
if( pass == LIGHT_PASS )
u->SetValue( tr.deflight_fbo->colortarget[2] );
else u->SetValue( tr.defscene_fbo->colortarget[4] );
break;
case UT_DEPTHMAP:
if( pass == LIGHT_PASS )
u->SetValue( tr.deflight_fbo->depthtarget );
else u->SetValue( tr.defscene_fbo->depthtarget );
break;
case UT_BSPPLANESMAP:
u->SetValue( tr.packed_planes_texture );
break;
case UT_BSPNODESMAP:
u->SetValue( tr.packed_nodes_texture );
break;
case UT_BSPLIGHTSMAP:
u->SetValue( tr.packed_lights_texture );
break;
case UT_BSPMODELSMAP:
u->SetValue( tr.packed_models_texture );
break;
case UT_SHADOWMAP:
if( pl ) u->SetValue( pl->shadowTexture[0] );
else u->SetValue( tr.fbo_light.GetTexture() );
break;
case UT_SHADOWMAP0:
if( pl ) u->SetValue( pl->shadowTexture[0] );
else u->SetValue( tr.depthTexture );
break;
case UT_SHADOWMAP1:
if( pl ) u->SetValue( pl->shadowTexture[1] );
else u->SetValue( tr.depthTexture );
break;
case UT_SHADOWMAP2:
if( pl ) u->SetValue( pl->shadowTexture[2] );
else u->SetValue( tr.depthTexture );
break;
case UT_SHADOWMAP3:
if( pl ) u->SetValue( pl->shadowTexture[3] );
else u->SetValue( tr.depthTexture );
break;
case UT_PROJECTMAP:
if( pl && pl->type == LIGHT_SPOT )
u->SetValue( pl->spotlightTexture );
else u->SetValue( tr.whiteTexture );
break;
case UT_VIEWORIGIN:
u->SetValue( RI->view.matrix[3][0], RI->view.matrix[3][1], RI->view.matrix[3][2] );
break;
case UT_LIGHTSTYLEVALUES:
u->SetValue( &tr.lightstyle[0], MAX_LIGHTSTYLES );
break;
case UT_GAMMATABLE:
u->SetValue( &tr.gamma_table[0][0], 64 );
break;
case UT_LIGHTTHRESHOLD:
u->SetValue( tr.light_threshold );
break;
case UT_LIGHTSCALE:
u->SetValue( tr.direct_scale );
break;
case UT_LIGHTGAMMA:
u->SetValue( tr.light_gamma );
break;
case UT_ZFAR:
u->SetValue( RI->view.farClip );
break;
case UT_SCREENSIZEINV:
u->SetValue( 1.0f / (float)glState.width, 1.0f / (float)glState.height );
break;
case UT_DIFFUSEFACTOR:
u->SetValue( tr.diffuseFactor );
break;
case UT_AMBIENTFACTOR:
if( pl && pl->type == LIGHT_DIRECTIONAL )
u->SetValue( tr.sun_ambient );
else u->SetValue( tr.ambientFactor );
break;
case UT_SUNREFRACT:
u->SetValue( tr.sun_refract );
break;
case UT_REALTIME:
u->SetValue( (float)tr.time );
break;
case UT_FOGPARAMS:
u->SetValue( tr.fogColor[0], tr.fogColor[1], tr.fogColor[2], tr.fogDensity );
break;
case UT_SHADOWPARMS:
if( pl != NULL )
{
float shadowWidth = 1.0f / (float)RENDER_GET_PARM( PARM_TEX_WIDTH, pl->shadowTexture[0] );
float shadowHeight = 1.0f / (float)RENDER_GET_PARM( PARM_TEX_HEIGHT, pl->shadowTexture[0] );
// depth scale and bias and shadowmap resolution
u->SetValue( shadowWidth, shadowHeight, -pl->projectionMatrix[2][2], pl->projectionMatrix[3][2] );
}
else u->SetValue( 0.0f, 0.0f, 0.0f, 0.0f );
break;
case UT_SHADOWMATRIX:
if( pl ) u->SetValue( &pl->gl_shadowMatrix[0][0], MAX_SHADOWMAPS );
break;
case UT_SHADOWSPLITDIST:
v = RI->view.parallelSplitDistances;
u->SetValue( v[0], v[1], v[2], v[3] );
break;
case UT_TEXELSIZE:
u->SetValue( 1.0f / (float)sunSize[0], 1.0f / (float)sunSize[1], 1.0f / (float)sunSize[2], 1.0f / (float)sunSize[3] );
break;
case UT_LIGHTDIR:
if( pl )
{
if( pl->type == LIGHT_DIRECTIONAL ) lightdir = -tr.sky_normal;
else lightdir = pl->frustum.GetPlane( FRUSTUM_FAR )->normal;
u->SetValue( lightdir.x, lightdir.y, lightdir.z, pl->fov );
}
break;
case UT_LIGHTDIFFUSE:
if( pl ) u->SetValue( pl->color.x, pl->color.y, pl->color.z );
break;
case UT_LIGHTORIGIN:
if( pl ) u->SetValue( pl->origin.x, pl->origin.y, pl->origin.z, ( 1.0f / pl->radius ));
break;
case UT_LIGHTVIEWPROJMATRIX:
if( pl )
{
GLfloat gl_lightViewProjMatrix[16];
pl->lightviewProjMatrix.CopyToArray( gl_lightViewProjMatrix );
u->SetValue( &gl_lightViewProjMatrix[0] );
}
break;
case UT_NUMVISIBLEMODELS:
u->SetValue( world->num_visible_models );
break;
default:
ALERT( at_error, "%s: unhandled uniform %s\n", RI->currentshader->name, u->name );
break;
}
}
GL_DrawScreenSpaceQuad( tr.screen_normals );
}
static void GL_DrawBilateralFilter( word hProgram, int pass )
{
if( hProgram <= 0 )
{
GL_BindShader( NULL );
return; // bad shader?
}
if( RI->currentshader != &glsl_programs[hProgram] )
{
// force to bind new shader
GL_BindShader( &glsl_programs[hProgram] );
}
glsl_program_t *shader = RI->currentshader;
// setup specified uniforms (and texture bindings)
for( int i = 0; i < shader->numUniforms; i++ )
{
uniform_t *u = &shader->uniforms[i];
switch( u->type )
{
case UT_COLORMAP:
if( pass == BILATERAL_PASS0 )
u->SetValue( tr.fbo_light.GetTexture() );
else if( pass = BILATERAL_PASS1 )
u->SetValue( tr.fbo_filter.GetTexture() );
else u->SetValue( tr.defscene_fbo->colortarget[0] );
break;
case UT_DEPTHMAP:
u->SetValue( tr.defscene_fbo->depthtarget );
break;
case UT_ZFAR:
u->SetValue( RI->view.farClip );
break;
case UT_SCREENSIZEINV:
if( pass == BILATERAL_PASS0 )
u->SetValue( 1.0f / (float)glState.width, 0.0f );
else if( pass = BILATERAL_PASS1 )
u->SetValue( 0.0f, 1.0f / (float)glState.height );
else u->SetValue( 1.0f / (float)glState.width, 1.0f / (float)glState.height );
break;
case UT_SHADOWPARMS:
u->SetValue( RI->view.projectionMatrix[3][2], RI->view.projectionMatrix[2][2] );
break;
default:
ALERT( at_error, "%s: unhandled uniform %s\n", RI->currentshader->name, u->name );
break;
}
}
RenderFSQ( glState.width, glState.height );
}
void GL_SetupWorldLightPass( void )
{
tr.fbo_shadow.Bind(); // <- render to shadow texture
// FIXME! modelview isn't be changed anyway until current pass!!!
// pglMatrixMode( GL_MODELVIEW );
// pglLoadMatrixf( RI->glstate.modelviewMatrix );
GL_DrawDeferred( tr.defLightShader, LIGHT_PASS );
GL_CleanupAllTextureUnits();
GL_Setup2D();
tr.fbo_light.Bind(); // <- copy to fbo_light result of works complex light shader
GL_BindShader( NULL );
GL_BindTexture( GL_TEXTURE0, tr.fbo_shadow.GetTexture() );
RenderFSQ( glState.width, glState.height );
if( tr.bilateralShader )
{
// apply bilateral filter
tr.fbo_filter.Bind(); // <- bilateral pass0, filtering by width, store to fbo_filter
GL_DrawBilateralFilter( tr.bilateralShader, BILATERAL_PASS0 );
tr.fbo_light.Bind(); // <- bilateral pass1, filtering by height, store back to fbo_light
GL_DrawBilateralFilter( tr.bilateralShader, BILATERAL_PASS1 );
}
}
void GL_SetupDynamicPass( void )
{
if( !FBitSet( RI->view.flags, RF_HASDYNLIGHTS ))
return;
pglEnable( GL_SCISSOR_TEST );
CDynLight *pl = tr.dlights;
for( int i = 0; i < MAX_DLIGHTS; i++, pl++ )
{
// deferred path are ignored sunlights
if( pl->Expired( ) || pl->type == LIGHT_DIRECTIONAL )
continue;
if( !pl->Active( )) continue;
if( !Mod_CheckBoxVisible( pl->absmin, pl->absmax ))
continue;
if( R_CullFrustum( &pl->frustum ))
continue;
float y2 = (float)RI->view.port[3] - pl->h - pl->y;
pglScissor( pl->x, y2, pl->w, pl->h );
RI->currentlight = pl;
GL_DrawDeferred( tr.defDynLightShader[pl->type], SCENE_PASS );
}
pglDisable( GL_SCISSOR_TEST );
RI->currentlight = NULL;
}
void GL_SetupWorldScenePass( void )
{
mworldlight_t *wl;
int i;
// debug
for( i = 0, wl = world->worldlights; i < world->numworldlights; i++, wl++ )
{
if( wl->emittype == emit_ignored )
continue;
if( !CHECKVISBIT( RI->view.vislight, i ))
continue;
r_stats.c_worldlights++;
}
int type = CVAR_TO_BOOL( cv_deferred_full ) ? 1 : 0;
GL_DrawDeferred( tr.defSceneShader[type], SCENE_PASS );
// also render a standard dynamic lights
GL_SetupDynamicPass();
}
void GL_DrawDeferredPass( void )
{
if( !tr.defSceneShader || !tr.defLightShader )
return; // oops!
GL_ComputeScreenRays();
if( FBitSet( RI->params, RP_DEFERREDSCENE ))
GL_SetupWorldScenePass();
if( FBitSet( RI->params, RP_DEFERREDLIGHT ))
GL_SetupWorldLightPass();
GL_CleanupDrawState();
GL_BindFBO( FBO_MAIN );
GL_Setup3D();
}

779
cl_dll/render/gl_dlight.cpp Normal file
View File

@ -0,0 +1,779 @@
/*
gl_dlight.cpp - dynamic lighting
Copyright (C) 2014 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "hud.h"
#include <stringlib.h>
#include "cl_util.h"
#include "pm_defs.h"
#include "event_api.h"
#include "gl_local.h"
#include "gl_studio.h"
#include "gl_world.h"
#include "gl_grass.h"
/*
=============================================================================
PROJECTED LIGHTS
=============================================================================
*/
/*
===============
CL_ClearDlights
===============
*/
void CL_ClearDlights( void )
{
memset( tr.dlights, 0, sizeof( tr.dlights ));
}
/*
===============
CL_AllocDlight
===============
*/
CDynLight *CL_AllocDlight( int key )
{
CDynLight *dl;
// first look for an exact key match
if( key )
{
dl = tr.dlights;
for( int i = 0; i < MAX_DLIGHTS; i++, dl++ )
{
if( dl->key == key )
{
// reuse this light
return dl;
}
}
}
float time = GET_CLIENT_TIME();
// then look for anything else
dl = tr.dlights;
for( int i = 0; i < MAX_DLIGHTS; i++, dl++ )
{
if( dl->die < time && dl->key == 0 )
{
memset( dl, 0, sizeof( *dl ));
dl->key = key;
return dl;
}
}
dl = &tr.dlights[0];
memset( dl, 0, sizeof( *dl ));
dl->key = key;
return dl;
}
/*
===============
CL_DecayLights
===============
*/
void CL_DecayLights( void )
{
float time = GET_CLIENT_TIME();
CDynLight *pl = tr.dlights;
for( int i = 0; i < MAX_DLIGHTS; i++, pl++ )
{
if( !pl->radius ) continue;
pl->radius -= tr.frametime * pl->decay;
if( pl->radius < 0.0f ) pl->radius = 0.0f;
if( pl->Expired( ))
memset( pl, 0, sizeof( *pl ));
}
}
//=====================================
// HasDynamicLights
//
// Return count dynamic lights for current frame
//=====================================
int HasDynamicLights( void )
{
int numDlights = 0;
if( !worldmodel->lightdata || !CVAR_TO_BOOL( cv_dynamiclight ))
return numDlights;
for( int i = 0; i < MAX_DLIGHTS; i++ )
{
CDynLight *pl = &tr.dlights[i];
if( pl->Expired( )) continue;
numDlights++;
}
return numDlights;
}
//=====================================
// HasStaticLights
//
// Return count static lights for current frame
//=====================================
int HasStaticLights( void )
{
int i, numLights = 0;
mworldlight_t *wl;
for( i = 0, wl = world->worldlights; i < world->numworldlights; i++, wl++ )
{
if( wl->emittype == emit_ignored )
continue;
if( !CHECKVISBIT( RI->view.vislight, i ))
continue;
numLights++;
}
return numLights;
}
/*
=============================================================================
DYNAMIC LIGHTS
=============================================================================
*/
/*
==================
R_AnimateLight
==================
*/
void R_AnimateLight( void )
{
int i, k, flight, clight;
float l, lerpfrac, backlerp;
float scale = 1.0f;
lightstyle_t *ls;
scale = tr.diffuseFactor;
if( tr.realframecount != 1 && !CVAR_TO_BOOL( r_lightstyles ))
return;
// light animations
// 'm' is normal light, 'a' is no light, 'z' is double bright
for( i = 0; i < MAX_LIGHTSTYLES; i++ )
{
ls = GET_LIGHTSTYLE( i );
if( !worldmodel->lightdata )
{
tr.lightstyle[i] = 256.0f * scale;
continue;
}
flight = (int)Q_floor( ls->time * 10.0f );
clight = (int)Q_ceil( ls->time * 10.0f );
lerpfrac = ( ls->time * 10 ) - flight;
backlerp = 1.0f - lerpfrac;
if( !ls->length )
{
tr.lightstyle[i] = 256.0f * scale;
continue;
}
else if( ls->length == 1 )
{
float value = ls->map[0];
// turn off the baked sunlight
if( tr.sun_light_enabled && i == LS_SKY )
value = (float)('a' - 'a');
// single length style so don't bother interpolating
tr.lightstyle[i] = value * 22.0f * scale;
continue;
}
else if( !ls->interp || !CVAR_TO_BOOL( r_lightstyle_lerping ))
{
tr.lightstyle[i] = ls->map[flight%ls->length] * 22.0f * scale;
continue;
}
// interpolate animating light
// frame just gone
k = ls->map[flight % ls->length];
l = (float)( k * 22.0f ) * backlerp;
// upcoming frame
k = ls->map[clight % ls->length];
l += (float)( k * 22.0f ) * lerpfrac;
tr.lightstyle[i] = l * scale;
}
}
/*
=======================================================================
GATHER DYNAMIC LIGHTING
=======================================================================
*/
/*
=================
R_LightsForPoint
=================
*/
Vector R_LightsForPoint( const Vector &point, float radius )
{
Vector lightColor;
if( radius <= 0.0f )
radius = 1.0f;
lightColor = g_vecZero;
for( int lnum = 0; lnum < MAX_DLIGHTS; lnum++ )
{
CDynLight *dl = &tr.dlights[lnum];
float atten = 1.0f;
if( dl->type == LIGHT_DIRECTIONAL )
continue;
if( dl->die < GET_CLIENT_TIME() || !dl->radius )
continue;
Vector dir = (dl->origin - point);
float dist = dir.Length();
if( !dist || dist > ( dl->radius + radius ))
continue;
if( dl->frustum.CullSphere( point, radius ))
continue;
atten = 1.0 - saturate( pow( dist * ( 1.0f / dl->radius ), 2.2f ));
if( atten <= 0.0 ) continue; // fast reject
if( dl->type == LIGHT_SPOT )
{
Vector lightDir = dl->frustum.GetPlane( FRUSTUM_FAR )->normal.Normalize();
float fov_x, fov_y;
// BUGBUG: we use 5:4 aspect not an 4:3
if( dl->flags & DLF_ASPECT3X4 )
fov_y = dl->fov * (5.0f / 4.0f);
else if( dl->flags & DLF_ASPECT4X3 )
fov_y = dl->fov * (4.0f / 5.0f);
else fov_y = dl->fov;
fov_x = dl->fov;
// spot attenuation
float spotDot = DotProduct( dir.Normalize(), lightDir );
fov_x = DEG2RAD( fov_x * 0.25f );
fov_y = DEG2RAD( fov_y * 0.25f );
float spotCos = cos( fov_x + fov_y );
if( spotDot < spotCos ) continue;
}
lightColor += (dl->color * 0.5f * atten);
}
return lightColor;
}
/*
================
R_GetLightVectors
Get light vectors for entity
================
*/
void R_GetLightVectors( cl_entity_t *pEnt, Vector &origin, Vector &angles )
{
// fill default case
origin = pEnt->origin;
angles = pEnt->angles;
// try to grab position from attachment
if( pEnt->curstate.aiment > 0 && pEnt->curstate.movetype == MOVETYPE_FOLLOW )
{
cl_entity_t *pParent = GET_ENTITY( pEnt->curstate.aiment );
studiohdr_t *pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata( pParent->model );
if( pParent && pParent->model && pStudioHeader != NULL )
{
// make sure what model really has attachements
if( pEnt->curstate.body > 0 && ( pStudioHeader && pStudioHeader->numattachments > 0 ))
{
int num = bound( 1, pEnt->curstate.body, MAXSTUDIOATTACHMENTS );
R_StudioAttachmentPosAng( pParent, num - 1, &origin, &angles );
angles[PITCH] = -angles[PITCH]; // stupid quake bug
}
else if( pParent->curstate.movetype == MOVETYPE_STEP )
{
origin = pParent->origin;
angles = pParent->angles;
// add the eye position for monster
if( pParent->curstate.eflags & EFLAG_SLERP )
origin += pStudioHeader->eyeposition;
}
else
{
origin = pParent->origin;
angles = pParent->angles;
}
}
}
// all other parent types will be attached on the server
}
/*
================
R_SetupLightTexture
Must be called after R_SetupLightParams
================
*/
void R_SetupLightTexture( CDynLight *pl, int texture )
{
ASSERT( pl != NULL );
pl->spotlightTexture = texture;
}
/*
================
R_SetupLightParams
================
*/
void R_SetupLightParams( CDynLight *pl, const Vector &origin, const Vector &angles, float radius, float fov, int type, int flags )
{
pl->type = bound( LIGHT_SPOT, type, LIGHT_DIRECTIONAL );
if( pl->type == LIGHT_OMNI )
{
for( int i = 0; i < MAX_SHADOWMAPS; i++ )
pl->shadowTexture[i] = tr.depthCubemap; // stub
if( !GL_Support( R_TEXTURECUBEMAP_EXT ))
flags |= DLF_NOSHADOWS;
}
else
{
for( int i = 0; i < MAX_SHADOWMAPS; i++ )
pl->shadowTexture[i] = tr.depthTexture; // stub
}
if( pl->origin != origin || pl->angles != angles || pl->fov != fov || pl->radius != radius || pl->flags != flags )
{
pl->origin = origin;
pl->angles = angles;
pl->radius = radius;
pl->flags = flags;
pl->update = true;
pl->fov = fov;
}
}
/*
================
R_SetupLightProjection
General setup light projections.
Calling only once per frame
================
*/
void R_SetupLightProjection( CDynLight *pl )
{
if( !pl->update )
{
if( pl->type != LIGHT_DIRECTIONAL )
{
if( !R_ScissorForFrustum( &pl->frustum, &pl->x, &pl->y, &pl->w, &pl->h ))
SetBits( pl->flags, DLF_CULLED );
else ClearBits( pl->flags, DLF_CULLED );
}
return;
}
if( pl->type == LIGHT_SPOT )
{
float fov_x, fov_y;
// BUGBUG: we use 5:4 aspect not an 4:3
if( pl->flags & DLF_ASPECT3X4 )
fov_y = pl->fov * (5.0f / 4.0f);
else if( pl->flags & DLF_ASPECT4X3 )
fov_y = pl->fov * (4.0f / 5.0f);
else fov_y = pl->fov;
// e.g. for fake cinema projectors
if( FBitSet( pl->flags, DLF_FLIPTEXTURE ))
fov_x = -pl->fov;
else fov_x = pl->fov;
pl->projectionMatrix.CreateProjection( fov_x, fov_y, Z_NEAR_LIGHT, pl->radius );
pl->modelviewMatrix.CreateModelview(); // init quake world orientation
pl->viewMatrix = matrix4x4( pl->origin, pl->angles );
// transform projector by position and angles
pl->modelviewMatrix.ConcatRotate( -pl->angles.z, 1, 0, 0 );
pl->modelviewMatrix.ConcatRotate( -pl->angles.x, 0, 1, 0 );
pl->modelviewMatrix.ConcatRotate( -pl->angles.y, 0, 0, 1 );
pl->modelviewMatrix.ConcatTranslate( -pl->origin.x, -pl->origin.y, -pl->origin.z );
pl->frustum.InitProjection( pl->viewMatrix, Z_NEAR_LIGHT, pl->radius, pl->fov, fov_y );
pl->frustum.ComputeFrustumBounds( pl->absmin, pl->absmax );
pl->frustum.DisablePlane( FRUSTUM_FAR ); // only use plane.normal
}
else if( pl->type == LIGHT_OMNI )
{
pl->modelviewMatrix.CreateModelview();
pl->viewMatrix = matrix4x4( pl->origin, g_vecZero );
pl->projectionMatrix.CreateProjection( 90.0f, 90.0f, Z_NEAR_LIGHT, pl->radius );
// transform omnilight by position
pl->modelviewMatrix.ConcatTranslate( -pl->origin.x, -pl->origin.y, -pl->origin.z );
pl->frustum.InitBoxFrustum( pl->origin, pl->radius );
pl->frustum.ComputeFrustumBounds( pl->absmin, pl->absmax );
}
else if( pl->type == LIGHT_DIRECTIONAL )
{
Vector skyDir, angles, up;
skyDir = tr.sky_normal.Normalize();
VectorAngles2( skyDir, angles );
AngleVectors( angles, NULL, NULL, up );
pl->viewMatrix.LookAt( tr.cached_vieworigin, skyDir, up );
pl->modelviewMatrix = pl->viewMatrix;
ClearBounds( pl->absmin, pl->absmax );
}
else
{
HOST_ERROR( "R_SetupLightProjection: unknown light type %i\n", pl->type );
}
if( pl->type != LIGHT_DIRECTIONAL )
{
matrix4x4 projectionView, s1;
projectionView = pl->projectionMatrix.Concat( pl->modelviewMatrix );
pl->lightviewProjMatrix = projectionView;
s1.CreateTranslate( 0.5f, 0.5f, 0.5f );
s1.ConcatScale( 0.5f, 0.5f, 0.5f );
pl->textureMatrix[0] = projectionView;
pl->shadowMatrix[0] = s1.Concat( projectionView );
if( !R_ScissorForFrustum( &pl->frustum, &pl->x, &pl->y, &pl->w, &pl->h ))
SetBits( pl->flags, DLF_CULLED );
else ClearBits( pl->flags, DLF_CULLED );
}
pl->update = false;
}
/*
================
R_SetupDynamicLights
================
*/
void R_SetupDynamicLights( void )
{
CDynLight *pl;
dlight_t *dl;
for( int lnum = 0; lnum < MAX_ENGINE_DLIGHTS; lnum++ )
{
dl = GET_DYNAMIC_LIGHT( lnum );
pl = &tr.dlights[MAX_ENGINE_DLIGHTS+lnum];
// NOTE: here we copies dlight settings 'as-is'
// without reallocating by key because key may
// be set indirectly without call CL_AllocDlight
if( dl->die < GET_CLIENT_TIME() || !dl->radius )
{
// light is expired. Clear it
memset( pl, 0, sizeof( *pl ));
continue;
}
pl->key = dl->key;
pl->die = dl->die + tr.frametime;
pl->decay = dl->decay;
pl->color.x = dl->color.r * (1.0 / 255.0f);
pl->color.y = dl->color.g * (1.0 / 255.0f);
pl->color.z = dl->color.b * (1.0 / 255.0f);
pl->origin = dl->origin;
pl->radius = dl->radius;
pl->type = LIGHT_OMNI;
pl->update = true;
R_SetupLightProjection( pl );
}
pl = tr.dlights;
for( int i = 0; i < MAX_DLIGHTS; i++, pl++ )
{
if( pl->Expired( )) continue;
R_SetupLightProjection( pl );
}
}
/*
=======================================================================
WORLDLIGHTS PROCESSING
=======================================================================
*/
static vec_t LightDistanceFalloff( const mworldlight_t *wl, const Vector &direction )
{
Vector delta = direction;
float dist = VectorNormalize( delta );
float dot = 1.0f; // assume dot is 1.0f
dist = Q_max( dist, 1.0 );
switch( wl->emittype )
{
case emit_surface:
return dot / (dist * dist);
case emit_skylight:
return dot;
break;
case emit_spotlight: // directional & positional
case emit_point:
// cull out stuff that's too far
if( dist > wl->radius )
return 0.0f;
return dot / (dist * dist);
break;
}
return 1.0f;
}
//-----------------------------------------------------------------------------
// This method returns the effective intensity of a light as seen from
// a particular point. PVS is used to speed up the task.
//-----------------------------------------------------------------------------
static float LightIntensityAtPoint( mworldlight_t *wl, const Vector &mid, bool skipZ )
{
lightzbuffer_t *pZBuf = world->shadowzbuffers;
Vector direction;
// special case lights
if( wl->emittype == emit_skylight )
{
// check to see if you can hit the sky texture
Vector end = mid + wl->normal * -BOGUS_RANGE; // max_range * sqrt(3)
msurface_t *surf = gEngfuncs.pEventAPI->EV_TraceSurface( 0, (float *)&mid, (float *)end );
// here, we didn't hit the sky, so we must be in shadow
if( !surf || !FBitSet( surf->flags, SURF_DRAWSKY ))
return 0.0f;
return 1.0f;
}
// all other lights
// check distance
direction = wl->origin - mid;
float ratio = LightDistanceFalloff( wl, direction );
// Early out for really low-intensity lights
// That way we don't need to ray-cast or normalize
float intensity = VectorMax( wl->intensity );
if( intensity * ratio < 4e-3 )
return 0.0f;
if( skipZ ) return ratio;
float dist = VectorNormalize( direction );
float flTraceDistance = dist;
// check if we are so close to the light that we shouldn't use our coarse z buf
if( dist < 8 * SHADOW_ZBUF_RES )
pZBuf = NULL;
LightShadowZBufferSample_t *pSample = NULL;
Vector epnt = mid;
if( pZBuf )
{
pSample = &( pZBuf->GetSample( direction ));
if(( pSample->m_flHitDistance < pSample->m_flTraceDistance ) || ( pSample->m_flTraceDistance >= dist ))
{
// hit!
if( dist > pSample->m_flHitDistance + 8 ) // shadow hit
return 0;
return ratio;
}
// cache miss
flTraceDistance = Q_max( 100.0f, 2.0f * dist ); // trace a little further for better caching
epnt += direction * ( dist - flTraceDistance );
}
pmtrace_t pm;
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( wl->origin, epnt, PM_WORLD_ONLY, -1, &pm );
// pm.fraction = 1.0f - pm.fraction;
float flHitDistance = ( pm.startsolid ) ? FLT_EPSILON : ( pm.fraction ) * flTraceDistance;
if( pSample )
{
pSample->m_flTraceDistance = flTraceDistance;
pSample->m_flHitDistance = ( pm.fraction >= 1.0 ) ? 1.0e23 : flHitDistance;
}
if( dist > flHitDistance + 8 )
return 0.0f;
return ratio;
}
static float LightIntensityInBox( mworldlight_t *wl, const Vector &mid, const Vector &mins, const Vector &maxs, bool skipZ )
{
float sphereRadius;
float angle, sinAngle;
float dist, distSqr;
// Choose the point closest on the box to the light to get max intensity
// within the box....
switch( wl->emittype )
{
case emit_spotlight: // directional & positional
sphereRadius = (maxs - mid).Length();
// first do a sphere/sphere check
dist = (wl->origin - mid).Length();
if( dist > (sphereRadius + wl->radius ))
return 0;
// PERFORMANCE: precalc this and store in the light?
angle = acos( wl->stopdot2 );
sinAngle = sin( angle );
if( !IsSphereIntersectingCone( mid, sphereRadius, wl->origin, wl->normal, sinAngle, wl->stopdot2 ))
return 0;
// NOTE: fall through to radius check in point case
case emit_point:
distSqr = CalcSqrDistanceToAABB( mins, maxs, wl->origin );
if( distSqr > wl->radius * wl->radius )
return 0;
break;
case emit_surface: // directional & positional, fixed cone size
sphereRadius = (maxs - mid).Length();
// first do a sphere/sphere check
dist = (wl->origin - mid).Length();
if( dist > ( sphereRadius + wl->radius ))
return 0;
// PERFORMANCE: precalc this and store in the light?
if( !IsSphereIntersectingCone( mid, sphereRadius, wl->origin, wl->normal, 1.0f, 0.0f ))
return 0;
break;
}
return LightIntensityAtPoint( wl, mid, skipZ );
}
/*
=================
R_FindWorldLights
search for lights that potentially can lit bbox
=================
*/
void R_FindWorldLights( const Vector &origin, const Vector &mins, const Vector &maxs, byte lights[MAXDYNLIGHTS], bool skipZ )
{
mworldlight_t *wl = world->worldlights;
Vector absmin = origin + mins;
Vector absmax = origin + maxs;
vec2_t indexes[32];
int count = 0;
for( int i = 0; i < world->numworldlights; i++, wl++ )
{
if( !Mod_BoxVisible( absmin, absmax, wl->pvs ))
continue;
float ratio = LightIntensityInBox( wl, origin, mins, maxs, skipZ );
// no light contribution?
if( ratio <= 0.0f ) continue;
Vector add = wl->intensity * ratio;
float illum = VectorMax( add );
//Msg( "#%i, type %d, illum %.5f, intensity %g %g %g\n", i, wl->emittype, illum, wl->intensity[0], wl->intensity[1], wl->intensity[2] );
if( illum <= 4e-3 )
continue;
if( count >= ARRAYSIZE( indexes ) / 2 )
break;
indexes[count][0] = i;
indexes[count][1] = illum;
count++;
}
memset( lights, 255, sizeof( byte ) * MAXDYNLIGHTS );
get_next_light:
float maxIllum = 0.0;
int ignored = -1;
int light = 255;
for( i = 0; i < count; i++ )
{
if( indexes[i][0] == -1.0f )
continue;
// skylight has a maximum priority
if( indexes[i][1] > maxIllum )
{
maxIllum = indexes[i][1];
light = indexes[i][0];
ignored = i;
}
}
if( ignored == -1 )
return;
for( i = 0; i < (int)cv_deferred_maxlights->value && lights[i] != 255; i++ );
if( i < (int)cv_deferred_maxlights->value )
lights[i] = light; // nearest light for surf
indexes[ignored][0] = -1; // this light is handled
// if( count > (int)cv_deferred_maxlights->value && i == (int)cv_deferred_maxlights->value )
// Msg( "skipped light %i intensity %g, type %d\n", light, maxIllum, world->worldlights[light].emittype );
goto get_next_light;
}

1029
cl_dll/render/gl_export.cpp Normal file

File diff suppressed because it is too large Load Diff

1366
cl_dll/render/gl_export.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,628 @@
/*
gl_framebuffer.cpp - framebuffer implementation class
Copyright (C) 2014 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "hud.h"
#include "cl_util.h"
#include "gl_local.h"
#include <mathlib.h>
#include <stringlib.h>
static gl_drawbuffer_t gl_drawbuffers[MAX_FRAMEBUFFERS];
static int gl_num_drawbuffers;
/*
==================
GL_AllocDrawbuffer
==================
*/
gl_drawbuffer_t *GL_AllocDrawbuffer( const char *name, int width, int height, int depth )
{
gl_drawbuffer_t *fbo;
int i;
if( !GL_Support( R_FRAMEBUFFER_OBJECT ))
return NULL;
// find a free FBO slot
for( i = 0, fbo = gl_drawbuffers; i < gl_num_drawbuffers; i++, fbo++ )
if( !fbo->name[0] ) break;
if( i == gl_num_drawbuffers )
{
if( gl_num_drawbuffers == MAX_FRAMEBUFFERS )
HOST_ERROR( "GL_AllocDrawBuffer: MAX_FRAMEBUFFERS limit exceeds\n" );
gl_num_drawbuffers++;
}
if( !GL_Support( R_ARB_TEXTURE_NPOT_EXT ))
{
width = NearestPOW( width, true );
height = NearestPOW( height, true );
}
// fill it in
Q_strncpy( fbo->name, name, sizeof( fbo->name ));
// make sure it's fit in limits
fbo->width = Q_min( glConfig.max_2d_texture_size, width );
fbo->height = Q_min( glConfig.max_2d_texture_size, height );
fbo->depth = depth;
// generate the drawbuffer
pglGenFramebuffers( 1, &fbo->id );
return fbo;
}
/*
==================
GL_ResizeDrawbuffer
==================
*/
void GL_ResizeDrawbuffer( gl_drawbuffer_t *fbo, int width, int height, int depth )
{
ASSERT( fbo != NULL );
// fill it in
fbo->width = width;
fbo->height = height;
fbo->depth = depth;
}
/*
==================
GL_AttachColorTextureToFBO
==================
*/
void GL_AttachColorTextureToFBO( gl_drawbuffer_t *fbo, int texture, int colorIndex, int index )
{
GLuint target = RENDER_GET_PARM( PARM_TEX_TARGET, texture );
GLuint format = RENDER_GET_PARM( PARM_TEX_GLFORMAT, texture );
GLint width = RENDER_GET_PARM( PARM_TEX_WIDTH, texture );
GLint height = RENDER_GET_PARM( PARM_TEX_HEIGHT, texture );
GLint depth = RENDER_GET_PARM( PARM_TEX_DEPTH, texture );
if( target == GL_TEXTURE_2D )
{
// set the texture
fbo->colortarget[colorIndex] = texture;
// if the drawbuffer has been resized
if( width != fbo->width || height != fbo->height )
{
// check the dimensions
if( fbo->width > glConfig.max_2d_texture_size || fbo->height > glConfig.max_2d_texture_size )
HOST_ERROR( "GL_AttachColorTextureToFBO: size exceeds hardware limits (%i > %i or %i > %i)\n",
fbo->width, glConfig.max_2d_texture_size, fbo->height, glConfig.max_2d_texture_size );
// reallocate the texture
GL_UpdateTexSize( texture, fbo->width, fbo->height, fbo->depth );
GL_BindTexture( GL_KEEP_UNIT, texture );
// need to refresh real FBO size with possible hardware limitations
fbo->width = RENDER_GET_PARM( PARM_TEX_WIDTH, texture );
fbo->height = RENDER_GET_PARM( PARM_TEX_HEIGHT, texture );
pglTexImage2D( target, 0, format, fbo->width, fbo->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
}
// Bind the drawbuffer
GL_BindDrawbuffer( fbo );
// Set up the color attachment
pglFramebufferTexture2D( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + colorIndex, GL_TEXTURE_2D, texture, 0 );
}
else if( target == GL_TEXTURE_CUBE_MAP_ARB )
{
// set the texture
fbo->colortarget[colorIndex] = texture;
// if the drawbuffer has been resized
if( width != fbo->width || height != fbo->height )
{
// check the dimensions
if( fbo->width > glConfig.max_cubemap_size || fbo->height > glConfig.max_cubemap_size )
HOST_ERROR( "GL_AttachColorTextureToFBO: size exceeds hardware limits (%i > %i or %i > %i)\n",
fbo->width, glConfig.max_cubemap_size, fbo->height, glConfig.max_cubemap_size );
// reallocate the texture
GL_UpdateTexSize( texture, fbo->width, fbo->height, fbo->depth );
GL_BindTexture( GL_KEEP_UNIT, texture );
// need to refresh real FBO size with possible hardware limitations
fbo->width = RENDER_GET_PARM( PARM_TEX_WIDTH, texture );
fbo->height = RENDER_GET_PARM( PARM_TEX_HEIGHT, texture );
pglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, 0, format, fbo->width, fbo->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
pglTexImage2D( GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, 0, format, fbo->width, fbo->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
pglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, 0, format, fbo->width, fbo->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
pglTexImage2D( GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, 0, format, fbo->width, fbo->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
pglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, 0, format, fbo->width, fbo->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
pglTexImage2D( GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, 0, format, fbo->width, fbo->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
}
// bind the drawbuffer
GL_BindDrawbuffer( fbo );
// set up the color attachment
pglFramebufferTexture2D( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + colorIndex, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + index, texture, 0 );
}
else if( target == GL_TEXTURE_2D_ARRAY_EXT )
{
// Set the texture
fbo->colortarget[colorIndex] = texture;
// if the drawbuffer has been resized
if( width != fbo->width || height != fbo->height || depth != fbo->depth )
{
// check the dimensions
if( fbo->width > glConfig.max_2d_texture_size || fbo->height > glConfig.max_2d_texture_size || fbo->depth > glConfig.max_2d_texture_layers )
HOST_ERROR( "GL_AttachColorTextureToFBO: size exceeds hardware limits (%i > %i or %i > %i or %i > %i)\n",
fbo->width, glConfig.max_2d_texture_size, fbo->height, glConfig.max_2d_texture_size, fbo->depth, glConfig.max_2d_texture_layers );
// reallocate the texture
GL_UpdateTexSize( texture, fbo->width, fbo->height, fbo->depth );
GL_BindTexture( GL_KEEP_UNIT, texture );
// need to refresh real FBO size with possible hardware limitations
fbo->width = RENDER_GET_PARM( PARM_TEX_WIDTH, texture );
fbo->height = RENDER_GET_PARM( PARM_TEX_HEIGHT, texture );
fbo->depth = RENDER_GET_PARM( PARM_TEX_DEPTH, texture );
pglTexImage3D( target, 0, format, fbo->width, fbo->height, fbo->depth, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
}
// bind the drawbuffer
GL_BindDrawbuffer( fbo );
// Set up the color attachment
pglFramebufferTextureLayer( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + colorIndex, texture, 0, index );
}
else if( target == GL_TEXTURE_3D )
{
// Set the texture
fbo->colortarget[colorIndex] = texture;
// if the drawbuffer has been resized
if( width != fbo->width || height != fbo->height || depth != fbo->depth )
{
// check the dimensions
if( fbo->width > glConfig.max_3d_texture_size || fbo->height > glConfig.max_3d_texture_size || fbo->depth > glConfig.max_3d_texture_size )
HOST_ERROR( "GL_AttachColorTextureToFBO: size exceeds hardware limits (%i > %i or %i > %i or %i > %i)\n",
fbo->width, glConfig.max_3d_texture_size, fbo->height, glConfig.max_3d_texture_size, fbo->depth, glConfig.max_3d_texture_size );
// reallocate the texture
GL_UpdateTexSize( texture, fbo->width, fbo->height, fbo->depth );
GL_BindTexture( GL_KEEP_UNIT, texture );
// need to refresh real FBO size with possible hardware limitations
fbo->width = RENDER_GET_PARM( PARM_TEX_WIDTH, texture );
fbo->height = RENDER_GET_PARM( PARM_TEX_HEIGHT, texture );
fbo->depth = RENDER_GET_PARM( PARM_TEX_DEPTH, texture );
pglTexImage3D( target, 0, format, fbo->width, fbo->height, fbo->depth, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
}
// bind the drawbuffer
GL_BindDrawbuffer( fbo );
// Set up the color attachment
pglFramebufferTexture3D( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + colorIndex, GL_TEXTURE_3D, texture, 0, index );
}
else
{
HOST_ERROR( "GL_AttachColorTextureToFBO: bad texture target (%i)\n", target );
}
}
/*
==================
GL_AttachDepthTextureToFBO
==================
*/
void GL_AttachDepthTextureToFBO( gl_drawbuffer_t *fbo, int texture, int index )
{
GLuint target = RENDER_GET_PARM( PARM_TEX_TARGET, texture );
GLuint format = RENDER_GET_PARM( PARM_TEX_GLFORMAT, texture );
GLint width = RENDER_GET_PARM( PARM_TEX_WIDTH, texture );
GLint height = RENDER_GET_PARM( PARM_TEX_HEIGHT, texture );
GLint depth = RENDER_GET_PARM( PARM_TEX_DEPTH, texture );
if( target == GL_TEXTURE_2D )
{
// set the texture
fbo->depthtarget = texture;
// if the drawbuffer has been resized
if( width != fbo->width || height != fbo->height )
{
// check the dimensions
if( fbo->width > glConfig.max_2d_texture_size || fbo->height > glConfig.max_2d_texture_size )
HOST_ERROR( "GL_AttachDepthTextureToFBO: size exceeds hardware limits (%i > %i or %i > %i)\n",
fbo->width, glConfig.max_2d_texture_size, fbo->height, glConfig.max_2d_texture_size );
// reallocate the texture
GL_UpdateTexSize( texture, fbo->width, fbo->height, fbo->depth );
GL_BindTexture( GL_KEEP_UNIT, texture );
// need to refresh real FBO size with possible hardware limitations
fbo->width = RENDER_GET_PARM( PARM_TEX_WIDTH, texture );
fbo->height = RENDER_GET_PARM( PARM_TEX_HEIGHT, texture );
pglTexImage2D( target, 0, format, fbo->width, fbo->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL );
}
// Bind the drawbuffer
GL_BindDrawbuffer( fbo );
// Set up the color attachment
pglFramebufferTexture2D( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, texture, 0 );
}
else if( target == GL_TEXTURE_CUBE_MAP_ARB )
{
// set the texture
fbo->depthtarget = texture;
// if the drawbuffer has been resized
if( width != fbo->width || height != fbo->height )
{
// check the dimensions
if( fbo->width > glConfig.max_cubemap_size || fbo->height > glConfig.max_cubemap_size )
HOST_ERROR( "GL_AttachDepthTextureToFBO: size exceeds hardware limits (%i > %i or %i > %i)\n",
fbo->width, glConfig.max_cubemap_size, fbo->height, glConfig.max_cubemap_size );
// reallocate the texture
GL_UpdateTexSize( texture, fbo->width, fbo->height, fbo->depth );
GL_BindTexture( GL_KEEP_UNIT, texture );
// need to refresh real FBO size with possible hardware limitations
fbo->width = RENDER_GET_PARM( PARM_TEX_WIDTH, texture );
fbo->height = RENDER_GET_PARM( PARM_TEX_HEIGHT, texture );
pglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, 0, format, fbo->width, fbo->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL );
pglTexImage2D( GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, 0, format, fbo->width, fbo->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL );
pglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, 0, format, fbo->width, fbo->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL );
pglTexImage2D( GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, 0, format, fbo->width, fbo->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL );
pglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, 0, format, fbo->width, fbo->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL );
pglTexImage2D( GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, 0, format, fbo->width, fbo->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL );
}
// bind the drawbuffer
GL_BindDrawbuffer( fbo );
// set up the color attachment
pglFramebufferTexture2D( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + index, texture, 0 );
}
else if( target == GL_TEXTURE_2D_ARRAY_EXT )
{
// Set the texture
fbo->depthtarget = texture;
// if the drawbuffer has been resized
if( width != fbo->width || height != fbo->height || depth != fbo->depth )
{
// check the dimensions
if( fbo->width > glConfig.max_2d_texture_size || fbo->height > glConfig.max_2d_texture_size || fbo->depth > glConfig.max_2d_texture_layers )
HOST_ERROR( "GL_AttachDepthTextureToFBO: size exceeds hardware limits (%i > %i or %i > %i or %i > %i)\n",
fbo->width, glConfig.max_2d_texture_size, fbo->height, glConfig.max_2d_texture_size, fbo->depth, glConfig.max_2d_texture_layers );
// reallocate the texture
GL_UpdateTexSize( texture, fbo->width, fbo->height, fbo->depth );
GL_BindTexture( GL_KEEP_UNIT, texture );
// need to refresh real FBO size with possible hardware limitations
fbo->width = RENDER_GET_PARM( PARM_TEX_WIDTH, texture );
fbo->height = RENDER_GET_PARM( PARM_TEX_HEIGHT, texture );
fbo->depth = RENDER_GET_PARM( PARM_TEX_DEPTH, texture );
pglTexImage3D( target, 0, format, fbo->width, fbo->height, fbo->depth, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL );
}
// bind the drawbuffer
GL_BindDrawbuffer( fbo );
// Set up the color attachment
pglFramebufferTextureLayer( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texture, 0, index );
}
else
{
HOST_ERROR( "GL_AttachDepthTextureToFBO: bad texture target (%i)\n", target );
}
}
/*
==================
GL_CheckFBOStatus
==================
*/
void GL_CheckFBOStatus( gl_drawbuffer_t *fbo )
{
const char *string;
int status;
// bind the drawbuffer
GL_BindDrawbuffer( fbo );
// check the framebuffer status
status = pglCheckFramebufferStatus( GL_FRAMEBUFFER_EXT );
if( status == GL_FRAMEBUFFER_COMPLETE_EXT )
return;
switch( status )
{
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
string = "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
string = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
string = "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER";
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
string = "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER";
break;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
string = "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE";
break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
string = "GL_FRAMEBUFFER_UNSUPPORTED";
break;
case GL_FRAMEBUFFER_UNDEFINED_EXT:
string = "GL_FRAMEBUFFER_UNDEFINED";
break;
default:
string = "UNKNOWN STATUS";
break;
}
HOST_ERROR( "GL_CheckFBOStatus: %s for '%s'\n", string, fbo->name );
}
/*
==================
GL_FreeDrawbuffers
==================
*/
void GL_FreeDrawbuffers( void )
{
gl_drawbuffer_t *fbo;
// unbind the drawbuffer
GL_BindDrawbuffer( NULL );
// delete all the drawbuffers
for( int i = 0; i < gl_num_drawbuffers; i++ )
{
fbo = &gl_drawbuffers[i];
pglDeleteFramebuffers( 1, &fbo->id );
}
// NOTE: let the engine release attached textures
memset( gl_drawbuffers, 0, sizeof( gl_drawbuffers ));
gl_num_drawbuffers = 0;
}
CFrameBuffer :: CFrameBuffer( void )
{
m_iFrameWidth = m_iFrameHeight = 0;
m_iFrameBuffer = m_iDepthBuffer = 0;
m_iTexture = m_iAttachment = 0;
m_bAllowFBO = false;
}
CFrameBuffer :: ~CFrameBuffer( void )
{
// NOTE: static case will be failed
Free();
}
int CFrameBuffer :: m_iBufferNum = 0;
bool CFrameBuffer :: Init( FBO_TYPE type, GLuint width, GLuint height, GLuint flags )
{
Free(); // release old buffer
m_iFlags = flags;
if( !GL_Support( R_ARB_TEXTURE_NPOT_EXT ))
SetBits( m_iFlags, FBO_MAKEPOW );
if( FBitSet( m_iFlags, FBO_MAKEPOW ))
{
width = NearestPOW( width, true );
height = NearestPOW( height, true );
}
// clamp size to hardware limits
if( type == FBO_CUBE )
{
m_iFrameWidth = bound( 0, width, glConfig.max_cubemap_size );
m_iFrameHeight = bound( 0, height, glConfig.max_cubemap_size );
}
else
{
m_iFrameWidth = bound( 0, width, glConfig.max_2d_texture_size );
m_iFrameHeight = bound( 0, height, glConfig.max_2d_texture_size );
}
if( !m_iFrameWidth || !m_iFrameHeight )
{
ALERT( at_error, "CFrameBuffer( %i x %i ) invalid size\n", m_iFrameWidth, m_iFrameHeight );
return false;
}
// create FBO texture
if( !FBitSet( m_iFlags, FBO_NOTEXTURE ))
{
int texFlags = (TF_NOMIPMAP|TF_CLAMP);
if( type == FBO_CUBE )
SetBits( texFlags, TF_CUBEMAP );
else if( type == FBO_DEPTH )
SetBits( texFlags, TF_DEPTHMAP );
if( !FBitSet( m_iFlags, FBO_LINEAR ))
SetBits( texFlags, TF_NEAREST );
if( FBitSet( m_iFlags, FBO_FLOAT ))
SetBits( texFlags, TF_ARB_FLOAT );
if( FBitSet( m_iFlags, FBO_RECTANGLE ))
SetBits( texFlags, TF_RECTANGLE );
if( FBitSet( m_iFlags, FBO_LUMINANCE ))
SetBits( texFlags, TF_LUMINANCE );
else if( type == FBO_COLOR )
SetBits( texFlags, TF_HAS_ALPHA );
m_iTexture = CREATE_TEXTURE( va( "*framebuffer#%i", m_iBufferNum++ ), m_iFrameWidth, m_iFrameHeight, NULL, texFlags );
}
m_bAllowFBO = (GL_Support( R_FRAMEBUFFER_OBJECT )) ? true : false;
if( m_bAllowFBO )
{
// frame buffer
pglGenFramebuffers( 1, &m_iFrameBuffer );
pglBindFramebuffer( GL_FRAMEBUFFER_EXT, m_iFrameBuffer );
// depth buffer
pglGenRenderbuffers( 1, &m_iDepthBuffer );
pglBindRenderbuffer( GL_RENDERBUFFER_EXT, m_iDepthBuffer );
pglRenderbufferStorage( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, m_iFrameWidth, m_iFrameHeight );
// attach depthbuffer to framebuffer
pglFramebufferRenderbuffer( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_iDepthBuffer );
// attach the framebuffer to our texture, which may be a depth texture
if( type == FBO_DEPTH )
{
m_iAttachment = GL_DEPTH_ATTACHMENT_EXT;
pglDrawBuffer( GL_NONE );
pglReadBuffer( GL_NONE );
}
else
{
m_iAttachment = GL_COLOR_ATTACHMENT0_EXT;
pglDrawBuffer( m_iAttachment );
pglReadBuffer( m_iAttachment );
}
if( m_iTexture != 0 )
{
GLuint target = RENDER_GET_PARM( PARM_TEX_TARGET, m_iTexture );
GLuint texnum = RENDER_GET_PARM( PARM_TEX_TEXNUM, m_iTexture );
if( target == GL_TEXTURE_CUBE_MAP_ARB )
{
target = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB;
for( int i = 0; i < 6; i++ )
pglFramebufferTexture2D( GL_FRAMEBUFFER_EXT, m_iAttachment, target + i, texnum, 0 );
}
else pglFramebufferTexture2D( GL_FRAMEBUFFER_EXT, m_iAttachment, target, texnum, 0 );
}
m_bAllowFBO = ValidateFBO();
pglBindFramebuffer( GL_FRAMEBUFFER_EXT, 0 );
}
return true;
}
void CFrameBuffer :: Free( void )
{
if( !m_bAllowFBO ) return;
if( !FBitSet( m_iFlags, FBO_NOTEXTURE ) && m_iTexture != 0 )
FREE_TEXTURE( m_iTexture );
pglDeleteRenderbuffers( 1, &m_iDepthBuffer );
pglDeleteFramebuffers( 1, &m_iFrameBuffer );
m_iFrameWidth = m_iFrameHeight = 0;
m_iFrameBuffer = m_iDepthBuffer = 0;
m_iTexture = m_iAttachment = 0;
m_bAllowFBO = false;
}
bool CFrameBuffer :: ValidateFBO( void )
{
if( !GL_Support( R_FRAMEBUFFER_OBJECT ))
return false;
// check FBO status
GLenum status = pglCheckFramebufferStatus( GL_FRAMEBUFFER_EXT );
switch( status )
{
case GL_FRAMEBUFFER_COMPLETE_EXT:
return true;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
ALERT( at_error, "CFrameBuffer: attachment is NOT complete\n" );
return false;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
ALERT( at_error, "CFrameBuffer: no image is attached to FBO\n" );
return false;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
ALERT( at_error, "CFrameBuffer: attached images have different dimensions\n" );
return false;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
ALERT( at_error, "CFrameBuffer: color attached images have different internal formats\n" );
return false;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
ALERT( at_error, "CFrameBuffer: draw buffer incomplete\n" );
return false;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
ALERT( at_error, "CFrameBuffere: read buffer incomplete\n" );
return false;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
ALERT( at_error, "CFrameBuffer: unsupported by current FBO implementation\n" );
return false;
default:
ALERT( at_error, "CFrameBuffer: unknown error\n" );
return false;
}
}
void CFrameBuffer :: Bind( GLuint texture, GLuint side )
{
if( !m_bAllowFBO ) return;
if( glState.frameBuffer != m_iFrameBuffer )
{
pglBindFramebuffer( GL_FRAMEBUFFER_EXT, m_iFrameBuffer );
glState.frameBuffer = m_iFrameBuffer;
}
// change texture if needs
if( FBitSet( m_iFlags, FBO_NOTEXTURE ) && texture != 0 )
{
m_iTexture = texture;
GLuint target = RENDER_GET_PARM( PARM_TEX_TARGET, m_iTexture );
GLuint texnum = RENDER_GET_PARM( PARM_TEX_TEXNUM, m_iTexture );
if( target == GL_TEXTURE_CUBE_MAP_ARB )
target = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side;
pglFramebufferTexture2D( GL_FRAMEBUFFER_EXT, m_iAttachment, target, texnum, 0 );
}
ValidateFBO();
}

View File

@ -0,0 +1,63 @@
/*
gl_framebuffer.h - framebuffer implementation class
this code written for Paranoia 2: Savior modification
Copyright (C) 2014 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef GL_FRAMEBUFFER_H
#define GL_FRAMEBUFFER_H
typedef enum
{
FBO_COLOR = 0, // only color texture is used
FBO_DEPTH, // only depth texture is used
FBO_CUBE, // only color texture as cubemap is side
} FBO_TYPE;
#define FBO_MAKEPOW (1<<0) // round buffer size to nearest pow
#define FBO_NOTEXTURE (1<<1) // don't create texture on initialization
#define FBO_FLOAT (1<<2) // use float texture
#define FBO_RECTANGLE (1<<3) // use rectangle texture
#define FBO_LINEAR (1<<4) // use linear filtering
#define FBO_LUMINANCE (1<<5) // force to luminance texture
class CFrameBuffer
{
public:
CFrameBuffer();
~CFrameBuffer();
bool Init( FBO_TYPE type, GLuint width, GLuint height, GLuint flags = 0 );
void Bind( GLuint texture = 0, GLuint side = 0 );
bool ValidateFBO( void );
void Free( void );
unsigned int GetWidth( void ) const { return m_iFrameWidth; }
unsigned int GetHeight( void ) const { return m_iFrameHeight; }
int GetTexture( void ) const { return m_iTexture; }
bool Active( void ) const { return m_bAllowFBO; }
protected:
static int m_iBufferNum; // single object for all instances
private:
GLuint m_iFrameWidth;
GLuint m_iFrameHeight;
GLint m_iTexture;
GLuint m_iFrameBuffer;
GLuint m_iDepthBuffer;
GLenum m_iAttachment; // attachment type
bool m_bAllowFBO; // FBO is valid
GLuint m_iFlags; // member FBO flags
};
#endif//GL_FRAMEBUFFER_H

View File

@ -0,0 +1,374 @@
/*
gl_frustum.cpp - frustum test implementation class
Copyright (C) 2014 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "hud.h"
#include "cl_util.h"
#include "const.h"
#include "ref_params.h"
#include "gl_local.h"
#include <mathlib.h>
#include <stringlib.h>
void CFrustum :: ClearFrustum( void )
{
memset( planes, 0, sizeof( planes ));
clipFlags = 0;
}
void CFrustum :: EnablePlane( int side )
{
ASSERT( side >= 0 && side < FRUSTUM_PLANES );
// make sure what plane is ready
if( planes[side].normal != g_vecZero )
SetBits( clipFlags, BIT( side ));
}
void CFrustum :: DisablePlane( int side )
{
ASSERT( side >= 0 && side < FRUSTUM_PLANES );
ClearBits( clipFlags, BIT( side ));
}
void CFrustum :: InitProjection( const matrix4x4 &view, float flZNear, float flZFar, float flFovX, float flFovY )
{
float xs, xc;
Vector normal;
// horizontal fov used for left and right planes
SinCos( DEG2RAD( flFovX ) * 0.5f, &xs, &xc );
// setup left plane
normal = view.GetForward() * xs + view.GetRight() * -xc;
SetPlane( FRUSTUM_LEFT, normal, DotProduct( view.GetOrigin(), normal ));
// setup right plane
normal = view.GetForward() * xs + view.GetRight() * xc;
SetPlane( FRUSTUM_RIGHT, normal, DotProduct( view.GetOrigin(), normal ));
// vertical fov used for top and bottom planes
SinCos( DEG2RAD( flFovY ) * 0.5f, &xs, &xc );
// setup bottom plane
normal = view.GetForward() * xs + view.GetUp() * -xc;
SetPlane( FRUSTUM_BOTTOM, normal, DotProduct( view.GetOrigin(), normal ));
// setup top plane
normal = view.GetForward() * xs + view.GetUp() * xc;
SetPlane( FRUSTUM_TOP, normal, DotProduct( view.GetOrigin(), normal ));
// setup far plane
SetPlane( FRUSTUM_FAR, -view.GetForward(), DotProduct( -view.GetForward(), ( view.GetOrigin() + view.GetForward() * flZFar )));
// no need to setup backplane for general view. It's only used for portals and mirrors
if( flZNear == 0.0f ) return;
// setup near plane
SetPlane( FRUSTUM_NEAR, view.GetForward(), DotProduct( view.GetForward(), ( view.GetOrigin() + view.GetForward() * flZNear )));
}
void CFrustum :: InitOrthogonal( const matrix4x4 &view, float xLeft, float xRight, float yBottom, float yTop, float flZNear, float flZFar )
{
// setup the near and far planes
float orgOffset = DotProduct( view.GetOrigin(), view.GetForward() );
SetPlane( FRUSTUM_FAR, -view.GetForward(), -flZNear - orgOffset );
SetPlane( FRUSTUM_NEAR, view.GetForward(), flZFar + orgOffset );
// setup left and right planes
orgOffset = DotProduct( view.GetOrigin(), view.GetRight() );
SetPlane( FRUSTUM_LEFT, view.GetRight(), xLeft + orgOffset );
SetPlane( FRUSTUM_RIGHT, -view.GetRight(), -xRight - orgOffset );
// setup top and buttom planes
orgOffset = DotProduct( view.GetOrigin(), view.GetUp() );
SetPlane( FRUSTUM_TOP, view.GetUp(), yTop + orgOffset );
SetPlane( FRUSTUM_BOTTOM, -view.GetUp(), -yBottom - orgOffset );
}
void CFrustum :: InitBoxFrustum( const Vector &org, float radius )
{
for( int i = 0; i < 6; i++ )
{
// setup normal for each direction
Vector normal = g_vecZero;
normal[((i >> 1) + 1) % 3] = (i & 1) ? 1.0f : -1.0f;
SetPlane( i, normal, DotProduct( org, normal ) - radius );
}
}
void CFrustum :: InitProjectionFromMatrix( const matrix4x4 &projection )
{
// left
planes[FRUSTUM_LEFT].normal[0] = projection[0][3] + projection[0][0];
planes[FRUSTUM_LEFT].normal[1] = projection[1][3] + projection[1][0];
planes[FRUSTUM_LEFT].normal[2] = projection[2][3] + projection[2][0];
planes[FRUSTUM_LEFT].dist = -(projection[3][3] + projection[3][0]);
// right
planes[FRUSTUM_RIGHT].normal[0] = projection[0][3] - projection[0][0];
planes[FRUSTUM_RIGHT].normal[1] = projection[1][3] - projection[1][0];
planes[FRUSTUM_RIGHT].normal[2] = projection[2][3] - projection[2][0];
planes[FRUSTUM_RIGHT].dist = -(projection[3][3] - projection[3][0]);
// bottom
planes[FRUSTUM_BOTTOM].normal[0] = projection[0][3] + projection[0][1];
planes[FRUSTUM_BOTTOM].normal[1] = projection[1][3] + projection[1][1];
planes[FRUSTUM_BOTTOM].normal[2] = projection[2][3] + projection[2][1];
planes[FRUSTUM_BOTTOM].dist = -(projection[3][3] + projection[3][1]);
// top
planes[FRUSTUM_TOP].normal[0] = projection[0][3] - projection[0][1];
planes[FRUSTUM_TOP].normal[1] = projection[1][3] - projection[1][1];
planes[FRUSTUM_TOP].normal[2] = projection[2][3] - projection[2][1];
planes[FRUSTUM_TOP].dist = -(projection[3][3] - projection[3][1]);
// near
planes[FRUSTUM_NEAR].normal[0] = projection[0][3] + projection[0][2];
planes[FRUSTUM_NEAR].normal[1] = projection[1][3] + projection[1][2];
planes[FRUSTUM_NEAR].normal[2] = projection[2][3] + projection[2][2];
planes[FRUSTUM_NEAR].dist = -(projection[3][3] + projection[3][2]);
// far
planes[FRUSTUM_FAR].normal[0] = projection[0][3] - projection[0][2];
planes[FRUSTUM_FAR].normal[1] = projection[1][3] - projection[1][2];
planes[FRUSTUM_FAR].normal[2] = projection[2][3] - projection[2][2];
planes[FRUSTUM_FAR].dist = -(projection[3][3] - projection[3][2]);
for( int i = 0; i < FRUSTUM_PLANES; i++ )
{
NormalizePlane( i );
}
}
void CFrustum :: SetPlane( int side, const Vector &vecNormal, float flDist )
{
ASSERT( side >= 0 && side < FRUSTUM_PLANES );
planes[side].type = PlaneTypeForNormal( vecNormal );
planes[side].signbits = SignbitsForPlane( vecNormal );
planes[side].normal = vecNormal;
planes[side].dist = flDist;
clipFlags |= BIT( side );
}
void CFrustum :: NormalizePlane( int side )
{
ASSERT( side >= 0 && side < FRUSTUM_PLANES );
// normalize
float length = planes[side].normal.Length();
if( length )
{
float ilength = (1.0f / length);
planes[side].normal.x *= ilength;
planes[side].normal.y *= ilength;
planes[side].normal.z *= ilength;
planes[side].dist *= ilength;
}
planes[side].type = PlaneTypeForNormal( planes[side].normal );
planes[side].signbits = SignbitsForPlane( planes[side].normal );
clipFlags |= BIT( side );
}
void CFrustum :: ComputeFrustumCorners( Vector corners[8] )
{
memset( corners, 0, sizeof( Vector ) * 8 );
PlanesGetIntersectionPoint( &planes[FRUSTUM_LEFT], &planes[FRUSTUM_TOP], &planes[FRUSTUM_FAR], corners[0] );
PlanesGetIntersectionPoint( &planes[FRUSTUM_RIGHT], &planes[FRUSTUM_TOP], &planes[FRUSTUM_FAR], corners[1] );
PlanesGetIntersectionPoint( &planes[FRUSTUM_LEFT], &planes[FRUSTUM_BOTTOM], &planes[FRUSTUM_FAR], corners[2] );
PlanesGetIntersectionPoint( &planes[FRUSTUM_RIGHT], &planes[FRUSTUM_BOTTOM], &planes[FRUSTUM_FAR], corners[3] );
if( FBitSet( clipFlags, BIT( FRUSTUM_NEAR )))
{
PlanesGetIntersectionPoint( &planes[FRUSTUM_LEFT], &planes[FRUSTUM_TOP], &planes[FRUSTUM_NEAR], corners[4] );
PlanesGetIntersectionPoint( &planes[FRUSTUM_RIGHT], &planes[FRUSTUM_TOP], &planes[FRUSTUM_NEAR], corners[5] );
PlanesGetIntersectionPoint( &planes[FRUSTUM_LEFT], &planes[FRUSTUM_BOTTOM], &planes[FRUSTUM_NEAR], corners[6] );
PlanesGetIntersectionPoint( &planes[FRUSTUM_RIGHT], &planes[FRUSTUM_BOTTOM], &planes[FRUSTUM_NEAR], corners[7] );
}
else
{
PlanesGetIntersectionPoint( &planes[FRUSTUM_LEFT], &planes[FRUSTUM_RIGHT], &planes[FRUSTUM_TOP], corners[4] );
corners[7] = corners[6] = corners[5] = corners[4];
}
}
void CFrustum :: ComputeFrustumBounds( Vector &mins, Vector &maxs )
{
Vector corners[8];
ComputeFrustumCorners( corners );
ClearBounds( mins, maxs );
for( int i = 0; i < 8; i++ )
AddPointToBounds( corners[i], mins, maxs );
}
void CFrustum :: DrawFrustumDebug( void )
{
Vector bbox[8];
ComputeFrustumCorners( bbox );
// g-cont. frustum must be yellow :-)
pglColor4f( 1.0f, 1.0f, 0.0f, 1.0f );
GL_BindTexture( GL_TEXTURE0, tr.whiteTexture );
pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
pglBegin( GL_LINES );
for( int i = 0; i < 2; i += 1 )
{
pglVertex3fv( bbox[i+0] );
pglVertex3fv( bbox[i+2] );
pglVertex3fv( bbox[i+4] );
pglVertex3fv( bbox[i+6] );
pglVertex3fv( bbox[i+0] );
pglVertex3fv( bbox[i+4] );
pglVertex3fv( bbox[i+2] );
pglVertex3fv( bbox[i+6] );
pglVertex3fv( bbox[i*2+0] );
pglVertex3fv( bbox[i*2+1] );
pglVertex3fv( bbox[i*2+4] );
pglVertex3fv( bbox[i*2+5] );
}
pglEnd();
}
bool CFrustum :: CullBox( const Vector &mins, const Vector &maxs, int userClipFlags )
{
int iClipFlags;
if( CVAR_TO_BOOL( r_nocull ))
return false;
if( userClipFlags != 0 )
iClipFlags = userClipFlags;
else iClipFlags = clipFlags;
for( int i = 0; i < FRUSTUM_PLANES; i++ )
{
if( !FBitSet( iClipFlags, BIT( i )))
continue;
const mplane_t *p = &planes[i];
switch( p->signbits )
{
case 0:
if( p->normal.x * maxs.x + p->normal.y * maxs.y + p->normal.z * maxs.z < p->dist )
return true;
break;
case 1:
if( p->normal.x * mins.x + p->normal.y * maxs.y + p->normal.z * maxs.z < p->dist )
return true;
break;
case 2:
if( p->normal.x * maxs.x + p->normal.y * mins.y + p->normal.z * maxs.z < p->dist )
return true;
break;
case 3:
if( p->normal.x * mins.x + p->normal.y * mins.y + p->normal.z * maxs.z < p->dist )
return true;
break;
case 4:
if( p->normal.x * maxs.x + p->normal.y * maxs.y + p->normal.z * mins.z < p->dist )
return true;
break;
case 5:
if( p->normal.x * mins.x + p->normal.y * maxs.y + p->normal.z * mins.z < p->dist )
return true;
break;
case 6:
if( p->normal.x * maxs.x + p->normal.y * mins.y + p->normal.z * mins.z < p->dist )
return true;
break;
case 7:
if( p->normal.x * mins.x + p->normal.y * mins.y + p->normal.z * mins.z < p->dist )
return true;
break;
default:
return false;
}
}
return false;
}
bool CFrustum :: CullSphere( const Vector &centre, float radius, int userClipFlags )
{
int iClipFlags;
if( CVAR_TO_BOOL( r_nocull ))
return false;
if( userClipFlags != 0 )
iClipFlags = userClipFlags;
else iClipFlags = clipFlags;
for( int i = 0; i < FRUSTUM_PLANES; i++ )
{
if( !FBitSet( iClipFlags, BIT( i )))
continue;
const mplane_t *p = &planes[i];
if( DotProduct( centre, p->normal ) - p->dist <= -radius )
return true;
}
return false;
}
// FIXME: could be optimize?
bool CFrustum :: CullFrustum( CFrustum *frustum, int userClipFlags )
{
int iClipFlags;
Vector bbox[8];
if( CVAR_TO_BOOL( r_nocull ))
return false;
if( userClipFlags != 0 )
iClipFlags = userClipFlags;
else iClipFlags = clipFlags;
frustum->ComputeFrustumCorners( bbox );
for( int i = 0; i < FRUSTUM_PLANES; i++ )
{
if( !FBitSet( iClipFlags, BIT( i )))
continue;
const mplane_t *p = &planes[i];
for( int j = 0; j < 8; j++ )
{
// at least one point of other frustum intersect with our frustum
if( DotProduct( bbox[j], p->normal ) - p->dist >= ON_EPSILON )
return false;
}
}
return true;
}

View File

@ -0,0 +1,60 @@
/*
gl_frustum.h - frustum test implementation class
this code written for Paranoia 2: Savior modification
Copyright (C) 2014 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef GL_FRUSTUM_H
#define GL_FRUSTUM_H
// don't change this order
#define FRUSTUM_LEFT 0
#define FRUSTUM_RIGHT 1
#define FRUSTUM_BOTTOM 2
#define FRUSTUM_TOP 3
#define FRUSTUM_FAR 4
#define FRUSTUM_NEAR 5
#define FRUSTUM_PLANES 6
class CFrustum
{
public:
void InitProjection( const matrix4x4 &view, float flZNear, float flZFar, float flFovX, float flFovY );
void InitOrthogonal( const matrix4x4 &view, float xLeft, float xRight, float yBottom, float yTop, float flZNear, float flZFar );
void InitBoxFrustum( const Vector &org, float radius ); // used for pointlights
void InitProjectionFromMatrix( const matrix4x4 &projection );
void SetPlane( int side, const mplane_t *plane ) { planes[side] = *plane; }
void SetPlane( int side, const Vector &vecNormal, float flDist );
void NormalizePlane( int side );
const mplane_t *GetPlane( int side ) const { return &planes[side]; }
const mplane_t *GetPlanes( void ) const { return &planes[0]; }
unsigned int GetClipFlags( void ) const { return clipFlags; }
void ComputeFrustumBounds( Vector &mins, Vector &maxs );
void ComputeFrustumCorners( Vector bbox[8] );
void DrawFrustumDebug( void );
void ClearFrustum( void );
// cull methods
bool CullBox( const Vector &mins, const Vector &maxs, int userClipFlags = 0 );
bool CullSphere( const Vector &centre, float radius, int userClipFlags = 0 );
bool CullFrustum( CFrustum *frustum, int userClipFlags = 0 );
// plane manipulating
void EnablePlane( int side );
void DisablePlane( int side );
private:
mplane_t planes[FRUSTUM_PLANES];
unsigned int clipFlags;
};
#endif//GL_FRUSTUM_H

1775
cl_dll/render/gl_grass.cpp Normal file

File diff suppressed because it is too large Load Diff

116
cl_dll/render/gl_grass.h Normal file
View File

@ -0,0 +1,116 @@
/*
gl_grass.h - grass construct & rendering
this code written for Paranoia 2: Savior modification
Copyright (C) 2014 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef GL_GRASS_H
#define GL_GRASS_H
#define GRASS_TEXTURES 256 // unique textures for grass (a byte limit, don't change)
#define GRASS_ANIM_DIST 512.0f // if this is changed it must be changed in glsl too!
#define MAX_GRASS_ELEMS 65536 // unsigned short limit
#define MAX_GRASS_VERTS ( MAX_GRASS_ELEMS / 2 ) // ( numelems / 1.5 ) actually
#define MAX_GRASS_BUSHES ( MAX_GRASS_VERTS / 16 ) // one bush contain 4 poly, so we have 2048 bushes max per one surface
#define GRASS_SKY_DIST BOGUS_RANGE // in-world grass never reach this value
typedef struct grassentry_s
{
char name[16]; // name of level texture
byte texture; // number in array of grass textures
float density; // grass density (0 - 100)
float min; // min grass scale
float max; // max grass scale
int seed; // seed for predictable random (auto-filled)
} grassentry_t;
typedef struct grasstexture_s
{
char name[256]; // path to grass texture
int gl_texturenum; // gl-texture
} grasstexture_t;
typedef struct gvert_s
{
float center[4]; // used for rescale
float normal[4]; // center + vertex[2] * vertex[3];
float light[MAXLIGHTMAPS]; // packed color + unused entry
float delux[MAXLIGHTMAPS]; // packed lightdir + unused entry
byte styles[MAXLIGHTMAPS]; // styles on surface
} gvert_t;
#define FGRASS_NODRAW BIT( 0 ) // grass shader is failed to build
#define FGRASS_NODLIGHT BIT( 1 ) // grass dlight shader is failed to build
#define FGRASS_NOSUNLIGHT BIT( 2 ) // grass dlight shader is failed to build
#define FRGASS_SKYENTITY BIT( 3 ) // it's sky grass
// all the grassdata for one polygon and specified texture
// stored into single vbo
typedef struct grass_s
{
// shader cache
shader_t forwardScene;
shader_t forwardLightSpot;
shader_t forwardLightOmni;
shader_t forwardLightProj;
shader_t deferredScene;
shader_t deferredLight;
shader_t forwardDepth;
byte texture; // not a real texture just index into array
byte flags; // state flags
unsigned short numVerts; // for glDrawRangeElementsEXT
unsigned short numElems; // for glDrawElements
unsigned int vbo, vao, ibo; // buffer objects
unsigned short hCachedMatrix; // HACKHACK: get matrices
byte lights[MAXDYNLIGHTS];/// light numbers
unsigned int cacheSize; // debug info: uploaded cache size for this buffer
} grass_t;
typedef void (*pfnCreateGrassBuffer)( grass_t *pOut, gvert_t *arrayxvert );
typedef void (*pfnBindGrassBuffer)( grass_t *pOut, int attrFlags );
enum
{
GRASSLOADER_BASE = 0,
GRASSLOADER_BASEBUMP,
GRASSLOADER_COUNT,
};
typedef struct
{
pfnCreateGrassBuffer CreateBuffer;
pfnBindGrassBuffer BindBuffer;
const char* BufferName; // debug
} grass_loader_t;
typedef struct grasshdr_s
{
Vector mins, maxs; // per-poly culling
int count; // total bush count for this poly
grass_t g[1]; // variable sized
} grasshdr_t;
extern void R_GrassInit( void );
extern void R_GrassShutdown( void );
extern void R_GrassInitForSurface( msurface_t *surf );
extern void R_RenderGrassOnList( void );
extern void R_GrassSetupFrame( void );
extern void R_RenderShadowGrassOnList( void );
extern void R_DrawLightForGrass( CDynLight *pl );
extern void R_AddGrassToDrawList( msurface_t *s, drawlist_t type );
extern void R_PrecacheGrass( msurface_t *s, mextraleaf_t *leaf );
extern void R_RemoveGrassForSurface( mextrasurf_t *es );
extern void R_UnloadFarGrass( void );
#endif//GL_GRASS_H

View File

@ -0,0 +1,757 @@
/*
gl_lightmap.cpp - generate lightmaps and uploading them
Copyright (C) 2016 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "hud.h"
#include "cl_util.h"
#include "const.h"
#include "studio.h"
#include "com_model.h"
#include "ref_params.h"
#include "gl_local.h"
#include <stringlib.h>
#include "gl_shader.h"
#include "gl_world.h"
/*
=============================================================================
LIGHTMAP ALLOCATION
=============================================================================
*/
static int LM_AllocBlock( unsigned short w, unsigned short h, unsigned short *x, unsigned short *y )
{
gl_lightmap_t *lms = &tr.lightmaps[tr.current_lightmap_texture];
unsigned short i, j, best, best2;
best = BLOCK_SIZE;
for( i = 0; i < BLOCK_SIZE - w; i++ )
{
best2 = 0;
for( j = 0; j < w; j++ )
{
if( lms->allocated[i+j] >= best )
break;
if( lms->allocated[i+j] > best2 )
best2 = lms->allocated[i+j];
}
if( j == w )
{
// this is a valid spot
*x = i;
*y = best = best2;
}
}
if( best + h > BLOCK_SIZE )
{
// current lightmap is full
lms->state = LM_DONE;
return false;
}
for( i = 0; i < w; i++ )
lms->allocated[*x + i] = best + h;
lms->state = LM_USED; // lightmap in use
return true;
}
static void LM_InitBlock( void )
{
word dummy;
gl_lightmap_t *lms = &tr.lightmaps[tr.current_lightmap_texture];
memset( lms->allocated, 0, sizeof( lms->allocated ));
// first block at pos 0,0 used as black lightmap for studiomodel
LM_AllocBlock( 1, 1, &dummy, &dummy );
}
static void LM_UploadPages( bool lightmap, bool deluxmap )
{
char lmName[16];
byte lightBuf[4];
byte deluxBuf[4];
int i;
lightBuf[0] = 0;
lightBuf[1] = 0;
lightBuf[2] = 0;
lightBuf[3] = 0;
deluxBuf[0] = 127;
deluxBuf[1] = 127;
deluxBuf[2] = 255;
deluxBuf[3] = 0;
for( i = 0; i < MAX_LIGHTMAPS && tr.lightmaps[i].state != LM_FREE; i++ )
{
gl_lightmap_t *lms = &tr.lightmaps[i];
if( lightmap && !lms->lightmap )
{
Q_snprintf( lmName, sizeof( lmName ), "*diffuse%i", i );
lms->lightmap = CREATE_TEXTURE( lmName, BLOCK_SIZE, BLOCK_SIZE, NULL, TF_LIGHTMAP );
// also loading dummy blackpixel
GL_BindTexture( GL_TEXTURE0, lms->lightmap );
pglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, lightBuf );
}
if( deluxmap && !lms->deluxmap )
{
Q_snprintf( lmName, sizeof( lmName ), "*normals%i", i );
lms->deluxmap = CREATE_TEXTURE( lmName, BLOCK_SIZE, BLOCK_SIZE, NULL, TF_DELUXMAP );
// also loading dummy blackpixel
GL_BindTexture( GL_TEXTURE0, lms->deluxmap );
pglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, deluxBuf );
}
}
}
static void LM_GoToNextPage( void )
{
gl_lightmap_t *lms = &tr.lightmaps[tr.current_lightmap_texture];
if( lms->state != LM_DONE ) return; // current atlas not completed
if( ++tr.current_lightmap_texture == MAX_LIGHTMAPS )
HOST_ERROR( "MAX_LIGHTMAPS limit exceded\n" );
}
/*
==================
GL_BeginBuildingLightmaps
==================
*/
void GL_BeginBuildingLightmaps( void )
{
int i;
// release old lightmaps first
for( i = 0; i < MAX_LIGHTMAPS && tr.lightmaps[i].state != LM_FREE; i++ )
{
FREE_TEXTURE( tr.lightmaps[i].lightmap );
FREE_TEXTURE( tr.lightmaps[i].deluxmap );
}
memset( tr.lightmaps, 0, sizeof( tr.lightmaps ));
tr.current_lightmap_texture = 0;
LM_InitBlock();
}
/*
=================
Mod_AllocLightmapForFace
NOTE: we don't loading lightmap here.
just create lmcoords and set lmnum
=================
*/
void GL_AllocLightmapForFace( msurface_t *surf )
{
mextrasurf_t *esrf = surf->info;
word smax, tmax;
int map;
// always reject the tiled faces
if( FBitSet( surf->flags, SURF_DRAWSKY ))
return;
// no lightdata and no deluxdata
if( !surf->samples && !esrf->normals )
return;
int sample_size = Mod_SampleSizeForFace( surf );
smax = ( surf->info->lightextents[0] / sample_size ) + 1;
tmax = ( surf->info->lightextents[1] / sample_size ) + 1;
new_page:
// alloc blocks for all the styles on current page
for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != LS_NONE; map++ )
{
if( !LM_AllocBlock( smax, tmax, &esrf->light_s[map], &esrf->light_t[map] ))
{
// current page is not enough room for next 1-4 blocks
LM_GoToNextPage();
LM_InitBlock();
goto new_page;
}
}
// lightmap will be uploaded as far as player can see it
esrf->lightmaptexturenum = tr.current_lightmap_texture;
SetBits( surf->flags, SURF_LM_UPDATE|SURF_DM_UPDATE );
}
/*
=================
Mod_AllocLightmapForFace
NOTE: we don't loading lightmap here.
just create lmcoords and set lmnum
=================
*/
bool GL_AllocLightmapForFace( mstudiosurface_t *surf )
{
word smax, tmax;
int map;
smax = surf->lightextents[0] + 1;
tmax = surf->lightextents[1] + 1;
// alloc blocks for all the styles on current page
for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != LS_NONE; map++ )
{
if( !LM_AllocBlock( smax, tmax, &surf->light_s[map], &surf->light_t[map] ))
{
// current page is not enough room for next 1-4 blocks
LM_GoToNextPage();
LM_InitBlock();
return false;
}
}
// lightmap will be uploaded as far as player can see it
surf->lightmaptexturenum = tr.current_lightmap_texture;
SetBits( surf->flags, SURF_LM_UPDATE|SURF_DM_UPDATE );
return true;
}
/*
=======================
GL_EndBuildingLightmaps
=======================
*/
void GL_EndBuildingLightmaps( bool lightmap, bool deluxmap )
{
LM_UploadPages( lightmap, deluxmap );
}
/*
=================
R_BuildLightMapForStyle
write lightmap into page for a given style
=================
*/
static void R_BuildLightMapForStyle( msurface_t *surf, byte *dest, int style )
{
mextrasurf_t *esrf = surf->info;
int stride, size;
int smax, tmax;
int s, t;
color24 *lm;
byte *sm;
ASSERT( style >= 0 && style < MAXLIGHTMAPS );
// always reject the sky faces
if( FBitSet( surf->flags, SURF_DRAWSKY ))
return;
// no lightdata or style missed
if( !surf->samples || surf->styles[style] == LS_NONE )
return;
int sample_size = Mod_SampleSizeForFace( surf );
smax = ( surf->info->lightextents[0] / sample_size ) + 1;
tmax = ( surf->info->lightextents[1] / sample_size ) + 1;
size = smax * tmax;
// jump to specified style
lm = surf->samples + size * style;
sm = esrf->shadows + size * style;
// put into texture format
stride = (smax * 4) - (smax << 2);
for( t = 0; t < tmax; t++, dest += stride )
{
for( s = 0; s < smax; s++ )
{
dest[0] = TEXTURE_TO_TEXGAMMA( lm->r );
dest[1] = TEXTURE_TO_TEXGAMMA( lm->g );
dest[2] = TEXTURE_TO_TEXGAMMA( lm->b );
if( esrf->shadows != NULL )
dest[3] = *sm++;
else dest[3] = 255;
dest += 4;
lm++;
}
}
}
/*
=================
R_BuildLightMapForStyle
write lightmap into page for a given style
=================
*/
static void R_BuildLightMapForStyle( mstudiosurface_t *surf, byte *dest, int style )
{
int stride, size;
int smax, tmax;
int s, t;
color24 *lm;
byte *sm;
ASSERT( style >= 0 && style < MAXLIGHTMAPS );
// no lightdata or style missed
if( !surf->samples || surf->styles[style] == LS_NONE )
return;
smax = surf->lightextents[0] + 1;
tmax = surf->lightextents[1] + 1;
size = smax * tmax;
// jump to specified style
lm = surf->samples + size * style;
sm = surf->shadows + size * style;
// put into texture format
stride = (smax * 4) - (smax << 2);
for( t = 0; t < tmax; t++, dest += stride )
{
for( s = 0; s < smax; s++ )
{
dest[0] = TEXTURE_TO_TEXGAMMA( lm->r );
dest[1] = TEXTURE_TO_TEXGAMMA( lm->g );
dest[2] = TEXTURE_TO_TEXGAMMA( lm->b );
if( surf->shadows != NULL )
dest[3] = *sm++;
else dest[3] = 255;
dest += 4;
lm++;
}
}
}
/*
=================
R_BuildDeluxMapForStyle
write deluxmap into page for a given style
=================
*/
static void R_BuildDeluxMapForStyle( msurface_t *surf, byte *dest, int style )
{
mextrasurf_t *esrf = surf->info;
int stride, size;
int smax, tmax;
int s, t;
color24 *dm;
ASSERT( style >= 0 && style < MAXLIGHTMAPS );
// always reject the sky faces
if( FBitSet( surf->flags, SURF_DRAWSKY ))
return;
// no lightdata or style missed
if( !esrf->normals || surf->styles[style] == LS_NONE )
return;
int sample_size = Mod_SampleSizeForFace( surf );
smax = ( surf->info->lightextents[0] / sample_size ) + 1;
tmax = ( surf->info->lightextents[1] / sample_size ) + 1;
size = smax * tmax;
// jump to specified style
dm = esrf->normals + size * style;
// put into texture format
stride = (smax * 4) - (smax << 2);
for( t = 0; t < tmax; t++, dest += stride )
{
for( s = 0; s < smax; s++ )
{
dest[0] = dm->r;
dest[1] = dm->g;
dest[2] = dm->b;
dest[3] = 255;
dest += 4;
dm++;
}
}
}
/*
=================
R_BuildDeluxMapForStyle
write deluxmap into page for a given style
=================
*/
static void R_BuildDeluxMapForStyle( mstudiosurface_t *surf, byte *dest, int style )
{
int stride, size;
int smax, tmax;
int s, t;
color24 *dm;
ASSERT( style >= 0 && style < MAXLIGHTMAPS );
// no lightdata or style missed
if( !surf->normals || surf->styles[style] == LS_NONE )
return;
smax = surf->lightextents[0] + 1;
tmax = surf->lightextents[1] + 1;
size = smax * tmax;
// jump to specified style
dm = surf->normals + size * style;
// put into texture format
stride = (smax * 4) - (smax << 2);
for( t = 0; t < tmax; t++, dest += stride )
{
for( s = 0; s < smax; s++ )
{
dest[0] = dm->r;
dest[1] = dm->g;
dest[2] = dm->b;
dest[3] = 255;
dest += 4;
dm++;
}
}
}
/*
=================
R_UpdateLightMap
Combine and scale multiple lightmaps into the floating
format in r_blocklights
=================
*/
static void R_UpdateLightMap( msurface_t *surf )
{
mextrasurf_t *esrf = surf->info;
static byte buf[132*132*4];
int map, smax, tmax;
// always reject the sky faces
if( FBitSet( surf->flags, SURF_DRAWSKY ))
return;
int sample_size = Mod_SampleSizeForFace( surf );
smax = ( surf->info->lightextents[0] / sample_size ) + 1;
tmax = ( surf->info->lightextents[1] / sample_size ) + 1;
// upload the lightmap
if( surf->samples != NULL && FBitSet( surf->flags, SURF_LM_UPDATE ))
{
GL_BindTexture( GL_TEXTURE0, tr.lightmaps[esrf->lightmaptexturenum].lightmap );
// write lightmaps into page
for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != LS_NONE; map++ )
{
R_BuildLightMapForStyle( surf, buf, map );
pglTexSubImage2D( GL_TEXTURE_2D, 0, esrf->light_s[map], esrf->light_t[map], smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, buf );
}
}
ClearBits( surf->flags, SURF_LM_UPDATE );
// upload the deluxemap
if( esrf->normals != NULL && FBitSet( surf->flags, SURF_DM_UPDATE ))
{
GL_BindTexture( GL_TEXTURE0, tr.lightmaps[esrf->lightmaptexturenum].deluxmap );
// write lightmaps into page
for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != LS_NONE; map++ )
{
R_BuildDeluxMapForStyle( surf, buf, map );
pglTexSubImage2D( GL_TEXTURE_2D, 0, esrf->light_s[map], esrf->light_t[map], smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, buf );
}
}
ClearBits( surf->flags, SURF_DM_UPDATE );
}
/*
=================
R_UpdateLightMap
Combine and scale multiple lightmaps into the floating
format in r_blocklights
=================
*/
static void R_UpdateLightMap( mstudiosurface_t *surf )
{
static byte buf[512*512*4];
int map, smax, tmax;
smax = surf->lightextents[0] + 1;
tmax = surf->lightextents[1] + 1;
// upload the lightmap
if( surf->samples != NULL && FBitSet( surf->flags, SURF_LM_UPDATE ))
{
GL_BindTexture( GL_TEXTURE0, tr.lightmaps[surf->lightmaptexturenum].lightmap );
// write lightmaps into page
for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != LS_NONE; map++ )
{
R_BuildLightMapForStyle( surf, buf, map );
pglTexSubImage2D( GL_TEXTURE_2D, 0, surf->light_s[map], surf->light_t[map], smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, buf );
}
}
ClearBits( surf->flags, SURF_LM_UPDATE );
// upload the deluxemap
if( surf->normals != NULL && FBitSet( surf->flags, SURF_DM_UPDATE ))
{
GL_BindTexture( GL_TEXTURE0, tr.lightmaps[surf->lightmaptexturenum].deluxmap );
// write lightmaps into page
for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != LS_NONE; map++ )
{
R_BuildDeluxMapForStyle( surf, buf, map );
pglTexSubImage2D( GL_TEXTURE_2D, 0, surf->light_s[map], surf->light_t[map], smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, buf );
}
}
ClearBits( surf->flags, SURF_DM_UPDATE );
}
/*
========================
R_TextureCoords
fill vec2_t with texture coords
========================
*/
void R_TextureCoords( msurface_t *surf, const Vector &vec, float *out )
{
float s, t;
s = DotProduct( vec, surf->texinfo->vecs[0] ) + surf->texinfo->vecs[0][3];
s /= surf->texinfo->texture->width;
t = DotProduct( vec, surf->texinfo->vecs[1] ) + surf->texinfo->vecs[1][3];
t /= surf->texinfo->texture->height;
out[0] = s;
out[1] = t;
}
/*
========================
R_GlobalCoords
fill vec2_t with global coords
========================
*/
void R_GlobalCoords( msurface_t *surf, const Vector &point, float *out )
{
mfaceinfo_t *land = surf->texinfo->faceinfo;
terrain_t *terra;
Vector size;
indexMap_t *im;
if( !land ) return;
terra = land->terrain;
if( !terra ) return;
im = &terra->indexmap;
for( int i = 0; i < 3; i++ )
size[i] = land->maxs[i] - land->mins[i];
out[2] = ( point[0] - land->mins[0] ) / size[0];
out[3] = ( land->maxs[1] - point[1] ) / size[1];
}
/*
========================
R_GlobalCoords
fill vec2_t with global coords
========================
*/
void R_GlobalCoords( msurface_t *surf, const Vector &point, const Vector &absmin, const Vector &absmax, float scale, float *out )
{
Vector size;
for( int i = 0; i < 3; i++ )
size[i] = absmax[i] - absmin[i];
out[2] = (( point[0] - absmin[0] ) / size[0]) * scale;
out[3] = (( absmax[1] - point[1] ) / size[1]) * scale;
}
/*
========================
R_LightmapCoords
fill Vector4D with lightstyle coords (two styles per array)
========================
*/
void R_LightmapCoords( msurface_t *surf, const Vector &vec, float *coords, int style )
{
mextrasurf_t *esrf = surf->info;
float sample_size = Mod_SampleSizeForFace( surf );
float s, t;
for( int i = 0; i < 2; i++ )
{
if( surf->styles[style+i] == LS_NONE )
return; // end of styles
s = DotProduct( vec, surf->info->lmvecs[0] ) + surf->info->lmvecs[0][3];
s -= surf->info->lightmapmins[0];
s += esrf->light_s[style+i] * sample_size;
s += sample_size * 0.5f;
s /= BLOCK_SIZE * sample_size;
t = DotProduct( vec, surf->info->lmvecs[1] ) + surf->info->lmvecs[1][3];
t -= surf->info->lightmapmins[1];
t += esrf->light_t[style+i] * sample_size;
t += sample_size * 0.5f;
t /= BLOCK_SIZE * sample_size;
coords[i*2+0] = s;
coords[i*2+1] = t;
}
}
/*
========================
R_LightmapCoords
fill Vector4D with lightstyle coords (two styles per array)
========================
*/
void R_LightmapCoords( mstudiosurface_t *surf, const Vector &vec, const Vector lmvecs[2], float *coords, int style )
{
float s, t;
for( int i = 0; i < 2; i++ )
{
if( surf->styles[style+i] == LS_NONE )
return; // end of styles
s = DotProduct( vec, lmvecs[0] ) + surf->light_s[style+i] + 0.5f;
t = DotProduct( vec, lmvecs[1] ) + surf->light_t[style+i] + 0.5f;
s /= (float)BLOCK_SIZE;
t /= (float)BLOCK_SIZE;
coords[i*2+0] = s;
coords[i*2+1] = t;
}
}
/*
=================
R_UpdateSurfaceParams
update some surface params
if this was changed
=================
*/
void R_UpdateSurfaceParams( msurface_t *surf )
{
mextrasurf_t *esrf = surf->info;
cl_entity_t *e = RI->currententity;
model_t *clmodel = e->model;
// check for lightmap modification
if( FBitSet( surf->flags, SURF_LM_UPDATE|SURF_DM_UPDATE ))
R_UpdateLightMap( surf );
if( FBitSet( surf->flags, SURF_MOVIE ))
R_UpdateCinematic( surf );
// handle conveyor movement
if( FBitSet( clmodel->flags, BIT( 0 )) && FBitSet( surf->flags, SURF_CONVEYOR ))
{
float flRate, flAngle;
float flWidth, flConveyorSpeed;
float sOffset, sy;
float tOffset, cy;
flConveyorSpeed = (e->curstate.rendercolor.g<<8|e->curstate.rendercolor.b) / 16.0f;
if( e->curstate.rendercolor.r ) flConveyorSpeed = -flConveyorSpeed;
flWidth = (float)RENDER_GET_PARM( PARM_TEX_SRC_WIDTH, surf->texinfo->texture->gl_texturenum );
if( flWidth != 0.0f )
{
flRate = abs( flConveyorSpeed ) / flWidth;
flAngle = ( flConveyorSpeed >= 0.0f ) ? 180.0f : 0.0f;
SinCos( DEG2RAD( flAngle ), &sy, &cy );
sOffset = tr.time * cy * flRate;
tOffset = tr.time * sy * flRate;
// make sure that we are positive
if( sOffset < 0.0f ) sOffset += 1.0f + -(int)sOffset;
if( tOffset < 0.0f ) tOffset += 1.0f + -(int)tOffset;
// make sure that we are in a [0,1] range
sOffset = sOffset - (int)sOffset;
tOffset = tOffset - (int)tOffset;
esrf->texofs[0] = sOffset;
esrf->texofs[1] = tOffset;
}
else
{
// no conveyor
esrf->texofs[0] = 0.0f;
esrf->texofs[1] = 0.0f;
}
}
else
{
// no conveyor
esrf->texofs[0] = 0.0f;
esrf->texofs[1] = 0.0f;
}
}
/*
=================
R_UpdateSurfaceParams
update some surface params
if this was changed
=================
*/
void R_UpdateSurfaceParams( mstudiosurface_t *surf )
{
// check for lightmap modification
if( FBitSet( surf->flags, SURF_LM_UPDATE|SURF_DM_UPDATE ))
R_UpdateLightMap( surf );
}

998
cl_dll/render/gl_local.h Normal file
View File

@ -0,0 +1,998 @@
/*
gl_local.h - renderer local definitions
this code written for Paranoia 2: Savior modification
Copyright (C) 2013 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef GL_LOCAL_H
#define GL_LOCAL_H
#include "gl_export.h"
#include "ref_params.h"
#include "com_model.h"
#include "r_studioint.h"
#include "gl_framebuffer.h"
#include "gl_frustum.h"
#include "gl_primitive.h"
#include "cl_dlight.h"
#include "features.h"
#include <utlarray.h>
#include <matrix.h>
#define ACTUAL_GL_VERSION 30.0f
// limits
#define MAX_REF_STACK 8 // pass depth
#define MAX_VISIBLE_ENTS 4096 // total pack of frame ents
#define MAX_SORTED_FACES 32768 // bmodels only
#define MAX_SUBVIEW_FACES 1024 // mirrors, portals, monitors, water, puddles. NOTE: multipass faces can merge view passes
#define MAX_OCCLUDED_FACES 1024 // mirrors + water
#define MAX_SORTED_MESHES 2048 // studio only
#define MAX_MOVIES 16 // max various movies per level
#define MAX_MOVIE_TEXTURES 64 // max # of unique video textures per level
#define MAX_LIGHTSTYLES 64 // a byte limit, don't modify
#define MAX_LIGHTMAPS 256 // Xash3D supports up to 256 lightmaps
#define MAX_DLIGHTS 64 // per one frame. unsigned int limit
#define MAX_ENGINE_DLIGHTS 32
#define MAX_LIGHTCACHE 2048 // unique models with instanced vertex lighting
#define MAX_SHADOWS MAX_DLIGHTS
#define MAX_SUBVIEW_TEXTURES 64 // total depth
#define MAX_FRAMEBUFFERS MAX_SUBVIEW_TEXTURES
#define MAX_FBO_ATTACHMENTS 8 // color attachments per FBO
#define DEFAULT_CUBEMAP_SIZE 32 // same as in Source
#define AMBIENT_EPSILON 0.001f // to avoid division by zero
#define STAIR_INTERP_TIME 100.0f
#define LIGHT_PROBES 10 // eight OBB corners, center and one reserved slot (NOTE: not all the probes will be used)
#define LIGHT_SAMPLES 8 // GPU limitation for local arrays (very slowly if more than eight elements)
#define MOD_FRAMES 20
#define WATER_TEXTURES 29
#define WATER_ANIMTIME 20.0f
#define INVALID_HANDLE 0xFFFF // studio cache
#define FLASHLIGHT_KEY -666
#define SUNLIGHT_KEY -777
#define SKYBOX_ENTITY 70
#define LM_SAMPLE_SIZE 16
#define LM_SAMPLE_EXTRASIZE 8
#define BLOCK_SIZE glConfig.block_size // lightmap blocksize
#define BLOCK_SIZE_DEFAULT 128 // for keep backward compatibility
#define BLOCK_SIZE_MAX 2048 // must match with engine const!!!
#define SHADOW_SIZE 4096 // atlas size
#define WORLD_MATRIX 0 // must be 0 always
#define REFPVS_RADIUS 2.0f // PVS radius for rendering
#define Z_NEAR 4.0f
#define Z_NEAR_LIGHT 0.1f
#define BACKFACE_EPSILON 0.01f
#define CVAR_TO_BOOL( x ) ((x) && ((x)->value != 0.0f) ? true : false )
// VBO offsets
#define OFFSET( type, var ) ((const void *)&(((type *)NULL)->var))
#define R_OpaqueEntity( e ) (( (e)->curstate.rendermode == kRenderNormal ) || ( (e)->curstate.rendermode == kRenderTransAlpha ))
#define R_ModelOpaque( rm ) (( rm == kRenderNormal ) || ( rm == kRenderTransAlpha ))
#define R_StaticEntity( e ) ( (e)->origin == g_vecZero && (e)->angles == g_vecZero && (e)->curstate.renderfx != SKYBOX_ENTITY )
#define R_FullBright() ( CVAR_TO_BOOL( r_fullbright ) || !worldmodel->lightdata )
#define RP_OUTSIDE( leaf ) (((( leaf ) - worldmodel->leafs ) - 1 ) == -1 )
#define R_WaterEntity( m ) ( FBitSet( m->flags, BIT( 2 )))
#define ScreenCopyRequired( x ) ((x) && FBitSet( (x)->status, SHADER_USE_SCREENCOPY ))
#define IsReflectShader( x ) ((x) && FBitSet( (x)->status, SHADER_USE_CUBEMAPS ))
// refparams
#define RP_NONE 0
#define RP_THIRDPERSON BIT( 0 )
#define RP_DRAW_WORLD BIT( 1 ) // otherwise it's player customization window
#define RP_DRAW_OVERVIEW BIT( 2 ) // dev_overview is active
#define RP_CLIPPLANE BIT( 3 ) // mirrors used
#define RP_MERGE_PVS BIT( 4 ) // merge PVS with previous pass
#define RP_MIRRORVIEW BIT( 5 ) // lock pvs at vieworg
#define RP_ENVVIEW BIT( 6 ) // used for cubemapshot
#define RP_SHADOWVIEW BIT( 7 ) // view through light
#define RP_NOSHADOWS BIT( 8 ) // disable shadows for this pass
#define RP_SKYVIEW BIT( 9 ) // render skyonly
#define RP_WATERPASS BIT( 10 ) // it's mirorring plane for water surface
#define RP_NOGRASS BIT( 11 ) // don't draw grass
#define RP_DEFERREDSCENE BIT( 12 ) // render scene into geometry buffer
#define RP_DEFERREDLIGHT BIT( 13 ) // render scene into low-res lightmap
// RI->view.changed
#define RC_ORIGIN_CHANGED BIT( 0 ) // origin is changed from the previous frame
#define RC_ANGLES_CHANGED BIT( 1 ) // angles is changed from the previous frame
#define RC_VIEWLEAF_CHANGED BIT( 2 ) // viewleaf is changed
#define RC_FOV_CHANGED BIT( 3 ) // FOV is changed
#define RC_PVS_CHANGED BIT( 4 ) // now our PVS was potentially changed :-)
#define RC_FRUSTUM_CHANGED BIT( 5 ) // now our frustum was potentially changed :-)
#define RC_FORCE_UPDATE BIT( 6 ) // some cvar manipulations invoke updates of visible list
// RI->view.flags
#define RF_SKYVISIBLE BIT( 0 ) // sky is visible for this frame
#define RF_HASDYNLIGHTS BIT( 1 ) // pass have dynlights
#define RP_NONVIEWERREF (RP_MIRRORVIEW|RP_ENVVIEW|RP_SHADOWVIEW|RP_SKYVIEW)
#define RP_LOCALCLIENT( e ) (gEngfuncs.GetLocalPlayer() && ((e)->index == gEngfuncs.GetLocalPlayer()->index && e->curstate.entityType == ET_PLAYER ))
#define RP_NORMALPASS() ( FBitSet( RI->params, RP_NONVIEWERREF ) == 0 )
#define RP_CUBEPASS() ( FBitSet( RI->params, RP_SKYVIEW|RP_ENVVIEW ))
#define TF_LIGHTMAP (TF_NOMIPMAP|TF_CLAMP|TF_ATLAS_PAGE|TF_HAS_ALPHA)
#define TF_DELUXMAP (TF_CLAMP|TF_NOMIPMAP|TF_NORMALMAP|TF_ATLAS_PAGE)
#define TF_IMAGE (TF_NOMIPMAP|TF_CLAMP)
#define TF_SCREEN (TF_NOMIPMAP|TF_CLAMP)
#define TF_SPOTLIGHT (TF_NOMIPMAP|TF_BORDER)
#define TF_SHADOW (TF_NOMIPMAP|TF_CLAMP|TF_DEPTHMAP|TF_LUMINANCE)
#define TF_SHADOW_CUBEMAP (TF_NOMIPMAP|TF_CLAMP|TF_CUBEMAP|TF_DEPTHMAP|TF_LUMINANCE)
#define TF_RECTANGLE_SCREEN (TF_RECTANGLE|TF_NOMIPMAP|TF_CLAMP)
#define TF_DEPTH (TF_NOMIPMAP|TF_CLAMP|TF_NEAREST|TF_DEPTHMAP|TF_LUMINANCE|TF_NOCOMPARE)
#define TF_GRASS (TF_CLAMP)
#define TF_DEPTHBUFF (TF_DEPTHMAP|TF_LUMINANCE|TF_NOCOMPARE)
#define TF_STORAGE (TF_NEAREST|TF_RECTANGLE|TF_ARB_FLOAT|TF_HAS_ALPHA|TF_CLAMP|TF_NOMIPMAP)
#define TF_DEPTHBUFFER (TF_SCREEN|TF_DEPTHMAP|TF_NEAREST|TF_NOCOMPARE)
#define TF_COLORBUFFER (TF_SCREEN|TF_NEAREST)
#define CULL_VISIBLE 0 // not culled
#define CULL_BACKSIDE 1 // backside of transparent wall
#define CULL_FRUSTUM 2 // culled by frustum
#define CULL_OTHER 3 // culled by other reason
#define TF_RT_COLOR (TF_NEAREST|TF_CLAMP|TF_NOMIPMAP)
#define TF_RT_NORMAL (TF_NEAREST|TF_CLAMP|TF_NOMIPMAP|TF_NORMALMAP)
#define TF_RT_DEPTH (TF_NEAREST|TF_CLAMP|TF_NOMIPMAP|TF_DEPTHMAP|TF_NOCOMPARE)
#define MAT_ALL_EFFECTS (BRUSH_HAS_BUMP|BRUSH_HAS_SPECULAR|BRUSH_REFLECT|BRUSH_FULLBRIGHT)
#define FBO_MAIN 0
// light types
#define LIGHT_SPOT 0 // standard projection light
#define LIGHT_OMNI 1 // omnidirectional light
#define LIGHT_DIRECTIONAL 2 // parallel light (sun light)
// helpers
#define GetVForward() Vector( RI->view.matrix[0] )
#define GetVRight() Vector( RI->view.matrix[1] )
#define GetVLeft() -Vector(RI->view.matrix[1] )
#define GetVUp() Vector( RI->view.matrix[2] )
#define GetVieworg() RI->view.origin
typedef enum
{
DRAWLIST_ALL = 0, // special case for decals
DRAWLIST_SOLID,
DRAWLIST_TRANS,
DRAWLIST_LIGHT,
DRAWLIST_SUBVIEW,
DRAWLIST_SHADOW,
} drawlist_t;
enum
{
BUMP_BASELIGHT_STYLE = 61,
BUMP_ADDLIGHT_STYLE = 62,
BUMP_LIGHTVECS_STYLE = 63,
};
class DecalGroupEntry;
typedef int (*cmpfunc)( const void *a, const void *b );
typedef void (*pfnShaderCallback)( struct glsl_prog_s *shader );
// multiple output draw buffers
typedef struct
{
char name[32];
int width;
int height;
int depth;
int colortarget[MAX_FBO_ATTACHMENTS];
int depthtarget;
uint id;
} gl_drawbuffer_t;
typedef struct gl_fbo_s
{
GLboolean init;
GLuint framebuffer;
GLuint renderbuffer;
int texture;
} gl_fbo_t;
typedef struct gl_movie_s
{
char name[32];
void *state;
float length; // total cinematic length
long xres, yres; // size of cinematic
} gl_movie_t;
typedef struct gl_texbuffer_s
{
int framebuffer;
int texturenum;
int texframe; // this frame texture was used
matrix4x4 matrix; // texture matrix
} gl_texbuffer_t;
class gl_state_t
{
public:
GLfloat modelMatrix[16]; // matrix4x4( origin, angles, scale )
matrix4x4 transform; // entity transformation matrix
bool m_bSkyEntity;
const Vector GetModelOrigin( void );
};
typedef enum
{
LM_FREE = 0, // lightmap is clear
LM_USED, // partially used, has free space
LM_DONE, // completely full
} lmstate_t;
typedef struct
{
lmstate_t state;
unsigned short allocated[BLOCK_SIZE_MAX];
int lightmap;
int deluxmap;
} gl_lightmap_t;
typedef struct
{
unsigned short allocated[SHADOW_SIZE];
CFrameBuffer shadowmap;
} gl_shadowmap_t;
typedef struct
{
Vector diffuse; // direct light color
Vector normal; // direct light normal
int ambientlight; // clip at 128
int shadelight; // clip at 192 - ambientlight
Vector ambient[6]; // cubemap 1x1 (single pixel per side)
bool nointerp; // flickering light force nointerp
} mstudiolight_t;
// NOTE: if this is changed it must be changed in studio.h and com_model.h too!!!
typedef struct
{
float smoothness; // smoothness factor
float detailScale[2]; // detail texture scales x, y
float reflectScale; // reflection scale for translucent water
float refractScale; // refraction scale for mirrors, windows, water
float aberrationScale; // chromatic abberation
float reliefScale; // relief-mapping
struct matdef_s *effects; // hit, impact, particle effects etc
char name[64];
unsigned short dt_texturenum; // detail texture load directly from material specific
char diffusemap[64];
char normalmap[64];
char glossmap[64];
} matdesc_t;
typedef struct
{
char name[64];
char diffuse[64];
unsigned short gl_diffuse_id; // diffuse texture
unsigned short gl_heightmap_id;
unsigned short width, height;
byte maxHeight;
byte numLayers; // layers that specified on heightmap
byte *pixels; // pixels are immediately goes here
} indexMap_t;
typedef struct
{
char pathes[MAX_LANDSCAPE_LAYERS][64]; // path to texture (may include extension etc)
char names[MAX_LANDSCAPE_LAYERS][64]; // basenames
matdesc_t *material[MAX_LANDSCAPE_LAYERS]; // layer settings
float smoothness[MAX_LANDSCAPE_LAYERS]; // shader params
unsigned short gl_diffuse_id; // diffuse texture array
unsigned short gl_detail_id; // detail texture
unsigned short gl_normalmap_id; // normalmap array
unsigned short gl_specular_id; // specular array
} layerMap_t;
typedef struct terrain_s
{
char name[16];
indexMap_t indexmap;
layerMap_t layermap;
int numLayers; // count of array textures
int tessSize;
float texScale; // global texture scale
bool valid; // if heightmap was actual
} terrain_t;
typedef struct
{
int changed; // whats changed from last frame
int flags; // some info about current frame (sets by renderer)
int entity; // playernum or camera edict
Vector origin;
Vector angles;
Vector pvspoint;
ref_overview_t over; // cached overview
int client_frame; // cached client frame
bool novis_cached; // last value of r_novis variable
bool lockpvs_cached; // last value of r_lockpvs variable
float fov_x; // actual fov_x
float fov_y; // actual fov_y
float farClip;
float planedist; // for sort translucent surfaces
float lodScale;
int port[4]; // cached view.port
CFrustum frustum; // view frustum
CFrustum splitFrustum[MAX_SHADOWMAPS];
float parallelSplitDistances[MAX_SHADOWMAPS]; // distances in camera space
matrix4x4 matrix; // untransformed viewmatrix
matrix4x4 worldMatrix; // modelview for world
matrix4x4 projectionMatrix; // gl frustum
matrix4x4 worldProjectionMatrix; // worldviewMatrix * projectionMatrix
mleaf_t *leaf; // leaf where are vieworg located
vec3_t visMins; // visMins used for compute precision farclip
vec3_t visMaxs;
float skyMins[2][6]; // sky texcoords
float skyMaxs[2][6]; // sky texcoords
byte pvsarray[(MAX_MAP_LEAFS+7)/8]; // actual PVS for current frame
byte visfaces[(MAX_MAP_FACES+7)/8]; // actual visible faces for current frame (world only)
byte vislight[(MAX_MAP_WORLDLIGHTS+7)/8]; // visible lights per current frame
} ref_viewcache_t;
typedef struct
{
// forward rendering lists
CUtlArray<CSolidEntry> solid_faces;
CUtlArray<CSolidEntry> solid_meshes;
CUtlArray<CTransEntry> trans_list;
CUtlArray<struct grass_s*> grass_list;
CUtlArray<Vector> primverts; // primitive vertexes
// forward lighting lists
CUtlArray<CSolidEntry> light_faces;
CUtlArray<CSolidEntry> light_meshes;
CUtlArray<struct grass_s*> light_grass;
msurface_t *subview_faces[MAX_SUBVIEW_FACES]; // 6 kb
int num_subview_faces;
} ref_drawlist_t;
// contain gl-friendly data that may keep from previous frame
// to avoid to recompute it again
typedef struct
{
int viewport[4]; // in OpenGL space
GLfloat modelviewMatrix[16]; // worldviewMatrix
GLfloat projectionMatrix[16]; // projection matrix
GLfloat modelviewProjectionMatrix[16];// send to engine
} ref_glstate_t;
typedef struct
{
int params; // rendering parameters
// NEW STATE
ref_viewcache_t view; // cached view
ref_glstate_t glstate; // cached glstate
ref_drawlist_t frame; // frame lists
// GLOBAL STATE
mplane_t clipPlane;
cl_entity_t *currententity;
model_t *currentmodel;
CDynLight *currentlight;
struct glsl_prog_s *currentshader;
msurface_t *reject_face; // avoid recursion to himself
} ref_instance_t;
/*
=======================================================================
GL STATE MACHINE
=======================================================================
*/
enum
{
R_OPENGL_110 = 0, // base
R_WGL_PROCADDRESS,
R_ARB_VERTEX_BUFFER_OBJECT_EXT,
R_ARB_VERTEX_ARRAY_OBJECT_EXT,
R_TEXTURE_ARRAY_EXT, // shaders only
R_EXT_GPU_SHADER4, // shaders only
R_DRAW_BUFFERS_EXT,
R_ARB_MULTITEXTURE,
R_TEXTURECUBEMAP_EXT,
R_SHADER_GLSL100_EXT,
R_DRAW_RANGEELEMENTS_EXT,
R_TEXTURE_3D_EXT,
R_SHADER_OBJECTS_EXT,
R_VERTEX_SHADER_EXT, // glsl vertex program
R_FRAGMENT_SHADER_EXT, // glsl fragment program
R_ARB_TEXTURE_NPOT_EXT,
R_TEXTURE_2D_RECT_EXT,
R_DEPTH_TEXTURE,
R_SHADOW_EXT,
R_FRAMEBUFFER_OBJECT,
R_SEPARATE_BLENDFUNC_EXT,
R_OCCLUSION_QUERIES_EXT,
R_SEAMLESS_CUBEMAP,
R_BINARY_SHADER_EXT,
R_PARANOIA_EXT, // custom OpenGL32.dll with hacked function glDepthRange
R_DEBUG_OUTPUT,
R_EXTCOUNT, // must be last
};
enum
{
GL_KEEP_UNIT = -1, // alternative way - change the unit by GL_SelectTexture
GL_TEXTURE0 = 0,
GL_TEXTURE1,
GL_TEXTURE2,
GL_TEXTURE3,
GL_TEXTURE4,
GL_TEXTURE5,
GL_TEXTURE6,
GL_TEXTURE7,
GL_TEXTURE8,
GL_TEXTURE9,
GL_TEXTURE10,
GL_TEXTURE11,
MAX_TEXTURE_UNITS
};
typedef struct
{
bool fCustomRendering;
bool fClearScreen; // force clear if world shaders failed to build
int fGamePaused;
double time; // cl.time
double oldtime; // cl.oldtime
double frametime; // special frametime for multipass rendering (will set to 0 on a nextview)
double saved_frametime; // push\pop
cl_entity_t *draw_entities[MAX_VISIBLE_ENTS]; // list of all pending entities for current frame
int num_draw_entities; // count for actual rendering frame
int defaultTexture; // use for bad textures
int skyboxTextures[6]; // skybox sides
int normalmapTexture; // default normalmap
int deluxemapTexture; // default deluxemap
int vsdctCubeTexture; // Virtual Shadow Depth Cubemap Texture
int whiteCubeTexture; // stub
int depthTexture; // stub
int depthCubemap; // stub
int normalsFitting; // best fit normals
int defaultProjTexture; // fallback for missed textures
int flashlightTexture; // flashlight projection texture
int spotlightTexture[8];// reserve for eight textures
int cinTextures[MAX_MOVIE_TEXTURES];
gl_texbuffer_t subviewTextures[MAX_SUBVIEW_TEXTURES];
int shadowTextures[MAX_SHADOWS];
int shadowCubemaps[MAX_SHADOWS];
int waterTextures[WATER_TEXTURES];
int num_2D_shadows_used; // used shadow textures per full frame
int num_CM_shadows_used; // used shadow textures per full frame
int num_subview_used; // used mirror textures per full frame
int num_cin_used; // used movie textures per full frame
int screen_color;
int screen_depth;
int grayTexture;
int whiteTexture;
int blackTexture;
int screenTexture;
CUtlArray<gl_state_t> cached_state;
gl_lightmap_t lightmaps[MAX_LIGHTMAPS];
byte current_lightmap_texture;
int packed_lights_texture;
int packed_planes_texture;
int packed_nodes_texture;
int packed_models_texture;
gl_shadowmap_t shadowmap; // single atlas
// framebuffers
CFrameBuffer fbo_shadow2D; // used for projection shadowmapping
CFrameBuffer fbo_shadowCM; // used for omnidirectional shadowmapping
CFrameBuffer sunShadowFBO[MAX_SHADOWMAPS]; // extra-large shadowmap for sun rendering
CFrameBuffer fbo_light; // store lightmap
CFrameBuffer fbo_filter; // store filtered lightmap
CFrameBuffer fbo_shadow; // store shadowflags
gl_drawbuffer_t *defscene_fbo;
gl_drawbuffer_t *deflight_fbo;
word defSceneShader[2]; // geometry pass
word defLightShader; // light pass
word defDynLightShader[2];// dynamic light pass
word bilateralShader; // upscale filter
// skybox shaders
word skyboxEnv[2]; // skybox & sun
word defSceneSky; // skybox & sun
word defLightSky; // skybox & sun
// framebuffers
gl_fbo_t frame_buffers[MAX_FRAMEBUFFERS];
int num_framebuffers;
int realframecount; // not including passes
int grassunloadframe; // unload too far grass to save video memory
Vector ambientLight; // at vieworg
int waterlevel; // player waterlevel
cl_entity_t *waterentity; // player inside
// fog params
bool fogEnabled;
Vector fogColor;
float fogDensity;
float fogSkyDensity;
// sky params
Vector sky_origin;
Vector sky_world_origin;
float sky_speed;
Vector sky_normal; // sky vector
Vector sky_ambient; // sky ambient color
// global ambient\direct factors
float ambientFactor;
float diffuseFactor;
float sun_refract;
float sun_ambient;
Vector sun_diffuse;
CDynLight *sunlight; // sun is active if not a NULL
Vector screen_normals[4]; // helper to transform world->screen space
float farclip; // max viewable distance
float gravity; // particles used
float lightstyle[MAX_LIGHTSTYLES]; // value 0 - 65536
gl_movie_t cinematics[MAX_MOVIES]; // precached cinematics
struct movevars_s *movevars;
// generic light that used to cache shaders
CDynLight defaultlightSpot;
CDynLight defaultlightOmni;
CDynLight defaultlightProj;
matdesc_t *materials;
unsigned int matcount;
bool params_changed; // some cvars are toggled, shaders needs to recompile and resort
bool local_client_added; // indicate what a local client already been added into renderlist
bool sun_light_enabled; // map have a light_environment with valid direction
bool lighting_changed; // r_lighting_modulate was changed
bool shadows_notsupport; // no shadow textures
bool show_uniforms_peak; // print the maxcount of used uniforms
int glsl_valid_sequence; // reloas shaders while some render cvars was changed
int total_vbo_memory; // statistics
Vector4D gamma_table[64];
CDynLight dlights[MAX_DLIGHTS];
vec3_t ambient_color;
float direct_scale;
float light_gamma;
float light_threshold;
float smoothing_threshold;
// original player vieworg and angles
Vector cached_vieworigin;
Vector cached_viewangles;
struct mvbocache_s *vertex_light_cache[MAX_LIGHTCACHE]; // FIXME: make growable
struct mvbocache_s *surface_light_cache[MAX_LIGHTCACHE];
// cull info
Vector modelorg; // relative to viewpoint
} ref_globals_t;
typedef struct
{
unsigned int c_world_leafs;
unsigned int c_world_nodes; // walking by BSP tree
unsigned int c_culled_entities;
unsigned int c_total_tris; // triangle count
unsigned int c_subview_passes;
unsigned int c_shadow_passes;
unsigned int c_worldlights;
unsigned int c_occlusion_culled; // culled by occlusion query
unsigned int c_screen_copy; // how many times screen was copied
unsigned int num_shader_binds;
unsigned int num_flushes;
msurface_t *debug_surface;
} ref_stats_t;
typedef struct
{
double compile_shader;
double create_light_cache;
double create_buffer_object;
double total_buildtime;
} ref_buildstats_t;
typedef enum
{
GLHW_GENERIC, // where everthing works the way it should
GLHW_RADEON, // where you don't have proper GLSL support
GLHW_NVIDIA // Geforce 8/9 class DX10 hardware
} glHWType_t;
typedef struct
{
int width, height;
int defWidth, defHeight;
qboolean fullScreen;
qboolean wideScreen;
int faceCull;
int frontFace;
int frameBuffer;
GLfloat depthmin;
GLfloat depthmax;
GLint depthmask;
GLfloat identityMatrix[16];
ref_instance_t stack[MAX_REF_STACK];
GLuint stack_position;
} glState_t;
typedef struct
{
const char *renderer_string; // ptrs to OpenGL32.dll, use with caution
const char *version_string;
const char *vendor_string;
glHWType_t hardware_type;
float version;
// list of supported extensions
const char *extensions_string;
bool extension[R_EXTCOUNT];
int block_size; // lightmap blocksize
int max_texture_units;
GLint max_2d_texture_size;
GLint max_3d_texture_size;
GLint max_2d_texture_layers;
GLint max_cubemap_size;
GLint binary_formats;
GLint num_formats;
int max_vertex_uniforms;
int max_vertex_attribs;
int max_varying_floats;
int max_skinning_bones; // total bones that can be transformed with GLSL
int peak_used_uniforms;
} glConfig_t;
extern glState_t glState;
extern glConfig_t glConfig;
extern engine_studio_api_t IEngineStudio;
extern float gldepthmin, gldepthmax;
extern int sunSize[MAX_SHADOWMAPS];
extern char r_speeds_msg[2048];
extern char r_depth_msg[2048];
extern model_t *worldmodel;
extern int g_iGunMode;
extern ref_stats_t r_stats;
extern ref_buildstats_t r_buildstats;
extern ref_instance_t *RI;
extern ref_globals_t tr;
//
// gl_backend.cpp
//
void R_InitRefState( void );
void R_PushRefState( void );
void R_PopRefState( void );
void R_ResetRefState( void );
ref_instance_t *R_GetPrevInstance( void );
void CompressNormalizedVector( char outVec[3], const Vector &inVec );
bool GL_BackendStartFrame( ref_viewpass_t *rvp, int params );
void GL_BackendEndFrame( ref_viewpass_t *rvp, int params );
int R_GetSpriteTexture( const model_t *m_pSpriteModel, int frame );
void GL_BindDrawbuffer( gl_drawbuffer_t *framebuffer );
void GL_DepthRange( GLfloat depthmin, GLfloat depthmax );
void R_RenderQuadPrimitive( CSolidEntry *entry );
void GL_LoadMatrix( const matrix4x4 &source );
void GL_LoadTexMatrix( const matrix4x4 &source );
void GL_BindFrameBuffer( int buffer, int texture );
void R_Speeds_Printf( const char *msg, ... );
int R_AllocFrameBuffer( int viewport[4] );
void GL_CheckVertexArrayBinding( void );
void R_FreeFrameBuffer( int buffer );
void GL_CleanupAllTextureUnits( void );
void GL_ComputeScreenRays( void );
void GL_DisableAllTexGens( void );
void GL_DepthMask( GLint enable );
void GL_FrontFace( GLenum front );
void GL_ClipPlane( bool enable );
void GL_BindFBO( GLuint buffer );
void GL_AlphaTest( GLint enable );
void GL_DepthTest( GLint enable );
void GL_CleanupDrawState( void );
void GL_SetDefaultState( void );
void GL_Blend( GLint enable );
void GL_Cull( GLenum cull );
void GL_Setup2D( void );
void GL_Setup3D( void );
//
// gl_cubemaps.cpp
//
void CL_FindNearestCubeMap( const Vector &pos, mcubemap_t **result );
void CL_FindTwoNearestCubeMap( const Vector &pos, mcubemap_t **result1, mcubemap_t **result2 );
void CL_FindNearestCubeMapForSurface( const Vector &pos, const msurface_t *surf, mcubemap_t **result );
void CL_FindTwoNearestCubeMapForSurface( const Vector &pos, const msurface_t *surf, mcubemap_t **result1, mcubemap_t **result2 );
void CL_BuildCubemaps_f( void );
//
// gl_cull.cpp
//
bool R_CullModel( cl_entity_t *e, const Vector &mins, const Vector &maxs );
int R_CullSurface( msurface_t *surf, const Vector &vieworg, CFrustum *frustum, int clipFlags = 0 );
bool R_CullBrushModel( cl_entity_t *e );
bool R_CullNodeTopView( mnode_t *node );
#define R_CullBox( mins, maxs ) ( RI->view.frustum.CullBox( mins, maxs ))
#define R_CullSphere( centre, radius ) ( RI->view.frustum.CullSphere( centre, radius ))
#define R_CullFrustum( otherFrustum ) ( RI->view.frustum.CullFrustum( otherFrustum ))
//
// gl_debug.cpp
//
void DBG_PrintVertexVBOSizes( void );
void DBG_DrawLightFrustum( void );
void DBG_DrawGlassScissors( void );
void DrawLightProbes( void );
void R_ShowLightMaps( void );
void R_RenderLightProbeInternal( const Vector &origin, const Vector lightCube[] );
void DBG_DrawBBox( const Vector &mins, const Vector &maxs );
void DrawWirePoly( msurface_t *surf );
void DrawTangentSpaces( void );
void DrawWireFrame( void );
void DrawViewLeaf( void );
void DrawCubeMaps( void );
//
// gl_deferred.cpp
//
void GL_SetupGBuffer( void );
void GL_ResetGBuffer( void );
void GL_DrawDeferredPass( void );
//
// gl_framebuffer.c
//
gl_drawbuffer_t *GL_AllocDrawbuffer( const char *name, int width, int height, int depth = 1 );
void GL_ResizeDrawbuffer( gl_drawbuffer_t *fbo, int width, int height, int depth = 1 );
void GL_AttachColorTextureToFBO( gl_drawbuffer_t *fbo, int textrue, int colorIndex, int side = 0 );
void GL_AttachDepthTextureToFBO( gl_drawbuffer_t *fbo, int texture, int side = 0 );
void GL_CheckFBOStatus( gl_drawbuffer_t *fbo );
void GL_VidInitDrawBuffers( void );
void GL_FreeDrawbuffers( void );
//
// gl_lightmap.cpp
//
void R_UpdateSurfaceParams( msurface_t *surf );
void R_UpdateSurfaceParams( struct mstudiosurface_s *surf );
void GL_BeginBuildingLightmaps( void );
void GL_AllocLightmapForFace( msurface_t *surf );
bool GL_AllocLightmapForFace( struct mstudiosurface_s *surf );
void GL_EndBuildingLightmaps( bool lightmap, bool deluxmap );
void R_TextureCoords( msurface_t *surf, const Vector &vec, float *out );
void R_GlobalCoords( msurface_t *surf, const Vector &point, float *out );
void R_GlobalCoords( msurface_t *surf, const Vector &point, const Vector &absmin, const Vector &absmax, float scale, float *out );
void R_LightmapCoords( msurface_t *surf, const Vector &vec, float *coords, int style );
void R_LightmapCoords( struct mstudiosurface_s *surf, const Vector &vec, const Vector lmvecs[2], float *coords, int style );
//
// gl_rlight.cpp
//
CDynLight *CL_AllocDlight( int key );
void R_GetLightVectors( cl_entity_t *pEnt, Vector &origin, Vector &angles );
void R_SetupLightParams( CDynLight *pl, const Vector &origin, const Vector &angles, float radius, float fov, int type, int flags = 0 );
void R_FindWorldLights( const Vector &origin, const Vector &mins, const Vector &maxs, byte lights[MAXDYNLIGHTS], bool skipZ = false );
void R_LightForStudio( const Vector &point, mstudiolight_t *light, bool ambient );
void R_PointAmbientFromLeaf( const Vector &point, mstudiolight_t *light );
void R_LightForSky( const Vector &point, mstudiolight_t *light );
void R_LightVec( const Vector &point, mstudiolight_t *light, bool ambient );
Vector R_LightsForPoint( const Vector &point, float radius );
void R_SetupLightTexture( CDynLight *pl, int texture );
void R_SetupDynamicLights( void );
void CL_ClearDlights( void );
void R_AnimateLight( void );
int HasDynamicLights( void );
int HasStaticLights( void );
void CL_DecayLights( void );
//
// gl_rmain.cpp
//
void R_ClearScene( void );
int R_ComputeFxBlend( cl_entity_t *e );
void R_RenderScene( const ref_viewpass_t *rvp, int params );
qboolean R_AddEntity( struct cl_entity_s *clent, int entityType );
bool R_WorldToScreen( const Vector &point, Vector &screen );
void R_ScreenToWorld( const Vector &screen, Vector &point );
void R_SetupProjectionMatrix( float fov_x, float fov_y, matrix4x4 &m );
unsigned short GL_CacheState( const Vector &origin, const Vector &angles, bool skyentity = false );
void R_MarkWorldVisibleFaces( model_t *model );
gl_state_t *GL_GetCache( word hCachedMatrix );
void R_DrawParticles( qboolean trans );
void R_SetupGLstate( void );
void R_RenderTransList( void );
void R_SetupFrustum( void );
void R_Clear( int bitMask );
//
// gl_rmisc.cpp
//
void R_NewMap( void );
void R_VidInit( void );
void CL_InitMaterials( void );
matdesc_t *CL_FindMaterial( const char *name );
void R_LoadLandscapes( const char *filename );
terrain_t *R_FindTerrain( const char *texname );
void R_InitDynLightShaders( void );
void R_InitShadowTextures( void );
void R_FreeLandscapes( void );
//
// gl_rsurf.cpp
//
texture_t *R_TextureAnimation( msurface_t *s );
void GL_InitRandomTable( void );
//
// gl_shader.cpp
//
const char *GL_PretifyListOptions( const char *options, bool newlines = false );
word GL_FindUberShader( const char *glname, const char *options = "" );
word GL_FindShader( const char *glname, const char *vpname, const char *fpname, const char *options = "" );
void GL_SetShaderDirective( char *options, const char *directive );
void GL_AddShaderDirective( char *options, const char *directive );
void GL_AddShaderFeature( word shaderNum, int feature );
void GL_CheckTextureAlpha( char *options, int texturenum );
void GL_EncodeNormal( char *options, int texturenum );
void GL_BindShader( struct glsl_prog_s *shader );
void GL_FreeUberShaders( void );
void GL_InitGPUShaders( void );
void GL_FreeGPUShaders( void );
//
// gl_shadows.cpp
//
void R_RenderShadowmaps( void );
void R_RenderDeferredShadows( void );
//
// gl_movie.cpp
//
void R_InitCinematics( void );
void R_FreeCinematics( void );
int R_PrecacheCinematic( const char *cinname );
int R_AllocateCinematicTexture( unsigned int txFlags );
void R_UpdateCinematic( const msurface_t *surf );
void R_UpdateCinSound( cl_entity_t *e );
//
// gl_mirror.cpp
//
void R_RenderSubview( void );
//
// gl_scene.cpp
//
void R_CheckChanges( void );
void R_InitDefaultLights( void );
//
// gl_sky.cpp
//
void R_AddSkyBoxSurface( msurface_t *fa );
void R_DrawSkyBox( void );
//
// gl_postprocess.cpp
//
void InitPostTextures( void );
void InitPostEffects( void );
void RenderDOF( void );
void RenderUnderwaterBlur( void );
void RenderNerveGasBlur( void );
void RenderMonochrome( void );
void RenderSunShafts( void );
void RenderFSQ( int wide, int tall );
//
// gl_world_new.cpp
//
void Mod_ThrowModelInstances( void );
void Mod_PrepareModelInstances( void );
void GL_LoadAndRebuildCubemaps( int refParams );
void Mod_SetOrthoBounds( const float *mins, const float *maxs );
bool Mod_CheckLayerNameForSurf( msurface_t *surf, const char *checkName );
bool Mod_CheckLayerNameForPixel( mfaceinfo_t *land, const Vector &point, const char *checkName );
int Mod_FatPVS( model_t *model, const vec3_t org, float radius, byte *visbuffer, int visbytes, bool merge, bool fullvis );
void Mod_FindStaticLights( byte *vislight, byte lights[MAXDYNLIGHTS], const Vector &origin );
void R_ProcessWorldData( model_t *mod, qboolean create, const byte *buffer );
bool R_AddSurfaceToDrawList( msurface_t *surf, drawlist_t type );
void R_MarkVisibleLights( byte lights[MAXDYNLIGHTS] );
gl_texbuffer_t *Surf_GetSubview( mextrasurf_t *es );
void R_RenderTransSurface( CTransEntry *entry );
int Mod_SampleSizeForFace( msurface_t *surf );
bool Surf_CheckSubview( mextrasurf_t *es, bool puddle = false );
void R_RenderDynLightList( bool solid );
void R_MarkSubmodelVisibleFaces( void );
void Mod_InitBSPModelsTexture( void );
void R_UpdateSubmodelParams( void );
void Mod_ResortFaces( void );
//
// gl_world.cpp
//
void R_RenderDeferredBrushList( void );
void R_RenderSolidBrushList( void );
void R_RenderShadowBrushList( void );
void R_RenderSurfOcclusionList( void );
//
// rain.cpp
//
void R_DrawWeather( void );
void ParseRain( void );
void ResetRain( void );
void InitRain( void );
#endif//GL_LOCAL_H

View File

@ -0,0 +1,37 @@
/*
gl_material.h - visible material settings
this code written for Paranoia 2: Savior modification
Copyright (C) 2016 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef GL_MATERIAL_H
#define GL_MATERIAL_H
typedef enum
{
PHYSMODEL_BRDF = 0, // BRDF as default
PHYSMODEL_DOOM3, // obsolete lighting model like Doom3
PHYSMODEL_FOLIAGE, // two-side rendering, vegetation lighting model
PHYSMODEL_GLASS, // translucent surface
PHYSMODEL_SKIN, // human skin lighting model
PHYSMODEL_HAIR, // anisotropic lighting model for hairs
PHYSMODEL_EYES, // eyes physical model
} physmodel_t;
typedef struct
{
physmodel_t physModel;
struct matdef_s *effects; // material common effects (decals, particles, etc)
} gl_material_t;
#endif//GL_MATERIAL_H

230
cl_dll/render/gl_movie.cpp Normal file
View File

@ -0,0 +1,230 @@
/*
gl_movie.cpp - draw screen movie surfaces
Copyright (C) 2011 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "hud.h"
#include "cl_util.h"
#include "gl_local.h"
#include "gl_world.h"
#include "mathlib.h"
#include "event_api.h"
#include <stringlib.h>
int R_PrecacheCinematic( const char *cinname )
{
int load_sound = 0;
if( !cinname || !*cinname )
return -1;
if( *cinname == '*' )
{
if( g_iXashEngineBuildNumber >= 4256 )
load_sound = 1;
cinname++;
}
// not AVI file
if( Q_stricmp( UTIL_FileExtension( cinname ), "avi" ))
return -1;
// first check for co-existing
for( int i = 0; i < MAX_MOVIES; i++ )
{
if( !Q_stricmp( tr.cinematics[i].name, cinname ))
{
// already existed
return i;
}
}
// found an empty slot
for( i = 0; i < MAX_MOVIES; i++ )
{
if( !tr.cinematics[i].name[0] )
break;
}
if( i == MAX_MOVIES )
{
ALERT( at_error, "R_PrecacheCinematic: cinematic list limit exceeded\n" );
return -1;
}
// register new cinematic
Q_strncpy( tr.cinematics[i].name, cinname, sizeof( tr.cinematics[0].name ));
if( tr.cinematics[i].state )
{
ALERT( at_warning, "Reused cin state %i with %s\n", i, tr.cinematics[i].name );
FREE_CINEMATIC( tr.cinematics[i].state );
}
ALERT( at_console, "Loading cinematic %s [%s]\n", cinname, load_sound ? "sound" : "muted" );
tr.cinematics[i].state = OPEN_CINEMATIC( tr.cinematics[i].name, load_sound );
// grab info about movie
if( tr.cinematics[i].state != NULL )
CIN_GET_VIDEO_INFO( tr.cinematics[i].state, &tr.cinematics[i].xres, &tr.cinematics[i].yres, &tr.cinematics[i].length );
return i;
}
void R_InitCinematics( void )
{
const char *name, *ext;
// make sure what we have texture to draw cinematics
if( !FBitSet( world->features, WORLD_HAS_MOVIES ))
return;
for( int i = 1; i < 1024; i++ )
{
name = gRenderfuncs.GetFileByIndex( i );
if( !name || !*name ) break; // end of files array
ext = UTIL_FileExtension( name );
if( Q_stricmp( ext, "avi" )) continue; // not AVI
if( R_PrecacheCinematic( name ) == -1 )
break; // full
}
}
void R_FreeCinematics( void )
{
for( int i = 0; i < MAX_MOVIES; i++ )
{
if( tr.cinematics[i].state )
{
ALERT( at_notice, "release cinematic %s\n", tr.cinematics[i].name );
FREE_CINEMATIC( tr.cinematics[i].state );
}
}
memset( tr.cinematics, 0, sizeof( tr.cinematics ));
for( i = 0; i < MAX_MOVIE_TEXTURES; i++ )
{
if( !tr.cinTextures[i] ) break;
FREE_TEXTURE( tr.cinTextures[i] );
}
memset( tr.cinTextures, 0, sizeof( tr.cinTextures ));
}
int R_AllocateCinematicTexture( unsigned int txFlags )
{
int i = tr.num_cin_used;
if( i >= MAX_MOVIE_TEXTURES )
{
ALERT( at_error, "R_AllocateCinematicTexture: cine textures limit exceeded!\n" );
return 0; // disable
}
tr.num_cin_used++;
if( !tr.cinTextures[i] )
{
char txName[16];
Q_snprintf( txName, sizeof( txName ), "*cinematic%i", i );
// create new cinematic texture
// NOTE: dimension of texture is no matter because CIN_UPLOAD_FRAME will be rescale texture
tr.cinTextures[i] = CREATE_TEXTURE( txName, 256, 256, NULL, txFlags );
}
return (i+1);
}
void R_UpdateCinematic( const msurface_t *surf )
{
if( !RI->currententity->curstate.body )
return; // just disabled
// draw the cinematic
mextrasurf_t *es = surf->info;
// found the corresponding cinstate
const char *cinname = gRenderfuncs.GetFileByIndex( RI->currententity->curstate.sequence );
int cinhandle = R_PrecacheCinematic( cinname );
if( cinhandle >= 0 && es->cintexturenum <= 0 )
es->cintexturenum = R_AllocateCinematicTexture( TF_NOMIPMAP );
if( cinhandle == -1 || es->cintexturenum <= 0 || CIN_IS_ACTIVE( tr.cinematics[cinhandle].state ) == false )
{
// cinematic textures limit exceeded, so remove SURF_MOVIE flag
((msurface_t *)surf)->flags &= ~SURF_MOVIE;
return;
}
gl_movie_t *cin = &tr.cinematics[cinhandle];
float cin_time;
if( FBitSet( RI->currententity->curstate.iuser1, CF_LOOPED_MOVIE ))
{
// advances cinematic time
cin_time = fmod( RI->currententity->curstate.fuser2, cin->length );
}
else
{
cin_time = RI->currententity->curstate.fuser2;
}
// read the next frame
int cin_frame = CIN_GET_FRAME_NUMBER( cin->state, cin_time );
// upload the new frame
if( cin_frame != es->checkcount )
{
GL_SelectTexture( GL_TEXTURE0 ); // doesn't matter. select 0-th unit just as default
byte *raw = CIN_GET_FRAMEDATA( cin->state, cin_frame );
CIN_UPLOAD_FRAME( tr.cinTextures[es->cintexturenum-1], cin->xres, cin->yres, cin->xres, cin->yres, raw );
es->checkcount = cin_frame;
}
}
void R_UpdateCinSound( cl_entity_t *e )
{
if( g_iXashEngineBuildNumber < 4256 )
return; // too old for this feature
if( !e->curstate.body || !FBitSet( e->curstate.iuser1, CF_MOVIE_SOUND ))
return; // just disabled
// found the corresponding cinstate
const char *cinname = gRenderfuncs.GetFileByIndex( e->curstate.sequence );
int cinhandle = R_PrecacheCinematic( cinname );
if( cinhandle == -1 || CIN_IS_ACTIVE( tr.cinematics[cinhandle].state ) == false )
return;
gl_movie_t *cin = &tr.cinematics[cinhandle];
float cin_time;
if( FBitSet( e->curstate.iuser1, CF_LOOPED_MOVIE ))
{
// advances cinematic time
cin_time = fmod( e->curstate.fuser2, cin->length );
}
else
{
cin_time = e->curstate.fuser2;
}
// stream avi sound
CIN_UPDATE_SOUND( cin->state, e->index, VOL_NORM, ATTN_IDLE, cin_time );
}

View File

@ -0,0 +1,231 @@
/*
gl_occlusion.cpp - occlusion query implementation class
this code written for Paranoia 2: Savior modification
Copyright (C) 2015 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "hud.h"
#include "cl_util.h"
#include "const.h"
#include "gl_local.h"
#include <utlarray.h>
#include "gl_occlusion.h"
#include "gl_world.h"
/*
===============
GL_AllocOcclusionQuery
===============
*/
void GL_AllocOcclusionQuery( msurface_t *surf )
{
if( !GL_Support( R_OCCLUSION_QUERIES_EXT ) || surf->info->query )
return;
pglGenQueriesARB( 1, &surf->info->query );
}
/*
===============
GL_DeleteOcclusionQuery
===============
*/
void GL_DeleteOcclusionQuery( msurface_t *surf )
{
if( !GL_Support( R_OCCLUSION_QUERIES_EXT ) || !surf->info->query )
return;
pglDeleteQueriesARB( 1, &surf->info->query );
}
/*
===============
GL_DrawOcclusionCube
===============
*/
static void GL_DrawOcclusionCube( const Vector &absmin, const Vector &absmax )
{
vec3_t bbox[8];
int i;
// compute a full bounding box
for( i = 0; i < 8; i++ )
{
bbox[i][0] = ( i & 1 ) ? absmin[0] : absmax[0];
bbox[i][1] = ( i & 2 ) ? absmin[1] : absmax[1];
bbox[i][2] = ( i & 4 ) ? absmin[2] : absmax[2];
}
pglBegin( GL_QUADS );
for( i = 0; i < 6; i++ )
{
pglVertex3fv( bbox[g_boxpnt[i][0]] );
pglVertex3fv( bbox[g_boxpnt[i][1]] );
pglVertex3fv( bbox[g_boxpnt[i][2]] );
pglVertex3fv( bbox[g_boxpnt[i][3]] );
}
pglEnd();
}
/*
===============
GL_TestSurfaceOcclusion
===============
*/
void GL_TestSurfaceOcclusion( msurface_t *surf )
{
mextrasurf_t *es = surf->info;
Vector absmin, absmax;
word cached_matrix;
Vector normal;
if( !es->query || FBitSet( surf->flags, SURF_QUEUED ))
return; // we already have the query
if( !es->parent ) cached_matrix = WORLD_MATRIX;
else cached_matrix = es->parent->hCachedMatrix;
gl_state_t *glm = GL_GetCache( cached_matrix );
if( FBitSet( surf->flags, SURF_PLANEBACK ))
normal = -surf->plane->normal;
else normal = surf->plane->normal;
// place above surface
absmin = es->mins + normal * 5.0f;
absmax = es->maxs + normal * 5.0f;
ExpandBounds( absmin, absmax, 2.0f );
if( cached_matrix != WORLD_MATRIX )
TransformAABB( glm->transform, es->mins, es->maxs, absmin, absmax );
pglBeginQueryARB( GL_SAMPLES_PASSED_ARB, es->query );
GL_DrawOcclusionCube( absmin, absmax );
pglEndQueryARB( GL_SAMPLES_PASSED_ARB );
// now we have a valid query
SetBits( surf->flags, SURF_QUEUED );
}
/*
===============
GL_TestSurfaceOcclusion
===============
*/
void GL_DebugSurfaceOcclusion( msurface_t *surf )
{
mextrasurf_t *es = surf->info;
Vector absmin, absmax;
word cached_matrix;
Vector normal;
if( !FBitSet( surf->flags, SURF_QUEUED ))
return; // draw only queue
if( !es->parent ) cached_matrix = WORLD_MATRIX;
else cached_matrix = es->parent->hCachedMatrix;
gl_state_t *glm = GL_GetCache( cached_matrix );
if( FBitSet( surf->flags, SURF_PLANEBACK ))
normal = -surf->plane->normal;
else normal = surf->plane->normal;
// place above surface
absmin = es->mins + normal * 5.0f;
absmax = es->maxs + normal * 5.0f;
ExpandBounds( absmin, absmax, 2.0f );
if( cached_matrix != WORLD_MATRIX )
TransformAABB( glm->transform, es->mins, es->maxs, absmin, absmax );
GL_DrawOcclusionCube( absmin, absmax );
}
/*
================
R_RenderOcclusionList
================
*/
void R_RenderSurfOcclusionList( void )
{
int i;
if( !RP_NORMALPASS() || !CVAR_TO_BOOL( r_occlusion_culling ))
return;
if( !RI->frame.num_subview_faces )
return;
pglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
GL_DepthMask( GL_FALSE );
GL_AlphaTest( GL_FALSE );
GL_BindShader( NULL );
for( i = 0; i < RI->frame.num_subview_faces; i++ )
GL_TestSurfaceOcclusion( RI->frame.subview_faces[i] );
pglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
GL_DepthMask( GL_TRUE );
pglFlush();
if( r_occlusion_culling->value < 2.0f )
return;
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
GL_Blend( GL_FALSE );
for( i = 0; i < RI->frame.num_subview_faces; i++ )
GL_DebugSurfaceOcclusion( RI->frame.subview_faces[i] );
}
/*
================
GL_SurfaceOccluded
================
*/
bool GL_SurfaceOccluded( msurface_t *surf )
{
mextrasurf_t *es = surf->info;
GLuint sampleCount = 0;
GLint available = false;
if( !RP_NORMALPASS() || !CVAR_TO_BOOL( r_occlusion_culling ))
return false;
if( !es->query ) return false;
if( !FBitSet( surf->flags, SURF_QUEUED ))
{
// occlusion is no more actual
ClearBits( surf->flags, SURF_OCCLUDED );
return false;
}
// i hope results will be arrived on a next frame...
pglGetQueryObjectivARB( es->query, GL_QUERY_RESULT_AVAILABLE_ARB, &available );
// NOTE: if we can't get actual information about query results
// assume that object was visible and cull him with default methods: frustum, pvs etc
if( !available ) return false;
pglGetQueryObjectuivARB( es->query, GL_QUERY_RESULT_ARB, &sampleCount );
ClearBits( surf->flags, SURF_QUEUED ); // we catch the results, so query is outdated
if( sampleCount == 0 ) SetBits( surf->flags, SURF_OCCLUDED );
else ClearBits( surf->flags, SURF_OCCLUDED );
if( !sampleCount ) r_stats.c_occlusion_culled++;
return (FBitSet( surf->flags, SURF_OCCLUDED ) != 0);
}

View File

@ -0,0 +1,25 @@
/*
gl_occlusion.h - occlusion query implementation
this code written for Paranoia 2: Savior modification
Copyright (C) 2015 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef GL_OCCLUSION_H
#define GL_OCCLUSION_H
void GL_AllocOcclusionQuery( msurface_t *surf );
void GL_DeleteOcclusionQuery( msurface_t *surf );
bool GL_SurfaceOccluded( msurface_t *surf );
void GL_TestSurfaceOcclusion( msurface_t *surf );
#endif//GL_OCCLUSION_H

View File

@ -0,0 +1,600 @@
//
// written by BUzer for HL: Paranoia modification
//
// 2006
#include "hud.h"
#include "cl_util.h"
#include "const.h"
#include "gl_local.h"
#include "mathlib.h"
#include "gl_shader.h"
#include "stringlib.h"
#include "gl_world.h"
extern int g_iGunMode;
#define DEAD_GRAYSCALE_TIME 5.0f
#define TARGET_SIZE 256
cvar_t *v_posteffects;
cvar_t *v_grayscale;
cvar_t *v_sunshafts;
// post-process shaders
class CBasePostEffects
{
public:
word blurShader[2]; // e.g. underwater blur
word dofShader; // iron sight with dof
word monoShader; // monochrome effect
word genSunShafts; // sunshafts effect
word drawSunShafts; // sunshafts effect
int target_rgb[2];
float grayScaleFactor;
float blurFactor[2];
bool m_bUseTarget;
// DOF parameters
float m_flCachedDepth;
float m_flLastDepth;
float m_flStartDepth;
float m_flOffsetDepth;
float m_flStartTime;
float m_flDelayTime;
int g_iGunLastMode;
float m_flStartLength;
float m_flOffsetLength;
float m_flLastLength;
float m_flDOFStartTime;
// sunshafts variables
Vector m_vecSunLightColor;
Vector m_vecSunPosition;
void InitScreenColor( void );
void InitScreenDepth( void );
void InitTargetColor( int slot );
void RequestScreenColor( void );
void RequestScreenDepth( void );
void RequestTargetCopy( int slot );
bool ProcessDepthOfField( void );
bool ProcessSunShafts( void );
void InitDepthOfField( void );
void SetNormalViewport( void );
void SetTargetViewport( void );
bool Begin( void );
void End( void );
};
void CBasePostEffects :: InitScreenColor( void )
{
if( tr.screen_color )
{
FREE_TEXTURE( tr.screen_color );
tr.screen_color = 0;
}
tr.screen_color = CREATE_TEXTURE( "*screencolor", glState.width, glState.height, NULL, TF_COLORBUFFER );
}
void CBasePostEffects :: InitScreenDepth( void )
{
if( tr.screen_depth )
{
FREE_TEXTURE( tr.screen_depth );
tr.screen_depth = 0;
}
tr.screen_depth = CREATE_TEXTURE( "*screendepth", glState.width, glState.height, NULL, TF_DEPTHBUFFER );
}
void CBasePostEffects :: InitTargetColor( int slot )
{
if( target_rgb[slot] )
{
FREE_TEXTURE( target_rgb[slot] );
target_rgb[slot] = 0;
}
target_rgb[slot] = CREATE_TEXTURE( va( "*target%i", slot ), TARGET_SIZE, TARGET_SIZE, NULL, TF_IMAGE );
}
void CBasePostEffects :: RequestScreenColor( void )
{
GL_BindTexture( GL_TEXTURE0, tr.screen_color );
pglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, glState.width, glState.height );
}
void CBasePostEffects :: RequestScreenDepth( void )
{
GL_BindTexture( GL_TEXTURE0, tr.screen_depth );
pglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, glState.width, glState.height );
}
void CBasePostEffects :: RequestTargetCopy( int slot )
{
GL_BindTexture( GL_TEXTURE0, target_rgb[slot] );
pglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, TARGET_SIZE, TARGET_SIZE );
}
void CBasePostEffects :: SetNormalViewport( void )
{
pglViewport( RI->glstate.viewport[0], RI->glstate.viewport[1], RI->glstate.viewport[2], RI->glstate.viewport[3] );
}
void CBasePostEffects :: SetTargetViewport( void )
{
pglViewport( 0, 0, TARGET_SIZE, TARGET_SIZE );
}
void CBasePostEffects :: InitDepthOfField( void )
{
g_iGunLastMode = 1;
}
bool CBasePostEffects :: ProcessDepthOfField( void )
{
if( !CVAR_TO_BOOL( r_dof ) || g_iGunMode == 0 )
return false; // disabled or unitialized
if( g_iGunMode != g_iGunLastMode )
{
if( g_iGunMode == 1 )
{
// disable iron sight
m_flStartLength = m_flLastLength;
m_flOffsetLength = -m_flStartLength;
m_flDOFStartTime = tr.time;
}
else
{
// enable iron sight
m_flStartLength = m_flLastLength;
m_flOffsetLength = r_dof_focal_length->value;
m_flDOFStartTime = tr.time;
}
// ALERT( at_console, "Iron sight changed( %i )\n", g_iGunMode );
g_iGunLastMode = g_iGunMode;
}
if( g_iGunLastMode == 1 && m_flDOFStartTime == 0.0f )
return false; // iron sight disabled
if( !Begin( )) return false;
if( m_flDOFStartTime != 0.0f )
{
float flDegree = (tr.time - m_flDOFStartTime) / 0.3f;
if( flDegree >= 1.0f )
{
// all done. holds the final value
m_flLastLength = m_flStartLength + m_flOffsetLength;
m_flDOFStartTime = 0.0f; // done
}
else
{
// evaluate focal length
m_flLastLength = m_flStartLength + m_flOffsetLength * flDegree;
}
}
float zNear = Z_NEAR; // fixed
float zFar = RI->view.farClip;
float depthValue = 0.0f;
// get current depth value
pglReadPixels( glState.width >> 1, glState.height >> 1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depthValue );
depthValue = RemapVal( depthValue, 0.0, 0.8, 0.0, 1.0 );
depthValue = -zFar * zNear / ( depthValue * ( zFar - zNear ) - zFar ); // linearize it
float holdTime = bound( 0.01f, r_dof_hold_time->value, 0.5f );
float changeTime = bound( 0.1f, r_dof_change_time->value, 2.0f );
if( Q_round( m_flCachedDepth, 10 ) != Q_round( depthValue, 10 ))
{
m_flStartTime = 0.0f; // cancelling changes
m_flDelayTime = tr.time; // make sure what focal point is not changed more than 0.5 secs
m_flStartDepth = m_flLastDepth; // get last valid depth
m_flOffsetDepth = depthValue - m_flStartDepth;
m_flCachedDepth = depthValue;
}
if(( tr.time - m_flDelayTime ) > holdTime && m_flStartTime == 0.0f && m_flDelayTime != 0.0f )
{
// begin the change depth
m_flStartTime = tr.time;
}
if( m_flStartTime != 0.0f )
{
float flDegree = (tr.time - m_flStartTime) / changeTime;
if( flDegree >= 1.0f )
{
// all done. holds the final value
m_flLastDepth = m_flStartDepth + m_flOffsetDepth;
m_flStartTime = m_flDelayTime = 0.0f;
}
else
{
// evaluate focal depth
m_flLastDepth = m_flStartDepth + m_flOffsetDepth * flDegree;
}
}
return true;
}
bool CBasePostEffects :: ProcessSunShafts( void )
{
if( !CVAR_TO_BOOL( v_sunshafts ))
return false;
if( !FBitSet( world->features, WORLD_HAS_SKYBOX ))
return false;
if( tr.sky_normal == g_vecZero )
return false;
// update blur params
blurFactor[0] = 0.15f;
blurFactor[1] = 0.15f;
if( tr.sun_light_enabled ) m_vecSunLightColor = tr.sun_diffuse;
else m_vecSunLightColor = tr.sky_ambient * (1.0f/128.0f) * tr.diffuseFactor;
Vector sunPos = tr.cached_vieworigin + tr.sky_normal * 1000.0;
ColorNormalize( m_vecSunLightColor, m_vecSunLightColor );
Vector ndc, view;
// project sunpos to screen
R_TransformWorldToDevice( sunPos, ndc );
R_TransformDeviceToScreen( ndc, m_vecSunPosition );
m_vecSunPosition.z = DotProduct( -tr.sky_normal, GetVForward( ));
if( m_vecSunPosition.z < 0.01f )
return false; // fade out
// convert to screen pixels
m_vecSunPosition.x = m_vecSunPosition.x / glState.width;
m_vecSunPosition.y = m_vecSunPosition.y / glState.height;
return Begin();
}
bool CBasePostEffects :: Begin( void )
{
// we are in cubemap rendering mode
if( !RP_NORMALPASS( ))
return false;
if( !CVAR_TO_BOOL( v_posteffects ))
return false;
GL_Setup2D();
return true;
}
void CBasePostEffects :: End( void )
{
GL_CleanUpTextureUnits( 0 );
GL_BindShader( NULL );
GL_Setup3D();
}
static CBasePostEffects post;
void InitPostEffects( void )
{
char options[MAX_OPTIONS_LENGTH];
v_posteffects = CVAR_REGISTER( "gl_posteffects", "1", FCVAR_ARCHIVE );
v_sunshafts = CVAR_REGISTER( "gl_sunshafts", "1", FCVAR_ARCHIVE );
v_grayscale = CVAR_REGISTER( "gl_grayscale", "0", 0 );
memset( &post, 0, sizeof( post ));
// monochrome effect
post.monoShader = GL_FindShader( "postfx/monochrome", "postfx/generic", "postfx/monochrome" );
// gaussian blur for X
GL_SetShaderDirective( options, "BLUR_X" );
post.blurShader[0] = GL_FindShader( "postfx/gaussblur", "postfx/generic", "postfx/gaussblur", options );
// gaussian blur for Y
GL_SetShaderDirective( options, "BLUR_Y" );
post.blurShader[1] = GL_FindShader( "postfx/gaussblur", "postfx/generic", "postfx/gaussblur", options );
// DOF with bokeh
post.dofShader = GL_FindShader( "postfx/dofbokeh", "postfx/generic", "postfx/dofbokeh" );
// prepare sunshafts
post.genSunShafts = GL_FindShader( "postfx/genshafts", "postfx/generic", "postfx/genshafts" );
// render sunshafts
post.drawSunShafts = GL_FindShader( "postfx/drawshafts", "postfx/generic", "postfx/drawshafts" );
}
void InitPostTextures( void )
{
post.InitScreenColor();
post.InitScreenDepth();
post.InitTargetColor( 0 );
post.InitDepthOfField();
}
static float GetGrayscaleFactor( void )
{
float grayscale = v_grayscale->value;
if( gHUD.m_flDeadTime )
{
float fact = (tr.time - gHUD.m_flDeadTime) / DEAD_GRAYSCALE_TIME;
fact = Q_min( fact, 1.0f );
grayscale = Q_max( fact, grayscale );
}
return grayscale;
}
// rectangle version
void RenderFSQ( void )
{
float screenWidth = (float)glState.width;
float screenHeight = (float)glState.height;
pglBegin( GL_QUADS );
pglTexCoord2f( 0.0f, screenHeight );
pglVertex2f( 0.0f, 0.0f );
pglTexCoord2f( screenWidth, screenHeight );
pglVertex2f( screenWidth, 0.0f );
pglTexCoord2f( screenWidth, 0.0f );
pglVertex2f( screenWidth, screenHeight );
pglTexCoord2f( 0.0f, 0.0f );
pglVertex2f( 0.0f, screenHeight );
pglEnd();
}
void RenderFSQ( int wide, int tall )
{
float screenWidth = (float)wide;
float screenHeight = (float)tall;
pglBegin( GL_QUADS );
pglTexCoord2f( 0.0f, 1.0f );
pglNormal3fv( tr.screen_normals[0] );
pglVertex2f( 0.0f, 0.0f );
pglTexCoord2f( 1.0f, 1.0f );
pglNormal3fv( tr.screen_normals[1] );
pglVertex2f( screenWidth, 0.0f );
pglTexCoord2f( 1.0f, 0.0f );
pglNormal3fv( tr.screen_normals[2] );
pglVertex2f( screenWidth, screenHeight );
pglTexCoord2f( 0.0f, 0.0f );
pglNormal3fv( tr.screen_normals[3] );
pglVertex2f( 0.0f, screenHeight );
pglEnd();
}
void GL_DrawScreenSpaceQuad( void )
{
pglBegin( GL_QUADS );
pglTexCoord2f( 0.0f, 1.0f );
pglNormal3fv( tr.screen_normals[0] );
pglVertex3f( 0.0f, 0.0f, 0.0f );
pglNormal3fv( tr.screen_normals[1] );
pglTexCoord2f( 0.0f, 0.0f );
pglVertex3f( 0.0f, glState.height, 0.0f );
pglNormal3fv( tr.screen_normals[2] );
pglTexCoord2f( 1.0f, 0.0f );
pglVertex3f( glState.width, glState.height, 0.0f );
pglNormal3fv( tr.screen_normals[3] );
pglTexCoord2f( 1.0f, 1.0f );
pglVertex3f( glState.width, 0.0f, 0.0f );
pglEnd();
}
void V_RenderPostEffect( word hProgram )
{
if( hProgram <= 0 )
{
GL_BindShader( NULL );
return; // bad shader?
}
if( RI->currentshader != &glsl_programs[hProgram] )
{
// force to bind new shader
GL_BindShader( &glsl_programs[hProgram] );
}
glsl_program_t *shader = RI->currentshader;
// setup specified uniforms (and texture bindings)
for( int i = 0; i < shader->numUniforms; i++ )
{
uniform_t *u = &shader->uniforms[i];
switch( u->type )
{
case UT_SCREENMAP:
if( post.m_bUseTarget ) // HACKHACK
u->SetValue( post.target_rgb[0] );
else u->SetValue( tr.screen_color );
break;
case UT_DEPTHMAP:
u->SetValue( tr.screen_depth );
break;
case UT_COLORMAP:
u->SetValue( post.target_rgb[0] );
break;
case UT_GRAYSCALE:
u->SetValue( post.grayScaleFactor );
break;
case UT_BLURFACTOR:
u->SetValue( post.blurFactor[0], post.blurFactor[1] );
break;
case UT_SCREENSIZEINV:
u->SetValue( 1.0f / (float)glState.width, 1.0f / (float)glState.height );
break;
case UT_SCREENWIDTH:
u->SetValue( (float)glState.width );
break;
case UT_SCREENHEIGHT:
u->SetValue( (float)glState.height );
break;
case UT_FOCALDEPTH:
u->SetValue( post.m_flLastDepth );
break;
case UT_FOCALLENGTH:
u->SetValue( post.m_flLastLength );
break;
case UT_DOFDEBUG:
u->SetValue( CVAR_TO_BOOL( r_dof_debug ));
break;
case UT_FSTOP:
u->SetValue( r_dof_fstop->value );
break;
case UT_ZFAR:
u->SetValue( RI->view.farClip );
break;
case UT_GAMMATABLE:
u->SetValue( &tr.gamma_table[0][0], 64 );
break;
case UT_DIFFUSEFACTOR:
u->SetValue( tr.diffuseFactor );
break;
case UT_AMBIENTFACTOR:
u->SetValue( tr.ambientFactor );
break;
case UT_SUNREFRACT:
u->SetValue( tr.sun_refract );
break;
case UT_REALTIME:
u->SetValue( (float)tr.time );
break;
case UT_LIGHTDIFFUSE:
u->SetValue( post.m_vecSunLightColor.x, post.m_vecSunLightColor.y, post.m_vecSunLightColor.z );
break;
case UT_LIGHTORIGIN:
u->SetValue( post.m_vecSunPosition.x, post.m_vecSunPosition.y, post.m_vecSunPosition.z );
break;
case UT_FOGPARAMS:
u->SetValue( tr.fogColor[0], tr.fogColor[1], tr.fogColor[2], tr.fogDensity );
break;
default:
ALERT( at_error, "%s: unhandled uniform %s\n", RI->currentshader->name, u->name );
break;
}
}
// render a fullscreen quad
RenderFSQ( glState.width, glState.height );
}
void RenderBlur( float blurX, float blurY )
{
if( !blurX && !blurY )
return;
// update blur params
post.blurFactor[0] = blurX;
post.blurFactor[1] = blurY;
if( !post.Begin( )) return;
// do vertical blur
post.RequestScreenColor();
V_RenderPostEffect( post.blurShader[0] );
// do horizontal blur
post.RequestScreenColor();
V_RenderPostEffect( post.blurShader[1] );
post.End();
}
void RenderMonochrome( void )
{
post.grayScaleFactor = GetGrayscaleFactor();
if( post.grayScaleFactor <= 0.0f ) return;
if( !post.Begin( )) return;
// apply monochromatic
post.RequestScreenColor();
V_RenderPostEffect( post.monoShader );
post.End();
}
void RenderUnderwaterBlur( void )
{
if( !CVAR_TO_BOOL( cv_water ) || tr.waterlevel < 3 )
return;
float factor = sin( tr.time * 0.1f * ( M_PI * 2.7f ));
float blurX = RemapVal( factor, -1.0f, 1.0f, 0.18f, 0.23f );
float blurY = RemapVal( factor, -1.0f, 1.0f, 0.15f, 0.24f );
RenderBlur( blurX, blurY );
}
void RenderNerveGasBlur( void )
{
if( gHUD.m_flBlurAmount <= 0.0f )
return;
float factor = sin( tr.time * 0.4f * ( M_PI * 1.7f ));
float blurX = RemapVal( factor, -1.0f, 1.0f, 0.0f, 0.3f );
float blurY = RemapVal( factor, -1.0f, 1.0f, 0.0f, 0.3f );
blurX = bound( 0.0f, blurX, gHUD.m_flBlurAmount );
blurY = bound( 0.0f, blurY, gHUD.m_flBlurAmount );
RenderBlur( blurX, blurY );
}
void RenderDOF( void )
{
if( !post.ProcessDepthOfField( ))
return;
post.RequestScreenColor();
post.RequestScreenDepth();
V_RenderPostEffect( post.dofShader );
post.End();
}
void RenderSunShafts( void )
{
if( !post.ProcessSunShafts( ))
return;
post.RequestScreenColor();
post.RequestScreenDepth();
// we operate in small window to increase speedup
post.SetTargetViewport();
V_RenderPostEffect( post.genSunShafts );
post.RequestTargetCopy( 0 );
post.m_bUseTarget = true;
V_RenderPostEffect( post.blurShader[0] );
post.RequestTargetCopy( 0 );
V_RenderPostEffect( post.blurShader[1] );
post.RequestTargetCopy( 0 );
post.m_bUseTarget = false;
// back to normal size
post.SetNormalViewport();
V_RenderPostEffect( post.drawSunShafts );
post.End();
}

View File

@ -0,0 +1,99 @@
/*
gl_primitive.cpp - rendering primitives
Copyright (C) 2018 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "hud.h"
#include <stringlib.h>
#include "cl_util.h"
#include "pm_defs.h"
#include "event_api.h"
#include "gl_local.h"
#include "gl_studio.h"
#include "gl_world.h"
#include "gl_grass.h"
void CSolidEntry :: SetRenderPrimitive( const Vector verts[4], const Vector4D &color, int texture, int rendermode )
{
m_bDrawType = DRAWTYPE_QUAD;
m_iStartVertex = RI->frame.primverts.Count();
for( int i = 0; i < 4; i++ )
RI->frame.primverts.AddToTail( verts[i] );
m_iColor = PackRGBA( color.x * 255, color.y * 255, color.z * 255, color.w * 255 );
m_iRenderMode = rendermode;
m_hTexture = texture;
}
void CSolidEntry :: SetRenderSurface( msurface_t *surface, word hProgram )
{
m_bDrawType = DRAWTYPE_SURFACE;
m_pSurf = surface;
m_pParentEntity = RI->currententity;
m_pRenderModel = RI->currentmodel;
m_hProgram = hProgram;
}
void CSolidEntry :: SetRenderMesh( vbomesh_t *mesh, word hProgram )
{
m_bDrawType = DRAWTYPE_MESH;
m_pMesh = mesh;
m_pParentEntity = RI->currententity;
m_pRenderModel = RI->currentmodel;
m_hProgram = hProgram;
}
void CTransEntry :: ComputeViewDistance( const Vector &absmin, const Vector &absmax )
{
#if 1
m_flViewDist = CalcSqrDistanceToAABB( absmin, absmax, GetVieworg( ));
#else
Vector origin = (absmin + absmax) * 0.5f;
m_flViewDist = DotProduct( origin, GetVForward() ) - RI->view.planedist;
// m_flViewDist = VectorDistance2( origin, GetVieworg( ));
#endif
}
void CTransEntry :: ComputeScissor( const Vector &absmin, const Vector &absmax )
{
ComputeViewDistance( absmin, absmax );
if( R_ScissorForAABB( absmin, absmax, &m_vecRect.x, &m_vecRect.y, &m_vecRect.z, &m_vecRect.w ))
m_bScissorReady = true;
else m_bScissorReady = false;
}
void CTransEntry :: RequestScreenColor( void )
{
if( !m_bScissorReady ) return;
float y2 = (float)RI->view.port[3] - m_vecRect.w - m_vecRect.y;
GL_BindTexture( GL_TEXTURE0, tr.screen_color );
pglCopyTexSubImage2D( GL_TEXTURE_2D, 0, m_vecRect.x, y2, m_vecRect.x, y2, m_vecRect.z, m_vecRect.w );
}
void CTransEntry :: RequestScreenDepth( void )
{
if( !m_bScissorReady ) return;
float y2 = (float)RI->view.port[3] - m_vecRect.w - m_vecRect.y;
GL_BindTexture( GL_TEXTURE0, tr.screen_depth );
pglCopyTexSubImage2D( GL_TEXTURE_2D, 0, m_vecRect.x, y2, m_vecRect.x, y2, m_vecRect.z, m_vecRect.w );
}
void CTransEntry :: RenderScissorDebug( void )
{
if( !m_bScissorReady ) return;
R_DrawScissorRectangle( m_vecRect.x, m_vecRect.y, m_vecRect.z, m_vecRect.w );
}

View File

@ -0,0 +1,80 @@
/*
gl_primitive.h - render primitives
this code written for Paranoia 2: Savior modification
Copyright (C) 2013 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef GL_PRIMITIVE_H
#define GL_PRIMITIVE_H
#define DRAWTYPE_UNKNOWN 0
#define DRAWTYPE_SURFACE 1
#define DRAWTYPE_MESH 2
#define DRAWTYPE_QUAD 3
//#pragma pack(1)
class CSolidEntry
{
public:
void SetRenderPrimitive( const Vector verts[4], const Vector4D &color, int texture, int rendermode );
void SetRenderSurface( msurface_t *surface, word hProgram );
void SetRenderMesh( struct vbomesh_s *mesh, word hProgram );
virtual bool IsTranslucent( void ) { return false; }
int GetType( void ) { return m_bDrawType; }
byte m_bDrawType; // type of entry
union
{
cl_entity_t *m_pParentEntity; // pointer to parent entity
int m_iRenderMode; // rendermode for primitive
};
union
{
model_t *m_pRenderModel; // render model
int m_iStartVertex; // offset in global heap
};
union
{
unsigned short m_hProgram; // handle to glsl program (may be 0)
unsigned short m_hTexture; // texture for primitive
};
union
{
struct vbomesh_s *m_pMesh; // NULL or mesh
msurface_t *m_pSurf; // NULL or surface
int m_iColor; // primitive color
};
};
class CTransEntry : public CSolidEntry
{
public:
void ComputeViewDistance( const Vector &absmin, const Vector &absmax );
void ComputeScissor( const Vector &absmin, const Vector &absmax );
virtual bool IsTranslucent( void ) { return true; }
void RequestScreenColor( void );
void RequestScreenDepth( void );
void RenderScissorDebug( void );
float m_flViewDist;
Vector4D m_vecRect;
bool m_bScissorReady : 1;
};
//#pragma pack()
#endif//GL_PRIMITIVE_H

1218
cl_dll/render/gl_rmain.cpp Normal file

File diff suppressed because it is too large Load Diff

1202
cl_dll/render/gl_rmisc.cpp Normal file

File diff suppressed because it is too large Load Diff

1181
cl_dll/render/gl_rpart.cpp Normal file

File diff suppressed because it is too large Load Diff

144
cl_dll/render/gl_rpart.h Normal file
View File

@ -0,0 +1,144 @@
/*
gl_rpart.h - quake-like particles
this code written for Paranoia 2: Savior modification
Copyright (C) 2013 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef GL_RPART_H
#define GL_RPART_H
#include "randomrange.h"
#define MAX_PARTICLES 8192
#define MAX_PARTINFOS 256 // various types of part-system
// built-in particle-system flags
#define FPART_BOUNCE (1<<0) // makes a bouncy particle
#define FPART_FRICTION (1<<1)
#define FPART_VERTEXLIGHT (1<<2) // give some ambient light for it
#define FPART_STRETCH (1<<3)
#define FPART_UNDERWATER (1<<4)
#define FPART_INSTANT (1<<5)
#define FPART_ADDITIVE (1<<6)
#define FPART_NOTWATER (1<<7) // don't spawn in water
class CQuakePart
{
public:
Vector m_vecOrigin; // position for current frame
Vector m_vecLastOrg; // position from previous frame
Vector m_vecVelocity; // linear velocity
Vector m_vecAccel;
Vector m_vecColor;
Vector m_vecColorVelocity;
float m_flAlpha;
float m_flAlphaVelocity;
float m_flRadius;
float m_flRadiusVelocity;
float m_flLength;
float m_flLengthVelocity;
float m_flRotation; // texture ROLL angle
float m_flBounceFactor;
CQuakePart *pNext; // linked list
int m_hTexture;
float m_flTime;
int m_iFlags;
bool Evaluate( float gravity );
};
typedef enum
{
NORMAL_IGNORE = 0,
NORMAL_OFFSET,
NORMAL_DIRECTION,
NORMAL_OFS_DIR,
};
class CQuakePartInfo
{
public:
char m_szName[32]; // effect name
struct model_s *m_pSprite; // sprite
int m_hTexture; // tga texture
RandomRange offset[3];
RandomRange velocity[3];
RandomRange accel[3];
RandomRange color[3];
RandomRange colorVel[3];
RandomRange alpha;
RandomRange alphaVel;
RandomRange radius;
RandomRange radiusVel;
RandomRange length;
RandomRange lengthVel;
RandomRange rotation;
RandomRange bounce;
RandomRange frame;
RandomRange count; // particle count
int normal; // how to use normal
int flags; // particle flags
};
class CQuakePartSystem
{
CQuakePart *m_pActiveParticles;
CQuakePart *m_pFreeParticles;
CQuakePart m_pParticles[MAX_PARTICLES];
CQuakePartInfo m_pPartInfo[MAX_PARTINFOS];
int m_iNumPartInfo;
// private partsystem shaders
int m_hDefaultParticle;
int m_hSparks;
int m_hSmoke;
int m_hWaterSplash;
cvar_t *m_pAllowParticles;
cvar_t *m_pParticleLod;
public:
CQuakePartSystem( void );
virtual ~CQuakePartSystem( void );
void Clear( void );
void Update( void );
void FreeParticle( CQuakePart *pCur );
CQuakePart *AllocParticle( void );
bool AddParticle( CQuakePart *src, int texture = 0, int flags = 0 );
void ParsePartInfos( const char *filename );
bool ParsePartInfo( CQuakePartInfo *info, char *&pfile );
bool ParseRandomVector( char *&pfile, RandomRange out[3] );
int ParseParticleFlags( char *pfile );
CQuakePartInfo *FindPartInfo( const char *name );
void CreateEffect( const char *name, const Vector &origin, const Vector &normal );
// example presets
void ExplosionParticles( const Vector &pos );
void BulletParticles( const Vector &org, const Vector &dir );
void BubbleParticles( const Vector &org, int count, float magnitude );
void SparkParticles( const Vector &org, const Vector &dir );
void RicochetSparks( const Vector &org, float scale );
void SmokeParticles( const Vector &pos, int count );
void GunSmoke( const Vector &pos, int count );
};
extern CQuakePartSystem g_pParticles;
#endif//GL_RPART_H

View File

@ -0,0 +1,99 @@
/*
gl_rsurf.cpp - surface-related code
Copyright (C) 2013 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "hud.h"
#include "cl_util.h"
#include "gl_local.h"
static int rtable[MOD_FRAMES][MOD_FRAMES];
/*
===============
R_TextureAnimation
Returns the proper texture for a given time and base texture
===============
*/
texture_t *R_TextureAnimation( msurface_t *s )
{
texture_t *base = s->texinfo->texture;
int count, reletive = 0;
if(( RI->currententity != NULL ) && ( RI->currententity->curstate.frame != 0.0f ))
{
if( base->alternate_anims )
base = base->alternate_anims;
}
if( !base->anim_total )
return base;
if( base->name[0] == '-' )
{
int tx = (int)((s->texturemins[0] + (base->width << 16)) / base->width) % MOD_FRAMES;
int ty = (int)((s->texturemins[1] + (base->height << 16)) / base->height) % MOD_FRAMES;
reletive = rtable[tx][ty] % base->anim_total;
}
else
{
reletive = (int)(tr.time * 20) % base->anim_total;
}
count = 0;
while( base->anim_min > reletive || base->anim_max <= reletive )
{
base = base->anim_next;
if( !base )
{
ALERT( at_error, "R_TextureAnimation: broken loop\n" );
return s->texinfo->texture;
}
if( ++count > MOD_FRAMES )
{
ALERT( at_error, "R_TextureAnimation: infinite loop\n" );
return s->texinfo->texture;
}
}
return base;
}
/*
=============================================================
WORLD MODEL
=============================================================
*/
void GL_InitRandomTable( void )
{
int tu, tv;
// make random predictable
RANDOM_SEED( 255 );
for( tu = 0; tu < MOD_FRAMES; tu++ )
{
for( tv = 0; tv < MOD_FRAMES; tv++ )
{
rtable[tu][tv] = RANDOM_LONG( 0, 0x7FFF );
}
}
RANDOM_SEED( 0 );
}

548
cl_dll/render/gl_scene.cpp Normal file
View File

@ -0,0 +1,548 @@
/*
gl_scene.cpp - scene management
Copyright (C) 2016 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "hud.h"
#include "cl_util.h"
#include "camera.h"
#include "entity_types.h"
#include "gl_local.h"
#include <mathlib.h>
#include "gl_aurora.h"
#include "gl_rpart.h"
#include "gl_studio.h"
#include "gl_sprite.h"
#include "event_api.h"
#include "gl_world.h"
#include "gl_grass.h"
#include "screenfade.h"
#include "shake.h"
/*
===============
R_CheckChanges
===============
*/
void R_CheckChanges( void )
{
static bool fog_enabled_old;
bool settings_changed = false;
if( FBitSet( r_showlightmaps->flags, FCVAR_CHANGED ))
{
float lightmap = bound( 0.0f, r_showlightmaps->value, MAX_LIGHTMAPS );
CVAR_SET_FLOAT( "r_showlightmaps", lightmap );
ClearBits( r_showlightmaps->flags, FCVAR_CHANGED );
}
if( FBitSet( r_studio_decals->flags, FCVAR_CHANGED ))
{
float maxStudioDecals = bound( 10.0f, r_studio_decals->value, 256.0f );
CVAR_SET_FLOAT( "r_studio_decals", maxStudioDecals );
ClearBits( r_studio_decals->flags, FCVAR_CHANGED );
}
if( FBitSet( cv_deferred_maxlights->flags, FCVAR_CHANGED ))
{
float maxDeferredLights = bound( 1, cv_deferred_maxlights->value, MAXDYNLIGHTS );
if( maxDeferredLights != cv_deferred_maxlights->value )
CVAR_SET_FLOAT( "gl_deferred_maxlights", maxDeferredLights );
ClearBits( cv_deferred_maxlights->flags, FCVAR_CHANGED );
}
if( FBitSet( cv_deferred_tracebmodels->flags, FCVAR_CHANGED ))
{
ClearBits( cv_deferred_tracebmodels->flags, FCVAR_CHANGED );
tr.params_changed = true;
}
if( FBitSet( r_recursion_depth->flags, FCVAR_CHANGED ))
{
float depth = bound( 0.0f, r_recursion_depth->value, MAX_REF_STACK - 2 );
CVAR_SET_FLOAT( "gl_recursion_depth", depth );
ClearBits( r_recursion_depth->flags, FCVAR_CHANGED );
}
if( FBitSet( r_drawentities->flags, FCVAR_CHANGED ))
{
ClearBits( r_drawentities->flags, FCVAR_CHANGED );
tr.params_changed = true;
}
if( FBitSet( r_lightstyles->flags, FCVAR_CHANGED ))
{
ClearBits( r_lightstyles->flags, FCVAR_CHANGED );
settings_changed = true;
}
if( FBitSet( cv_cubemaps->flags, FCVAR_CHANGED ))
{
ClearBits( cv_cubemaps->flags, FCVAR_CHANGED );
settings_changed = true;
}
if( FBitSet( cv_deferred->flags, FCVAR_CHANGED ))
{
ClearBits( cv_deferred->flags, FCVAR_CHANGED );
settings_changed = true;
}
if( FBitSet( r_lightmap->flags, FCVAR_CHANGED ))
{
ClearBits( r_lightmap->flags, FCVAR_CHANGED );
settings_changed = true;
}
if( FBitSet( r_allow_mirrors->flags, FCVAR_CHANGED ))
{
ClearBits( r_allow_mirrors->flags, FCVAR_CHANGED );
settings_changed = true;
}
if( FBitSet( cv_realtime_puddles->flags, FCVAR_CHANGED ))
{
ClearBits( cv_realtime_puddles->flags, FCVAR_CHANGED );
settings_changed = true;
}
if( FBitSet( r_detailtextures->flags, FCVAR_CHANGED ))
{
ClearBits( r_detailtextures->flags, FCVAR_CHANGED );
settings_changed = true;
}
if( FBitSet( r_fullbright->flags, FCVAR_CHANGED ))
{
ClearBits( r_fullbright->flags, FCVAR_CHANGED );
settings_changed = true;
}
if( FBitSet( r_sunshadows->flags, FCVAR_CHANGED ))
{
ClearBits( r_sunshadows->flags, FCVAR_CHANGED );
settings_changed = true;
}
if( FBitSet( r_sun_allowed->flags, FCVAR_CHANGED ))
{
ClearBits( r_sun_allowed->flags, FCVAR_CHANGED );
settings_changed = true;
}
if( FBitSet( cv_parallax->flags, FCVAR_CHANGED ))
{
ClearBits( cv_parallax->flags, FCVAR_CHANGED );
settings_changed = true;
}
if( FBitSet( cv_specular->flags, FCVAR_CHANGED ))
{
ClearBits( cv_specular->flags, FCVAR_CHANGED );
settings_changed = true;
}
if( FBitSet( r_grass_shadows->flags, FCVAR_CHANGED ))
{
ClearBits( r_grass_shadows->flags, FCVAR_CHANGED );
settings_changed = true;
}
if( FBitSet( r_shadows->flags, FCVAR_CHANGED ))
{
ClearBits( r_shadows->flags, FCVAR_CHANGED );
settings_changed = true;
}
if( FBitSet( cv_bump->flags, FCVAR_CHANGED ))
{
ClearBits( cv_bump->flags, FCVAR_CHANGED );
settings_changed = true;
}
if( FBitSet( cv_brdf->flags, FCVAR_CHANGED ))
{
ClearBits( cv_brdf->flags, FCVAR_CHANGED );
settings_changed = true;
}
if( FBitSet( r_test->flags, FCVAR_CHANGED ))
{
ClearBits( r_test->flags, FCVAR_CHANGED );
R_StudioClearLightCache();
settings_changed = true;
}
if( FBitSet( r_grass->flags, FCVAR_CHANGED ))
{
if( worldmodel != NULL )
{
for( int i = 0; i < worldmodel->numsurfaces; i++ )
SetBits( worldmodel->surfaces[i].flags, SURF_GRASS_UPDATE );
}
ClearBits( r_grass->flags, FCVAR_CHANGED );
settings_changed = true;
}
if( FBitSet( cv_gamma->flags, FCVAR_CHANGED ) || FBitSet( cv_brightness->flags, FCVAR_CHANGED ))
{
if( worldmodel != NULL )
{
for( int i = 0; i < worldmodel->numsurfaces; i++ )
SetBits( worldmodel->surfaces[i].flags, SURF_LM_UPDATE|SURF_GRASS_UPDATE );
}
R_StudioClearLightCache();
}
if( tr.fogEnabled != fog_enabled_old )
{
fog_enabled_old = tr.fogEnabled;
settings_changed = true;
}
if( settings_changed )
{
tr.glsl_valid_sequence++; // now all uber-shaders are invalidate and possible need for recompile
tr.params_changed = true;
}
}
/*
===============
R_ClearScene
===============
*/
void R_ClearScene( void )
{
if( !g_fRenderInitialized ) return;
CL_DecayLights();
tr.time = GET_CLIENT_TIME();
tr.oldtime = GET_CLIENT_OLDTIME();
tr.frametime = tr.time - tr.oldtime;
tr.saved_frametime = tr.frametime; // backup
memset( &r_stats, 0, sizeof( r_stats ));
tr.local_client_added = false;
tr.num_draw_entities = 0;
tr.cached_state.Purge(); // invalidate cache
GET_ENTITY( 0 )->hCachedMatrix = GL_CacheState( g_vecZero, g_vecZero );
tr.num_2D_shadows_used = tr.num_CM_shadows_used = 0;
tr.sun_light_enabled = false;
if( r_sunshadows->value > 2.0f )
CVAR_SET_FLOAT( "gl_sun_shadows", 2.0f );
else if( r_sunshadows->value < 0.0f )
CVAR_SET_FLOAT( "gl_sun_shadows", 0.0f );
if( tr.shadows_notsupport )
CVAR_SET_FLOAT( "r_shadows", 0.0f );
R_CheckChanges();
if( tr.params_changed )
R_InitDynLightShaders();
}
/*
===============
R_ComputeFxBlend
===============
*/
int R_ComputeFxBlend( cl_entity_t *e )
{
int blend = 0, renderAmt;
float offset, dist;
Vector tmp;
offset = ((int)e->index ) * 363.0f; // Use ent index to de-sync these fx
renderAmt = e->curstate.renderamt;
switch( e->curstate.renderfx )
{
case kRenderFxPulseSlowWide:
blend = renderAmt + 0x40 * sin( tr.time * 2 + offset );
break;
case kRenderFxPulseFastWide:
blend = renderAmt + 0x40 * sin( tr.time * 8 + offset );
break;
case kRenderFxPulseSlow:
blend = renderAmt + 0x10 * sin( tr.time * 2 + offset );
break;
case kRenderFxPulseFast:
blend = renderAmt + 0x10 * sin( tr.time * 8 + offset );
break;
// JAY: HACK for now -- not time based
case kRenderFxFadeSlow:
if( renderAmt > 0 )
renderAmt -= 1;
else renderAmt = 0;
blend = renderAmt;
break;
case kRenderFxFadeFast:
if( renderAmt > 3 )
renderAmt -= 4;
else renderAmt = 0;
blend = renderAmt;
break;
case kRenderFxSolidSlow:
if( renderAmt < 255 )
renderAmt += 1;
else renderAmt = 255;
blend = renderAmt;
break;
case kRenderFxSolidFast:
if( renderAmt < 252 )
renderAmt += 4;
else renderAmt = 255;
blend = renderAmt;
break;
case kRenderFxStrobeSlow:
blend = 20 * sin( tr.time * 4 + offset );
if( blend < 0 ) blend = 0;
else blend = renderAmt;
break;
case kRenderFxStrobeFast:
blend = 20 * sin( tr.time * 16 + offset );
if( blend < 0 ) blend = 0;
else blend = renderAmt;
break;
case kRenderFxStrobeFaster:
blend = 20 * sin( tr.time * 36 + offset );
if( blend < 0 ) blend = 0;
else blend = renderAmt;
break;
case kRenderFxFlickerSlow:
blend = 20 * (sin( tr.time * 2 ) + sin( tr.time * 17 + offset ));
if( blend < 0 ) blend = 0;
else blend = renderAmt;
break;
case kRenderFxFlickerFast:
blend = 20 * (sin( tr.time * 16 ) + sin( tr.time * 23 + offset ));
if( blend < 0 ) blend = 0;
else blend = renderAmt;
break;
case kRenderFxHologram:
case kRenderFxDistort:
tmp = e->origin - GetVieworg();
dist = DotProduct( tmp, GetVForward( ));
// Turn off distance fade
if( e->curstate.renderfx == kRenderFxDistort )
dist = 1;
if( dist <= 0 )
{
blend = 0;
}
else
{
renderAmt = 180;
if( dist <= 100 ) blend = renderAmt;
else blend = (int) ((1.0f - ( dist - 100 ) * ( 1.0f / 400.0f )) * renderAmt );
blend += RANDOM_LONG( -32, 31 );
}
break;
case kRenderFxGlowShell: // safe current renderamt because it's shell scale!
case kRenderFxDeadPlayer: // safe current renderamt because it's player index!
blend = renderAmt;
break;
case kRenderFxNone:
case kRenderFxClampMinScale:
default:
if( e->curstate.rendermode == kRenderNormal )
blend = 255;
else blend = renderAmt;
break;
}
if( e->model->type != mod_brush || R_WaterEntity( e->model ))
{
// NOTE: never pass sprites with rendercolor '0 0 0' it's a stupid Valve Hammer Editor bug
if( !e->curstate.rendercolor.r && !e->curstate.rendercolor.g && !e->curstate.rendercolor.b )
e->curstate.rendercolor.r = e->curstate.rendercolor.g = e->curstate.rendercolor.b = 255;
}
// apply scale to studiomodels and sprites only
if( e->model && e->model->type != mod_brush && !e->curstate.scale )
e->curstate.scale = 1.0f;
blend = bound( 0, blend, 255 );
return blend;
}
/*
===============
R_AddEntity
===============
*/
qboolean R_AddEntity( struct cl_entity_s *clent, int entityType )
{
if( !CVAR_TO_BOOL( r_drawentities ))
return false; // not allow to drawing
if( !clent || !clent->model )
return false; // if set to invisible, skip
if( clent->curstate.effects & EF_NODRAW )
return false; // done
if( entityType == ET_PLAYER && RP_LOCALCLIENT( clent ))
{
if( tr.local_client_added )
return false; // already present in list
tr.local_client_added = true;
}
if( clent->curstate.renderfx == 71 ) // dynamic light
{
CDynLight *dl = CL_AllocDlight( clent->curstate.number );
float radius = clent->curstate.renderamt * 8.0f;
float fov = clent->curstate.scale;
int tex = 0, flags = 0, type;
Vector origin, angles;
if( clent->curstate.scale ) // spotlight
{
int i = bound( 0, clent->curstate.rendermode, 7 );
tex = tr.spotlightTexture[i];
type = LIGHT_SPOT;
}
else type = LIGHT_OMNI;
if( clent->curstate.effects & EF_NOSHADOW )
flags |= DLF_NOSHADOWS;
if( clent->curstate.effects & EF_NOBUMP )
flags |= DLF_NOBUMP;
if( clent->curstate.effects & EF_LENSFLARE )
flags |= DLF_LENSFLARE;
R_GetLightVectors( clent, origin, angles );
R_SetupLightParams( dl, origin, angles, radius, clent->curstate.scale, type, flags );
R_SetupLightTexture( dl, tex );
dl->color[0] = (float)clent->curstate.rendercolor.r / 128;
dl->color[1] = (float)clent->curstate.rendercolor.g / 128;
dl->color[2] = (float)clent->curstate.rendercolor.b / 128;
dl->die = tr.time + 0.05f;
return true; // no reason to drawing this entity
}
else if( clent->curstate.renderfx == 72 ) // dynamic light with avi file
{
if( !clent->curstate.sequence )
return true; // bad avi file
CDynLight *dl = CL_AllocDlight( clent->curstate.number );
if( dl->spotlightTexture == tr.spotlightTexture[1] )
return true; // bad avi file
float radius = clent->curstate.renderamt * 8.0f;
float fov = clent->curstate.scale;
Vector origin, angles;
int flags = DLF_ASPECT3X4; // fit to film01.avi aspect
// found the corresponding cinstate
const char *cinname = gRenderfuncs.GetFileByIndex( clent->curstate.sequence );
int hCin = R_PrecacheCinematic( cinname );
if( hCin >= 0 && !dl->cinTexturenum )
dl->cinTexturenum = R_AllocateCinematicTexture( TF_SPOTLIGHT );
if( hCin == -1 || dl->cinTexturenum <= 0 || !CIN_IS_ACTIVE( tr.cinematics[hCin].state ))
{
// cinematic textures limit exceeded or movie not found
dl->spotlightTexture = tr.spotlightTexture[1];
return true;
}
gl_movie_t *cin = &tr.cinematics[hCin];
float cin_time;
// advances cinematic time
cin_time = fmod( clent->curstate.fuser2, cin->length );
// read the next frame
int cin_frame = CIN_GET_FRAME_NUMBER( cin->state, cin_time );
if( cin_frame != dl->lastframe )
{
// upload the new frame
byte *raw = CIN_GET_FRAMEDATA( cin->state, cin_frame );
CIN_UPLOAD_FRAME( tr.cinTextures[dl->cinTexturenum-1], cin->xres, cin->yres, cin->xres, cin->yres, raw );
dl->lastframe = cin_frame;
}
if( clent->curstate.effects & EF_NOSHADOW )
flags |= DLF_NOSHADOWS;
if( clent->curstate.effects & EF_NOBUMP )
flags |= DLF_NOBUMP;
R_GetLightVectors( clent, origin, angles );
R_SetupLightParams( dl, origin, angles, radius, clent->curstate.scale, LIGHT_SPOT, flags );
R_SetupLightTexture( dl, tr.cinTextures[dl->cinTexturenum-1] );
dl->color[0] = (float)clent->curstate.rendercolor.r / 128;
dl->color[1] = (float)clent->curstate.rendercolor.g / 128;
dl->color[2] = (float)clent->curstate.rendercolor.b / 128;
dl->die = GET_CLIENT_TIME() + 0.05f;
return true; // no reason to drawing this entity
}
if( clent->curstate.effects & EF_SCREENMOVIE )
{
// update cin sound properly
R_UpdateCinSound( clent );
}
clent->curstate.renderamt = R_ComputeFxBlend( clent );
if( !R_OpaqueEntity( clent ))
{
if( clent->curstate.renderamt <= 0.0f )
return true; // invisible
}
#if 0
if( clent->model->type == mod_brush && CVAR_TO_BOOL( r_test ))
return true;
#endif
if( clent->model->type == mod_brush )
clent->hCachedMatrix = GL_CacheState( clent->origin, clent->angles, ( clent->curstate.renderfx == SKYBOX_ENTITY ));
clent->curstate.entityType = entityType;
// mark static entity as visible
if( entityType == ET_FRAGMENTED )
{
// non-solid statics wants a new lighting too :-)
SetBits( clent->curstate.iuser1, CF_STATIC_ENTITY );
clent->visframe = tr.realframecount;
}
if( tr.num_draw_entities < MAX_VISIBLE_ENTS )
{
tr.draw_entities[tr.num_draw_entities] = clent;
tr.num_draw_entities++;
}
return true;
}

1357
cl_dll/render/gl_shader.cpp Normal file

File diff suppressed because it is too large Load Diff

262
cl_dll/render/gl_shader.h Normal file
View File

@ -0,0 +1,262 @@
/*
gl_shader.h - shader parsing and handling
this code written for Paranoia 2: Savior modification
Copyright (C) 2013 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef GL_SHADER_H
#define GL_SHADER_H
#define MAX_OPTIONS_LENGTH 512
#define MAX_GLSL_PROGRAMS 4096
#define SHADER_VERTEX_COMPILED BIT( 0 )
#define SHADER_FRAGMENT_COMPILED BIT( 1 )
#define SHADER_PROGRAM_LINKED BIT( 2 )
#define SHADER_UBERSHADER BIT( 3 )
#define SHADER_TRANSLUCENT BIT( 4 )
#define SHADER_USE_CUBEMAPS BIT( 5 )
#define SHADER_USE_SCREENCOPY BIT( 6 )
#define SHADER_ADDITIVE BIT( 7 )
#define SHADER_STATUS_OK ( SHADER_PROGRAM_LINKED|SHADER_VERTEX_COMPILED|SHADER_FRAGMENT_COMPILED )
#define CheckShader( shader ) ( shader && shader->status == SHADER_STATUS_OK )
enum
{
ATTR_INDEX_POSITION = 0,
ATTR_INDEX_TANGENT,
ATTR_INDEX_BINORMAL,
ATTR_INDEX_NORMAL,
ATTR_INDEX_TEXCOORD0, // texture coord
ATTR_INDEX_TEXCOORD1, // lightmap coord (styles0-1)
ATTR_INDEX_TEXCOORD2, // lightmap coord (styles2-3)
ATTR_INDEX_BONE_INDEXES, // studiomodels only
ATTR_INDEX_BONE_WEIGHTS, // studiomodels only
ATTR_INDEX_LIGHT_STYLES, // brushmodels only
ATTR_INDEX_LIGHT_COLOR, // studio & grass
ATTR_INDEX_LIGHT_VECS, // studio & grass
ATTR_INDEX_LIGHT_NUMS0, // brushmodels only
ATTR_INDEX_LIGHT_NUMS1, // brushmodels only
};
// shader->attribs
#define FATTR_POSITION BIT( 0 )
#define FATTR_TANGENT BIT( 1 )
#define FATTR_BINORMAL BIT( 2 )
#define FATTR_NORMAL BIT( 3 )
#define FATTR_TEXCOORD0 BIT( 4 )
#define FATTR_TEXCOORD1 BIT( 5 )
#define FATTR_TEXCOORD2 BIT( 6 )
#define FATTR_BONE_INDEXES BIT( 7 )
#define FATTR_BONE_WEIGHTS BIT( 8 )
#define FATTR_LIGHT_STYLES BIT( 9 )
#define FATTR_LIGHT_COLOR BIT( 10 )
#define FATTR_LIGHT_VECS BIT( 11 )
#define FATTR_LIGHT_NUMS0 BIT( 12 )
#define FATTR_LIGHT_NUMS1 BIT( 13 )
// uniform->flags
#define UFL_GLOBAL_PARM BIT( 0 )
#define UFL_TEXTURE_UNIT BIT( 1 )
// uniform->type
typedef enum
{
UT_COLORMAP = 0,
UT_DEPTHMAP,
UT_NORMALMAP,
UT_GLOSSMAP,
UT_DETAILMAP,
UT_PROJECTMAP, // spotlight texture
UT_SHADOWMAP0,
UT_SHADOWMAP1,
UT_SHADOWMAP2,
UT_SHADOWMAP3,
UT_SHADOWMAP,
UT_LIGHTMAP,
UT_DELUXEMAP,
UT_DECALMAP,
UT_SCREENMAP,
UT_VISLIGHTMAP0,
UT_VISLIGHTMAP1,
UT_ENVMAP0,
UT_ENVMAP1,
UT_ENVMAP,
UT_GLOWMAP,
UT_HEIGHTMAP,
UT_LAYERMAP,
UT_FRAGDATA0,
UT_FRAGDATA1,
UT_FRAGDATA2,
UT_BSPPLANESMAP,
UT_BSPNODESMAP,
UT_BSPLIGHTSMAP,
UT_BSPMODELSMAP,
UT_FITNORMALMAP,
UT_MODELMATRIX,
UT_REFLECTMATRIX,
UT_BONESARRAY,
UT_BONEQUATERNION,
UT_BONEPOSITION,
UT_SCREENSIZEINV,
UT_ZFAR,
UT_LIGHTSTYLEVALUES,
UT_LIGHTSTYLES,
UT_REALTIME,
UT_DETAILSCALE,
UT_FOGPARAMS,
UT_SHADOWPARMS,
UT_TEXOFFSET,
UT_VIEWORIGIN,
UT_VIEWRIGHT,
UT_RENDERCOLOR,
UT_RENDERALPHA,
UT_SMOOTHNESS,
UT_SHADOWMATRIX,
UT_SHADOWSPLITDIST,
UT_TEXELSIZE,
UT_GAMMATABLE,
UT_LIGHTDIR,
UT_LIGHTDIFFUSE,
UT_LIGHTSHADE,
UT_LIGHTORIGIN,
UT_LIGHTVIEWPROJMATRIX,
UT_DIFFUSEFACTOR,
UT_AMBIENTFACTOR,
UT_AMBIENTCUBE,
UT_SUNREFRACT,
UT_LERPFACTOR,
UT_REFRACTSCALE,
UT_REFLECTSCALE,
UT_ABERRATIONSCALE,
UT_BOXMINS,
UT_BOXMAXS,
UT_CUBEORIGIN,
UT_CUBEMIPCOUNT,
UT_LIGHTNUMS0,
UT_LIGHTNUMS1,
UT_GRASSPARAMS,
UT_RELIEFPARAMS,
UT_BLURFACTOR,
UT_SCREENWIDTH,
UT_SCREENHEIGHT,
UT_FOCALDEPTH,
UT_FOCALLENGTH,
UT_DOFDEBUG,
UT_FSTOP,
UT_GRAYSCALE,
UT_LIGHTGAMMA,
UT_LIGHTSCALE,
UT_LIGHTTHRESHOLD,
UT_NUMVISIBLEMODELS,
UT_UNDEFINED,
} uniformType_t;
union unicache_t
{
unicache_t( int v0 ) { iValue[0] = v0; iValue[1] = iValue[2] = iValue[3] = 0; }
unicache_t( int v0, int v1 ) { iValue[0] = v0; iValue[1] = v1; iValue[2] = iValue[3] = 0; }
unicache_t( int v0, int v1, int v2 ) { iValue[0] = v0; iValue[1] = v1; iValue[2] = v2; iValue[3] = 0; }
unicache_t( int v0, int v1, int v2, int v3 ) { iValue[0] = v0; iValue[1] = v1; iValue[2] = v2; iValue[3] = v3; }
unicache_t( float v0 ) { fValue[0] = v0; fValue[1] = fValue[2] = fValue[3] = 0.0f; }
unicache_t( float v0, float v1 ) { fValue[0] = v0; fValue[1] = v1; fValue[2] = fValue[3] = 0.0f; }
unicache_t( float v0, float v1, float v2 ) { fValue[0] = v0; fValue[1] = v1; fValue[2] = v2; fValue[3] = 0.0f; }
unicache_t( float v0, float v1, float v2, float v3 ) { fValue[0] = v0; fValue[1] = v1; fValue[2] = v2; fValue[3] = v3; }
float fValue[4];
int iValue[4];
};
class uniform_t
{
public:
char name[MAX_QPATH];
uniformType_t type;
int size;
uint format;
int location;
int unit; // texture unit
int flags; // hints
unicache_t cache;
// helpers
void SetValue( float v0 )
{
unicache_t pack( v0 );
SetValue( &pack );
}
void SetValue( float v0, float v1 )
{
unicache_t pack( v0, v1 );
SetValue( &pack );
}
void SetValue( float v0, float v1, float v2 )
{
unicache_t pack( v0, v1, v2 );
SetValue( &pack );
}
void SetValue( float v0, float v1, float v2, float v3 )
{
unicache_t pack( v0, v1, v2, v3 );
SetValue( &pack );
}
void SetValue( int v0 )
{
unicache_t pack( v0 );
SetValue( &pack );
}
void SetValue( int v0, int v1 )
{
unicache_t pack( v0, v1 );
SetValue( &pack );
}
void SetValue( int v0, int v1, int v2 )
{
unicache_t pack( v0, v1, v2 );
SetValue( &pack );
}
void SetValue( int v0, int v1, int v2, GLint v3 )
{
unicache_t pack( v0, v1, v2, v3 );
SetValue( &pack );
}
// passed any data here
void SetValue( const void *pdata, int count = -1 );
int GetSizeInBytes( void );
};
typedef struct glsl_prog_s
{
char name[64];
char options[MAX_OPTIONS_LENGTH]; // UberShader preprocess agrs
GLhandleARB handle;
unsigned short status;
struct glsl_prog_s *nextHash;
unsigned short attribs;
uniform_t *uniforms;
int numUniforms;
} glsl_program_t;
extern glsl_program_t glsl_programs[MAX_GLSL_PROGRAMS];
extern int num_glsl_programs;
#endif//GL_SHADER_H

View File

@ -0,0 +1,138 @@
/*
gl_shadowmap.cpp - render shadowmaps for directional lights
Copyright (C) 2018 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "hud.h"
#include "cl_util.h"
#include "const.h"
#include "gl_local.h"
#include <mathlib.h>
#include <stringlib.h>
#include "gl_studio.h"
#include "gl_sprite.h"
#include "gl_world.h"
#include "gl_grass.h"
#include "pm_defs.h"
/*
=============================================================================
SHADOWMAP ALLOCATION
=============================================================================
*/
static void SM_InitBlock( void )
{
gl_shadowmap_t *sms = &tr.shadowmap;
memset( sms->allocated, 0, sizeof( sms->allocated ));
sms->shadowmap.Init( FBO_DEPTH, SHADOW_SIZE, SHADOW_SIZE );
}
static int SM_AllocBlock( unsigned short w, unsigned short h, unsigned short *x, unsigned short *y )
{
gl_shadowmap_t *sms = &tr.shadowmap;
unsigned short i, j, best, best2;
best = SHADOW_SIZE;
for( i = 0; i < SHADOW_SIZE - w; i++ )
{
best2 = 0;
for( j = 0; j < w; j++ )
{
if( sms->allocated[i+j] >= best )
break;
if( sms->allocated[i+j] > best2 )
best2 = sms->allocated[i+j];
}
if( j == w )
{
// this is a valid spot
*x = i;
*y = best = best2;
}
}
// atlas is full
if( best + h > SHADOW_SIZE )
return false;
for( i = 0; i < w; i++ )
sms->allocated[*x + i] = best + h;
return true;
}
/*
================
R_RenderShadowScene
fast version of R_RenderScene: no colors, no texcords etc
================
*/
void R_RenderShadow( mworldlight_t *wl )
{
if( !wl->shadow_w || !wl->shadow_h )
{
wl->shadow_w = 256;
wl->shadow_h = 256;
SM_AllocBlock( wl->shadow_w, wl->shadow_h, &wl->shadow_x, &wl->shadow_y );
}
}
void R_RenderDeferredShadows( void )
{
unsigned int oldFBO;
mworldlight_t *wl;
int i;
if( R_FullBright() || !CVAR_TO_BOOL( r_shadows ) || tr.fGamePaused )
return;
if( FBitSet( RI->params, ( RP_NOSHADOWS|RP_ENVVIEW|RP_SKYVIEW )))
return;
// check for static lights
if( !HasStaticLights( )) return;
R_PushRefState(); // make refinst backup
oldFBO = glState.frameBuffer;
for( i = 0, wl = world->worldlights; i < world->numworldlights; i++, wl++ )
{
if( wl->emittype == emit_ignored )
continue;
// single visible check
if( !CHECKVISBIT( RI->view.vislight, i ))
continue;
switch( wl->emittype )
{
case emit_surface:
R_RenderShadow( wl );
break;
}
R_ResetRefState(); // restore ref instance
}
R_PopRefState(); // restore ref instance
// restore FBO state
GL_BindFBO( oldFBO );
GL_BindShader( NULL );
}

View File

@ -0,0 +1,658 @@
/*
gl_shadows.cpp - render shadowmaps for directional lights
Copyright (C) 2012 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "hud.h"
#include "cl_util.h"
#include "const.h"
#include "gl_local.h"
#include <mathlib.h>
#include <stringlib.h>
#include "gl_studio.h"
#include "gl_sprite.h"
#include "gl_world.h"
#include "gl_grass.h"
#include "pm_defs.h"
static Vector light_sides[] =
{
Vector( 0.0f, 0.0f, 90.0f ), // GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB
Vector( 0.0f, 180.0f, -90.0f ), // GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB
Vector( 0.0f, 90.0f, 0.0f ), // GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB
Vector( 0.0f, 270.0f, 180.0f ), // GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB
Vector(-90.0f, 180.0f, -90.0f ), // GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
Vector( 90.0f, 0.0f, 90.0f ), // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
};
/*
=============================================================
SHADOW RENDERING
=============================================================
*/
int R_AllocateShadowTexture( bool copyToImage = true )
{
int i = tr.num_2D_shadows_used;
if( i >= MAX_SHADOWS )
{
ALERT( at_error, "R_AllocateShadowTexture: shadow textures limit exceeded!\n" );
return 0; // disable
}
int texture = tr.shadowTextures[i];
tr.num_2D_shadows_used++;
if( !tr.shadowTextures[i] )
{
char txName[16];
Q_snprintf( txName, sizeof( txName ), "*shadow2D%i", i );
tr.shadowTextures[i] = CREATE_TEXTURE( txName, RI->view.port[2], RI->view.port[3], NULL, TF_SHADOW );
texture = tr.shadowTextures[i];
}
if( copyToImage )
{
GL_BindTexture( GL_TEXTURE0, texture );
pglCopyTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, RI->view.port[0], RI->view.port[1], RI->view.port[2], RI->view.port[3], 0 );
}
return texture;
}
int R_AllocateShadowCubemap( int side, bool copyToImage = true )
{
int texture = 0;
if( side != 0 )
{
int i = (tr.num_CM_shadows_used - 1);
if( i >= MAX_SHADOWS )
{
ALERT( at_error, "R_AllocateShadowCubemap: shadow cubemaps limit exceeded!\n" );
return 0; // disable
}
texture = tr.shadowCubemaps[i];
if( !tr.shadowCubemaps[i] )
{
ALERT( at_error, "R_AllocateShadowCubemap: cubemap not initialized!\n" );
return 0; // disable
}
}
else
{
int i = tr.num_CM_shadows_used;
if( i >= MAX_SHADOWS )
{
ALERT( at_error, "R_AllocateShadowCubemap: shadow cubemaps limit exceeded!\n" );
return 0; // disable
}
texture = tr.shadowCubemaps[i];
tr.num_CM_shadows_used++;
if( !tr.shadowCubemaps[i] )
{
char txName[16];
Q_snprintf( txName, sizeof( txName ), "*shadowCM%i", i );
tr.shadowCubemaps[i] = CREATE_TEXTURE( txName, RI->view.port[2], RI->view.port[3], NULL, TF_SHADOW_CUBEMAP );
texture = tr.shadowCubemaps[i];
}
}
if( copyToImage )
{
GL_BindTexture( GL_TEXTURE0, texture );
pglCopyTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, 0, GL_DEPTH_COMPONENT, RI->view.port[0], RI->view.port[1], RI->view.port[2], RI->view.port[3], 0 );
}
return texture;
}
static int R_ComputeCropBounds( const matrix4x4 &lightViewProjection, Vector bounds[2] )
{
Vector worldBounds[2];
int numCasters = 0;
ref_instance_t *prevRI = R_GetPrevInstance();
CFrustum frustum;
ClearBounds( bounds[0], bounds[1] );
frustum.InitProjectionFromMatrix( lightViewProjection );
// FIXME: nearplane culled studiomodels incorrectly. disabled for now
frustum.DisablePlane( FRUSTUM_NEAR );
frustum.DisablePlane( FRUSTUM_FAR );
for( int i = 0; i < prevRI->frame.solid_faces.Count(); i++ )
{
CSolidEntry *entry = &prevRI->frame.solid_faces[i];
if( entry->m_bDrawType != DRAWTYPE_SURFACE )
continue;
mextrasurf_t *es = entry->m_pSurf->info;
RI->currentmodel = es->parent->model;
RI->currententity = es->parent;
msurface_t *s = entry->m_pSurf;
bool worldpos = R_StaticEntity( RI->currententity );
if( !worldpos ) continue; // world polys only
if( es->grass && CVAR_TO_BOOL( r_grass ))
{
// already included surface minmax
worldBounds[0] = es->grass->mins;
worldBounds[1] = es->grass->maxs;
}
else
{
worldBounds[0] = es->mins;
worldBounds[1] = es->maxs;
}
if( frustum.CullBox( worldBounds[0], worldBounds[1] ))
continue;
for( int j = 0; j < 8; j++ )
{
Vector4D point;
point.x = worldBounds[(j >> 0) & 1].x;
point.y = worldBounds[(j >> 1) & 1].y;
point.z = worldBounds[(j >> 2) & 1].z;
point.w = 1.0f;
Vector4D transf = lightViewProjection.VectorTransform( point );
transf.x /= transf.w;
transf.y /= transf.w;
transf.z /= transf.w;
AddPointToBounds( transf, bounds[0], bounds[1] );
}
numCasters++;
}
// add studio models too
for( i = 0; i < prevRI->frame.solid_meshes.Count(); i++ )
{
if( !R_StudioGetBounds( &prevRI->frame.solid_meshes[i], worldBounds ))
continue;
if( frustum.CullBox( worldBounds[0], worldBounds[1] ))
continue;
for( int j = 0; j < 8; j++ )
{
Vector4D point;
point.x = worldBounds[(j >> 0) & 1].x;
point.y = worldBounds[(j >> 1) & 1].y;
point.z = worldBounds[(j >> 2) & 1].z;
point.w = 1.0f;
Vector4D transf = lightViewProjection.VectorTransform( point );
transf.x /= transf.w;
transf.y /= transf.w;
transf.z /= transf.w;
AddPointToBounds( transf, bounds[0], bounds[1] );
}
numCasters++;
}
return numCasters;
}
/*
===============
R_SetupLightDirectional
===============
*/
void R_SetupLightDirectional( CDynLight *pl, int split )
{
matrix4x4 projectionMatrix, cropMatrix, s1;
Vector splitFrustumCorners[8];
Vector splitFrustumBounds[2];
Vector splitFrustumClipBounds[2];
Vector casterBounds[2];
Vector cropBounds[2];
int i;
RI->view.splitFrustum[split].ComputeFrustumCorners( splitFrustumCorners );
ClearBounds( splitFrustumBounds[0], splitFrustumBounds[1] );
for( i = 0; i < 8; i++ )
AddPointToBounds( splitFrustumCorners[i], splitFrustumBounds[0], splitFrustumBounds[1] );
// find the bounding box of the current split in the light's view space
ClearBounds( cropBounds[0], cropBounds[1] );
for( i = 0; i < 8; i++ )
{
Vector4D point( splitFrustumCorners[i] );
Vector4D transf = pl->viewMatrix.VectorTransform( point );
transf.x /= transf.w;
transf.y /= transf.w;
transf.z /= transf.w;
AddPointToBounds( transf, cropBounds[0], cropBounds[1] );
}
projectionMatrix.CreateOrthoRH( cropBounds[0].x, cropBounds[1].x, cropBounds[0].y, cropBounds[1].y, -cropBounds[1].z, -cropBounds[0].z );
matrix4x4 viewProjectionMatrix = projectionMatrix.Concat( pl->viewMatrix );
int numCasters = R_ComputeCropBounds( viewProjectionMatrix, casterBounds );
// find the bounding box of the current split in the light's clip space
ClearBounds( splitFrustumClipBounds[0], splitFrustumClipBounds[1] );
for( i = 0; i < 8; i++ )
{
Vector4D point( splitFrustumCorners[i] );
Vector4D transf = viewProjectionMatrix.VectorTransform( point );
transf.x /= transf.w;
transf.y /= transf.w;
transf.z /= transf.w;
AddPointToBounds( transf, splitFrustumClipBounds[0], splitFrustumClipBounds[1] );
}
// scene-dependent bounding volume
cropBounds[0].x = Q_max( casterBounds[0].x, splitFrustumClipBounds[0].x );
cropBounds[0].y = Q_max( casterBounds[0].y, splitFrustumClipBounds[0].y );
cropBounds[0].z = Q_min( casterBounds[0].z, splitFrustumClipBounds[0].z );
cropBounds[1].x = Q_min( casterBounds[1].x, splitFrustumClipBounds[1].x );
cropBounds[1].y = Q_min( casterBounds[1].y, splitFrustumClipBounds[1].y );
cropBounds[1].z = Q_max( casterBounds[1].z, splitFrustumClipBounds[1].z );
if( numCasters == 0 )
{
cropBounds[0] = splitFrustumClipBounds[0];
cropBounds[1] = splitFrustumClipBounds[1];
}
cropMatrix.Crop( cropBounds[0], cropBounds[1] );
pl->projectionMatrix = cropMatrix.Concat( projectionMatrix );
s1.CreateTranslate( 0.5f, 0.5f, 0.5f );
s1.ConcatScale( 0.5f, 0.5f, 0.5f );
viewProjectionMatrix = pl->projectionMatrix.Concat( pl->modelviewMatrix );
// NOTE: texture matrix is not used. Save it for pssm show split debug tool
pl->textureMatrix[split] = pl->projectionMatrix;
// build shadow matrices for each split
pl->shadowMatrix[split] = s1.Concat( viewProjectionMatrix );
pl->shadowMatrix[split].CopyToArray( pl->gl_shadowMatrix[split] );
RI->view.frustum.InitProjectionFromMatrix( viewProjectionMatrix );
}
/*
===============
R_ShadowPassSetupViewCache
===============
*/
static void R_ShadowPassSetupViewCache( CDynLight *pl, int split = 0 )
{
memcpy( RI->glstate.viewport, RI->view.port, sizeof( RI->glstate.viewport ));
RI->view.farClip = pl->radius;
RI->view.origin = pl->origin;
// setup the screen FOV
RI->view.fov_x = pl->fov;
RI->view.fov_y = pl->fov;
// setup frustum
if( pl->type == LIGHT_DIRECTIONAL )
{
pl->splitFrustum[split] = RI->view.splitFrustum[split];
RI->view.matrix = pl->viewMatrix;
R_SetupLightDirectional( pl, split );
}
else if( pl->type == LIGHT_OMNI )
{
RI->view.angles = light_sides[split]; // this is cube side of course
RI->view.matrix = matrix4x4( RI->view.origin, RI->view.angles );
RI->view.frustum.InitProjection( RI->view.matrix, 0.1f, pl->radius, 90.0f, 90.0f );
}
else
{
RI->view.matrix = pl->viewMatrix;
RI->view.frustum = pl->frustum;
}
if( pl->type == LIGHT_OMNI )
{
RI->view.worldMatrix.CreateModelview();
RI->view.worldMatrix.ConcatRotate( -light_sides[split].z, 1, 0, 0 );
RI->view.worldMatrix.ConcatRotate( -light_sides[split].x, 0, 1, 0 );
RI->view.worldMatrix.ConcatRotate( -light_sides[split].y, 0, 0, 1 );
RI->view.worldMatrix.ConcatTranslate( -pl->origin.x, -pl->origin.y, -pl->origin.z );
RI->view.projectionMatrix = pl->projectionMatrix;
}
else
{
// matrices already computed
RI->view.worldMatrix = pl->modelviewMatrix;
RI->view.projectionMatrix = pl->projectionMatrix;
}
RI->view.worldProjectionMatrix = RI->view.projectionMatrix.Concat( RI->view.worldMatrix );
RI->view.worldProjectionMatrix.CopyToArray( RI->glstate.modelviewProjectionMatrix );
RI->view.projectionMatrix.CopyToArray( RI->glstate.projectionMatrix );
RI->view.worldMatrix.CopyToArray( RI->glstate.modelviewMatrix );
RI->currentlight = pl;
R_MarkWorldVisibleFaces( worldmodel );
msurface_t *surf;
mextrasurf_t *esrf;
int i, j;
// add all studio models, mark visible bmodels
for( i = 0; i < tr.num_draw_entities; i++ )
{
RI->currententity = tr.draw_entities[i];
RI->currentmodel = RI->currententity->model;
switch( RI->currentmodel->type )
{
case mod_studio:
R_AddStudioToDrawList( RI->currententity );
break;
case mod_brush:
R_MarkSubmodelVisibleFaces();
break;
}
}
// create drawlist for faces, do additional culling for world faces
for( i = 0; i < world->numsortedfaces; i++ )
{
ASSERT( world->sortedfaces != NULL );
j = world->sortedfaces[i];
ASSERT( j >= 0 && j < worldmodel->numsurfaces );
if( CHECKVISBIT( RI->view.visfaces, j ))
{
surf = worldmodel->surfaces + j;
esrf = surf->info;
// submodel faces already passed through this
// operation but world is not
if( FBitSet( surf->flags, SURF_OF_SUBMODEL ))
{
RI->currententity = esrf->parent;
RI->currentmodel = RI->currententity->model;
R_AddGrassToDrawList( surf, DRAWLIST_SHADOW );
}
else
{
RI->currententity = GET_ENTITY( 0 );
RI->currentmodel = RI->currententity->model;
esrf->parent = RI->currententity; // setup dynamic upcast
R_AddGrassToDrawList( surf, DRAWLIST_SHADOW );
if( R_CullSurface( surf, GetVieworg(), &RI->view.frustum ))
{
CLEARVISBIT( RI->view.visfaces, j ); // not visible
continue;
}
}
// only opaque faces interesting us
if( R_OpaqueEntity( RI->currententity ))
{
R_AddSurfaceToDrawList( surf, DRAWLIST_SHADOW );
}
}
}
}
/*
=============
R_ShadowPassSetupGL
=============
*/
static void R_ShadowPassSetupGL( const CDynLight *pl )
{
R_SetupGLstate();
pglEnable( GL_POLYGON_OFFSET_FILL );
if( RI->currentlight->type == LIGHT_DIRECTIONAL )
{
if( r_shadows->value > 2.0f )
pglPolygonOffset( 3.0f, 0.0f );
else pglPolygonOffset( 2.0f, 0.0f );
GL_Cull( GL_NONE );
}
else
{
if( r_shadows->value > 2.0f )
pglPolygonOffset( 2.0f, 0.0f );
else pglPolygonOffset( 1.0f, 0.0f );
GL_Cull( GL_FRONT );
}
// HACKHACK to ignore paranoia opengl32.dll
GL_DepthRange( 0.0001f, 1.0f );
pglEnable( GL_DEPTH_TEST );
GL_AlphaTest( GL_FALSE );
GL_DepthMask( GL_TRUE );
GL_Blend( GL_FALSE );
}
/*
=============
R_ShadowPassEndGL
=============
*/
static void R_ShadowPassEndGL( void )
{
pglDisable( GL_POLYGON_OFFSET_FILL );
GL_DepthRange( gldepthmin, gldepthmax );
pglPolygonOffset( -1, -2 );
r_stats.c_shadow_passes++;
GL_Cull( GL_FRONT );
}
/*
================
R_RenderShadowScene
fast version of R_RenderScene: no colors, no texcords etc
================
*/
void R_RenderShadowScene( CDynLight *pl, int split = 0 )
{
RI->params = RP_SHADOWVIEW;
bool using_fbo = false;
if( pl->type == LIGHT_DIRECTIONAL )
{
if( tr.sunShadowFBO[split].Active( ))
{
RI->view.port[2] = RI->view.port[3] = sunSize[split];
pl->shadowTexture[split] = tr.sunShadowFBO[split].GetTexture();
tr.sunShadowFBO[split].Bind();
using_fbo = true;
}
else RI->view.port[2] = RI->view.port[3] = 512; // simple size if FBO was missed
}
else
{
if( tr.fbo_shadow2D.Active( ))
{
RI->view.port[2] = tr.fbo_shadow2D.GetWidth();
RI->view.port[3] = tr.fbo_shadow2D.GetHeight();
pl->shadowTexture[0] = R_AllocateShadowTexture( false );
tr.fbo_shadow2D.Bind( pl->shadowTexture[0] );
using_fbo = true;
}
else RI->view.port[2] = RI->view.port[3] = 512;
}
R_ShadowPassSetupViewCache( pl, split );
R_ShadowPassSetupGL( pl );
pglClear( GL_DEPTH_BUFFER_BIT );
R_RenderShadowBrushList();
R_RenderShadowStudioList();
R_DrawParticles( false );
R_ShadowPassEndGL();
if( !using_fbo )
pl->shadowTexture[split] = R_AllocateShadowTexture();
}
/*
================
R_RenderShadowCubeSide
fast version of R_RenderScene: no colors, no texcords etc
================
*/
void R_RenderShadowCubeSide( CDynLight *pl, int side )
{
RI->params = RP_SHADOWVIEW;
bool using_fbo = false;
if( tr.fbo_shadowCM.Active( ))
{
RI->view.port[2] = tr.fbo_shadowCM.GetWidth();
RI->view.port[3] = tr.fbo_shadowCM.GetHeight();
pl->shadowTexture[0] = R_AllocateShadowCubemap( side, false );
tr.fbo_shadowCM.Bind( pl->shadowTexture[0], side );
using_fbo = true;
}
else
{
// same size if FBO was missed
RI->view.port[2] = RI->view.port[3] = 512;
using_fbo = false;
}
R_ShadowPassSetupViewCache( pl, side );
R_ShadowPassSetupGL( pl );
pglClear( GL_DEPTH_BUFFER_BIT );
R_RenderShadowBrushList();
R_RenderShadowStudioList();
R_DrawParticles( false );
R_ShadowPassEndGL();
if( !using_fbo )
pl->shadowTexture[0] = R_AllocateShadowCubemap( side );
}
void R_RenderShadowmaps( void )
{
unsigned int oldFBO;
if( R_FullBright() || !CVAR_TO_BOOL( r_shadows ) || tr.fGamePaused )
return;
if( FBitSet( RI->params, ( RP_NOSHADOWS|RP_ENVVIEW|RP_SKYVIEW )))
return;
// check for dynamic lights
if( !HasDynamicLights( )) return;
R_PushRefState(); // make refinst backup
oldFBO = glState.frameBuffer;
for( int i = 0; i < MAX_DLIGHTS; i++ )
{
CDynLight *pl = &tr.dlights[i];
if( !pl->Active() || FBitSet( pl->flags, DLF_NOSHADOWS ))
continue;
if( pl->type == LIGHT_OMNI )
{
// need GL_EXT_gpu_shader4 for cubemap shadows
if( !GL_Support( R_TEXTURECUBEMAP_EXT ) || !GL_Support( R_EXT_GPU_SHADER4 ))
continue;
if( !Mod_CheckBoxVisible( pl->absmin, pl->absmax ))
continue;
if( R_CullBox( pl->absmin, pl->absmax ))
continue;
for( int j = 0; j < 6; j++ )
{
R_RenderShadowCubeSide( pl, j );
R_ResetRefState(); // restore ref instance
}
}
else if( pl->type == LIGHT_SPOT )
{
if( !Mod_CheckBoxVisible( pl->absmin, pl->absmax ))
continue;
if( R_CullBox( pl->absmin, pl->absmax ))
continue;
R_RenderShadowScene( pl );
R_ResetRefState(); // restore ref instance
}
else if( pl->type == LIGHT_DIRECTIONAL )
{
if( !CVAR_TO_BOOL( r_sunshadows ) || tr.sky_normal.z >= 0.0f )
continue; // shadows are invisible
for( int j = 0; j <= NUM_SHADOW_SPLITS; j++ )
{
// PSSM: draw all the splits
R_RenderShadowScene( pl, j );
R_ResetRefState(); // restore ref instance
}
}
}
R_PopRefState(); // restore ref instance
// restore FBO state
GL_BindFBO( oldFBO );
GL_BindShader( NULL );
RI->currentlight = NULL;
}

1272
cl_dll/render/gl_shadows.new Normal file

File diff suppressed because it is too large Load Diff

373
cl_dll/render/gl_sky.cpp Normal file
View File

@ -0,0 +1,373 @@
//
// written by BUzer for HL: Paranoia modification
//
// 2006
#include "hud.h"
#include "cl_util.h"
#include "gl_local.h"
#include "gl_shader.h"
#define MAX_CLIP_VERTS 128 // skybox clip vertices
static const int r_skyTexOrder[6] = { 0, 2, 1, 3, 4, 5 };
static const Vector skyclip[6] =
{
Vector( 1, 1, 0 ),
Vector( 1, -1, 0 ),
Vector( 0, -1, 1 ),
Vector( 0, 1, 1 ),
Vector( 1, 0, 1 ),
Vector( -1, 0, 1 )
};
// 1 = s, 2 = t, 3 = 2048
static const 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
};
// s = [0]/[2], t = [1]/[2]
static const int vec_to_st[6][3] =
{
{ -2, 3, 1 },
{ 2, 3, -1 },
{ 1, 3, 2 },
{ -1, 3, -2 },
{ -2, -1, 3 },
{ -2, 1, -3 }
};
static void DrawSkyPolygon( int nump, Vector vecs[] )
{
int i, j, axis;
float s, t, dv;
Vector v, av;
// decide which face it maps to
v = g_vecZero;
for( i = 0; i < nump; i++ )
v += vecs[i];
av[0] = fabs( v[0] );
av[1] = fabs( v[1] );
av[2] = fabs( v[2] );
if( av[0] > av[1] && av[0] > av[2] )
axis = (v[0] < 0) ? 1 : 0;
else if( av[1] > av[2] && av[1] > av[0] )
axis = (v[1] < 0) ? 3 : 2;
else axis = (v[2] < 0) ? 5 : 4;
// project new texture coords
for( i = 0; i < nump; i++ )
{
j = vec_to_st[axis][2];
dv = (j > 0) ? (vecs[i])[j-1] : -(vecs[i])[-j-1];
j = vec_to_st[axis][0];
s = (j < 0) ? -vecs[i][-j-1] / dv : (vecs[i])[j-1] / dv;
j = vec_to_st[axis][1];
t = (j < 0) ? -(vecs[i])[-j-1] / dv : (vecs[i])[j-1] / dv;
if( s < RI->view.skyMins[0][axis] ) RI->view.skyMins[0][axis] = s;
if( t < RI->view.skyMins[1][axis] ) RI->view.skyMins[1][axis] = t;
if( s > RI->view.skyMaxs[0][axis] ) RI->view.skyMaxs[0][axis] = s;
if( t > RI->view.skyMaxs[1][axis] ) RI->view.skyMaxs[1][axis] = t;
}
}
/*
==============
ClipSkyPolygon
==============
*/
static void ClipSkyPolygon( int nump, Vector vecs[], int stage )
{
bool front, back;
float dists[MAX_CLIP_VERTS + 1];
int sides[MAX_CLIP_VERTS + 1];
Vector newv[2][MAX_CLIP_VERTS + 1];
int newc[2];
float d, e;
int i;
if( nump > MAX_CLIP_VERTS )
HOST_ERROR( "ClipSkyPolygon: MAX_CLIP_VERTS\n" );
loc1:
if( stage == 6 )
{
// fully clipped, so draw it
DrawSkyPolygon( nump, vecs );
return;
}
front = back = false;
const Vector &norm = skyclip[stage];
for( i = 0; i < nump; i++ )
{
d = DotProduct( vecs[i], norm );
if( d > ON_EPSILON )
{
front = true;
sides[i] = SIDE_FRONT;
}
else if( d < -ON_EPSILON )
{
back = true;
sides[i] = SIDE_BACK;
}
else
{
sides[i] = SIDE_ON;
}
dists[i] = d;
}
if( !front || !back )
{
// not clipped
stage++;
goto loc1;
}
// clip it
sides[i] = sides[0];
dists[i] = dists[0];
vecs[i] = vecs[0];
newc[0] = newc[1] = 0;
for( i = 0; i < nump; i++ )
{
switch( sides[i] )
{
case SIDE_FRONT:
newv[0][newc[0]] = vecs[i];
newc[0]++;
break;
case SIDE_BACK:
newv[1][newc[1]] = vecs[i];
newc[1]++;
break;
case SIDE_ON:
newv[0][newc[0]] = vecs[i];
newc[0]++;
newv[1][newc[1]] = vecs[i];
newc[1]++;
break;
}
if( sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i] )
continue;
d = dists[i] / ( dists[i] - dists[i+1] );
for( int j = 0; j < 3; j++ )
{
e = (vecs[i])[j] + d * ( (vecs[i+1])[j] - (vecs[i])[j] );
newv[0][newc[0]][j] = e;
newv[1][newc[1]][j] = e;
}
newc[0]++;
newc[1]++;
}
// continue
ClipSkyPolygon( newc[0], newv[0], stage + 1 );
ClipSkyPolygon( newc[1], newv[1], stage + 1 );
}
static void MakeSkyVec( float s, float t, int axis )
{
int j, k, farclip;
Vector v, b;
farclip = RI->view.farClip;
b[0] = s * (farclip >> 1);
b[1] = t * (farclip >> 1);
b[2] = (farclip >> 1);
for( j = 0; j < 3; j++ )
{
k = st_to_vec[axis][j];
v[j] = (k < 0) ? -b[-k-1] : b[k-1];
v[j] += GetVieworg()[j];
}
// avoid bilerp seam
s = (s + 1.0f) * 0.5f;
t = (t + 1.0f) * 0.5f;
if( s < ( 1.0f / 512.0f ))
s = (1.0f / 512.0f);
else if( s > ( 511.0f / 512.0f ))
s = (511.0f / 512.0f);
if( t < ( 1.0f / 512.0f ))
t = (1.0f / 512.0f);
else if( t > ( 511.0f / 512.0f ))
t = (511.0f / 512.0f);
t = 1.0f - t;
pglTexCoord2f( s, t );
pglVertex3fv( v );
}
/*
=================
R_AddSkyBoxSurface
=================
*/
void R_AddSkyBoxSurface( msurface_t *fa )
{
Vector verts[MAX_CLIP_VERTS];
// calculate vertex values for sky box
for( glpoly_t *p = fa->polys; p; p = p->next )
{
if( p->numverts >= MAX_CLIP_VERTS )
HOST_ERROR( "R_AddSkyBoxSurface: numverts >= MAX_CLIP_VERTS\n" );
for( int i = 0; i < p->numverts; i++ )
{
verts[i][0] = p->verts[i][0] - GetVieworg().x;
verts[i][1] = p->verts[i][1] - GetVieworg().y;
verts[i][2] = p->verts[i][2] - GetVieworg().z;
}
ClipSkyPolygon( p->numverts, verts, 0 );
}
}
static void GL_DrawSkySide( int skyside )
{
pglBegin( GL_QUADS );
MakeSkyVec( RI->view.skyMins[0][skyside], RI->view.skyMins[1][skyside], skyside );
MakeSkyVec( RI->view.skyMins[0][skyside], RI->view.skyMaxs[1][skyside], skyside );
MakeSkyVec( RI->view.skyMaxs[0][skyside], RI->view.skyMaxs[1][skyside], skyside );
MakeSkyVec( RI->view.skyMaxs[0][skyside], RI->view.skyMins[1][skyside], skyside );
pglEnd();
}
static void GL_DrawSkySide( word hProgram, int skyside )
{
if( hProgram <= 0 )
{
GL_BindShader( NULL );
GL_BindTexture( GL_TEXTURE0, tr.skyboxTextures[r_skyTexOrder[skyside]] );
GL_DrawSkySide( skyside );
return; // old method
}
if( RI->currentshader != &glsl_programs[hProgram] )
{
// force to bind new shader
GL_BindShader( &glsl_programs[hProgram] );
}
Vector sky_color = (tr.sun_light_enabled) ? tr.sun_diffuse : tr.sky_ambient * (1.0f/128.0f) * tr.diffuseFactor;
Vector sky_vec = tr.sky_normal.Normalize();
glsl_program_t *shader = RI->currentshader;
ColorNormalize( sky_color, sky_color );
// setup specified uniforms (and texture bindings)
for( int i = 0; i < shader->numUniforms; i++ )
{
uniform_t *u = &shader->uniforms[i];
switch( u->type )
{
case UT_COLORMAP:
u->SetValue( tr.skyboxTextures[r_skyTexOrder[skyside]] );
break;
case UT_LIGHTDIR:
u->SetValue( sky_vec.x, sky_vec.y, sky_vec.z );
break;
case UT_LIGHTDIFFUSE:
u->SetValue( sky_color.x, sky_color.y, sky_color.z );
break;
case UT_VIEWORIGIN:
u->SetValue( GetVieworg().x, GetVieworg().y, GetVieworg().z );
break;
case UT_FOGPARAMS:
u->SetValue( tr.fogColor[0], tr.fogColor[1], tr.fogColor[2], tr.fogDensity * 0.5f );
break;
case UT_ZFAR:
u->SetValue( RI->view.farClip );
break;
default:
ALERT( at_error, "%s: unhandled uniform %s\n", RI->currentshader->name, u->name );
break;
}
}
GL_DrawSkySide( skyside );
}
/*
==============
R_DrawSkybox
==============
*/
void R_DrawSkyBox( void )
{
bool drawSun = true;
float fogDenstity = tr.fogDensity;
word hSkyShader = 0;
int i;
if( !FBitSet( RI->view.flags, RF_SKYVISIBLE ))
return;
GL_DepthRange( 0.9f, 1.0f );
GL_DepthMask( GL_FALSE );
GL_Blend( GL_FALSE );
GL_AlphaTest( GL_FALSE );
// clipplane cut the sky if drawing through mirror. Disable it
GL_ClipPlane( false );
int type = tr.sun_light_enabled ? 1 : 0;
if( FBitSet( RI->params, RP_SKYVIEW ) || ( FBitSet( RI->params, RP_WATERPASS ) && CVAR_TO_BOOL( cv_specular )))
drawSun = false;
// disable sky fogging while underwater
if( tr.waterlevel >= 3 || FBitSet( RI->params, RP_SKYVIEW ))
fogDenstity = 0.0f;
// make sure what light_environment is present
if( tr.sky_normal != g_vecZero && drawSun )
{
if( FBitSet( RI->params, RP_DEFERREDSCENE ))
hSkyShader = tr.defSceneSky;
else if( FBitSet( RI->params, RP_DEFERREDLIGHT ))
hSkyShader = tr.defLightSky;
else hSkyShader = tr.skyboxEnv[type];
}
for( i = 0; i < 6; i++ )
{
if( RI->view.skyMins[0][i] >= RI->view.skyMaxs[0][i] || RI->view.skyMins[1][i] >= RI->view.skyMaxs[1][i] )
continue;
GL_DrawSkySide( hSkyShader, i );
}
GL_ClipPlane( true );
GL_DepthMask( GL_TRUE );
// back to normal depth range
GL_DepthRange( gldepthmin, gldepthmax );
}

733
cl_dll/render/gl_slight.cpp Normal file
View File

@ -0,0 +1,733 @@
/*
gl_slight.cpp - static lighting
Copyright (C) 2019 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "hud.h"
#include <stringlib.h>
#include "cl_util.h"
#include "pm_defs.h"
#include "event_api.h"
#include "gl_local.h"
#include "gl_studio.h"
#include "gl_world.h"
#define NUMVERTEXNORMALS 162
#define AMBIENT_CUBE_SCALE 1.0f
// lightpoint flags
#define LIGHTINFO_HITSKY (1<<0)
#define LIGHTINFO_AVERAGE (1<<1) // compute average color from lightmap
#define LIGHTINFO_STYLES (1<<2)
typedef struct
{
vec3_t diffuse;
vec3_t average;
colorVec lightmap;
vec3_t normal;
msurface_t *surf; // may be NULL
float fraction; // hit fraction
vec3_t origin;
int status;
} lightpoint_t;
static vec_t g_anorms[NUMVERTEXNORMALS][3] =
{
#include "anorms.h"
};
static Vector g_BoxDirections[6] =
{
Vector( 1.0f, 0.0f, 0.0f ),
Vector(-1.0f, 0.0f, 0.0f ),
Vector( 0.0f, 1.0f, 0.0f ),
Vector( 0.0f, -1.0f, 0.0f ),
Vector( 0.0f, 0.0f, 1.0f ),
Vector( 0.0f, 0.0f, -1.0f ),
};
/*
=======================================================================
AMBIENT & DIFFUSE LIGHTING
=======================================================================
*/
/*
=================
R_FindAmbientSkyLight
=================
*/
static mworldlight_t *R_FindAmbientSkyLight( void )
{
// find any ambient lights
for( int i = 0; i < world->numworldlights; i++ )
{
if( world->worldlights[i].emittype == emit_skylight )
return &world->worldlights[i];
}
return NULL;
}
/*
=================
R_LightTraceFilter
=================
*/
static int R_LightTraceFilter( physent_t *pe )
{
if( !pe || !pe->model )
return 1;
return 0;
}
/*
=================
R_GetDirectLightFromSurface
=================
*/
static bool R_GetDirectLightFromSurface( msurface_t *surf, const Vector &point, lightpoint_t *info )
{
mextrasurf_t *es = surf->info;
float ds, dt, s, t;
color24 *lm, *dm;
mtexinfo_t *tex;
int map, size;
tex = surf->texinfo;
if( FBitSet( surf->flags, SURF_DRAWSKY ))
{
info->status |= LIGHTINFO_HITSKY;
return false; // no lightmaps
}
if( FBitSet( surf->flags, SURF_DRAWTILED ))
return false; // no lightmaps
s = DotProduct( point, es->lmvecs[0] ) + es->lmvecs[0][3];
t = DotProduct( point, es->lmvecs[1] ) + es->lmvecs[1][3];
if( s < es->lightmapmins[0] || t < es->lightmapmins[1] )
return false;
ds = s - es->lightmapmins[0];
dt = t - es->lightmapmins[1];
if( ds > es->lightextents[0] || dt > es->lightextents[1] )
return false;
if( !surf->samples )
return true;
int sample_size = Mod_SampleSizeForFace( surf );
int smax = (es->lightextents[0] / sample_size) + 1;
int tmax = (es->lightextents[1] / sample_size) + 1;
ds /= sample_size;
dt /= sample_size;
lm = surf->samples + Q_rint( dt ) * smax + Q_rint( ds );
colorVec localDiffuse = { 0, 0, 0, 0 };
size = smax * tmax;
if( es->normals )
{
Vector vec_x, vec_y, vec_z;
matrix3x3 mat;
dm = es->normals + Q_rint( dt ) * smax + Q_rint( ds );
// flat TBN for better results
vec_x = Vector( surf->info->lmvecs[0] );
vec_y = Vector( surf->info->lmvecs[1] );
if( FBitSet( surf->flags, SURF_PLANEBACK ))
vec_z = -surf->plane->normal;
else vec_z = surf->plane->normal;
// create tangent space rotational matrix
mat.SetForward( vec_x.Normalize( ));
mat.SetRight( -vec_y.Normalize( ));
mat.SetUp( vec_z.Normalize( ));
for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ )
{
float f = (1.0f / 128.0f);
Vector normal = Vector(((float)dm->r - 128.0f) * f, ((float)dm->g - 128.0f) * f, ((float)dm->b - 128.0f) * f);
uint scale = tr.lightstyle[surf->styles[map]]; // style modifier
mworldlight_t *pSkyLight = NULL;
Vector localDir = g_vecZero;
Vector sky_color = g_vecZero;
// rotate from tangent to model space
localDir = mat.VectorRotate( normal );
// add local dir into main
info->normal += localDir * (float)scale; // direction factor
// compute diffuse color
localDiffuse.r += TEXTURE_TO_TEXGAMMA( lm->r ) * scale;
localDiffuse.g += TEXTURE_TO_TEXGAMMA( lm->g ) * scale;
localDiffuse.b += TEXTURE_TO_TEXGAMMA( lm->b ) * scale;
lm += size; // skip to next lightmap
dm += size; // skip to next deluxemap
}
info->lightmap.r = Q_min(( localDiffuse.r >> 7 ), 255 );
info->lightmap.g = Q_min(( localDiffuse.g >> 7 ), 255 );
info->lightmap.b = Q_min(( localDiffuse.b >> 7 ), 255 );
info->diffuse.x = (float)info->lightmap.r * (1.0f / 255.0f);
info->diffuse.y = (float)info->lightmap.g * (1.0f / 255.0f);
info->diffuse.z = (float)info->lightmap.b * (1.0f / 255.0f);
if( info->normal == g_vecZero ) info->normal = vec_z; // fixup some cases
info->normal = info->normal.Normalize();
}
else
{
for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ )
{
uint scale = tr.lightstyle[surf->styles[map]];
// compute diffuse color
localDiffuse.r += TEXTURE_TO_TEXGAMMA( lm->r ) * scale;
localDiffuse.g += TEXTURE_TO_TEXGAMMA( lm->g ) * scale;
localDiffuse.b += TEXTURE_TO_TEXGAMMA( lm->b ) * scale;
lm += size; // skip to next lightmap
}
info->lightmap.r = Q_min(( localDiffuse.r >> 7 ), 255 );
info->lightmap.g = Q_min(( localDiffuse.g >> 7 ), 255 );
info->lightmap.b = Q_min(( localDiffuse.b >> 7 ), 255 );
info->diffuse.x = (float)info->lightmap.r * (1.0f / 255.0f);
info->diffuse.y = (float)info->lightmap.g * (1.0f / 255.0f);
info->diffuse.z = (float)info->lightmap.b * (1.0f / 255.0f);
}
if(( surf->styles[0] != 0 && surf->styles[0] != LS_SKY ) || surf->styles[1] != 255 )
SetBits( info->status, LIGHTINFO_STYLES );
// also collect the average value
if( FBitSet( info->status, LIGHTINFO_AVERAGE ))
{
Vector localAverage = g_vecZero;
lm = surf->samples;
for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ )
{
float scale = tr.lightstyle[surf->styles[map]];
for( int i = 0; i < size; i++, lm++ )
{
localAverage.x += (float)TEXTURE_TO_TEXGAMMA( lm->r ) * scale;
localAverage.y += (float)TEXTURE_TO_TEXGAMMA( lm->g ) * scale;
localAverage.z += (float)TEXTURE_TO_TEXGAMMA( lm->b ) * scale;
}
localAverage *= (1.0f / (float)size );
}
info->average.x = Q_min( localAverage.x * (1.0f / 128.0f), 255.0f ) * (1.0f / 255.0f);
info->average.y = Q_min( localAverage.y * (1.0f / 128.0f), 255.0f ) * (1.0f / 255.0f);
info->average.z = Q_min( localAverage.z * (1.0f / 128.0f), 255.0f ) * (1.0f / 255.0f);
}
info->surf = surf;
return true;
}
/*
=================
R_RecursiveLightPoint
=================
*/
static bool R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f, float p2f, const Vector &start, const Vector &end, lightpoint_t *info )
{
float front, back;
float frac, midf;
int side;
msurface_t *surf;
Vector mid;
// didn't hit anything
if( !node || node->contents < 0 )
return false;
// calculate mid point
front = PlaneDiff( start, node->plane );
back = PlaneDiff( end, node->plane );
side = front < 0.0f;
if(( back < 0.0f ) == side )
return R_RecursiveLightPoint( model, node->children[side], p1f, p2f, start, end, info );
frac = front / ( front - back );
midf = p1f + ( p2f - p1f ) * frac;
VectorLerp( start, frac, end, mid );
// co down front side
if( R_RecursiveLightPoint( model, node->children[side], p1f, midf, start, mid, info ))
return true; // hit something
if(( back < 0.0f ) == side )
return false;// didn't hit anything
// check for impact on this node
surf = model->surfaces + node->firstsurface;
for( int i = 0; i < node->numsurfaces; i++, surf++ )
{
if( R_GetDirectLightFromSurface( surf, mid, info ))
{
info->fraction = midf;
return true;
}
}
// go down back side
return R_RecursiveLightPoint( model, node->children[!side], midf, p2f, mid, end, info );
}
/*
=================
R_LightPoint
=================
*/
static bool R_LightPoint( model_t *model, mnode_t *node, const Vector &start, const Vector &end, mstudiolight_t *light, bool ambient, float *fraction )
{
float factor = (ambient) ? 0.6f : 0.9f;
lightpoint_t info;
memset( &info, 0, sizeof( lightpoint_t ));
info.fraction = *fraction = 1.0f;
info.origin = start;
if( R_RecursiveLightPoint( model, node, 0.0f, 1.0f, start, end, &info ))
{
float total = Q_max( Q_max( info.lightmap.r, info.lightmap.g ), info.lightmap.b );
if( total == 0.0f ) total = 1.0f;
info.normal *= (total * factor);
light->shadelight = info.normal.Length();
light->ambientlight = total - light->shadelight;
if( total > 0.0f )
{
light->diffuse.x = (float)info.lightmap.r * ( 1.0f / total );
light->diffuse.y = (float)info.lightmap.g * ( 1.0f / total );
light->diffuse.z = (float)info.lightmap.b * ( 1.0f / total );
}
else light->diffuse = Vector( 1.0f, 1.0f, 1.0f );
if( light->ambientlight > 128 )
light->ambientlight = 128;
if( light->ambientlight + light->shadelight > 255 )
light->shadelight = 255 - light->ambientlight;
light->normal = info.normal.Normalize();
*fraction = info.fraction;
light->nointerp = FBitSet( info.status, LIGHTINFO_STYLES ) ? true : false;
return true;
}
return false;
}
/*
=================
ComputeLightmapColorFromPoint
=================
*/
static void ComputeLightmapColorFromPoint( lightpoint_t *info, mworldlight_t* pSkylight, float scale, Vector &radcolor, bool average )
{
if( !info->surf && FBitSet( info->status, LIGHTINFO_HITSKY ))
{
if( pSkylight )
{
radcolor += pSkylight->intensity * scale * 0.5f * (1.0f / 255.0f);
}
else if( world->numworldlights <= 0 ) // old bsp format?
{
Vector skyAmbient = tr.sky_ambient * (1.0f / 128.0f) * tr.diffuseFactor;
radcolor += skyAmbient * scale * 0.5f * (1.0f / 255.0f);
}
return;
}
if( info->surf != NULL )
{
Vector reflectivity;
byte rgba[4];
Vector color;
GET_EXTRA_PARAMS( info->surf->texinfo->texture->gl_texturenum, &rgba[0], &rgba[1], &rgba[2], &rgba[3] );
reflectivity.x = TextureToLinear( rgba[0] );
reflectivity.y = TextureToLinear( rgba[1] );
reflectivity.z = TextureToLinear( rgba[2] );
if( average ) color = info->average * scale;
else color = info->diffuse * scale;
#if 0
if( reflectivity != g_vecZero )
color *= reflectivity;
#endif
radcolor += color;
}
}
//-----------------------------------------------------------------------------
// Computes ambient lighting along a specified ray.
// Ray represents a cone, tanTheta is the tan of the inner cone angle
//-----------------------------------------------------------------------------
static void R_CalcRayAmbientLighting( const Vector &vStart, const Vector &vEnd, mworldlight_t *pSkyLight, float tanTheta, Vector &color )
{
cl_entity_t *ent = NULL;
model_t *model = worldmodel;
lightpoint_t info;
pmtrace_t tr0;
memset( &info, 0, sizeof( lightpoint_t ));
SetBits( info.status, LIGHTINFO_AVERAGE );
info.fraction = 1.0f;
info.origin = vStart;
color = g_vecZero;
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTraceExt( (float *)&vStart, (float *)&vEnd, PM_WORLD_ONLY, R_LightTraceFilter, &tr0 );
if( tr0.allsolid || tr0.startsolid || tr0.fraction == 1.0f )
return; // doesn't hit anything
if( gEngfuncs.pEventAPI->EV_IndexFromTrace( &tr0 ) != -1 )
ent = GET_ENTITY( gEngfuncs.pEventAPI->EV_IndexFromTrace( &tr0 ));
if( ent ) model = ent->model;
// Now that we've got a ray, see what surface we've hit
R_RecursiveLightPoint( model, &model->nodes[model->hulls[0].firstclipnode], 0.0f, 1.0f, vStart, vEnd, &info );
Vector delta = vEnd - vStart;
// compute the approximate radius of a circle centered around the intersection point
float dist = delta.Length() * tanTheta * info.fraction;
// until 20" we use the point sample, then blend in the average until we're covering 40"
// This is attempting to model the ray as a cone - in the ideal case we'd simply sample all
// luxels in the intersection of the cone with the surface. Since we don't have surface
// neighbor information computed we'll just approximate that sampling with a blend between
// a point sample and the face average.
// This yields results that are similar in that aliasing is reduced at distance while
// point samples provide accuracy for intersections with near geometry
float scaleAvg = RemapValClamped( dist, 20, 40, 0.0f, 1.0f );
// don't have luxel UV, so just use average sample
if( !info.surf ) scaleAvg = 1.0f;
float scaleSample = 1.0f - scaleAvg;
if( scaleAvg != 0.0f )
{
ComputeLightmapColorFromPoint( &info, pSkyLight, scaleAvg, color, true );
}
if( scaleSample != 0.0f )
{
ComputeLightmapColorFromPoint( &info, pSkyLight, scaleSample, color, false );
}
}
/*
=================
R_PointAmbientFromAxisAlignedSamples
fast ambient comptation
=================
*/
static bool R_PointAmbientFromAxisAlignedSamples( const Vector &p1, mstudiolight_t *light )
{
// use lightprobes instead
if( world->numleaflights && world->leafs )
return false;
mworldlight_t *pSkyLight = R_FindAmbientSkyLight();
Vector radcolor[NUMVERTEXNORMALS];
Vector lightBoxColor[6], p2;
lightpoint_t info;
// sample world only along cardinal axes
for( int i = 0; i < 6; i++ )
{
memset( &info, 0, sizeof( lightpoint_t ));
SetBits( info.status, LIGHTINFO_AVERAGE );
info.fraction = 1.0f;
info.origin = p1;
VectorMA( p1, 65536.0f * 1.74f, g_BoxDirections[i], p2 );
// now that we've got a ray, see what surface we've hit
if( !R_RecursiveLightPoint( worldmodel, worldmodel->nodes, 0.0f, 1.0f, p1, p2, &info ))
continue;
ComputeLightmapColorFromPoint( &info, pSkyLight, 1.0f, light->ambient[i], true );
light->ambient[i] *= AMBIENT_CUBE_SCALE;
}
return true;
}
/*
=================
R_PointAmbientFromSphericalSamples
reconstruct the ambient lighting for a leaf
at the given position in worldspace
=================
*/
static bool R_PointAmbientFromSphericalSamples( const Vector &p1, mstudiolight_t *light )
{
// use lightprobes instead
if( world->numleaflights && world->leafs )
return false;
// Figure out the color that rays hit when shot out from this position.
float tanTheta = tan( VERTEXNORMAL_CONE_INNER_ANGLE );
mworldlight_t *pSkylight = R_FindAmbientSkyLight();
Vector radcolor[NUMVERTEXNORMALS];
Vector lightBoxColor[6], p2;
// sample world by casting N rays distributed across a sphere
for( int i = 0; i < NUMVERTEXNORMALS; i++ )
{
// FIXME: a good optimization would be to scale this per leaf
VectorMA( p1, 65536.0f * 1.74f, g_anorms[i], p2 );
R_CalcRayAmbientLighting( p1, p2, pSkylight, tanTheta, radcolor[i] );
}
// accumulate samples into radiant box
for( int j = 0; j < 6; j++ )
{
float t = 0.0f;
VectorClear( light->ambient[j] );
for( int i = 0; i < NUMVERTEXNORMALS; i++ )
{
float c = DotProduct( g_anorms[i], g_BoxDirections[j] );
if( c > 0.0f )
{
VectorMA( light->ambient[j], c, radcolor[i], light->ambient[j] );
t += c;
}
}
VectorScale( light->ambient[j], ( 1.0 / t ) * AMBIENT_CUBE_SCALE, light->ambient[j] );
}
return true;
}
/*
=================
R_PointAmbientFromLeaf
reconstruct the ambient lighting for a leaf
at the given position in worldspace
=================
*/
void R_PointAmbientFromLeaf( const Vector &point, mstudiolight_t *light )
{
memset( light->ambient, 0, sizeof( light->ambient ));
if( r_lighting_extended->value > 1.0f )
{
if( R_PointAmbientFromSphericalSamples( point, light ))
return;
}
else
{
if( R_PointAmbientFromAxisAlignedSamples( point, light ))
return;
}
mleaf_t *leaf = Mod_PointInLeaf( point, worldmodel->nodes );
mextraleaf_t *info = LEAF_INFO( leaf, worldmodel );
mlightprobe_t *pAmbientProbe = info->ambient_light;
float totalFactor = 0.0f;
int i;
if( info->num_lightprobes > 0 )
{
for( i = 0; i < info->num_lightprobes; i++, pAmbientProbe++ )
{
// do an inverse squared distance weighted average of the samples
// to reconstruct the original function
float dist = (pAmbientProbe->origin - point).LengthSqr();
float factor = 1.0f / (dist + 1.0f);
totalFactor += factor;
for( int j = 0; j < 6; j++ )
{
Vector v;
v.x = (float)pAmbientProbe->cube.color[j][0] * (1.0f / 255.0f);
v.y = (float)pAmbientProbe->cube.color[j][1] * (1.0f / 255.0f);
v.z = (float)pAmbientProbe->cube.color[j][2] * (1.0f / 255.0f);
light->ambient[j] += v * factor;
}
}
for( i = 0; i < 6; i++ )
{
light->ambient[i] *= (1.0f / totalFactor) * AMBIENT_CUBE_SCALE;
}
}
}
/*
=================
R_LightIdentity
=================
*/
static void R_LightIdentity( mstudiolight_t *light )
{
// get default values
light->diffuse.x = (float)TEXTURE_TO_TEXGAMMA( 255 ) / 255.0f;
light->diffuse.y = (float)TEXTURE_TO_TEXGAMMA( 255 ) / 255.0f;
light->diffuse.z = (float)TEXTURE_TO_TEXGAMMA( 255 ) / 255.0f;
light->normal = Vector( 0.0f, 0.0f, 0.0f );
}
/*
=================
R_LightMin
=================
*/
static void R_LightMin( mstudiolight_t *light )
{
// get minlight values
light->diffuse.x = (float)TEXTURE_TO_TEXGAMMA( 10 ) / 255.0f;
light->diffuse.y = (float)TEXTURE_TO_TEXGAMMA( 10 ) / 255.0f;
light->diffuse.z = (float)TEXTURE_TO_TEXGAMMA( 10 ) / 255.0f;
light->normal = Vector( 0.0f, 0.0f, 0.0f );
}
/*
=================
R_LightVec
check bspmodels to get light from
=================
*/
void R_LightVec( const Vector &point, mstudiolight_t *light, bool ambient )
{
memset( light, 0 , sizeof( *light ));
if( worldmodel && worldmodel->lightdata )
{
Vector p0 = point + Vector( 0.0f, 0.0f, 8.0f );
Vector p1 = point + Vector( 0.0f, 0.0f, -512.0f );
float last_fraction = 1.0f, fraction;
Vector start = point;
mstudiolight_t probe;
for( int i = 0; i < MAX_PHYSENTS; i++ )
{
physent_t *pe = gEngfuncs.pEventAPI->EV_GetPhysent( i );
Vector offset, start_l, end_l;
matrix3x4 matrix;
mnode_t *pnodes;
if( !pe || !pe->model || pe->model->type != mod_brush )
continue; // skip non-bsp models
pnodes = &pe->model->nodes[pe->model->hulls[0].firstclipnode];
// rotate start and end into the models frame of reference
if( pe->angles != g_vecZero )
{
matrix = matrix3x4( pe->origin, pe->angles );
start_l = matrix.VectorITransform( p0 );
end_l = matrix.VectorITransform( p1 );
}
else
{
start_l = p0 - pe->origin;
end_l = p1 - pe->origin;
}
memset( &probe, 0 , sizeof( probe ));
if( !R_LightPoint( pe->model, pnodes, start_l, end_l, &probe, ambient, &fraction ))
continue; // didn't hit anything
if( fraction < last_fraction )
{
last_fraction = fraction;
*light = probe;
if( light->diffuse != g_vecZero )
return; // we get light now
}
// get light from bmodels too
if( !CVAR_TO_BOOL( r_lighting_extended ))
return; // get light from world and out
}
R_LightMin( light );
}
else
{
R_LightIdentity( light );
}
}
/*
=================
R_LightForSky
=================
*/
void R_LightForSky( const Vector &point, mstudiolight_t *light )
{
if( tr.sun_light_enabled )
{
light->diffuse = tr.sun_diffuse;
}
else
{
light->diffuse = tr.sky_ambient * ( 1.0f / 128.0f ) * tr.diffuseFactor;
}
// FIXME: this is correct?
light->normal = -tr.sky_normal;
light->ambientlight = 128;
light->shadelight = 192;
}
/*
=================
R_LightForStudio
given light for a studiomodel
=================
*/
void R_LightForStudio( const Vector &point, mstudiolight_t *light, bool ambient )
{
R_LightVec( point, light, ambient );
R_PointAmbientFromLeaf( point, light );
}

595
cl_dll/render/gl_sprite.cpp Normal file
View File

@ -0,0 +1,595 @@
/*
gl_sprite.cpp - sprite model rendering
Copyright (C) 2011 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "hud.h"
#include "cl_util.h"
#include "gl_local.h"
#include <mathlib.h>
#include "gl_sprite.h"
#include "gl_studio.h"
#include "event_api.h"
#include "pm_defs.h"
#include "studio.h"
#include "triangleapi.h"
CSpriteModelRenderer g_SpriteRenderer;
/*
====================
Init
====================
*/
void CSpriteModelRenderer :: Init( void )
{
// Set up some variables shared with engine
m_pCvarLerping = IEngineStudio.GetCvar( "r_sprite_lerping" );
m_pCvarLighting = IEngineStudio.GetCvar( "r_sprite_lighting" );
}
/*
====================
CSpriteModelRenderer
====================
*/
CSpriteModelRenderer :: CSpriteModelRenderer( void )
{
m_pCurrentEntity = NULL;
m_pCvarLerping = NULL;
m_pCvarLighting = NULL;
m_pSpriteHeader = NULL;
m_pRenderModel = NULL;
}
CSpriteModelRenderer :: ~CSpriteModelRenderer( void )
{
}
/*
================
GetSpriteFrame
================
*/
mspriteframe_t *CSpriteModelRenderer :: GetSpriteFrame( int frame, float yaw )
{
mspritegroup_t *pspritegroup;
mspriteframe_t *pspriteframe = NULL;
if( frame < 0 )
{
frame = 0;
}
else if( frame >= m_pSpriteHeader->numframes )
{
ALERT( at_warning, "R_GetSpriteFrame: no such frame %d (%s)\n", frame, m_pRenderModel->name );
frame = m_pSpriteHeader->numframes - 1;
}
if( m_pSpriteHeader->frames[frame].type == SPR_SINGLE )
{
pspriteframe = (mspriteframe_t *)m_pSpriteHeader->frames[frame].frameptr;
}
else if( m_pSpriteHeader->frames[frame].type == SPR_GROUP )
{
pspritegroup = (mspritegroup_t *)m_pSpriteHeader->frames[frame].frameptr;
float *pintervals = pspritegroup->intervals;
int numframes = pspritegroup->numframes;
float fullinterval = pintervals[numframes-1];
// when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
// are positive, so we don't have to worry about division by zero
float targettime = m_clTime - ((int)( m_clTime / fullinterval )) * fullinterval;
for( int i = 0; i < (numframes - 1); i++ )
{
if( pintervals[i] > targettime )
break;
}
pspriteframe = pspritegroup->frames[i];
}
else if( m_pSpriteHeader->frames[frame].type == FRAME_ANGLED )
{
int angleframe = (int)(Q_rint(( RI->view.angles[YAW] - yaw + 45.0f ) / 360 * 8 ) - 4) & 7;
// doom-style sprite monsters
pspritegroup = (mspritegroup_t *)m_pSpriteHeader->frames[frame].frameptr;
pspriteframe = pspritegroup->frames[angleframe];
}
return pspriteframe;
}
/*
================
CSpriteModelRenderer
Compute renderer origin (include parent movement, sky movement, etc)
================
*/
void CSpriteModelRenderer :: SpriteComputeOrigin( cl_entity_t *e )
{
sprite_origin = e->origin; // set render origin
// link sprite with parent (if present)
if( e->curstate.aiment > 0 && e->curstate.movetype == MOVETYPE_FOLLOW )
{
cl_entity_t *parent = GET_ENTITY( e->curstate.aiment );
if( parent && parent->model )
{
if( parent->model->type == mod_studio && e->curstate.body > 0 )
{
int num = bound( 1, e->curstate.body, MAXSTUDIOATTACHMENTS );
sprite_origin = R_StudioAttachmentPos( parent, num - 1 );
}
else
{
sprite_origin = parent->origin;
}
}
}
if( e->curstate.renderfx == SKYBOX_ENTITY )
{
Vector trans = GetVieworg() - tr.sky_origin;
if( tr.sky_speed )
{
trans = trans - (GetVieworg() - tr.sky_world_origin) / tr.sky_speed;
Vector skypos = tr.sky_origin + (GetVieworg() - tr.sky_world_origin) / tr.sky_speed;
tr.modelorg = skypos - sprite_origin;
}
else
{
tr.modelorg = tr.sky_origin - sprite_origin;
}
sprite_origin += trans; // move to the sky position
}
else
{
tr.modelorg = sprite_origin;
}
}
/*
================
SspriteComputeBBox
Compute a full bounding box for reference
================
*/
void CSpriteModelRenderer :: SpriteComputeBBox( cl_entity_t *e, Vector bbox[8] )
{
// always compute origin first
if( bbox != NULL ) SpriteComputeOrigin( e );
// copy original bbox (no rotation for sprites)
sprite_absmin = e->model->mins;
sprite_absmax = e->model->maxs;
float scale = 1.0f;
if( e->curstate.scale > 0.0f )
scale = e->curstate.scale;
sprite_absmin *= scale;
sprite_absmax *= scale;
sprite_absmin += sprite_origin;
sprite_absmax += sprite_origin;
// compute a full bounding box
for( int i = 0; bbox != NULL && i < 8; i++ )
{
bbox[i][0] = ( i & 1 ) ? sprite_absmin[0] : sprite_absmax[0];
bbox[i][1] = ( i & 2 ) ? sprite_absmin[1] : sprite_absmax[1];
bbox[i][2] = ( i & 4 ) ? sprite_absmin[2] : sprite_absmax[2];
}
}
/*
================
CullSpriteModel
Cull sprite model by bbox
================
*/
bool CSpriteModelRenderer :: CullSpriteModel( void )
{
if( !m_pSpriteHeader )
return true;
SpriteComputeBBox( m_pCurrentEntity, NULL );
return R_CullModel( m_pCurrentEntity, sprite_absmin, sprite_absmax );
}
/*
================
GlowSightDistance
Calc sight distance for glow-sprites
================
*/
float CSpriteModelRenderer :: GlowSightDistance( void )
{
pmtrace_t tr;
float dist = (sprite_origin - GetVieworg( )).Length();
if( !FBitSet( RI->params, RP_MIRRORVIEW ))
{
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( GetVieworg(), sprite_origin, PM_GLASS_IGNORE, -1, &tr );
if((( 1.0f - tr.fraction ) * dist ) > 8.0f )
return -1;
}
return dist;
}
/*
================
R_GlowSightDistance
Set sprite brightness factor
================
*/
float CSpriteModelRenderer :: SpriteGlowBlend( int rendermode, int renderfx, int alpha, float &scale )
{
float dist = GlowSightDistance();
float brightness;
if( dist <= 0 ) return 0.0f; // occluded
if( renderfx == kRenderFxNoDissipation )
return (float)alpha * (1.0f / 255.0f);
scale = 0.0f; // variable sized glow
brightness = 19000.0 / ( dist * dist );
brightness = bound( 0.05f, brightness, 1.0f );
// make the glow fixed size in screen space, taking into consideration the scale setting.
if( scale == 0.0f ) scale = 1.0f;
scale *= dist * ( 1.0f / 200.0f );
return brightness;
}
/*
================
SpriteOccluded
Do occlusion test for glow-sprites
================
*/
int CSpriteModelRenderer :: SpriteOccluded( int &alpha, float &pscale )
{
// always compute origin first
SpriteComputeOrigin( m_pCurrentEntity );
if( m_pCurrentEntity->curstate.rendermode == kRenderGlow )
{
// don't reflect this entity in mirrors
if( FBitSet( m_pCurrentEntity->curstate.effects, EF_NOREFLECT ) && FBitSet( RI->params, RP_MIRRORVIEW ))
return true;
// draw only in mirrors
if( FBitSet( m_pCurrentEntity->curstate.effects, EF_REFLECTONLY ) && !FBitSet( RI->params, RP_MIRRORVIEW ))
return true;
// original glow occlusion code by BUzer from Paranoia
if( m_pCurrentEntity->curstate.renderfx == kRenderFxNoDissipation && CVAR_TO_BOOL( v_glows ))
{
mspriteframe_t *frame = GetSpriteFrame( m_pCurrentEntity->curstate.frame, m_pCurrentEntity->angles[YAW] );
Vector left = Vector( 0.0f, ( frame->left * pscale ) / 5.0f, 0.0f );
Vector right = Vector( 0.0f, ( frame->right * pscale ) / 5.0f, 0.0f );
matrix4x4 sprite_transform = RI->view.matrix;
sprite_transform.SetOrigin( sprite_origin );
Vector aleft = sprite_transform.VectorTransform( left );
Vector aright = sprite_transform.VectorTransform( right );
Vector dist = aright - aleft;
float dst = DotProduct( GetVForward(), sprite_origin - GetVieworg() );
dst = bound( 0.0f, dst, 64.0f );
dst = dst / 64.0f;
int numtraces = GLOW_NUM_TRACES;
if( numtraces < 1 ) numtraces = 1;
Vector step = dist * (1.0f / ( numtraces + 1 ));
float frac = 1.0f / numtraces;
float totalfrac = 0.0f;
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
for( int j = 0; j < numtraces; j++ )
{
Vector start = aleft + step * (j+1);
pmtrace_t pmtrace;
gEngfuncs.pEventAPI->EV_PlayerTrace( GetVieworg(), start, PM_GLASS_IGNORE|PM_STUDIO_IGNORE, -1, &pmtrace );
if( pmtrace.fraction == 1.0f )
totalfrac += frac;
}
float targetalpha = totalfrac;
float blend;
if( m_pCurrentEntity->latched.sequencetime > targetalpha )
{
m_pCurrentEntity->latched.sequencetime -= tr.frametime * GLOW_INTERP_SPEED;
if( m_pCurrentEntity->latched.sequencetime <= targetalpha )
m_pCurrentEntity->latched.sequencetime = targetalpha;
}
else if( m_pCurrentEntity->latched.sequencetime < targetalpha )
{
m_pCurrentEntity->latched.sequencetime += tr.frametime * GLOW_INTERP_SPEED;
if( m_pCurrentEntity->latched.sequencetime >= targetalpha )
m_pCurrentEntity->latched.sequencetime = targetalpha;
}
blend = m_pCurrentEntity->latched.sequencetime * dst;
alpha *= blend;
if( blend <= 0.01f )
return true; // faded
}
else
{
Vector screenVec;
float blend;
WorldToScreen( sprite_origin, screenVec );
if( screenVec[0] < RI->view.port[0] || screenVec[0] > RI->view.port[0] + RI->view.port[2] )
return true; // out of screen
if( screenVec[1] < RI->view.port[1] || screenVec[1] > RI->view.port[1] + RI->view.port[3] )
return true; // out of screen
blend = SpriteGlowBlend( m_pCurrentEntity->curstate.rendermode, m_pCurrentEntity->curstate.renderfx, alpha, pscale );
alpha *= blend;
if( blend <= 0.01f )
return true; // faded
}
}
else
{
if( CullSpriteModel( ))
return true;
}
return false;
}
/*
=================
DrawSpriteQuad
=================
*/
void CSpriteModelRenderer :: DrawSpriteQuad( mspriteframe_t *frame, const Vector &org, const Vector &right, const Vector &up, float scale )
{
Vector point;
pglBegin( GL_QUADS );
pglTexCoord2f( 0.0f, 1.0f );
point = org + up * (frame->down * scale);
point = point + right * (frame->left * scale);
pglVertex3fv( point );
pglTexCoord2f( 0.0f, 0.0f );
point = org + up * (frame->up * scale);
point = point + right * (frame->left * scale);
pglVertex3fv( point );
pglTexCoord2f( 1.0f, 0.0f );
point = org + up * (frame->up * scale);
point = point + right * (frame->right * scale);
pglVertex3fv( point );
pglTexCoord2f( 1.0f, 1.0f );
point = org + up * (frame->down * scale);
point = point + right * (frame->right * scale);
pglVertex3fv( point );
pglEnd();
}
int CSpriteModelRenderer :: SpriteHasLightmap( int texFormat )
{
if( m_pCvarLighting->value == 0 )
return false;
if( texFormat != SPR_ALPHTEST )
return false;
if( FBitSet( m_pCurrentEntity->curstate.effects, EF_FULLBRIGHT ))
return false;
if( m_pCurrentEntity->curstate.renderamt <= 127 )
return false;
switch( m_pCurrentEntity->curstate.rendermode )
{
case kRenderNormal:
case kRenderTransAlpha:
case kRenderTransTexture:
break;
default:
return false;
}
return true;
}
/*
=================
R_DrawSpriteModel
=================
*/
void CSpriteModelRenderer :: AddSpriteModelToDrawList( cl_entity_t *e, bool update )
{
// obviously we can't update sprites...
if( update ) return;
m_pCurrentEntity = RI->currententity;
IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime );
m_pRenderModel = m_pCurrentEntity->model;
m_pSpriteHeader = (msprite_t *)Mod_Extradata( m_pRenderModel );
if( !m_pSpriteHeader ) return;
int alpha = m_pCurrentEntity->curstate.renderamt;
float scale = m_pCurrentEntity->curstate.scale;
int rendermode = m_pCurrentEntity->curstate.rendermode;
if( SpriteOccluded( alpha, scale ))
return; // sprite culled
if( m_pSpriteHeader->texFormat == SPR_ALPHTEST )
{
if( rendermode != kRenderGlow && rendermode != kRenderTransAdd )
rendermode = kRenderTransAlpha;
}
Vector color, color2;
// add basecolor (any rendermode can have colored sprite)
color[0] = (float)m_pCurrentEntity->curstate.rendercolor.r * ( 1.0f / 255.0f );
color[1] = (float)m_pCurrentEntity->curstate.rendercolor.g * ( 1.0f / 255.0f );
color[2] = (float)m_pCurrentEntity->curstate.rendercolor.b * ( 1.0f / 255.0f );
if( SpriteHasLightmap( m_pSpriteHeader->texFormat ))
{
gEngfuncs.pTriAPI->LightAtPoint( sprite_origin, (float *)&color2 );
color2 *= (1.0f / 255.0f);
color *= color2;
}
mspriteframe_t *frame = GetSpriteFrame( m_pCurrentEntity->curstate.frame, m_pCurrentEntity->angles[YAW] );
int type = m_pSpriteHeader->type;
// automatically roll parallel sprites if requested
if( m_pCurrentEntity->angles[ROLL] != 0.0f && type == SPR_FWD_PARALLEL )
type = SPR_FWD_PARALLEL_ORIENTED;
Vector v_forward, v_right, v_up;
switch( type )
{
case SPR_ORIENTED:
{
AngleVectors( m_pCurrentEntity->angles, v_forward, v_right, v_up );
sprite_origin = sprite_origin - v_forward * 0.01f; // to avoid z-fighting
}
break;
case SPR_FACING_UPRIGHT:
{
v_right.x = sprite_origin.y - GetVieworg().y;
v_right.y = -(sprite_origin.x - GetVieworg().x);
v_right.z = 0.0f;
v_up.x = v_up.y = 0.0f;
v_up.z = 1.0f;
v_right = v_right.Normalize();
}
break;
case SPR_FWD_PARALLEL_UPRIGHT:
{
float dot = GetVForward().z;
if(( dot > 0.999848f ) || ( dot < -0.999848f )) // cos(1 degree) = 0.999848
return; // invisible
v_right.x = GetVForward().y;
v_right.y = -GetVForward().x;
v_right.z = 0.0f;
v_up.x = v_up.y = 0.0f;
v_up.z = 1.0f;
v_right = v_right.Normalize();
}
break;
case SPR_FWD_PARALLEL_ORIENTED:
{
float angle = m_pCurrentEntity->angles[ROLL] * (M_PI * 2.0f / 360.0f);
float sr, cr;
SinCos( angle, &sr, &cr );
for( int i = 0; i < 3; i++ )
{
v_right[i] = (GetVLeft()[i] * cr + GetVUp()[i] * sr);
v_up[i] = GetVLeft()[i] * -sr + GetVUp()[i] * cr;
}
}
break;
case SPR_FWD_PARALLEL: // normal sprite
default:
{
v_right = GetVLeft();
v_up = GetVUp();
}
break;
}
float flAlpha = (float)alpha * ( 1.0f / 255.0f );
if( m_pCurrentEntity->curstate.rendermode == kRenderGlow && m_pCurrentEntity->curstate.renderfx == kRenderFxNoDissipation )
{
if( CVAR_TO_BOOL( v_glows ))
{
flAlpha = m_pCurrentEntity->curstate.renderamt * ( 1.0f/ 255.0f );
color *= (float)alpha * ( 1.0f/ 255.0f );
}
}
Vector point[4];
Vector4D spriteColor;
Vector absmin, absmax;
spriteColor = Vector4D( color[0], color[1], color[2], flAlpha );
point[0] = sprite_origin + v_up * (frame->down * scale);
point[0] = point[0] + v_right * (frame->left * scale);
point[1] = sprite_origin + v_up * (frame->up * scale);
point[1] = point[1] + v_right * (frame->left * scale);
point[2] = sprite_origin + v_up * (frame->up * scale);
point[2] = point[2] + v_right * (frame->right * scale);
point[3] = sprite_origin + v_up * (frame->down * scale);
point[3] = point[3] + v_right * (frame->right * scale);
// more precision bounds than sprite_absmin\absmax
ClearBounds( absmin, absmax );
for( int i = 0; i < 4; i++ )
AddPointToBounds( point[i], absmin, absmax );
CTransEntry entry;
entry.SetRenderPrimitive( point, spriteColor, frame->gl_texturenum, rendermode );
entry.ComputeViewDistance( absmin, absmax );
RI->frame.trans_list.AddToTail( entry );
}
mspriteframe_t *CSpriteModelRenderer :: GetSpriteFrame( const model_t *m_pSpriteModel, int frame )
{
if(( m_pSpriteHeader = (msprite_t *)Mod_Extradata( (model_t *)m_pSpriteModel )) == NULL )
return NULL;
m_pCurrentEntity = NULL;
return GetSpriteFrame( frame, 0.0f );
}

112
cl_dll/render/gl_sprite.h Normal file
View File

@ -0,0 +1,112 @@
/*
gl_sprite.h - sprite model rendering
Copyright (C) 2011 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef GL_SPRITE_H
#define GL_SPRITE_H
#include "sprite.h"
#define GLOW_NUM_TRACES 5
#define GLOW_INTERP_SPEED 2.0f // time to fade glows
/*
====================
CSpriteModelRenderer
====================
*/
class CSpriteModelRenderer
{
public:
// Construction/Destruction
CSpriteModelRenderer( void );
virtual ~CSpriteModelRenderer( void );
// Initialization
virtual void Init( void );
private:
// Get Sprite description for frame
virtual mspriteframe_t *GetSpriteFrame( int frame, float yaw );
virtual void SpriteComputeOrigin( cl_entity_t *e );
virtual void SpriteComputeBBox( cl_entity_t *e, Vector bbox[8] );
virtual bool CullSpriteModel( void );
virtual float GlowSightDistance( void );
virtual float SpriteGlowBlend( int rendermode, int renderfx, int alpha, float &scale );
virtual int SpriteOccluded( int &alpha, float &pscale );
virtual void DrawSpriteQuad( mspriteframe_t *frame, const Vector &org, const Vector &right, const Vector &up, float scale );
virtual int SpriteHasLightmap( int texFormat );
inline void *Mod_Extradata( model_t *mod )
{
if( mod && mod->type == mod_sprite )
return mod->cache.data;
return NULL;
}
Vector sprite_origin;
Vector sprite_absmin, sprite_absmax;
// Client clock
double m_clTime;
// Old Client clock
double m_clOldTime;
// Current render frame #
int m_nFrameCount;
// Cvars that sprite model code needs to reference
cvar_t *m_pCvarLerping; // Use lerping for animation?
cvar_t *m_pCvarLighting; // lighting mode
// The entity which we are currently rendering.
cl_entity_t *m_pCurrentEntity;
// The model for the entity being rendered
model_t *m_pRenderModel;
// Current model rendermode
int m_iRenderMode;
// Pointer to header block for sprite model data
msprite_t *m_pSpriteHeader;
// engine stuff (backend)
public:
void AddSpriteModelToDrawList( cl_entity_t *e, bool update = false );
// Draw generic spritemodel
mspriteframe_t *GetSpriteFrame( const model_t *m_pSpriteModel, int frame );
};
extern CSpriteModelRenderer g_SpriteRenderer;
inline mspriteframe_t *R_GetSpriteFrame( const model_t *m_pSpriteModel, int frame )
{
return g_SpriteRenderer.GetSpriteFrame( m_pSpriteModel, frame );
}
inline void R_AddSpriteToDrawList( cl_entity_t *e, bool update = false )
{
g_SpriteRenderer.AddSpriteModelToDrawList( e, update );
}
#endif// GL_SPRITE_H

744
cl_dll/render/gl_studio.h Normal file
View File

@ -0,0 +1,744 @@
/*
gl_studio.h - studio model rendering
this code written for Paranoia 2: Savior modification
Copyright (C) 2014 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef GL_STUDIO_H
#define GL_STUDIO_H
#include "pmtrace.h"
#include "studio.h"
#include <utllinkedlist.h>
#include <utlarray.h>
#include <stringlib.h>
#include "gl_decals.h"
#include "gl_studiodecal.h"
#include "trace.h"
#include "bs_defs.h"
#include "ikcontext.h"
#include "jigglebones.h"
#include "tbnfile.h"
#define EVENT_CLIENT 5000 // less than this value it's a server-side studio events
#define MAX_MODEL_MESHES (MAXSTUDIOBODYPARTS * MAXSTUDIOMODELS)
#define SHADE_LAMBERT 1.495f
#define MAXARRAYVERTS 65536 // max vertices per studio submodel
#define MAX_SEQBLENDS 8 // must be power of two
#define MASK_SEQBLENDS (MAX_SEQBLENDS - 1)
#define MF_STATIC_BOUNDS BIT( 0 ) // this model is a env_static. don't recalc bounds every frame
#define MF_CUSTOM_LIGHTGRID BIT( 1 ) // model has special attahaments that was accepted as light probe start points
#define MF_VERTEX_LIGHTING BIT( 2 ) // model has the custom vertex lighting (loading from level)
#define MF_SURFACE_LIGHTING BIT( 3 ) // model has the custom surface lighting (loading from level)
#define MF_VL_BAD_CACHE BIT( 4 ) // for some reasons this model can't be instanced with a vertex lighting (bad crc, mismatch vertexcount etc)
#define MF_INIT_SMOOTHSTAIRS BIT( 5 )
#define MF_ATTACHMENTS_DONE BIT( 6 )
#define MF_POSITION_CHANGED BIT( 7 )
// studiorenderer modes
#define DRAWSTUDIO_NORMAL 0 // as default
#define DRAWSTUDIO_VIEWMODEL 1 // rendeging viewmodel
#define DRAWSTUDIO_HEADSHIELD 2 // headshield or gasmask
#define DRAWSTUDIO_RUNEVENTS 3 // run events of studiomodel
#define LIGHTSTATIC_NONE 0
#define LIGHTSTATIC_VERTEX 1
#define LIGHTSTATIC_SURFACE 2
#define TBNSTATE_INACTIVE 0
#define TBNSTATE_LOADING 1
#define TBNSTATE_GENERATE 2
// holds temporary data
typedef struct
{
int firstvertex;
int numvertices;
int firstindex;
int numindices;
int lightmapnum;
} StudioMesh_t;
// new blending sequence system
typedef struct
{
float blendtime; // time to blend between current and previous sequence
int sequence; // previous sequence number
float cycle; // cycle where sequence was changed
float fadeout;
bool gaitseq;
} mstudioblendseq_t;
typedef struct
{
float frame;
int sequence;
float gaitframe;
int gaitsequence;
// for smooth stair climbing
float stairtime;
float stairoldz;
} mstudiolerp_t;
// source vertex data (106 bytes here)
typedef struct xvert_s
{
Vector vertex; // position
Vector normal; // normal
Vector tangent; // tangent
Vector binormal; // binormal
float stcoord[4]; // ST texture coords
float lmcoord0[4]; // LM texture coords
float lmcoord1[4]; // LM texture coords
char boneid[4]; // control bones
byte weight[4]; // boneweights
float light[MAXLIGHTMAPS]; // packed color
float deluxe[MAXLIGHTMAPS]; // packed lightdir
byte styles[MAXLIGHTMAPS]; // lightstyles
word m_MeshVertexIndex; // index into the mesh's vertex list (decals only)
} svert_t;
typedef void (*pfnCreateStudioBuffer)( vbomesh_t *pOut, svert_t *arrayxvert );
typedef void (*pfnBindStudioBuffer)( vbomesh_t *pOut, int attrFlags );
typedef struct
{
pfnCreateStudioBuffer CreateBuffer;
pfnBindStudioBuffer BindBuffer;
const char* BufferName; // debug
} mesh_loader_t;
class CBaseBoneSetup : public CStudioBoneSetup
{
public:
virtual void debugMsg( char *szFmt, ... );
virtual mstudioanim_t *GetAnimSourceData( mstudioseqdesc_t *pseqdesc );
virtual void debugLine( const Vector& origin, const Vector& dest, int r, int g, int b, bool noDepthTest = false, float duration = 0.0f );
};
/*
====================
CStudioModelRenderer
====================
*/
class CStudioModelRenderer
{
public:
// Construction/Destruction
CStudioModelRenderer( void );
virtual ~CStudioModelRenderer( void );
// Initialization
void Init( void );
void VidInit( void );
// Look up animation data for sequence
mstudioanim_t *StudioGetAnim ( model_t *pModel, mstudioseqdesc_t *pseqdesc );
// precache vertexlit mesh
void CreateStudioCacheVL( const char *modelname, int cacheID );
// precache lightmapped mesh
void CreateStudioCacheFL( const char *modelname, int cacheID );
// throw all the meshes when the engine is shutting down
void FreeStudioCacheVL( void );
void FreeStudioCacheFL( void );
private:
// Local interfaces
// Extract bbox from current sequence
int StudioExtractBbox ( studiohdr_t *phdr, int sequence, Vector &mins, Vector &maxs );
// Compute a full bounding box for current sequence
int StudioComputeBBox ( void );
float CalcStairSmoothValue( float oldz, float newz, float smoothtime, float smoothvalue );
const Vector StudioGetOrigin( void );
// Interpolate model position and angles and set up matrices
void StudioSetUpTransform( void );
// Set up model bone positions
void StudioSetupBones( void );
// Find final attachment points
void StudioCalcAttachments( matrix3x4 bones[] );
void AddBlendSequence( int oldseq, int newseq, float prevframe, bool gaitseq = false );
void BlendSequence( Vector pos[], Vector4D q[], mstudioblendseq_t *pseqblend );
void UpdateIKLocks( CIKContext *pIK );
void CalculateIKLocks( CIKContext *pIK );
// Merge cached bones with current bones for model
void StudioMergeBones( matrix3x4 &transform, matrix3x4 bones[], matrix3x4 cached_bones[], model_t *pModel, model_t *pParentModel );
// Determine interpolation fraction
float StudioEstimateInterpolant( void );
// Determine current gaitframe for rendering
float StudioEstimateGaitFrame ( mstudioseqdesc_t *pseqdesc );
// Determine current frame for rendering
float StudioEstimateFrame ( mstudioseqdesc_t *pseqdesc );
void StudioInterpolateControllers( cl_entity_t *e, float dadt );
void StudioInterpolatePoseParams( cl_entity_t *e, float dadt );
// Apply special effects to transform matrix
void StudioFxTransform( cl_entity_t *ent, matrix3x4 &transform );
void ComputeSkinMatrix( mstudioboneweight_t *boneweights, const matrix3x4 worldtransform[], matrix3x4 &result );
void ComputeSkinMatrix( svert_t *vertex, const matrix3x4 worldtransform[], matrix3x4 &result );
int StudioCheckLOD( void );
//calc bodies and get pointers to him
int StudioSetupModel ( int bodypart, mstudiomodel_t **ppsubmodel, msubmodel_t **ppvbomodel );
void DrawMeshFromBuffer( const vbomesh_t *mesh );
void DeleteVBOMesh( vbomesh_t *mesh );
// Process studio client events
void StudioClientEvents( void );
void StudioLighting( float *lv, int bone, int flags, const Vector &normal );
void StudioStaticLight( cl_entity_t *ent, mstudiolight_t *light );
void CacheVertexLight( cl_entity_t *ent );
void CacheSurfaceLight( cl_entity_t *ent );
void StudioFormatAttachment( Vector &point );
word ChooseStudioProgram( studiohdr_t *phdr, mstudiomaterial_t *mat, bool lightpass );
void AddMeshToDrawList( studiohdr_t *phdr, vbomesh_t *mesh, bool lightpass );
void AddBodyPartToDrawList( studiohdr_t *phdr, mbodypart_t *bodyparts, int bodypart, bool lightpass );
bool CheckBoneCache( float f );
word ShaderSceneForward( mstudiomaterial_t *mat, int lightmode, bool bone_weighting, int numbones );
word ShaderLightForward( CDynLight *dl, mstudiomaterial_t *mat, bool bone_weighting, int numbones );
word ShaderSceneDeferred( mstudiomaterial_t *mat, bool bone_weighting, int numbones );
word ShaderLightDeferred( mstudiomaterial_t *mat, bool bone_weighting, int numbones );
word ShaderSceneDepth( mstudiomaterial_t *mat, bool bone_weighting, int numbones );
word ShaderDecalForward( studiodecal_t *pDecal, bool has_vertexlight );
// Debug drawing
void StudioDrawDebug( cl_entity_t *e );
void StudioDrawHulls( int iHitbox = -1 );
void StudioDrawAbsBBox( void );
void StudioDrawBones( void );
void StudioDrawAttachments( bool bCustomFov );
int HeadShieldThink( void );
// intermediate structure. Used only for build unique submodels
struct TmpModel_t
{
char name[64];
mstudiomodel_t *pmodel;
msubmodel_t *pout;
};
struct BoneCache_t
{
float frame; // product of StudioEstimateFrame, not a curstate.frame!
short sequence;
byte blending[2];
byte controller[4];
byte mouthopen;
matrix3x4 transform; // cached transform because ent->angles\ent->origin doesn't contains interpolation info
float poseparam[MAXSTUDIOPOSEPARAM];
// special fields for player
short gaitsequence;
float gaitframe;
};
struct StudioAttachment_t
{
char name[MAXSTUDIONAME];
matrix3x4 local; // local position
Vector origin; // attachment pos
Vector angles; // VectorAngles
Vector dir; // old method
};
typedef struct
{
int m_VertCount; // Number of used vertices
int m_Indices[2][7]; // Indices into the clip verts array of the used vertices
bool m_Pass; // Helps us avoid copying the m_Indices array by using double-buffering
int m_ClipVertCount; // Add vertices we've started with and had to generate due to clipping
svert_t m_ClipVerts[16];
int m_ClipFlags[16]; // Union of the decal triangle clip flags above for each vert
} DecalClipState_t;
typedef CUtlArray<studiodecal_t> StudioDecalList_t;
typedef CUtlArray<int> CIntVector;
enum
{
MESHLOADER_BASE = 0,
MESHLOADER_BASEBUMP,
MESHLOADER_VLIGHT,
MESHLOADER_VLIGHTBUMP,
MESHLOADER_WEIGHT,
MESHLOADER_WEIGHTBUMP,
MESHLOADER_LIGHTMAP,
MESHLOADER_LIGHTMAPBUMP,
MESHLOADER_GENERIC,
MESHLOADER_COUNT,
};
struct ModelInstance_t
{
cl_entity_t *m_pEntity;
// Need to store off the model. When it changes, we lose all instance data..
model_t *m_pModel;
StudioDecalList_t m_DecalList; // new decal list for each instance
int m_DecalCount; // just used as timestamp for calculate decal depth
int info_flags;
// NOTE: each decal applied while model has some pose
// keep it in this array for each model and dump into
// savefile to properly restored decal positions
CUtlArray<modelstate_t> pose_stamps;
mstudiocache_t *m_VlCache; // valid only for env_statics that have vertexlight data
mstudiocache_t *m_FlCache; // valid only for env_statics that have surfacelight data
byte styles[MAXLIGHTMAPS];// actual only if MF_VERTEX_LIGHTING|MF_SURFACE_LIGHTING bit is set
// bounds info
Vector absmin;
Vector absmax;
float radius;
Vector origin; // transformed origin
BoneCache_t bonecache; // just compare to avoid recalc bones every frame
// attachments
StudioAttachment_t attachment[MAXSTUDIOATTACHMENTS];
int numattachments;
byte m_controller[MAXSTUDIOCONTROLLERS];
float m_poseparameter[MAXSTUDIOPOSEPARAM]; // blends for traditional studio models
float m_oldposeparams[MAXSTUDIOPOSEPARAM]; // latched values
mstudioblendseq_t m_seqblend[MAX_SEQBLENDS];
int m_current_seqblend;
// sequence blends stuff
mstudiolerp_t lerp;
CJiggleBones *m_pJiggleBones;
CIKContext m_ik;
// attached cubemaps
mcubemap_t *cubemap[2];
float lerpFactor;
mstudiomaterial_t *materials; // shaders cache
// light interpolation
mstudiolight_t oldlight;
mstudiolight_t newlight;
mstudiolight_t light; // cached light values
float lighttimecheck;
bool light_update;
byte lights[MAXDYNLIGHTS]; // dynamic lights cache
matrix3x4 m_protationmatrix;
matrix3x4 m_pbones[MAXSTUDIOBONES]; // bone to pose
matrix3x4 m_pwpnbones[MAXSTUDIOBONES];
Vector4D m_glstudiobones[MAXSTUDIOBONES*3]; // GLSL-friendly compacted matrix4x3
Vector4D m_glweaponbones[MAXSTUDIOBONES*3]; // GLSL-friendly compacted matrix4x3
// GLSL cached arrays
Vector4D m_studioquat[MAXSTUDIOBONES];
Vector m_studiopos[MAXSTUDIOBONES];
Vector4D m_weaponquat[MAXSTUDIOBONES];
Vector m_weaponpos[MAXSTUDIOBONES];
GLfloat m_glmatrix[16];
unsigned int cached_frame; // to avoid compute bones more than once per frame
unsigned int visframe; // model is visible this frame
};
struct DecalBuildInfo_t
{
// this part is constant all time while decal is build
const DecalGroupEntry* m_pTexInfo;
modelstate_t* modelState;
dmodelvertlight_t* modelLight;
Vector vecLocalNormal;
Vector vecLocalEnd;
Vector2D vecDecalScale;
bool m_UseClipVert;
int decalDepth;
byte decalFlags;
int poseState;
studiodecal_t *current;
float m_Radius;
// this part is changed for each mesh
vbomesh_t* m_pModelMesh;
StudioMesh_t* m_pDecalMesh;
dvertlight_t* m_pVertexLight;
DecalVertexInfo_t* m_pVertexInfo;
CUtlArray<svert_t> m_Vertices;
CUtlArray<unsigned int> m_Indices;
};
// keep model instances for each entity
CUtlLinkedList< ModelInstance_t, word > m_ModelInstances;
// decal stuff
bool ComputePoseToDecal( const Vector &vecStart, const Vector &vecEnd );
void AddDecalToModel( DecalBuildInfo_t& buildInfo );
void AddDecalToMesh( DecalBuildInfo_t& buildInfo );
void AllocDecalForMesh( DecalBuildInfo_t& build );
void ProjectDecalOntoMesh( DecalBuildInfo_t& build );
bool IsFrontFacing( const svert_t *vert );
void DecalCreateBuffer( DecalBuildInfo_t& build, studiodecal_t *pDecal );
bool TransformToDecalSpace( DecalBuildInfo_t& build, const svert_t *vert, Vector2D& uv );
matrix3x3 GetDecalRotateTransform( byte vertexBone );
void AddTriangleToDecal( DecalBuildInfo_t& build, int i1, int i2, int i3 );
int ComputeClipFlags( Vector2D const& uv );
bool ClipDecal( DecalBuildInfo_t& build, int i1, int i2, int i3, int *pClipFlags );
void ConvertMeshVertexToDecalVertex( DecalBuildInfo_t& build, int vertIndex, svert_t *out );
void ClipTriangleAgainstPlane( DecalClipState_t& state, int normalInd, int flag, float val );
int IntersectPlane( DecalClipState_t& state, int start, int end, int normalInd, float val );
word AddVertexToDecal( DecalBuildInfo_t& build, int vertIndex );
word AddVertexToDecal( DecalBuildInfo_t& build, svert_t *vert );
void AddClippedDecalToTriangle( DecalBuildInfo_t& build, DecalClipState_t& clipState );
void ComputeDecalTBN( DecalBuildInfo_t& build );
void PurgeDecals( ModelInstance_t *inst );
void PurgeDecals( cl_entity_t *pEnt );
bool StudioSetEntity( cl_entity_t *pEnt );
bool StudioSetEntity( CSolidEntry *entry );
bool IsModelInstanceValid( ModelInstance_t *inst );
bool StudioSetupInstance( void );
void DestroyInstance( word handle );
void SetDecalUniforms( studiodecal_t *pDecal );
void DrawDecal( CSolidEntry *entry, GLenum cull = GL_FRONT );
mstudiocache_t *CreateStudioCache( void *dml = NULL, int lightmode = LIGHTSTATIC_NONE );
void DeleteStudioCache( mstudiocache_t **ppcache );
void DestroyMeshCache( void );
void CreateStudioCacheVL( dmodelvertlight_t *dml, int cacheID );
void CreateStudioCacheFL( dmodelfacelight_t *dml, int cacheID );
void PrecacheStudioShaders( void );
void LoadStudioMaterials( void );
void FreeStudioMaterials( void );
void UpdateInstanceMaterials( void );
void ClearInstanceData( bool create );
// set uniforms data for specified shader
void DrawSingleMesh( CSolidEntry *mesh, bool force );
void SetupSubmodelVerts( const mstudiomodel_t *pSubModel, const matrix3x4 bones[], void *dml, int lightmode );
void MeshCreateBuffer( vbomesh_t *pDst, const mstudiomesh_t *pSrc, const StudioMesh_t *pMeshInfo, int lightmode );
void AllocLightmapsForMesh( StudioMesh_t *pCurMesh, const dmodelfacelight_t *dfl );
bool CalcLightmapAxis( mstudiosurface_t *surf, const dfacelight_t *fl, const dmodelfacelight_t *dfl );
static void CreateBufferBaseGL21( vbomesh_t *pOut, svert_t *arrayxvert );
static void CreateBufferBaseGL30( vbomesh_t *pOut, svert_t *arrayxvert );
static void CreateBufferBaseBumpGL21( vbomesh_t *pOut, svert_t *arrayxvert );
static void CreateBufferBaseBumpGL30( vbomesh_t *pOut, svert_t *arrayxvert );
static void CreateBufferVLightGL21( vbomesh_t *pOut, svert_t *arrayxvert );
static void CreateBufferVLightGL30( vbomesh_t *pOut, svert_t *arrayxvert );
static void CreateBufferVLightBumpGL21( vbomesh_t *pOut, svert_t *arrayxvert );
static void CreateBufferVLightBumpGL30( vbomesh_t *pOut, svert_t *arrayxvert );
static void CreateBufferWeightGL21( vbomesh_t *pOut, svert_t *arrayxvert );
static void CreateBufferWeightGL30( vbomesh_t *pOut, svert_t *arrayxvert );
static void CreateBufferWeightBumpGL21( vbomesh_t *pOut, svert_t *arrayxvert );
static void CreateBufferWeightBumpGL30( vbomesh_t *pOut, svert_t *arrayxvert );
static void CreateBufferLightMapGL21( vbomesh_t *pOut, svert_t *arrayxvert );
static void CreateBufferLightMapGL30( vbomesh_t *pOut, svert_t *arrayxvert );
static void CreateBufferLightMapBumpGL21( vbomesh_t *pOut, svert_t *arrayxvert );
static void CreateBufferLightMapBumpGL30( vbomesh_t *pOut, svert_t *arrayxvert );
static void CreateBufferGenericGL21( vbomesh_t *pOut, svert_t *arrayxvert );
static void CreateBufferGenericGL30( vbomesh_t *pOut, svert_t *arrayxvert );
static void BindBufferBaseGL21( vbomesh_t *pOut, int attrFlags );
static void BindBufferBaseGL30( vbomesh_t *pOut, int attrFlags );
static void BindBufferBaseBumpGL21( vbomesh_t *pOut, int attrFlags );
static void BindBufferBaseBumpGL30( vbomesh_t *pOut, int attrFlags );
static void BindBufferVLightGL21( vbomesh_t *pOut, int attrFlags );
static void BindBufferVLightGL30( vbomesh_t *pOut, int attrFlags );
static void BindBufferVLightBumpGL21( vbomesh_t *pOut, int attrFlags );
static void BindBufferVLightBumpGL30( vbomesh_t *pOut, int attrFlags );
static void BindBufferWeightGL21( vbomesh_t *pOut, int attrFlags );
static void BindBufferWeightGL30( vbomesh_t *pOut, int attrFlags );
static void BindBufferWeightBumpGL21( vbomesh_t *pOut, int attrFlags );
static void BindBufferWeightBumpGL30( vbomesh_t *pOut, int attrFlags );
static void BindBufferLightMapGL21( vbomesh_t *pOut, int attrFlags );
static void BindBufferLightMapGL30( vbomesh_t *pOut, int attrFlags );
static void BindBufferLightMapBumpGL21( vbomesh_t *pOut, int attrFlags );
static void BindBufferLightMapBumpGL30( vbomesh_t *pOut, int attrFlags );
static void BindBufferGenericGL21( vbomesh_t *pOut, int attrFlags );
static void BindBufferGenericGL30( vbomesh_t *pOut, int attrFlags );
static void CreateIndexBuffer( vbomesh_t *pOut, unsigned int *arrayelems );
static void BindIndexBuffer( vbomesh_t *pOut );
static int SortSolidMeshes( const CSolidEntry *a, const CSolidEntry *b );
unsigned int ComputeAttribFlags( int numbones, bool has_bumpmap, bool has_boneweights, bool has_vertexlight, bool has_lightmap );
unsigned int SelectMeshLoader( int numbones, bool has_bumpmap, bool has_boneweights, bool has_vertexlight, bool has_lightmap );
static mesh_loader_t m_pfnMeshLoaderGL21[MESHLOADER_COUNT];
static mesh_loader_t m_pfnMeshLoaderGL30[MESHLOADER_COUNT];
bool m_fShootDecal; // disable all interpolations and bonecache
float m_flViewmodelFov; // custom fov for viewmodel
int m_iDrawModelType; // various modes of rendering
// Cvars that studio model code needs to reference
cvar_t *m_pCvarHiModels; // Use high quality models?
cvar_t *m_pCvarDrawViewModel;
cvar_t *m_pCvarHand; // handness
cvar_t *m_pCvarViewmodelFov;
cvar_t *m_pCvarHeadShieldFov;
cvar_t *m_pCvarLegsOffset;
cvar_t *m_pCvarDrawLegs;
cvar_t *m_pCvarCompatible;
cvar_t *m_pCvarLodScale;
cvar_t *m_pCvarLodBias;
CBaseBoneSetup m_boneSetup;
// current mesh material
mstudiomaterial_t *m_pCurrentMaterial;
ModelInstance_t *m_pModelInstance;
// Pointer to header block for studio model data
studiohdr_t *m_pStudioHeader;
mstudiocache_t *m_pStudioCache; // only valid while mesh is build
msubmodel_t *m_pVboModel;
mstudiomodel_t *m_pSubModel;
StudioMesh_t m_pTempMesh[MAXSTUDIOSKINS]; // temp structure
// used by PushEntity\PopEntity
entity_state_t m_savestate;
Vector m_saveorigin;
Vector m_saveangles;
Vector m_bonelightvecs[MAXSTUDIOBONES]; // debug used this
Vector m_arrayverts[MAXARRAYVERTS];
svert_t m_arrayxvert[MAXARRAYVERTS];
dmodeltbn_t *m_tbnverts; // variable sized
unsigned int m_arrayelems[MAXARRAYVERTS*3];
unsigned int m_nNumArrayVerts;
unsigned int m_nNumArrayElems;
unsigned int m_nNumLightVerts;
unsigned int m_nNumLightFaces;
unsigned int m_nNumTBNVerts;
unsigned int m_nNumTempVerts; // used to conversion to fan sequence
// decal building stuff
matrix3x4 m_pdecaltransform[MAXSTUDIOBONES]; // decal->world
matrix3x4 m_pworldtransform[MAXSTUDIOBONES]; // world->decal
// firstperson legs stuff
model_t *m_pPlayerLegsModel;
int m_iTBNState;
public:
void DestroyAllModelInstances( void );
int StudioGetBounds( cl_entity_t *e, Vector bounds[2] );
int StudioGetBounds( CSolidEntry *entry, Vector bounds[2] );
bool StudioLoadTBN( void );
bool StudioSaveTBN( void );
void PushEntityState( cl_entity_t *ent );
void PopEntityState( cl_entity_t *ent );
void EntityToModelState( modelstate_t *state, const cl_entity_t *ent );
void ModelStateToEntity( cl_entity_t *ent, const modelstate_t *state );
void StudioDecalShoot( const Vector &vecNorm, const Vector &vecEnd, const char *name, cl_entity_t *ent, int flags, modelstate_t *state );
void StudioDecalShoot( struct pmtrace_s *tr, const char *name, bool visent = false );
int StudioDecalList( decallist_t *pList, int count );
void StudioClearDecals( void );
void RemoveAllDecals( int entityIndex );
void UpdateLatchedVars( cl_entity_t *e, qboolean reset );
void ProcessUserData( model_t *mod, qboolean create, const byte *buffer );
void LoadLocalMatrix( int bone, mstudioboneinfo_t *boneinfo );
void AddStudioModelToDrawList( cl_entity_t *e, bool update = false );
void StudioGetAttachment( const cl_entity_t *ent, int iAttachment, Vector *pos, Vector *ang, Vector *dir );
// Process viewmodel events (at start the frame so muzzleflashes will be correct added)
void RunViewModelEvents( void );
bool ComputeCustomFov( matrix4x4 &projMatrix, matrix4x4 &worldViewProjMatrix );
void RestoreNormalFov( matrix4x4 &projMatrix, matrix4x4 &worldViewProjMatrix );
// Draw view model (at end the frame)
void DrawViewModel( void );
// draw head shield (after viewmodel)
void DrawHeadShield( void );
void RenderDeferredStudioList( void );
void RenderSolidStudioList( void );
void RenderShadowStudioList( void );
void RenderDebugStudioList( bool bViewModel );
void RenderDynLightList( bool solid );
void RenderTransMesh( CTransEntry *entry );
void BuildMeshListForLight( CDynLight *pl, bool solid );
void DrawLightForMeshList( CDynLight *pl );
int CacheCount( void ) { return m_ModelInstances.Count(); }
void ClearLightCache( void );
};
extern CStudioModelRenderer g_StudioRenderer;
// implementation of drawing funcs
inline void R_RunViewmodelEvents( void ) { g_StudioRenderer.RunViewModelEvents(); }
inline void R_DrawViewModel( void ) { g_StudioRenderer.DrawViewModel(); }
inline void R_DrawHeadShield( void ) { g_StudioRenderer.DrawHeadShield(); }
inline void R_ProcessStudioData( model_t *mod, qboolean create, const byte *buffer )
{
if( mod->type == mod_studio )
g_StudioRenderer.ProcessUserData( mod, create, buffer );
}
inline int R_CreateStudioDecalList( decallist_t *pList, int count )
{
return g_StudioRenderer.StudioDecalList( pList, count );
}
inline void R_ClearStudioDecals( void )
{
g_StudioRenderer.StudioClearDecals();
}
inline int R_StudioGetBounds( cl_entity_t *e, Vector bounds[2] )
{
return g_StudioRenderer.StudioGetBounds( e, bounds );
}
inline int R_StudioGetBounds( CSolidEntry *entry, Vector bounds[2] )
{
return g_StudioRenderer.StudioGetBounds( entry, bounds );
}
inline void R_RenderDeferredStudioList( void )
{
g_StudioRenderer.RenderDeferredStudioList();
}
inline void R_RenderSolidStudioList( void )
{
g_StudioRenderer.RenderSolidStudioList();
}
inline void R_RenderTransMesh( CTransEntry *entry )
{
g_StudioRenderer.RenderTransMesh( entry );
}
inline void R_RenderLightForTransMeshes( void )
{
g_StudioRenderer.RenderDynLightList( false );
}
inline void R_RenderShadowStudioList( void )
{
g_StudioRenderer.RenderShadowStudioList();
}
inline void R_RenderDebugStudioList( bool bViewModel )
{
g_StudioRenderer.RenderDebugStudioList( bViewModel );
}
inline void R_AddStudioToDrawList( cl_entity_t *e, bool update = false )
{
g_StudioRenderer.AddStudioModelToDrawList( e, update );
}
inline void R_StudioClearLightCache( void )
{
g_StudioRenderer.ClearLightCache();
}
inline void R_StudioAttachmentPosAng( const cl_entity_t *ent, int num, Vector *pos, Vector *ang )
{
g_StudioRenderer.StudioGetAttachment( ent, num, pos, ang, NULL );
}
inline void R_StudioAttachmentPosDir( const cl_entity_t *ent, int num, Vector *pos, Vector *dir )
{
g_StudioRenderer.StudioGetAttachment( ent, num, pos, NULL, dir );
}
inline Vector R_StudioAttachmentPos( const cl_entity_t *ent, int num )
{
Vector pos = g_vecZero;
g_StudioRenderer.StudioGetAttachment( ent, num, &pos, NULL, NULL );
return pos;
}
inline Vector R_StudioAttachmentAng( const cl_entity_t *ent, int num )
{
Vector ang = g_vecZero;
g_StudioRenderer.StudioGetAttachment( ent, num, NULL, &ang, NULL );
return ang;
}
inline void R_UpdateLatchedVars( cl_entity_t *e, qboolean reset )
{
g_StudioRenderer.UpdateLatchedVars( e, reset );
}
#endif// GL_STUDIO_H

5448
cl_dll/render/gl_studio.old Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More