From 95af1226ef957bf07b0f3f7a49f33616a8b5a2f3 Mon Sep 17 00:00:00 2001 From: g-cont Date: Fri, 7 Oct 2011 00:00:00 +0400 Subject: [PATCH] 07 Oct 2011 --- change.log | 24 +- dlls/hl.plg | 243 +----------- engine/client/cl_frame.c | 6 +- engine/client/cl_game.c | 11 +- engine/client/cl_menu.c | 8 +- engine/client/cl_parse.c | 68 +++- engine/client/cl_tent.c | 6 +- engine/client/client.h | 9 +- engine/client/gl_backend.c | 6 +- engine/client/gl_beams.c | 55 +-- engine/client/gl_cull.c | 73 ++++ engine/client/gl_decals.c | 6 +- engine/client/gl_image.c | 82 +++- engine/client/gl_local.h | 36 +- engine/client/gl_mirror.c | 579 +++++++++++++++++++++++++++++ engine/client/gl_refrag.c | 11 +- engine/client/gl_rlight.c | 18 +- engine/client/gl_rmain.c | 127 ++++--- engine/client/gl_rmisc.c | 1 + engine/client/gl_rpart.c | 16 +- engine/client/gl_rsurf.c | 335 +++++------------ engine/client/gl_sprite.c | 2 +- engine/client/gl_studio.c | 13 +- engine/client/gl_vidnt.c | 29 +- engine/client/gl_warp.c | 34 ++ engine/client/s_load.c | 1 + engine/common/avikit.c | 4 +- engine/common/common.h | 8 +- engine/common/gamma.c | 68 ++++ engine/common/imagelib/img_utils.c | 33 +- engine/common/mathlib.h | 1 + engine/common/matrixlib.c | 11 + engine/common/mod_local.h | 2 + engine/common/model.c | 11 +- engine/common/net_encode.c | 8 + engine/engine.dsp | 8 + engine/menu_int.h | 1 + engine/server/server.h | 2 + engine/server/sv_game.c | 14 +- engine/server/sv_main.c | 26 +- engine/server/sv_phys.c | 8 + engine/server/sv_save.c | 21 ++ engine/server/sv_studio.c | 4 +- mainui/enginecallback.h | 2 + mainui/menu_vidoptions.cpp | 32 +- pm_shared/pm_movevars.h | 4 + 46 files changed, 1411 insertions(+), 656 deletions(-) create mode 100644 engine/client/gl_mirror.c create mode 100644 engine/common/gamma.c diff --git a/change.log b/change.log index 9f54226d..1a3cf4ae 100644 --- a/change.log +++ b/change.log @@ -12,14 +12,34 @@ Render: allow 16-bit color mode when decktop has same Render: rename "vid_gamma" to "gamma", make backward compatibility with GoldSource config Sound: get support for automatic ambient sounds like in Quake Sound: add cvar "s_combine" that trying to combine mutilpe channels with same sounds into one -Engine: add "secure" option for both liblist.gam and gameinfo.txt +Engine: add "secure" option support for both liblist.gam and gameinfo.txt Engine: fix bug determine current directory Server: fix bug when some sound messages can't be sended to client (e.g. not vised map) Render: allow to load hi-res quake sky (two layers called as sky_solid and sky_alpha) Physic: fix trace bug when bbox mins are 0 0 0 and bbox maxs are positive values (like quake boxes) GameUI: add checkbox "allow materials" in menu Video Options. Client: implement "viewsize" cvar - +GameUI: add new function to inteface called as pfnProcessImage +Client: add support for default studiomodel flags like quake effects (light, smoke, blood etc) +Render: add engine mirrors (can be set on map with texture "decals.wad\reflect1") +Client: rewrite client font system to allow support for "hud_scale" feature +Client: re-enable client static entities (see engine function MAKE_STATIC for details) +Sound: clear "loop" flags for client engine functions PlaySoundByName and PlaySoundByIndex +Client: fix potentially crash in StudioRemap code +Client: finalize 'GlowShell' effect on StudioModels +Render: implement software gamma control that based on lightmap adjusting (gl_ignorehwgamma 1) +Render: restore projection and modelview matrices before call V_CalcRefdef to avoid errors on custom rendering (e.g. HLFX 0.5, Trinity Renderers) +Render: remove all stuff for 3dfx gamma control +Render: add missing function R_ScreenToWorld +Engine: add "icon" option support for both liblist.gam and gameinfo.txt +Render: get support for rotational skybox that can be saved and restored with current angle +Engine: fix bug with incorrect detecting Blue-Shift maps in some rare cases +Engine: add autocomplete for 'entpatch' command +Engine: fix Host_Error issues +Network: add IPX and IPX_BROADCAST for backward compatibility with GoldSrc +Engine: do revision for 'allow_studio_scale' cvar in trace code +GameUI: added support for Steam backgrounds +GameUI: hide input symbols for "password" field in "create server" menu page build 1662 diff --git a/dlls/hl.plg b/dlls/hl.plg index 5bda0261..67e43085 100644 --- a/dlls/hl.plg +++ b/dlls/hl.plg @@ -3,244 +3,23 @@
 

Build Log

---------------------Configuration: hl - Win32 Debug-------------------- +--------------------Configuration: hl - Win32 Release--------------------

Command Lines

-Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP3740.tmp" with contents -[ -/nologo /G5 /MTd /W3 /Gm /ZI /Od /I "..\dlls" /I "..\engine" /I "..\common" /I "..\game_shared" /I "..\pm_shared" /I "..\\" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /D "CLIENT_WEAPONS" /FR"..\temp\dlls\!debug/" /Fp"..\temp\dlls\!debug/hl.pch" /YX /Fo"..\temp\dlls\!debug/" /Fd"..\temp\dlls\!debug/" /FD /c -"D:\Xash3D\src_main\dlls\aflock.cpp" -"D:\Xash3D\src_main\dlls\agrunt.cpp" -"D:\Xash3D\src_main\dlls\airtank.cpp" -"D:\Xash3D\src_main\dlls\animating.cpp" -"D:\Xash3D\src_main\dlls\animation.cpp" -"D:\Xash3D\src_main\dlls\apache.cpp" -"D:\Xash3D\src_main\dlls\barnacle.cpp" -"D:\Xash3D\src_main\dlls\barney.cpp" -"D:\Xash3D\src_main\dlls\bigmomma.cpp" -"D:\Xash3D\src_main\dlls\bloater.cpp" -"D:\Xash3D\src_main\dlls\bmodels.cpp" -"D:\Xash3D\src_main\dlls\bullsquid.cpp" -"D:\Xash3D\src_main\dlls\buttons.cpp" -"D:\Xash3D\src_main\dlls\cbase.cpp" -"D:\Xash3D\src_main\dlls\client.cpp" -"D:\Xash3D\src_main\dlls\combat.cpp" -"D:\Xash3D\src_main\dlls\controller.cpp" -"D:\Xash3D\src_main\dlls\crossbow.cpp" -"D:\Xash3D\src_main\dlls\crowbar.cpp" -"D:\Xash3D\src_main\dlls\defaultai.cpp" -"D:\Xash3D\src_main\dlls\doors.cpp" -"D:\Xash3D\src_main\dlls\effects.cpp" -"D:\Xash3D\src_main\dlls\egon.cpp" -"D:\Xash3D\src_main\dlls\explode.cpp" -"D:\Xash3D\src_main\dlls\flyingmonster.cpp" -"D:\Xash3D\src_main\dlls\func_break.cpp" -"D:\Xash3D\src_main\dlls\func_tank.cpp" -"D:\Xash3D\src_main\dlls\game.cpp" -"D:\Xash3D\src_main\dlls\gamerules.cpp" -"D:\Xash3D\src_main\dlls\gargantua.cpp" -"D:\Xash3D\src_main\dlls\gauss.cpp" -"D:\Xash3D\src_main\dlls\genericmonster.cpp" -"D:\Xash3D\src_main\dlls\ggrenade.cpp" -"D:\Xash3D\src_main\dlls\globals.cpp" -"D:\Xash3D\src_main\dlls\gman.cpp" -"D:\Xash3D\src_main\dlls\h_ai.cpp" -"D:\Xash3D\src_main\dlls\h_battery.cpp" -"D:\Xash3D\src_main\dlls\h_cine.cpp" -"D:\Xash3D\src_main\dlls\h_cycler.cpp" -"D:\Xash3D\src_main\dlls\h_export.cpp" -"D:\Xash3D\src_main\dlls\handgrenade.cpp" -"D:\Xash3D\src_main\dlls\hassassin.cpp" -"D:\Xash3D\src_main\dlls\headcrab.cpp" -"D:\Xash3D\src_main\dlls\healthkit.cpp" -"D:\Xash3D\src_main\dlls\hgrunt.cpp" -"D:\Xash3D\src_main\dlls\wpn_shared\hl_wpn_glock.cpp" -"D:\Xash3D\src_main\dlls\hornet.cpp" -"D:\Xash3D\src_main\dlls\hornetgun.cpp" -"D:\Xash3D\src_main\dlls\houndeye.cpp" -"D:\Xash3D\src_main\dlls\ichthyosaur.cpp" -"D:\Xash3D\src_main\dlls\islave.cpp" -"D:\Xash3D\src_main\dlls\items.cpp" -"D:\Xash3D\src_main\dlls\leech.cpp" -"D:\Xash3D\src_main\dlls\lights.cpp" -"D:\Xash3D\src_main\dlls\maprules.cpp" -"D:\Xash3D\src_main\dlls\monstermaker.cpp" -"D:\Xash3D\src_main\dlls\monsters.cpp" -"D:\Xash3D\src_main\dlls\monsterstate.cpp" -"D:\Xash3D\src_main\dlls\mortar.cpp" -"D:\Xash3D\src_main\dlls\mp5.cpp" -"D:\Xash3D\src_main\dlls\multiplay_gamerules.cpp" -"D:\Xash3D\src_main\dlls\nihilanth.cpp" -"D:\Xash3D\src_main\dlls\nodes.cpp" -"D:\Xash3D\src_main\dlls\osprey.cpp" -"D:\Xash3D\src_main\dlls\pathcorner.cpp" -"D:\Xash3D\src_main\dlls\plane.cpp" -"D:\Xash3D\src_main\dlls\plats.cpp" -"D:\Xash3D\src_main\dlls\player.cpp" -"D:\Xash3D\src_main\pm_shared\pm_debug.c" -"D:\Xash3D\src_main\pm_shared\pm_math.c" -"D:\Xash3D\src_main\pm_shared\pm_shared.c" -"D:\Xash3D\src_main\dlls\python.cpp" -"D:\Xash3D\src_main\dlls\rat.cpp" -"D:\Xash3D\src_main\dlls\roach.cpp" -"D:\Xash3D\src_main\dlls\rpg.cpp" -"D:\Xash3D\src_main\dlls\satchel.cpp" -"D:\Xash3D\src_main\dlls\schedule.cpp" -"D:\Xash3D\src_main\dlls\scientist.cpp" -"D:\Xash3D\src_main\dlls\scripted.cpp" -"D:\Xash3D\src_main\dlls\shotgun.cpp" -"D:\Xash3D\src_main\dlls\singleplay_gamerules.cpp" -"D:\Xash3D\src_main\dlls\skill.cpp" -"D:\Xash3D\src_main\dlls\sound.cpp" -"D:\Xash3D\src_main\dlls\soundent.cpp" -"D:\Xash3D\src_main\dlls\spectator.cpp" -"D:\Xash3D\src_main\dlls\squadmonster.cpp" -"D:\Xash3D\src_main\dlls\squeakgrenade.cpp" -"D:\Xash3D\src_main\dlls\subs.cpp" -"D:\Xash3D\src_main\dlls\talkmonster.cpp" -"D:\Xash3D\src_main\dlls\teamplay_gamerules.cpp" -"D:\Xash3D\src_main\dlls\tempmonster.cpp" -"D:\Xash3D\src_main\dlls\tentacle.cpp" -"D:\Xash3D\src_main\dlls\triggers.cpp" -"D:\Xash3D\src_main\dlls\tripmine.cpp" -"D:\Xash3D\src_main\dlls\turret.cpp" -"D:\Xash3D\src_main\dlls\util.cpp" -"D:\Xash3D\src_main\game_shared\voice_gamemgr.cpp" -"D:\Xash3D\src_main\dlls\weapons.cpp" -"D:\Xash3D\src_main\dlls\world.cpp" -"D:\Xash3D\src_main\dlls\xen.cpp" -"D:\Xash3D\src_main\dlls\zombie.cpp" -] -Creating command line "cl.exe @"C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP3740.tmp"" -Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP3741.tmp" with contents -[ -user32.lib advapi32.lib /nologo /subsystem:windows /dll /incremental:yes /pdb:"..\temp\dlls\!debug/hl.pdb" /debug /machine:I386 /def:".\hl.def" /out:"..\temp\dlls\!debug/hl.dll" /implib:"..\temp\dlls\!debug/hl.lib" -"\Xash3D\src_main\temp\dlls\!debug\aflock.obj" -"\Xash3D\src_main\temp\dlls\!debug\agrunt.obj" -"\Xash3D\src_main\temp\dlls\!debug\airtank.obj" -"\Xash3D\src_main\temp\dlls\!debug\animating.obj" -"\Xash3D\src_main\temp\dlls\!debug\animation.obj" -"\Xash3D\src_main\temp\dlls\!debug\apache.obj" -"\Xash3D\src_main\temp\dlls\!debug\barnacle.obj" -"\Xash3D\src_main\temp\dlls\!debug\barney.obj" -"\Xash3D\src_main\temp\dlls\!debug\bigmomma.obj" -"\Xash3D\src_main\temp\dlls\!debug\bloater.obj" -"\Xash3D\src_main\temp\dlls\!debug\bmodels.obj" -"\Xash3D\src_main\temp\dlls\!debug\bullsquid.obj" -"\Xash3D\src_main\temp\dlls\!debug\buttons.obj" -"\Xash3D\src_main\temp\dlls\!debug\cbase.obj" -"\Xash3D\src_main\temp\dlls\!debug\client.obj" -"\Xash3D\src_main\temp\dlls\!debug\combat.obj" -"\Xash3D\src_main\temp\dlls\!debug\controller.obj" -"\Xash3D\src_main\temp\dlls\!debug\crossbow.obj" -"\Xash3D\src_main\temp\dlls\!debug\crowbar.obj" -"\Xash3D\src_main\temp\dlls\!debug\defaultai.obj" -"\Xash3D\src_main\temp\dlls\!debug\doors.obj" -"\Xash3D\src_main\temp\dlls\!debug\effects.obj" -"\Xash3D\src_main\temp\dlls\!debug\egon.obj" -"\Xash3D\src_main\temp\dlls\!debug\explode.obj" -"\Xash3D\src_main\temp\dlls\!debug\flyingmonster.obj" -"\Xash3D\src_main\temp\dlls\!debug\func_break.obj" -"\Xash3D\src_main\temp\dlls\!debug\func_tank.obj" -"\Xash3D\src_main\temp\dlls\!debug\game.obj" -"\Xash3D\src_main\temp\dlls\!debug\gamerules.obj" -"\Xash3D\src_main\temp\dlls\!debug\gargantua.obj" -"\Xash3D\src_main\temp\dlls\!debug\gauss.obj" -"\Xash3D\src_main\temp\dlls\!debug\genericmonster.obj" -"\Xash3D\src_main\temp\dlls\!debug\ggrenade.obj" -"\Xash3D\src_main\temp\dlls\!debug\globals.obj" -"\Xash3D\src_main\temp\dlls\!debug\gman.obj" -"\Xash3D\src_main\temp\dlls\!debug\h_ai.obj" -"\Xash3D\src_main\temp\dlls\!debug\h_battery.obj" -"\Xash3D\src_main\temp\dlls\!debug\h_cine.obj" -"\Xash3D\src_main\temp\dlls\!debug\h_cycler.obj" -"\Xash3D\src_main\temp\dlls\!debug\h_export.obj" -"\Xash3D\src_main\temp\dlls\!debug\handgrenade.obj" -"\Xash3D\src_main\temp\dlls\!debug\hassassin.obj" -"\Xash3D\src_main\temp\dlls\!debug\headcrab.obj" -"\Xash3D\src_main\temp\dlls\!debug\healthkit.obj" -"\Xash3D\src_main\temp\dlls\!debug\hgrunt.obj" -"\Xash3D\src_main\temp\dlls\!debug\hl_wpn_glock.obj" -"\Xash3D\src_main\temp\dlls\!debug\hornet.obj" -"\Xash3D\src_main\temp\dlls\!debug\hornetgun.obj" -"\Xash3D\src_main\temp\dlls\!debug\houndeye.obj" -"\Xash3D\src_main\temp\dlls\!debug\ichthyosaur.obj" -"\Xash3D\src_main\temp\dlls\!debug\islave.obj" -"\Xash3D\src_main\temp\dlls\!debug\items.obj" -"\Xash3D\src_main\temp\dlls\!debug\leech.obj" -"\Xash3D\src_main\temp\dlls\!debug\lights.obj" -"\Xash3D\src_main\temp\dlls\!debug\maprules.obj" -"\Xash3D\src_main\temp\dlls\!debug\monstermaker.obj" -"\Xash3D\src_main\temp\dlls\!debug\monsters.obj" -"\Xash3D\src_main\temp\dlls\!debug\monsterstate.obj" -"\Xash3D\src_main\temp\dlls\!debug\mortar.obj" -"\Xash3D\src_main\temp\dlls\!debug\mp5.obj" -"\Xash3D\src_main\temp\dlls\!debug\multiplay_gamerules.obj" -"\Xash3D\src_main\temp\dlls\!debug\nihilanth.obj" -"\Xash3D\src_main\temp\dlls\!debug\nodes.obj" -"\Xash3D\src_main\temp\dlls\!debug\osprey.obj" -"\Xash3D\src_main\temp\dlls\!debug\pathcorner.obj" -"\Xash3D\src_main\temp\dlls\!debug\plane.obj" -"\Xash3D\src_main\temp\dlls\!debug\plats.obj" -"\Xash3D\src_main\temp\dlls\!debug\player.obj" -"\Xash3D\src_main\temp\dlls\!debug\pm_debug.obj" -"\Xash3D\src_main\temp\dlls\!debug\pm_math.obj" -"\Xash3D\src_main\temp\dlls\!debug\pm_shared.obj" -"\Xash3D\src_main\temp\dlls\!debug\python.obj" -"\Xash3D\src_main\temp\dlls\!debug\rat.obj" -"\Xash3D\src_main\temp\dlls\!debug\roach.obj" -"\Xash3D\src_main\temp\dlls\!debug\rpg.obj" -"\Xash3D\src_main\temp\dlls\!debug\satchel.obj" -"\Xash3D\src_main\temp\dlls\!debug\schedule.obj" -"\Xash3D\src_main\temp\dlls\!debug\scientist.obj" -"\Xash3D\src_main\temp\dlls\!debug\scripted.obj" -"\Xash3D\src_main\temp\dlls\!debug\shotgun.obj" -"\Xash3D\src_main\temp\dlls\!debug\singleplay_gamerules.obj" -"\Xash3D\src_main\temp\dlls\!debug\skill.obj" -"\Xash3D\src_main\temp\dlls\!debug\sound.obj" -"\Xash3D\src_main\temp\dlls\!debug\soundent.obj" -"\Xash3D\src_main\temp\dlls\!debug\spectator.obj" -"\Xash3D\src_main\temp\dlls\!debug\squadmonster.obj" -"\Xash3D\src_main\temp\dlls\!debug\squeakgrenade.obj" -"\Xash3D\src_main\temp\dlls\!debug\subs.obj" -"\Xash3D\src_main\temp\dlls\!debug\talkmonster.obj" -"\Xash3D\src_main\temp\dlls\!debug\teamplay_gamerules.obj" -"\Xash3D\src_main\temp\dlls\!debug\tempmonster.obj" -"\Xash3D\src_main\temp\dlls\!debug\tentacle.obj" -"\Xash3D\src_main\temp\dlls\!debug\triggers.obj" -"\Xash3D\src_main\temp\dlls\!debug\tripmine.obj" -"\Xash3D\src_main\temp\dlls\!debug\turret.obj" -"\Xash3D\src_main\temp\dlls\!debug\util.obj" -"\Xash3D\src_main\temp\dlls\!debug\voice_gamemgr.obj" -"\Xash3D\src_main\temp\dlls\!debug\weapons.obj" -"\Xash3D\src_main\temp\dlls\!debug\world.obj" -"\Xash3D\src_main\temp\dlls\!debug\xen.obj" -"\Xash3D\src_main\temp\dlls\!debug\zombie.obj" -] -Creating command line "link.exe @"C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP3741.tmp"" -Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP3742.bat" with contents +Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP614.bat" with contents [ @echo off -copy \Xash3D\src_main\temp\dlls\!debug\hl.dll "D:\Xash3D\valve\dlls\hl.dll" +copy \Xash3D\src_main\temp\dlls\!release\hl.dll "D:\Xash3D\valve\dlls\hl.dll" ] -Creating command line ""C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP3742.bat"" -Compiling... -aflock.cpp -agrunt.cpp -airtank.cpp -animating.cpp -animation.cpp -apache.cpp -barnacle.cpp -barney.cpp -bigmomma.cpp -bloater.cpp -bmodels.cpp -bullsquid.cpp -buttons.cpp -cbase.cpp -cl.exe terminated at user request. +Creating command line ""C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP614.bat"" +

Output Window

+Performing Custom Build Step on \Xash3D\src_main\temp\dlls\!release\hl.dll +‘ª®¯¨à®¢ ­® ä ©«®¢: 1. + + +

Results

+hl.dll - 0 error(s), 0 warning(s)
diff --git a/engine/client/cl_frame.c b/engine/client/cl_frame.c index 24cfbaf5..56d4b802 100644 --- a/engine/client/cl_frame.c +++ b/engine/client/cl_frame.c @@ -168,10 +168,8 @@ qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType ) if(( ent->index - 1 ) == cl.playernum && ent != &clgame.viewent && cl.thirdperson == false && cls.key_dest != key_menu && cl.refdef.viewentity == ( cl.playernum + 1 )) { -#ifdef MIRROR_TEST - // will be drawn in mirror - R_AddEntity( ent, entityType ); -#endif + if( gl_allow_mirrors->integer && world.has_mirrors ) + R_AddEntity( ent, entityType ); // will be drawn in mirror } else { diff --git a/engine/client/cl_game.c b/engine/client/cl_game.c index 4e8d5909..3e736abc 100644 --- a/engine/client/cl_game.c +++ b/engine/client/cl_game.c @@ -1357,6 +1357,7 @@ void CL_ClearWorld( void ) cl.world->index = 0; clgame.ds.cullMode = GL_FRONT; + clgame.numStatics = 0; } void CL_InitEdicts( void ) @@ -1367,6 +1368,8 @@ void CL_InitEdicts( void ) cls.num_client_entities = CL_UPDATE_BACKUP * 64; cls.packet_entities = Z_Realloc( cls.packet_entities, sizeof( entity_state_t ) * cls.num_client_entities ); clgame.entities = Mem_Alloc( clgame.mempool, sizeof( cl_entity_t ) * clgame.maxEntities ); + clgame.static_entities = Mem_Alloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES ); + clgame.numStatics = 0; if(( clgame.maxRemapInfos - 1 ) != clgame.maxEntities ) { @@ -1382,11 +1385,17 @@ void CL_FreeEdicts( void ) Mem_Free( clgame.entities ); clgame.entities = NULL; + if( clgame.static_entities ) + Mem_Free( clgame.static_entities ); + clgame.static_entities = NULL; + if( cls.packet_entities ) Z_Free( cls.packet_entities ); + cls.packet_entities = NULL; cls.num_client_entities = 0; cls.next_client_entities = 0; + clgame.numStatics = 0; } /* @@ -3460,7 +3469,7 @@ Voice_StartVoiceTweakMode */ int Voice_StartVoiceTweakMode( void ) { - // UNDONE: wait for voice implementation + // TODO: implement return 0; } diff --git a/engine/client/cl_menu.c b/engine/client/cl_menu.c index a0a60caa..3e4a404a 100644 --- a/engine/client/cl_menu.c +++ b/engine/client/cl_menu.c @@ -348,6 +348,7 @@ pfnPIC_Load static HIMAGE pfnPIC_Load( const char *szPicName, const byte *image_buf, long image_size ) { HIMAGE tx; + int flags = TF_IMAGE; if( !szPicName || !*szPicName ) { @@ -355,8 +356,12 @@ static HIMAGE pfnPIC_Load( const char *szPicName, const byte *image_buf, long im return 0; } + // HACKHACK: keep source for gfx\shell\gamma + if( !glConfig.deviceSupportsGamma && Q_stristr( szPicName, "gamma" )) + flags |= TF_KEEP_RGBDATA; + host.decal_loading = true; - tx = GL_LoadTexture( szPicName, image_buf, image_size, TF_IMAGE ); + tx = GL_LoadTexture( szPicName, image_buf, image_size, flags ); host.decal_loading = false; return tx; @@ -920,6 +925,7 @@ static ui_enginefuncs_t gEngfuncs = Com_RandomLong, IN_SetCursor, pfnIsMapValid, + GL_ProcessTexture, }; void UI_UnloadProgs( void ) diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index e3151c2f..984fe003 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -346,42 +346,70 @@ void CL_ParseParticles( sizebuf_t *msg ) ================== CL_ParseStaticEntity +UDNONE: we need a client implementation of save\restore for use it not in multiplayer only +wait for XashXT when it should be done ================== */ void CL_ParseStaticEntity( sizebuf_t *msg ) { - entity_state_t ent; + entity_state_t state; + cl_entity_t *ent; int i; - Q_memset( &ent, 0, sizeof( ent )); + Q_memset( &state, 0, sizeof( state )); - ent.modelindex = BF_ReadShort( msg ); - ent.sequence = BF_ReadByte( msg ); - ent.frame = BF_ReadByte( msg ); - ent.colormap = BF_ReadWord( msg ); - ent.skin = BF_ReadByte( msg ); + state.modelindex = BF_ReadShort( msg ); + state.sequence = BF_ReadByte( msg ); + state.frame = BF_ReadByte( msg ); + state.colormap = BF_ReadWord( msg ); + state.skin = BF_ReadByte( msg ); for( i = 0; i < 3; i++ ) { - ent.origin[i] = BF_ReadBitCoord( msg ); - ent.angles[i] = BF_ReadBitAngle( msg, 16 ); + state.origin[i] = BF_ReadBitCoord( msg ); + state.angles[i] = BF_ReadBitAngle( msg, 16 ); } - ent.rendermode = BF_ReadByte( msg ); + state.rendermode = BF_ReadByte( msg ); - if( ent.rendermode != kRenderNormal ) + if( state.rendermode != kRenderNormal ) { - ent.renderamt = BF_ReadByte( msg ); - ent.rendercolor.r = BF_ReadByte( msg ); - ent.rendercolor.g = BF_ReadByte( msg ); - ent.rendercolor.b = BF_ReadByte( msg ); - ent.renderfx = BF_ReadByte( msg ); + state.renderamt = BF_ReadByte( msg ); + state.rendercolor.r = BF_ReadByte( msg ); + state.rendercolor.g = BF_ReadByte( msg ); + state.rendercolor.b = BF_ReadByte( msg ); + state.renderfx = BF_ReadByte( msg ); } -// R_AddEfrags( ent ); + i = clgame.numStatics; + if( i >= MAX_STATIC_ENTITIES ) + { + MsgDev( D_ERROR, "CL_ParseStaticEntity: static entities limit exceeded!\n" ); + return; + } - // TODO: allocate client entity, add new static... - MsgDev( D_ERROR, "Static entities are not implemented\n" ); + ent = &clgame.static_entities[i]; + clgame.numStatics++; + + ent->index = 0; // ??? + ent->baseline = state; + ent->curstate = state; + ent->prevstate = state; + + // setup the new static entity + CL_UpdateEntityFields( ent ); + + if( Mod_GetType( state.modelindex ) == mod_studio ) + { + CL_UpdateStudioVars( ent, &state, true ); + + // animate studio model + ent->curstate.animtime = cl.time; + ent->curstate.framerate = 1.0f; + ent->latched.prevframe = 0.0f; + } + + R_AddEfrags( ent ); // add link } /* @@ -430,7 +458,7 @@ void CL_ParseReliableEvent( sizebuf_t *msg, int flags ) Q_memset( &nullargs, 0, sizeof( nullargs )); event_index = BF_ReadWord( msg ); // read event index delay = (float)BF_ReadWord( msg ) / 100.0f; // read event delay - MSG_ReadDeltaEvent( msg, &nullargs, &args ); // TODO: delta-compressing + MSG_ReadDeltaEvent( msg, &nullargs, &args ); // reliable events not use delta CL_QueueEvent( flags, event_index, delay, &args ); } diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 49d08937..58545695 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -2622,10 +2622,10 @@ void CL_ClearEfrags( void ) Q_memset( cl_efrags, 0, sizeof( cl_efrags )); // allocate the efrags and chain together into a free list - cl.free_efrags = cl_efrags; + clgame.free_efrags = cl_efrags; for( i = 0; i < MAX_EFRAGS - 1; i++ ) - cl.free_efrags[i].entnext = &cl.free_efrags[i+1]; - cl.free_efrags[i].entnext = NULL; + clgame.free_efrags[i].entnext = &clgame.free_efrags[i+1]; + clgame.free_efrags[i].entnext = NULL; } /* diff --git a/engine/client/client.h b/engine/client/client.h index 2ca760e7..36db622e 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -34,8 +34,9 @@ GNU General Public License for more details. #define MAX_MOVIES 8 #define MAX_CDTRACKS 32 #define MAX_IMAGES 256 // SpriteTextures -#define MAX_EFRAGS 640 +#define MAX_EFRAGS 256 // g-cont. just no need more #define MAX_REQUESTS 32 +#define MAX_STATIC_ENTITIES 128 // same as in quake1 // screenshot types #define VID_SCREENSHOT 0 @@ -141,7 +142,6 @@ typedef struct cl_entity_t *world; model_t *worldmodel; // pointer to world - efrag_t *free_efrags; } client_t; /* @@ -362,10 +362,12 @@ typedef struct string itemspath; // path to items description for auto-complete func cl_entity_t *entities; // dynamically allocated entity array + cl_entity_t *static_entities; // dynamically allocated static entity array remap_info_t **remap_info; // store local copy of all remap textures for each entity int maxEntities; int maxRemapInfos; // maxEntities + cl.viewEnt; also used for catch entcount + int numStatics; // actual static entity count // movement values from server movevars_t movevars; @@ -399,6 +401,7 @@ typedef struct net_request_t net_requests[MAX_REQUESTS]; // no reason to keep more + efrag_t *free_efrags; // efrags cl_entity_t viewent; // viewmodel } clgame_static_t; @@ -695,6 +698,8 @@ qboolean CL_InitStudioAPI( void ); void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ); qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType ); qboolean CL_GetEntitySpatialization( int ent, vec3_t origin, vec3_t velocity ); +void CL_UpdateStudioVars( cl_entity_t *ent, entity_state_t *newstate, qboolean noInterp ); +void CL_UpdateEntityFields( cl_entity_t *ent ); qboolean CL_IsPlayerIndex( int idx ); // diff --git a/engine/client/gl_backend.c b/engine/client/gl_backend.c index 4ea9bf46..3eb5cb45 100644 --- a/engine/client/gl_backend.c +++ b/engine/client/gl_backend.c @@ -393,7 +393,7 @@ VID_ImageAdjustGamma void VID_ImageAdjustGamma( byte *in, uint width, uint height ) { int i, c = width * height; - float g = 1.0f / bound( 0.5f, vid_gamma->value, 3.0f ); + float g = 1.0f / bound( 0.5f, vid_gamma->value, 2.3f ); byte r_gammaTable[256]; // adjust screenshot gamma byte *p = in; @@ -459,7 +459,7 @@ qboolean VID_ScreenShot( const char *filename, int shot_type ) break; } - Image_Process( &r_shot, width, height, flags ); + Image_Process( &r_shot, width, height, 0.0f, flags ); // write image result = FS_SaveImage( filename, r_shot ); @@ -524,7 +524,7 @@ qboolean VID_CubemapShot( const char *base, uint size, const float *vieworg, qbo r_side->size = r_side->width * r_side->height * 3; r_side->buffer = temp; - if( flags ) Image_Process( &r_side, 0, 0, flags ); + if( flags ) Image_Process( &r_side, 0, 0, 0.0f, flags ); Q_memcpy( buffer + (size * size * 3 * i), r_side->buffer, size * size * 3 ); } diff --git a/engine/client/gl_beams.c b/engine/client/gl_beams.c index 58ce63a6..52569750 100644 --- a/engine/client/gl_beams.c +++ b/engine/client/gl_beams.c @@ -142,7 +142,7 @@ static void ComputeBeamPerpendicular( const vec3_t vecBeamDelta, vec3_t pPerp ) vec3_t vecBeamCenter; VectorNormalize2( vecBeamDelta, vecBeamCenter ); - CrossProduct( cl.refdef.forward, vecBeamCenter, pPerp ); + CrossProduct( RI.vforward, vecBeamCenter, pPerp ); VectorNormalize( pPerp ); } @@ -154,7 +154,7 @@ static void ComputeNormal( const vec3_t vStartPos, const vec3_t vNextPos, vec3_t VectorSubtract( vStartPos, vNextPos, vTangentY ); // vDirToBeam = vector from viewer origin to beam - VectorSubtract( vStartPos, cl.refdef.vieworg, vDirToBeam ); + VectorSubtract( vStartPos, RI.vieworg, vDirToBeam ); // Get a vector that is perpendicular to us and perpendicular to the beam. // This is used to fatten the beam. @@ -212,18 +212,13 @@ static void CL_DrawSegs( int modelIndex, float frame, int rendermode, const vec3 if( segments < 2 ) segments = 2; } - if( segments > NOISE_DIVISIONS ) // UNDONE: Allow more segments? - { + if( segments > NOISE_DIVISIONS ) segments = NOISE_DIVISIONS; - } div = 1.0f / (segments - 1); length *= 0.01f; - - // UNDONE: Expose texture length scale factor to control "fuzziness" vStep = length * div; // Texture length texels per space pixel - // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture) vLast = fmod( freq * speed, 1 ); @@ -314,11 +309,11 @@ static void CL_DrawSegs( int modelIndex, float frame, int rendermode, const vec3 float s, c; SinCos( fraction * M_PI * length + freq, &s, &c ); - VectorMA( nextSeg.pos, (factor * s), cl.refdef.up, nextSeg.pos ); + VectorMA( nextSeg.pos, (factor * s), RI.vup, nextSeg.pos ); // rotate the noise along the perpendicluar axis a bit to keep the bolt // from looking diagonal - VectorMA( nextSeg.pos, (factor * c), cl.refdef.right, nextSeg.pos ); + VectorMA( nextSeg.pos, (factor * c), RI.vright, nextSeg.pos ); } else { @@ -416,18 +411,15 @@ static void CL_DrawDisk( int modelIndex, float frame, int rendermode, const vec3 if( !m_hSprite || segments < 2 ) return; - if( segments > NOISE_DIVISIONS ) // UNDONE: Allow more segments? + if( segments > NOISE_DIVISIONS ) segments = NOISE_DIVISIONS; length = VectorLength( delta ) * 0.01f; if( length < 0.5f ) length = 0.5f; // don't lose all of the noise/texture on short beams div = 1.0f / (segments - 1); - - // UNDONE: Expose texture length scale factor to control "fuzziness" vStep = length * div; // Texture length texels per space pixel - // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture) vLast = fmod( freq * speed, 1 ); scale = scale * length; @@ -487,18 +479,15 @@ static void CL_DrawCylinder( int modelIndex, float frame, int rendermode, const if( !m_hSprite || segments < 2 ) return; - if( segments > NOISE_DIVISIONS ) // UNDONE: Allow more segments? + if( segments > NOISE_DIVISIONS ) segments = NOISE_DIVISIONS; length = VectorLength( delta ) * 0.01f; if( length < 0.5f ) length = 0.5f; // Don't lose all of the noise/texture on short beams div = 1.0f / (segments - 1); - - // UNDONE: Expose texture length scale factor to control "fuzziness" vStep = length * div; // Texture length texels per space pixel - // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture) vLast = fmod( freq * speed, 1.0f ); scale = scale * length; @@ -567,7 +556,7 @@ void CL_DrawRing( int modelIndex, float frame, int rendermode, const vec3_t sour VectorClear( screenLast ); segments = segments * M_PI; - if( segments > NOISE_DIVISIONS * 8 ) // UNDONE: Allow more segments? + if( segments > NOISE_DIVISIONS * 8 ) segments = NOISE_DIVISIONS * 8; length = VectorLength( d ) * 0.01f * M_PI; @@ -575,10 +564,8 @@ void CL_DrawRing( int modelIndex, float frame, int rendermode, const vec3_t sour div = 1.0 / ( segments - 1 ); - // UNDONE: Expose texture length scale factor to control "fuzziness" vStep = length * div / 8.0f; // Texture length texels per space pixel - // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture) vLast = fmod( freq * speed, 1.0f ); scale = amplitude * length / 8.0f; @@ -633,12 +620,12 @@ void CL_DrawRing( int modelIndex, float frame, int rendermode, const vec3_t sour // Distort using noise factor = rgNoise[(noiseIndex >> 16) & (NOISE_DIVISIONS - 1)] * scale; - VectorMA( point, factor, cl.refdef.up, point ); + VectorMA( point, factor, RI.vup, point ); // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal factor = rgNoise[(noiseIndex>>16) & (NOISE_DIVISIONS - 1)] * scale; factor *= cos( fraction * M_PI * 24 + freq ); - VectorMA( point, factor, cl.refdef.right, point ); + VectorMA( point, factor, RI.vright, point ); // Transform point into screen space TriWorldToScreen( point, screen ); @@ -653,8 +640,8 @@ void CL_DrawRing( int modelIndex, float frame, int rendermode, const vec3_t sour VectorNormalize( tmp ); // Build point along normal line (normal is -y, x) - VectorScale( cl.refdef.up, tmp[0], normal ); - VectorMA( normal, tmp[1], cl.refdef.right, normal ); + VectorScale( RI.vup, tmp[0], normal ); + VectorMA( normal, tmp[1], RI.vright, normal ); // make a wide line VectorMA( point, width, normal, last1 ); @@ -694,7 +681,6 @@ Helper to drawing laser void CL_DrawLaser( BEAM *pbeam, int frame, int rendermode, float *color, int spriteIndex ) { float color2[3]; - vec3_t vecForward; vec3_t beamDir; float flDot; @@ -703,8 +689,7 @@ void CL_DrawLaser( BEAM *pbeam, int frame, int rendermode, float *color, int spr VectorSubtract( pbeam->target, pbeam->source, beamDir ); VectorNormalize( beamDir ); - AngleVectors( cl.refdef.viewangles, vecForward, NULL, NULL ); - flDot = DotProduct( beamDir, vecForward ); + flDot = DotProduct( beamDir, RI.vforward ); // abort if the player's looking along it away from the source if( flDot > 0 ) @@ -719,7 +704,7 @@ void CL_DrawLaser( BEAM *pbeam, int frame, int rendermode, float *color, int spr float flDistance; // Fade the beam based on the player's proximity to the beam - VectorSubtract( cl.refdef.vieworg, pbeam->source, localDir ); + VectorSubtract( RI.vieworg, pbeam->source, localDir ); flDot = DotProduct( beamDir, localDir ); VectorScale( beamDir, flDot, vecProjection ); VectorSubtract( localDir, vecProjection, tmp ); @@ -764,9 +749,7 @@ static void DrawBeamFollow( int modelIndex, particle_t *pHead, int frame, int re rgb_t nColor; m_hSprite = R_GetSpriteTexture( Mod_Handle( modelIndex ), frame ); - - if( !m_hSprite ) - return; + if( !m_hSprite ) return; // UNDONE: This won't work, screen and screenLast must be extrapolated here to fix the // first beam segment for this trail @@ -778,8 +761,8 @@ static void DrawBeamFollow( int modelIndex, particle_t *pHead, int frame, int re VectorNormalize( tmp ); // Build point along noraml line (normal is -y, x) - VectorScale( cl.refdef.up, tmp[0], normal ); // Build point along normal line (normal is -y, x) - VectorMA( normal, tmp[1], cl.refdef.right, normal ); + VectorScale( RI.vup, tmp[0], normal ); // Build point along normal line (normal is -y, x) + VectorMA( normal, tmp[1], RI.vright, normal ); // make a wide line VectorMA( delta, width, normal, last1 ); @@ -818,8 +801,8 @@ static void DrawBeamFollow( int modelIndex, particle_t *pHead, int frame, int re VectorNormalize( tmp ); // build point along normal line (normal is -y, x) - VectorScale( cl.refdef.up, tmp[0], normal ); - VectorMA( normal, tmp[1], cl.refdef.right, normal ); + VectorScale( RI.vup, tmp[0], normal ); + VectorMA( normal, tmp[1], RI.vright, normal ); // Make a wide line VectorMA( pHead->org, width, normal, last1 ); diff --git a/engine/client/gl_cull.c b/engine/client/gl_cull.c index 88b4eee8..43b44b27 100644 --- a/engine/client/gl_cull.c +++ b/engine/client/gl_cull.c @@ -143,4 +143,77 @@ int R_CullModel( cl_entity_t *e, vec3_t origin, vec3_t mins, vec3_t maxs, float return 1; return 0; +} + +/* +================= +R_CullSurface + +cull invisible surfaces +================= +*/ +qboolean R_CullSurface( msurface_t *surf, uint clipflags ) +{ + mextrasurf_t *info; + + if( !surf || !surf->texinfo || !surf->texinfo->texture ) + return true; + + if( surf->flags & SURF_WATERCSG && !( RI.currententity->curstate.effects & EF_NOWATERCSG )) + return true; + + if( surf->flags & SURF_NOCULL ) + return false; + + if( r_nocull->integer ) + return false; + + // world surfaces can be culled by vis frame too + if( RI.currententity == clgame.entities && surf->visframe != tr.framecount ) + return true; + + if( r_faceplanecull->integer && glState.faceCull != 0 ) + { + if(!(surf->flags & SURF_DRAWTURB) || !RI.currentWaveHeight ) + { + if( !VectorIsNull( surf->plane->normal )) + { + float dist; + + if( RI.drawOrtho ) dist = surf->plane->normal[2]; + else dist = PlaneDiff( tr.modelorg, surf->plane ); + + if( glState.faceCull == GL_FRONT || ( RI.params & RP_MIRRORVIEW )) + { + if( surf->flags & SURF_PLANEBACK ) + { + if( dist >= -BACKFACE_EPSILON ) + return true; // wrong side + } + else + { + if( dist <= BACKFACE_EPSILON ) + return true; // wrong side + } + } + else if( glState.faceCull == GL_BACK ) + { + if( surf->flags & SURF_PLANEBACK ) + { + if( dist <= BACKFACE_EPSILON ) + return true; // wrong side + } + else + { + if( dist >= -BACKFACE_EPSILON ) + return true; // wrong side + } + } + } + } + } + + info = SURF_INFO( surf, RI.currentmodel ); + + return ( clipflags && R_CullBox( info->mins, info->maxs, clipflags )); } \ No newline at end of file diff --git a/engine/client/gl_decals.c b/engine/client/gl_decals.c index fbc2f3fd..1a4a5be9 100644 --- a/engine/client/gl_decals.c +++ b/engine/client/gl_decals.c @@ -963,11 +963,9 @@ static int DecalListAdd( decallist_t *pList, int count ) if( !Q_strcmp( pdecal->name, pList[i].name ) && pdecal->entityIndex == pList[i].entityIndex ) { VectorSubtract( pdecal->position, pList[i].position, tmp ); // Merge - if( VectorLength( tmp ) < 2 ) - { - // UNDONE: Tune this '2' constant + + if( VectorLength( tmp ) < 2 ) // UNDONE: Tune this '2' constant return count; - } } } diff --git a/engine/client/gl_image.c b/engine/client/gl_image.c index 2aca9b63..f80dd3d9 100644 --- a/engine/client/gl_image.c +++ b/engine/client/gl_image.c @@ -676,6 +676,34 @@ byte *GL_ResampleTexture( const byte *source, int inWidth, int inHeight, int out return scaledImage; } +/* +================= +GL_ResampleTexture + +Assume input buffer is RGBA +================= +*/ +byte *GL_ApplyGamma( const byte *source, int pixels, qboolean isNormalMap ) +{ + byte *in = (byte *)source; + byte *out = (byte *)source; + int i; + + if( isNormalMap ) + { + } + else + { + for( i = 0; i < pixels; i++, in += 4 ) + { + in[0] = TextureToGamma( in[0] ); + in[1] = TextureToGamma( in[1] ); + in[2] = TextureToGamma( in[2] ); + } + } + return out; +} + /* ================= GL_BuildMipMap @@ -851,7 +879,7 @@ static void GL_UploadTexture( rgbdata_t *pic, gltexture_t *tex, qboolean subImag img_flags |= IMAGE_FORCE_RGBA; // processing image before uploading (force to rgba, make luma etc) - if( pic->buffer ) Image_Process( &pic, 0, 0, img_flags ); + if( pic->buffer ) Image_Process( &pic, 0, 0, 0.0f, img_flags ); if( tex->flags & TF_LUMINANCE ) { @@ -930,7 +958,13 @@ static void GL_UploadTexture( rgbdata_t *pic, gltexture_t *tex, qboolean subImag { data = GL_ResampleTexture( buf, tex->srcWidth, tex->srcHeight, tex->width, tex->height, ( tex->flags & TF_NORMALMAP )); } - + + if( !glConfig.deviceSupportsGamma ) + { + if(!( tex->flags & TF_NOMIPMAP ) && !( tex->flags & TF_SKYSIDE )) + data = GL_ApplyGamma( data, tex->width * tex->height, ( tex->flags & TF_NORMALMAP )); + } + if( GL_Support( GL_SGIS_MIPMAPS_EXT )) GL_GenerateMipmaps( data, pic, tex, glTarget, inFormat, i, subImage ); if( subImage ) pglTexSubImage2D( tex->target + i, 0, 0, 0, tex->width, tex->height, inFormat, GL_UNSIGNED_BYTE, data ); else pglTexImage2D( tex->target + i, 0, outFormat, tex->width, tex->height, 0, inFormat, GL_UNSIGNED_BYTE, data ); @@ -1012,7 +1046,10 @@ int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags ) GL_UploadTexture( pic, tex, false ); GL_TexFilter( tex, false ); // update texture filter, wrap etc - FS_FreeImage( pic ); // release source texture + + if( flags & TF_KEEP_RGBDATA ) + tex->original = pic; + else FS_FreeImage( pic ); // release source texture // add to hash table hash = Com_HashKey( tex->name, TEXTURES_HASH_SIZE ); @@ -1108,6 +1145,41 @@ int GL_LoadTextureInternal( const char *name, rgbdata_t *pic, texFlags_t flags, return tex->texnum; } +/* +================ +GL_ProcessTexture +================ +*/ +void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor ) +{ + gltexture_t *image; + rgbdata_t *pic; + byte *buf; + + ASSERT( texnum > 0 && texnum < MAX_TEXTURES ); + image = &r_textures[texnum]; + + if(!( image->flags & TF_KEEP_RGBDATA ) || !image->original ) + { + MsgDev( D_ERROR, "GL_ProcessTexture: no input data for %s\n", image->name ); + return; + } + + pic = image->original; + buf = Mem_Alloc( r_temppool, pic->size ); + Q_memcpy( buf, pic->buffer, pic->size ); + + // UNDONE: topColor and bottomColor just for future expansions + Image_Process( &pic, topColor, bottomColor, gamma, IMAGE_LIGHTGAMMA ); + + GL_UploadTexture( pic, image, true ); + GL_TexFilter( image, true ); // update texture filter, wrap etc + + // restore original image + Q_memcpy( pic->buffer, buf, pic->size ); + Mem_Free( buf ); +} + /* ================ GL_LoadTexture @@ -1221,6 +1293,10 @@ void GL_FreeTexture( GLenum texnum ) prev = &cur->nextHash; } + // release source + if( image->flags & TF_KEEP_RGBDATA && image->original ) + FS_FreeImage( image->original ); + pglDeleteTextures( 1, &image->texnum ); Q_memset( image, 0, sizeof( *image )); } diff --git a/engine/client/gl_local.h b/engine/client/gl_local.h index 71d2bac3..290cd66a 100644 --- a/engine/client/gl_local.h +++ b/engine/client/gl_local.h @@ -32,12 +32,11 @@ extern byte *r_temppool; #define MAX_DETAIL_TEXTURES 256 #define MAX_LIGHTMAPS 128 #define SUBDIVIDE_SIZE 64 +#define MAX_MIRRORS 32 // per one frame! #define NUMVERTEXNORMALS 162 #define SHADEDOT_QUANT 16 // precalculated dot products for quantized angles -//#define MIRROR_TEST - // refparams #define RP_NONE 0 #define RP_MIRRORVIEW BIT( 0 ) // lock pvs at vieworg @@ -68,7 +67,8 @@ typedef enum TEX_VGUI, // vgui fonts or images TEX_CUBEMAP, // cubemap textures (sky) TEX_DETAIL, // detail textures - TEX_REMAP // local copy of remap texture + TEX_REMAP, // local copy of remap texture + TEX_SCREENCOPY // keep screen copy e.g. for mirror } texType_t; typedef enum @@ -89,6 +89,7 @@ typedef enum TF_NORMALMAP = BIT(13), // is a normalmap TF_LIGHTMAP = BIT(14), // is a lightmap TF_FORCE_COLOR = BIT(15), // force upload monochrome textures as RGB (detail textures) + TF_KEEP_RGBDATA = BIT(16), // some images keep source } texFlags_t; typedef struct gltexture_s @@ -106,6 +107,8 @@ typedef struct gltexture_s rgba_t fogParams; // some water textures // contain info about underwater fog + rgbdata_t *original; // keep original image + // debug info byte texType; // used for gl_showtextures size_t size; // upload size for debug targets @@ -125,13 +128,17 @@ typedef struct mextrasurf_s int checkcount; // for multi-check avoidance int dlight_s, dlight_t; // gl lightmap coordinates for dynamic lightmaps + + int mirrortexturenum; // gl texnum + matrix4x4 mirrormatrix; + struct mextrasurf_s *mirrorchain; // for gl_texsort drawing } mextrasurf_t; // mirror entity typedef struct gl_entity_s { cl_entity_t *ent; - msurface_t *chain; + mextrasurf_t *chain; } gl_entity_t; typedef struct @@ -202,6 +209,8 @@ typedef struct int lightmapTextures[MAX_LIGHTMAPS]; int dlightTexture; // custom dlight texture int skyboxTextures[6]; // skybox sides + int mirrorTextures[MAX_MIRRORS]; + int num_mirrors_used; // used mirror textures int skytexturenum; // this not a gl_texturenum! @@ -225,6 +234,9 @@ typedef struct int visframecount; // PVS frame int dlightframecount; // dynamic light frame int framecount; + + // cull info + vec3_t modelorg; // relative to viewpoint } ref_globals_t; typedef struct @@ -270,6 +282,7 @@ void GL_SelectTexture( GLenum texture ); void GL_DisableMultitexture( void ); void GL_EnableMultitexture( void ); void GL_LoadIdentityTexMatrix( void ); +void GL_DisableAllTexGens( void ); void GL_SetRenderMode( int mode ); void GL_FrontFace( GLenum front ); void GL_MBind( GLenum texnum ); @@ -282,6 +295,7 @@ void R_ShowTextures( void ); int R_CullModel( cl_entity_t *e, vec3_t origin, vec3_t mins, vec3_t maxs, float radius ); qboolean R_CullBox( const vec3_t mins, const vec3_t maxs, uint clipflags ); qboolean R_CullSphere( const vec3_t centre, const float radius, const uint clipflags ); +qboolean R_CullSurface( msurface_t *surf, uint clipflags ); // // gl_decals.c @@ -306,6 +320,7 @@ void GL_SetTextureType( GLenum texnum, GLenum type ); int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags ); int GL_LoadTextureInternal( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update ); byte *GL_ResampleTexture( const byte *source, int in_w, int in_h, int out_w, int out_h, qboolean isNormalMap ); +void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor ); int GL_FindTexture( const char *name ); void GL_FreeTexture( GLenum texnum ); void GL_FreeImage( const char *name ); @@ -313,6 +328,14 @@ void R_TextureList_f( void ); void R_InitImages( void ); void R_ShutdownImages( void ); +// +// gl_mirror.c +// +void R_BeginDrawMirror( msurface_t *fa ); +void R_EndDrawMirror( void ); +void R_DrawMirrors( void ); +void R_FindMirrors( const ref_params_t *fd ); + // // gl_refrag.c // @@ -339,6 +362,8 @@ qboolean R_WorldToScreen2( const vec3_t in, vec3_t out ); void R_TranslateForEntity( cl_entity_t *e ); void R_RotateForEntity( cl_entity_t *e ); int R_ComputeFxBlend( cl_entity_t *e ); +void R_SetupFrustum( void ); +void R_FindViewLeaf( void ); void R_DrawFog( void ); // @@ -372,6 +397,7 @@ void R_DrawWaterSurfaces( void ); void R_DrawBrushModel( cl_entity_t *e ); void GL_SubdivideSurface( msurface_t *fa ); void GL_BuildPolygonFromSurface( msurface_t *fa ); +void GL_RebuildLightmaps( void ); void GL_BuildLightmaps( void ); // @@ -600,6 +626,7 @@ extern convar_t *gl_luminance_textures; extern convar_t *gl_overview; // draw map in overview mode extern convar_t *gl_wireframe; extern convar_t *gl_allow_static; +extern convar_t *gl_allow_mirrors; extern convar_t *gl_picmip; extern convar_t *gl_skymip; extern convar_t *gl_finish; @@ -632,6 +659,7 @@ extern convar_t *r_fastsky; extern convar_t *vid_displayfrequency; extern convar_t *vid_fullscreen; extern convar_t *vid_gamma; +extern convar_t *vid_texgamma; extern convar_t *vid_mode; #endif//GL_LOCAL_H \ No newline at end of file diff --git a/engine/client/gl_mirror.c b/engine/client/gl_mirror.c new file mode 100644 index 00000000..62118b21 --- /dev/null +++ b/engine/client/gl_mirror.c @@ -0,0 +1,579 @@ +/* +gl_mirror.c - draw reflected surfaces +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. +*/ + +#include "common.h" +#include "client.h" +#include "gl_local.h" +#include "mod_local.h" +#include "mathlib.h" + +/* +================ +R_BeginDrawMirror + +Setup texture matrix for mirror texture +================ +*/ +void R_BeginDrawMirror( msurface_t *fa ) +{ + matrix4x4 m1, m2, matrix; + GLfloat genVector[4][4]; + mextrasurf_t *es; + int i; + + es = SURF_INFO( fa, RI.currentmodel ); + Matrix4x4_Copy( matrix, es->mirrormatrix ); + + Matrix4x4_LoadIdentity( m1 ); + Matrix4x4_ConcatScale( m1, 0.5 ); + Matrix4x4_Concat( m2, m1, matrix ); + + Matrix4x4_LoadIdentity( m1 ); + Matrix4x4_ConcatTranslate( m1, 0.5f, 0.5f, 0.5f ); + Matrix4x4_Concat( matrix, m1, m2 ); + + for( i = 0; i < 4; i++ ) + { + genVector[0][i] = i == 0 ? 1 : 0; + genVector[1][i] = i == 1 ? 1 : 0; + genVector[2][i] = i == 2 ? 1 : 0; + genVector[3][i] = i == 3 ? 1 : 0; + } + + GL_TexGen( GL_S, GL_OBJECT_LINEAR ); + GL_TexGen( GL_T, GL_OBJECT_LINEAR ); + GL_TexGen( GL_R, GL_OBJECT_LINEAR ); + GL_TexGen( GL_Q, GL_OBJECT_LINEAR ); + + pglTexGenfv( GL_S, GL_OBJECT_PLANE, genVector[0] ); + pglTexGenfv( GL_T, GL_OBJECT_PLANE, genVector[1] ); + pglTexGenfv( GL_R, GL_OBJECT_PLANE, genVector[2] ); + pglTexGenfv( GL_Q, GL_OBJECT_PLANE, genVector[3] ); + + GL_LoadTexMatrix( matrix ); +} + +/* +================ +R_EndDrawMirror + +Restore identity texmatrix +================ +*/ +void R_EndDrawMirror( void ) +{ + GL_DisableAllTexGens(); + GL_LoadIdentityTexMatrix(); + pglMatrixMode( GL_MODELVIEW ); +} + +/* +============================================================= + + MIRROR RENDERING + +============================================================= +*/ +/* +================ +R_PlaneForMirror + +Get transformed mirrorplane and entity matrix +================ +*/ +void R_PlaneForMirror( msurface_t *surf, mplane_t *out, matrix4x4 m ) +{ + cl_entity_t *ent; + + ASSERT( out != NULL ); + + ent = RI.currententity; + + // setup mirror plane + *out = *surf->plane; + + if( surf->flags & SURF_PLANEBACK ) + { + VectorNegate( out->normal, out->normal ); + out->dist = -out->dist; + } + + if( !VectorIsNull( ent->origin ) || !VectorIsNull( ent->angles )) + { + mplane_t tmp; + + if( !VectorIsNull( ent->angles )) Matrix4x4_CreateFromEntity( m, ent->angles, ent->origin, 1.0f ); + else Matrix4x4_CreateFromEntity( m, vec3_origin, ent->origin, 1.0f ); + + tmp = *out; + + // transform mirror plane by entity matrix + Matrix4x4_TransformPositivePlane( m, tmp.normal, tmp.dist, out->normal, &out->dist ); + } + else Matrix4x4_LoadIdentity( m ); +} + +/* +================ +R_AllocateMirrorTexture + +Allocate the screen texture and make copy +================ +*/ +int R_AllocateMirrorTexture( void ) +{ + rgbdata_t r_screen; + int i, texture; + char txName[16]; + + i = tr.num_mirrors_used; + if( i >= MAX_MIRRORS ) + { + MsgDev( D_ERROR, "R_AllocateMirrorTexture: mirror textures limit exceeded!\n" ); + return 0; // disable + } + + texture = tr.mirrorTextures[i]; + tr.num_mirrors_used++; + + if( !texture ) + { + // not iniatlized ? + Q_memset( &r_screen, 0, sizeof( r_screen )); + Q_snprintf( txName, sizeof( txName ), "*screen%i", i ); + + r_screen.width = RI.viewport[2]; + r_screen.height = RI.viewport[3]; + r_screen.type = PF_RGBA_32; + r_screen.size = r_screen.width * r_screen.height * 4; + r_screen.flags = IMAGE_HAS_COLOR; + r_screen.buffer = NULL; // create empty texture for now + tr.mirrorTextures[i] = GL_LoadTextureInternal( txName, &r_screen, TF_IMAGE, false ); + GL_SetTextureType( tr.mirrorTextures[i], TEX_SCREENCOPY ); + texture = tr.mirrorTextures[i]; + } + + GL_Bind( GL_TEXTURE0, texture ); + pglCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, RI.viewport[0], RI.viewport[1], RI.viewport[2], RI.viewport[3], 0 ); + + return texture; +} + +/* +================ +R_DrawMirrors + +Draw all viewpasess from mirror position +Mirror textures will be drawn in normal pass +================ +*/ +void R_DrawMirrors( void ) +{ + ref_instance_t oldRI; + mplane_t plane; + msurface_t *surf; + int i, oldframecount; + mextrasurf_t *es, *tmp, *mirrorchain; + vec3_t forward, right, up; + vec3_t origin, angles; + matrix4x4 mirrormatrix; + cl_entity_t *e; + model_t *m; + float d; + + if( !tr.num_mirror_entities ) return; // mo mirrors for this frame + + oldRI = RI; // make refinst backup + oldframecount = tr.framecount; + + for( i = 0; i < tr.num_mirror_entities; i++ ) + { + mirrorchain = tr.mirror_entities[i].chain; + + for( es = mirrorchain; es != NULL; ) + { + RI.currententity = e = tr.mirror_entities[i].ent; + RI.currentmodel = m = RI.currententity->model; + + surf = INFO_SURF( es, m ); + + ASSERT( RI.currententity != NULL ); + ASSERT( RI.currentmodel != NULL ); + + R_PlaneForMirror( surf, &plane, mirrormatrix ); + + d = -2.0f * ( DotProduct( RI.vieworg, plane.normal ) - plane.dist ); + VectorMA( RI.vieworg, d, plane.normal, origin ); + + d = -2.0f * DotProduct( RI.vforward, plane.normal ); + VectorMA( RI.vforward, d, plane.normal, forward ); + VectorNormalize( forward ); + + d = -2.0f * DotProduct( RI.vright, plane.normal ); + VectorMA( RI.vright, d, plane.normal, right ); + VectorNormalize( right ); + + d = -2.0f * DotProduct( RI.vup, plane.normal ); + VectorMA( RI.vup, d, plane.normal, up ); + VectorNormalize( up ); + + VectorsAngles( forward, right, up, angles ); + angles[ROLL] = -angles[ROLL]; + + RI.params = RP_MIRRORVIEW|RP_FLIPFRONTFACE|RP_CLIPPLANE|RP_OLDVIEWLEAF; + + RI.clipPlane = plane; + RI.clipFlags |= ( 1<<5 ); + + RI.frustum[5] = plane; + RI.frustum[5].signbits = SignbitsForPlane( RI.frustum[5].normal ); + RI.frustum[5].type = PLANE_NONAXIAL; + + RI.refdef.viewangles[0] = anglemod( angles[0] ); + RI.refdef.viewangles[1] = anglemod( angles[1] ); + RI.refdef.viewangles[2] = anglemod( angles[2] ); + VectorCopy( origin, RI.refdef.vieworg ); +#if 0 + // put pvsorigin before the mirror plane to avoid get full visibility on world mirrors + if( RI.currententity == clgame.entities ) VectorMA( es->origin, 5.0f, plane.normal, origin ); +#endif + VectorCopy( origin, RI.pvsorigin ); + VectorCopy( origin, RI.cullorigin ); + + // combine two leafs from client and mirror views + r_viewleaf = Mod_PointInLeaf( oldRI.pvsorigin, cl.worldmodel->nodes ); + r_viewleaf2 = Mod_PointInLeaf( RI.pvsorigin, cl.worldmodel->nodes ); + + // FIXME: how to combine two cull origins ? + + if( GL_Support( GL_ARB_TEXTURE_NPOT_EXT )) + { + // allow screen size + RI.viewport[2] = bound( 96, RI.viewport[2], 1024 ); + RI.viewport[3] = bound( 72, RI.viewport[3], 768 ); + } + else + { + RI.viewport[2] = NearestPOW( RI.viewport[2], true ); + RI.viewport[3] = NearestPOW( RI.viewport[3], true ); + RI.viewport[2] = bound( 128, RI.viewport[2], 1024 ); + RI.viewport[3] = bound( 64, RI.viewport[3], 512 ); + } + + tr.framecount++; + R_RenderScene( &RI.refdef ); + + es->mirrortexturenum = R_AllocateMirrorTexture(); + + // create personal projection matrix for mirror + if( VectorIsNull( e->origin ) && VectorIsNull( e->angles )) + { + Matrix4x4_Copy( es->mirrormatrix, RI.worldviewProjectionMatrix ); + } + else + { + Matrix4x4_ConcatTransforms( RI.modelviewMatrix, RI.worldviewMatrix, mirrormatrix ); + Matrix4x4_Concat( es->mirrormatrix, RI.projectionMatrix, RI.modelviewMatrix ); + } + + tmp = es->mirrorchain; + es->mirrorchain = NULL; + es = tmp; + + RI = oldRI; // restore ref instance + } + + tr.mirror_entities[i].chain = NULL; // done + tr.mirror_entities[i].ent = NULL; + } + + + r_oldviewleaf = r_viewleaf = NULL; // force markleafs next frame + tr.framecount = oldframecount; // restore real framecount + tr.num_mirror_entities = 0; + tr.num_mirrors_used = 0; +} + +/* +================ +R_RecursiveMirrorNode +================ +*/ +void R_RecursiveMirrorNode( mnode_t *node, uint clipflags ) +{ + mextrasurf_t *extrasurf; + const mplane_t *clipplane; + int i, clipped; + msurface_t *surf, **mark; + mleaf_t *pleaf; + int c, side; + float dot; + + if( node->contents == CONTENTS_SOLID ) + return; // hit a solid leaf + + if( node->visframe != tr.visframecount ) + return; + + if( clipflags ) + { + for( i = 0, clipplane = RI.frustum; i < 6; i++, clipplane++ ) + { + if(!( clipflags & ( 1<minmaxs, node->minmaxs + 3, clipplane ); + if( clipped == 2 ) return; + if( clipped == 1 ) clipflags &= ~(1<contents < 0 ) + { + pleaf = (mleaf_t *)node; + + mark = pleaf->firstmarksurface; + c = pleaf->nummarksurfaces; + + if( c ) + { + do + { + (*mark)->visframe = tr.framecount; + mark++; + } while( --c ); + } + return; + } + + // node is just a decision point, so go down the apropriate sides + + // find which side of the node we are on + dot = PlaneDiff( tr.modelorg, node->plane ); + side = (dot >= 0) ? 0 : 1; + + // recurse down the children, front side first + R_RecursiveMirrorNode( node->children[side], clipflags ); + + // draw stuff + for( c = node->numsurfaces, surf = cl.worldmodel->surfaces + node->firstsurface; c; c--, surf++ ) + { + if(!( surf->flags & SURF_MIRROR )) + continue; + + if( R_CullSurface( surf, clipflags )) + continue; + + extrasurf = SURF_INFO( surf, RI.currentmodel ); + extrasurf->mirrorchain = tr.mirror_entities[0].chain; + tr.mirror_entities[0].chain = extrasurf; + } + + // recurse down the back side + R_RecursiveMirrorNode( node->children[!side], clipflags ); +} + +/* +================= +R_FindBmodelMirrors + +Check all bmodel surfaces and make personal mirror chain +================= +*/ +void R_FindBmodelMirrors( cl_entity_t *e, qboolean static_entity ) +{ + mextrasurf_t *extrasurf; + vec3_t mins, maxs; + msurface_t *psurf; + model_t *clmodel; + qboolean rotated; + int i, clipFlags; + + clmodel = e->model; + + if( static_entity ) + { + Matrix4x4_LoadIdentity( RI.objectMatrix ); + + if( R_CullBox( clmodel->mins, clmodel->maxs, RI.clipFlags )) + return; + + VectorCopy( RI.cullorigin, tr.modelorg ); + clipFlags = RI.clipFlags; + } + else + { + if( !VectorIsNull( e->angles )) + { + for( i = 0; i < 3; i++ ) + { + mins[i] = e->origin[i] - clmodel->radius; + maxs[i] = e->origin[i] + clmodel->radius; + } + rotated = true; + } + else + { + VectorAdd( e->origin, clmodel->mins, mins ); + VectorAdd( e->origin, clmodel->maxs, maxs ); + rotated = false; + } + + if( R_CullBox( mins, maxs, RI.clipFlags )) + return; + + if( !VectorIsNull( e->origin ) || !VectorIsNull( e->angles )) + { + if( rotated ) Matrix4x4_CreateFromEntity( RI.objectMatrix, e->angles, e->origin, 1.0f ); + else Matrix4x4_CreateFromEntity( RI.objectMatrix, vec3_origin, e->origin, 1.0f ); + } + else Matrix4x4_LoadIdentity( RI.objectMatrix ); + + VectorSubtract( RI.cullorigin, e->origin, tr.modelorg ); + e->visframe = tr.framecount; // visible + + if( rotated ) + { + vec3_t temp; + VectorCopy( tr.modelorg, temp ); + Matrix4x4_VectorITransform( RI.objectMatrix, temp, tr.modelorg ); + } + + clipFlags = 0; + } + + psurf = &clmodel->surfaces[clmodel->firstmodelsurface]; + for( i = 0; i < clmodel->nummodelsurfaces; i++, psurf++ ) + { + if(!( psurf->flags & SURF_MIRROR )) + continue; + + if( R_CullSurface( psurf, clipFlags )) + continue; + + extrasurf = SURF_INFO( psurf, RI.currentmodel ); + extrasurf->mirrorchain = tr.mirror_entities[tr.num_mirror_entities].chain; + tr.mirror_entities[tr.num_mirror_entities].chain = extrasurf; + } + + // store new mirror entity + if( !static_entity && tr.mirror_entities[tr.num_mirror_entities].chain != NULL ) + { + tr.mirror_entities[tr.num_mirror_entities].ent = RI.currententity; + tr.num_mirror_entities++; + } +} + +/* +================= +R_CheckEntitiesOnList + +Check all bmodels for mirror surfaces +================= +*/ +void R_CheckEntitiesOnList( void ) +{ + int i; + + // check static entities + for( i = 0; i < tr.num_static_entities; i++ ) + { + RI.currententity = tr.static_entities[i]; + RI.currentmodel = RI.currententity->model; + + ASSERT( RI.currententity != NULL ); + ASSERT( RI.currententity->model != NULL ); + + switch( RI.currentmodel->type ) + { + case mod_brush: + R_FindBmodelMirrors( RI.currententity, true ); + break; + } + } + + // world or static entities has mirror surfaces + if( tr.mirror_entities[0].chain != NULL ) + { + tr.mirror_entities[0].ent = clgame.entities; + tr.num_mirror_entities++; + } + + // check solid entities + for( i = 0; i < tr.num_solid_entities; i++ ) + { + RI.currententity = tr.solid_entities[i]; + RI.currentmodel = RI.currententity->model; + + ASSERT( RI.currententity != NULL ); + ASSERT( RI.currententity->model != NULL ); + + switch( RI.currentmodel->type ) + { + case mod_brush: + R_FindBmodelMirrors( RI.currententity, false ); + break; + } + } + + // check translucent entities + for( i = 0; i < tr.num_trans_entities; i++ ) + { + RI.currententity = tr.trans_entities[i]; + RI.currentmodel = RI.currententity->model; + + ASSERT( RI.currententity != NULL ); + ASSERT( RI.currententity->model != NULL ); + + switch( RI.currentmodel->type ) + { + case mod_brush: + R_FindBmodelMirrors( RI.currententity, false ); + break; + } + } +} + +/* +================ +R_FindMirrors + +Build mirror chains for this frame +================ +*/ +void R_FindMirrors( const ref_params_t *fd ) +{ + if( !world.has_mirrors || RI.drawOrtho || !RI.drawWorld || RI.refdef.onlyClientDraw || !cl.worldmodel ) + return; + + RI.refdef = *fd; + + // build the transformation matrix for the given view angles + VectorCopy( RI.refdef.vieworg, RI.vieworg ); + AngleVectors( RI.refdef.viewangles, RI.vforward, RI.vright, RI.vup ); + + R_FindViewLeaf(); + R_SetupFrustum(); + R_MarkLeaves (); + + VectorCopy( RI.cullorigin, tr.modelorg ); + RI.currententity = clgame.entities; + RI.currentmodel = RI.currententity->model; + + R_RecursiveMirrorNode( cl.worldmodel->nodes, RI.clipFlags ); + + R_CheckEntitiesOnList(); +} \ No newline at end of file diff --git a/engine/client/gl_refrag.c b/engine/client/gl_refrag.c index 4089460e..a0da133b 100644 --- a/engine/client/gl_refrag.c +++ b/engine/client/gl_refrag.c @@ -66,8 +66,8 @@ void R_RemoveEfrags( cl_entity_t *ent ) ef = ef->entnext; // put it on the free list - old->entnext = cl.free_efrags; - cl.free_efrags = old; + old->entnext = clgame.free_efrags; + clgame.free_efrags = old; } ent->efrag = NULL; } @@ -96,14 +96,14 @@ static void R_SplitEntityOnNode( mnode_t *node ) leaf = (mleaf_t *)node; // grab an efrag off the free list - ef = cl.free_efrags; + ef = clgame.free_efrags; if( !ef ) { MsgDev( D_ERROR, "too many efrags!\n" ); return; // no free fragments... } - cl.free_efrags = cl.free_efrags->entnext; + clgame.free_efrags = clgame.free_efrags->entnext; ef->entity = r_addent; // add the entity link @@ -134,8 +134,6 @@ static void R_SplitEntityOnNode( mnode_t *node ) if( sides & 2 ) R_SplitEntityOnNode( node->children[1] ); } - - /* =========== R_AddEfrags @@ -162,7 +160,6 @@ void R_AddEfrags( cl_entity_t *ent ) ent->topnode = r_pefragtopnode; } - /* ================ R_StoreEfrags diff --git a/engine/client/gl_rlight.c b/engine/client/gl_rlight.c index bc2a7c8d..92b3fdb5 100644 --- a/engine/client/gl_rlight.c +++ b/engine/client/gl_rlight.c @@ -254,9 +254,9 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, const vec3 { uint scale = RI.lightstylevalue[surf->styles[map]]; - r_pointColor[0] += lm->r * scale; - r_pointColor[1] += lm->g * scale; - r_pointColor[2] += lm->b * scale; + r_pointColor[0] += TextureToTexGamma( lm->r ) * scale; + r_pointColor[1] += TextureToTexGamma( lm->g ) * scale; + r_pointColor[2] += TextureToTexGamma( lm->b ) * scale; lm += size; // skip to next lightmap } @@ -293,9 +293,9 @@ void R_LightForPoint( const vec3_t point, color24 *ambientLight, qboolean invLig // set to full bright if no light data if( !cl.worldmodel || !cl.worldmodel->lightdata ) { - ambientLight->r = RI.refdef.movevars->skycolor_r; - ambientLight->g = RI.refdef.movevars->skycolor_g; - ambientLight->b = RI.refdef.movevars->skycolor_b; + ambientLight->r = TextureToTexGamma( RI.refdef.movevars->skycolor_r ); + ambientLight->g = TextureToTexGamma( RI.refdef.movevars->skycolor_g ); + ambientLight->b = TextureToTexGamma( RI.refdef.movevars->skycolor_b ); return; } @@ -398,9 +398,9 @@ void R_LightForPoint( const vec3_t point, color24 *ambientLight, qboolean invLig continue; add = 1.0f - (dist / ( dl->radius + radius )); - r_pointColor[0] += dl->color.r * add; - r_pointColor[1] += dl->color.g * add; - r_pointColor[2] += dl->color.b * add; + r_pointColor[0] += TextureToTexGamma( dl->color.r ) * add; + r_pointColor[1] += TextureToTexGamma( dl->color.g ) * add; + r_pointColor[2] += TextureToTexGamma( dl->color.b ) * add; total++; } diff --git a/engine/client/gl_rmain.c b/engine/client/gl_rmain.c index ad86df67..528a81e3 100644 --- a/engine/client/gl_rmain.c +++ b/engine/client/gl_rmain.c @@ -202,9 +202,7 @@ qboolean R_WorldToScreen( const vec3_t point, vec3_t screen ) screen[1] = worldToScreen[1][0] * point[0] + worldToScreen[1][1] * point[1] + worldToScreen[1][2] * point[2] + worldToScreen[1][3]; // z = worldToScreen[2][0] * point[0] + worldToScreen[2][1] * point[1] + worldToScreen[2][2] * point[2] + worldToScreen[2][3]; w = worldToScreen[3][0] * point[0] + worldToScreen[3][1] * point[1] + worldToScreen[3][2] * point[2] + worldToScreen[3][3]; - - // Just so we have something valid here - screen[2] = 0.0f; + screen[2] = 0.0f; // just so we have something valid here if( w < 0.001f ) { @@ -224,7 +222,24 @@ qboolean R_WorldToScreen( const vec3_t point, vec3_t screen ) void R_ScreenToWorld( const vec3_t screen, vec3_t point ) { - // TODO: implement + matrix4x4 screenToWorld; + vec3_t temp; + float w; + + if( !point || !screen ) + return; + + // FIXME: does we need a full invert here? + Matrix4x4_Invert_Simple( screenToWorld, RI.worldviewProjectionMatrix ); + temp[0] = 2.0f * (screen[0] - RI.viewport[0]) / RI.viewport[2] - 1; + temp[1] = -2.0f * (screen[1] - RI.viewport[1]) / RI.viewport[3] + 1; + temp[2] = 0.0f; // just so we have something valid here + + point[0] = temp[0] * screenToWorld[0][0] + temp[1] * screenToWorld[0][1] + temp[2] * screenToWorld[0][2] + screenToWorld[0][3]; + point[1] = temp[0] * screenToWorld[1][0] + temp[1] * screenToWorld[1][1] + temp[2] * screenToWorld[1][2] + screenToWorld[1][3]; + point[2] = temp[0] * screenToWorld[2][0] + temp[1] * screenToWorld[2][1] + temp[2] * screenToWorld[2][2] + screenToWorld[2][3]; + w = temp[0] * screenToWorld[3][0] + temp[1] * screenToWorld[3][1] + temp[2] * screenToWorld[3][2] + screenToWorld[3][3]; + if( w ) VectorScale( point, ( 1.0f / w ), point ); } /* @@ -541,7 +556,7 @@ static void R_SetupFrustumOrtho( void ) R_SetupFrustum =============== */ -static void R_SetupFrustum( void ) +void R_SetupFrustum( void ) { vec3_t farPoint; int i; @@ -644,6 +659,8 @@ void R_LoadIdentity( void ) Matrix4x4_LoadIdentity( RI.objectMatrix ); Matrix4x4_Copy( RI.modelviewMatrix, RI.worldviewMatrix ); + + pglMatrixMode( GL_MODELVIEW ); GL_LoadMatrix( RI.modelviewMatrix ); tr.modelviewIdentity = true; } @@ -669,6 +686,7 @@ void R_RotateForEntity( cl_entity_t *e ) Matrix4x4_CreateFromEntity( RI.objectMatrix, e->angles, e->origin, scale ); Matrix4x4_ConcatTransforms( RI.modelviewMatrix, RI.worldviewMatrix, RI.objectMatrix ); + pglMatrixMode( GL_MODELVIEW ); GL_LoadMatrix( RI.modelviewMatrix ); tr.modelviewIdentity = false; } @@ -694,10 +712,49 @@ void R_TranslateForEntity( cl_entity_t *e ) Matrix4x4_CreateFromEntity( RI.objectMatrix, vec3_origin, e->origin, scale ); Matrix4x4_ConcatTransforms( RI.modelviewMatrix, RI.worldviewMatrix, RI.objectMatrix ); + pglMatrixMode( GL_MODELVIEW ); GL_LoadMatrix( RI.modelviewMatrix ); tr.modelviewIdentity = false; } +/* +=============== +R_FindViewLeaf +=============== +*/ +void R_FindViewLeaf( void ) +{ + float height; + mleaf_t *leaf; + vec3_t tmp; + + r_oldviewleaf = r_viewleaf; + r_oldviewleaf2 = r_viewleaf2; + leaf = Mod_PointInLeaf( RI.pvsorigin, cl.worldmodel->nodes ); + r_viewleaf2 = r_viewleaf = leaf; + height = RI.waveHeight ? RI.waveHeight : 16; + + // check above and below so crossing solid water doesn't draw wrong + if( leaf->contents == CONTENTS_EMPTY ) + { + // look down a bit + VectorCopy( RI.pvsorigin, tmp ); + tmp[2] -= height; + leaf = Mod_PointInLeaf( tmp, cl.worldmodel->nodes ); + if(( leaf->contents != CONTENTS_SOLID ) && ( leaf != r_viewleaf2 )) + r_viewleaf2 = leaf; + } + else + { + // look up a bit + VectorCopy( RI.pvsorigin, tmp ); + tmp[2] += height; + leaf = Mod_PointInLeaf( tmp, cl.worldmodel->nodes ); + if(( leaf->contents != CONTENTS_SOLID ) && ( leaf != r_viewleaf2 )) + r_viewleaf2 = leaf; + } +} + /* =============== R_SetupFrame @@ -721,41 +778,11 @@ static void R_SetupFrame( void ) // current viewleaf if( RI.drawWorld ) { - float height; - mleaf_t *leaf; - vec3_t tmp; - RI.waveHeight = RI.refdef.movevars->waveHeight * 2.0f; // set global waveheight RI.isSkyVisible = false; // unknown at this moment if(!( RI.params & RP_OLDVIEWLEAF )) - { - r_oldviewleaf = r_viewleaf; - r_oldviewleaf2 = r_viewleaf2; - leaf = Mod_PointInLeaf( RI.pvsorigin, cl.worldmodel->nodes ); - r_viewleaf2 = r_viewleaf = leaf; - height = RI.waveHeight ? RI.waveHeight : 16; - - // check above and below so crossing solid water doesn't draw wrong - if( leaf->contents == CONTENTS_EMPTY ) - { - // look down a bit - VectorCopy( RI.pvsorigin, tmp ); - tmp[2] -= height; - leaf = Mod_PointInLeaf( tmp, cl.worldmodel->nodes ); - if(( leaf->contents != CONTENTS_SOLID ) && ( leaf != r_viewleaf2 )) - r_viewleaf2 = leaf; - } - else - { - // look up a bit - VectorCopy( RI.pvsorigin, tmp ); - tmp[2] += height; - leaf = Mod_PointInLeaf( tmp, cl.worldmodel->nodes ); - if(( leaf->contents != CONTENTS_SOLID ) && ( leaf != r_viewleaf2 )) - r_viewleaf2 = leaf; - } - } + R_FindViewLeaf(); } } @@ -847,7 +874,7 @@ static void R_CheckFog( void ) if( RI.refdef.waterlevel < 2 || !RI.drawWorld || !r_viewleaf ) return; - ent = CL_GetWaterEntity( cl.refdef.vieworg ); + ent = CL_GetWaterEntity( RI.vieworg ); if( ent && ent->model && ent->model->type == mod_brush && ent->curstate.skin < 0 ) cnt = ent->curstate.skin; else cnt = r_viewleaf->contents; @@ -1092,8 +1119,16 @@ void R_BeginFrame( qboolean clearScene ) // update gamma if( vid_gamma->modified ) { - vid_gamma->modified = false; - GL_UpdateGammaRamp(); + if( glConfig.deviceSupportsGamma ) + { + GL_UpdateGammaRamp(); + vid_gamma->modified = false; + } + else + { + BuildGammaTable( vid_gamma->value, vid_texgamma->value ); + GL_RebuildLightmaps(); + } } R_Set2DMode( true ); @@ -1123,6 +1158,7 @@ void R_RenderFrame( const ref_params_t *fd, qboolean drawWorld ) return; if( drawWorld ) r_lastRefdef = *fd; + GL_BackendStartFrame(); RI.params = RP_NONE; RI.farClip = 0; @@ -1131,8 +1167,6 @@ void R_RenderFrame( const ref_params_t *fd, qboolean drawWorld ) RI.thirdPerson = cl.thirdperson; RI.drawOrtho = gl_overview->integer; - GL_BackendStartFrame(); - // adjust field of view for widescreen if( glState.wideScreen && r_adjust_fov->integer ) V_AdjustFov( &RI.refdef.fov_x, &RI.refdef.fov_y, glState.width, glState.height, false ); @@ -1156,10 +1190,15 @@ void R_RenderFrame( const ref_params_t *fd, qboolean drawWorld ) if( gl_finish->integer && drawWorld ) pglFinish(); + if( gl_allow_mirrors->integer ) + { + // render mirrors + R_FindMirrors( fd ); + R_DrawMirrors (); + } + R_RenderScene( fd ); -#ifdef MIRROR_TEST - R_DrawMirrors (); -#endif + GL_BackendEndFrame(); } diff --git a/engine/client/gl_rmisc.c b/engine/client/gl_rmisc.c index 9adc8841..39aeac63 100644 --- a/engine/client/gl_rmisc.c +++ b/engine/client/gl_rmisc.c @@ -50,6 +50,7 @@ static const dmaterial_t detail_table[] = { "car", "dt_metal%i", 'M', 1, 2 }, { "circuit", "dt_metal%i", 'M', 1, 2 }, { "steel", "dt_ssteel1", 'M', 0, 0 }, +{ "reflect", "dt_ssteel1", 'G', 0, 0 }, { "dirt", "dt_ground%i", 'D', 1, 5 }, // dirt { "drt", "dt_ground%i", 'D', 1, 5 }, { "out", "dt_ground%i", 'D', 1, 5 }, diff --git a/engine/client/gl_rpart.c b/engine/client/gl_rpart.c index 81b21d1b..f193d944 100644 --- a/engine/client/gl_rpart.c +++ b/engine/client/gl_rpart.c @@ -356,7 +356,7 @@ static void CL_BulletTracerDraw( particle_t *p, float frametime ) // setup our info for drawing the line VectorSubtract( vecEnd, vecStart, lineDir ); - VectorSubtract( vecEnd, cl.refdef.vieworg, viewDir ); + VectorSubtract( vecEnd, RI.vieworg, viewDir ); CrossProduct( lineDir, viewDir, cross ); VectorNormalize( cross ); @@ -490,16 +490,16 @@ void CL_UpdateParticle( particle_t *p, float ft ) #if 0 // HACKHACK a scale up to keep particles from disappearing - size += (p->org[0] - cl.refdef.vieworg[0]) * cl.refdef.forward[0]; - size += (p->org[1] - cl.refdef.vieworg[1]) * cl.refdef.forward[1]; - size += (p->org[2] - cl.refdef.vieworg[2]) * cl.refdef.forward[2]; + size += (p->org[0] - RI.vieworg[0]) * RI.vforward[0]; + size += (p->org[1] - RI.vieworg[1]) * RI.vforward[1]; + size += (p->org[2] - RI.vieworg[2]) * RI.vforward[2]; if( size < 20.0f ) size = 1.0f; else size = 1.0f + size * 0.004f; #endif // scale the axes by radius - VectorScale( cl.refdef.right, size, right ); - VectorScale( cl.refdef.up, size, up ); + VectorScale( RI.vright, size, right ); + VectorScale( RI.vup, size, up ); p->color = bound( 0, p->color, 255 ); VectorSet( color, clgame.palette[p->color][0], clgame.palette[p->color][1], clgame.palette[p->color][2] ); @@ -1328,8 +1328,8 @@ qboolean CL_TracerComputeVerts( const vec3_t start, const vec3_t delta, float wi VectorNormalize( tmp ); // build point along noraml line (normal is -y, x) - VectorScale( cl.refdef.up, tmp[0], normal ); - VectorScale( cl.refdef.right, -tmp[1], tmp2 ); + VectorScale( RI.vup, tmp[0], normal ); + VectorScale( RI.vright, -tmp[1], tmp2 ); VectorSubtract( normal, tmp2, normal ); // compute four vertexes diff --git a/engine/client/gl_rsurf.c b/engine/client/gl_rsurf.c index 2530580a..f0758328 100644 --- a/engine/client/gl_rsurf.c +++ b/engine/client/gl_rsurf.c @@ -28,9 +28,6 @@ typedef struct byte lightmap_buffer[BLOCK_WIDTH*BLOCK_HEIGHT*4]; } gllightmapstate_t; -static vec3_t modelorg; // relative to viewpoint -static vec3_t modelmins; -static vec3_t modelmaxs; static vec2_t world_orthocenter; static vec2_t world_orthohalf; static byte visbytes[MAX_MAP_LEAFS/8]; @@ -446,9 +443,9 @@ void R_AddDynamicLights( msurface_t *surf ) if( dist < minlight ) { - bl[0] += ( rad - dist ) * dl->color.r; - bl[1] += ( rad - dist ) * dl->color.g; - bl[2] += ( rad - dist ) * dl->color.b; + bl[0] += ( rad - dist ) * TextureToTexGamma( dl->color.r ); + bl[1] += ( rad - dist ) * TextureToTexGamma( dl->color.g ); + bl[2] += ( rad - dist ) * TextureToTexGamma( dl->color.b ); } } } @@ -592,9 +589,9 @@ static void R_BuildLightMap( msurface_t *surf, byte *dest, int stride ) for( i = 0, bl = r_blocklights; i < size; i++, bl += 3, lm++ ) { - bl[0] += lm->r * scale; - bl[1] += lm->g * scale; - bl[2] += lm->b * scale; + bl[0] += TextureToTexGamma( lm->r ) * scale; + bl[1] += TextureToTexGamma( lm->g ) * scale; + bl[2] += TextureToTexGamma( lm->b ) * scale; } } @@ -974,6 +971,7 @@ void R_RenderBrushPoly( msurface_t *fa ) texture_t *t; int maps; qboolean is_dynamic = false; + qboolean is_mirror = false; if( RI.currententity == clgame.entities ) r_stats.c_world_polys++; @@ -990,7 +988,20 @@ void R_RenderBrushPoly( msurface_t *fa ) } t = R_TextureAnimation( fa->texinfo->texture, fa - RI.currententity->model->surfaces ); - GL_MBind( t->gl_texturenum ); + + if( RP_NORMALPASS() && fa->flags & SURF_MIRROR ) + { + if( SURF_INFO( fa, RI.currentmodel )->mirrortexturenum ) + { + GL_MBind( SURF_INFO( fa, RI.currentmodel )->mirrortexturenum ); + is_mirror = true; + } + else GL_MBind( t->gl_texturenum ); // dummy + + // DEBUG: reset the mirror texture after drawing + SURF_INFO( fa, RI.currentmodel )->mirrortexturenum = 0; + } + else GL_MBind( t->gl_texturenum ); if( fa->flags & SURF_DRAWTURB ) { @@ -1015,9 +1026,15 @@ void R_RenderBrushPoly( msurface_t *fa ) draw_details = true; } + if( is_mirror ) R_BeginDrawMirror( fa ); DrawGLPoly( fa->polys, 0.0f, 0.0f ); + if( is_mirror ) R_EndDrawMirror(); DrawSurfaceDecals( fa ); + // NOTE: draw mirror through in mirror show dummy lightmapped texture + if( fa->flags & SURF_MIRROR && RP_NORMALPASS() && r_lighting_extended->integer < 2 ) + return; // no lightmaps for mirror + // check for lightmap modification for( maps = 0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++ ) { @@ -1086,13 +1103,6 @@ void R_DrawTextureChains( void ) RI.currententity = clgame.entities; RI.currentmodel = RI.currententity->model; - // world has mirrors! - if( RP_NORMALPASS() && tr.mirror_entities[0].chain != NULL ) - { - tr.mirror_entities[0].ent = clgame.entities; - tr.num_mirror_entities++; - } - // clip skybox surfaces for( s = skychain; s != NULL; s = s->texturechain ) R_AddSkyBoxSurface( s ); @@ -1141,8 +1151,7 @@ void R_DrawWaterSurfaces( void ) return; // go back to the world matrix - pglMatrixMode( GL_MODELVIEW ); - GL_LoadMatrix( RI.worldviewMatrix ); + R_LoadIdentity(); pglEnable( GL_BLEND ); pglDepthMask( GL_FALSE ); @@ -1214,79 +1223,6 @@ static int R_SurfaceCompare( const msurface_t **a, const msurface_t **b ) return 0; } -/* -================= -R_CullSurface - -cull invisible surfaces -================= -*/ -static _inline qboolean R_CullSurface( msurface_t *surf, uint clipflags ) -{ - mextrasurf_t *info; - - if( !surf || !surf->texinfo || !surf->texinfo->texture ) - return true; - - if( surf->flags & SURF_WATERCSG && !( RI.currententity->curstate.effects & EF_NOWATERCSG )) - return true; - - if( surf->flags & SURF_NOCULL ) - return false; - - if( r_nocull->integer ) - return false; - - // world surfaces can be culled by vis frame too - if( RI.currententity == clgame.entities && surf->visframe != tr.framecount ) - return true; - - if( r_faceplanecull->integer && glState.faceCull != 0 ) - { - if(!(surf->flags & SURF_DRAWTURB) || !RI.currentWaveHeight ) - { - if( !VectorIsNull( surf->plane->normal )) - { - float dist; - - if( RI.drawOrtho ) dist = surf->plane->normal[2]; - else dist = PlaneDiff( modelorg, surf->plane ); - - if( glState.faceCull == GL_FRONT || ( RI.params & RP_MIRRORVIEW )) - { - if( surf->flags & SURF_PLANEBACK ) - { - if( dist >= -BACKFACE_EPSILON ) - return true; // wrong side - } - else - { - if( dist <= BACKFACE_EPSILON ) - return true; // wrong side - } - } - else if( glState.faceCull == GL_BACK ) - { - if( surf->flags & SURF_PLANEBACK ) - { - if( dist <= BACKFACE_EPSILON ) - return true; // wrong side - } - else - { - if( dist >= -BACKFACE_EPSILON ) - return true; // wrong side - } - } - } - } - } - - info = SURF_INFO( surf, RI.currentmodel ); - - return ( clipflags && R_CullBox( info->mins, info->maxs, clipflags )); -} - /* ================= R_DrawBrushModel @@ -1332,14 +1268,14 @@ void R_DrawBrushModel( cl_entity_t *e ) if( rotated ) R_RotateForEntity( e ); else R_TranslateForEntity( e ); - VectorSubtract( RI.cullorigin, e->origin, modelorg ); + VectorSubtract( RI.cullorigin, e->origin, tr.modelorg ); e->visframe = tr.framecount; // visible if( rotated ) { vec3_t temp; - VectorCopy( modelorg, temp ); - Matrix4x4_VectorITransform( RI.objectMatrix, temp, modelorg ); + VectorCopy( tr.modelorg, temp ); + Matrix4x4_VectorITransform( RI.objectMatrix, temp, tr.modelorg ); } // calculate dynamic lighting for bmodel @@ -1389,12 +1325,7 @@ void R_DrawBrushModel( cl_entity_t *e ) if( R_CullSurface( psurf, 0 )) continue; - if( RP_NORMALPASS() && psurf->flags & SURF_MIRROR ) - { - psurf->texturechain = tr.mirror_entities[tr.num_mirror_entities].chain; - tr.mirror_entities[tr.num_mirror_entities].chain = psurf; - } - else if( need_sort ) + if( need_sort ) { world.draw_surfaces[num_sorted] = psurf; num_sorted++; @@ -1407,13 +1338,6 @@ void R_DrawBrushModel( cl_entity_t *e ) } } - // store new mirror entity - if( RP_NORMALPASS() && tr.mirror_entities[tr.num_mirror_entities].chain != NULL ) - { - tr.mirror_entities[tr.num_mirror_entities].ent = RI.currententity; - tr.num_mirror_entities++; - } - if( need_sort ) qsort( world.draw_surfaces, num_sorted, sizeof( msurface_t* ), R_SurfaceCompare ); @@ -1460,16 +1384,17 @@ void R_DrawStaticModel( cl_entity_t *e ) psurf = &clmodel->surfaces[clmodel->firstmodelsurface]; for( i = 0; i < clmodel->nummodelsurfaces; i++, psurf++ ) { - if( R_CullSurface( psurf, 0 )) + if( R_CullSurface( psurf, RI.clipFlags )) continue; - if( RP_NORMALPASS() && psurf->flags & SURF_MIRROR ) + if( psurf->flags & SURF_DRAWSKY && !world.sky_sphere ) { - psurf->texturechain = tr.mirror_entities[0].chain; - tr.mirror_entities[0].chain = psurf; + // make sky chain to right clip the skybox + psurf->texturechain = skychain; + skychain = psurf; } else - { + { psurf->texturechain = psurf->texinfo->texture->texturechain; psurf->texinfo->texture->texturechain = psurf; } @@ -1490,9 +1415,6 @@ void R_DrawStaticBrushes( void ) // draw static entities for( i = 0; i < tr.num_static_entities; i++ ) { - if( RI.refdef.onlyClientDraw ) - break; - RI.currententity = tr.static_entities[i]; RI.currentmodel = RI.currententity->model; @@ -1511,123 +1433,6 @@ void R_DrawStaticBrushes( void ) } } -/* -============================================================= - - MIRROR RENDERING - -============================================================= -*/ -void R_PlaneForMirror( msurface_t *surf, mplane_t *out ) -{ - cl_entity_t *ent; - - ASSERT( out != NULL ); - - ent = RI.currententity; - - // setup mirror plane - *out = *surf->plane; - - if( surf->flags & SURF_PLANEBACK ) - { - VectorNegate( out->normal, out->normal ); - } - - if( !VectorIsNull( ent->angles )) - R_RotateForEntity( ent ); - else R_TranslateForEntity( ent ); - - // transform mirror plane by entity matrix - if( !tr.modelviewIdentity ) - { - mplane_t tmp; - - tmp = *out; - Matrix4x4_TransformPositivePlane( RI.objectMatrix, tmp.normal, tmp.dist, out->normal, &out->dist ); - } -} - -void R_DrawMirrors( void ) -{ - ref_instance_t oldRI; - mplane_t plane; - msurface_t *surf, *mirrorchain; - vec3_t forward, right, up; - vec3_t origin, angles; - int i; - float d; - - if( !tr.num_mirror_entities ) return; // mo mirrors for this frame - - oldRI = RI; // make refinst backup - - for( i = 0; i < tr.num_mirror_entities; i++ ) - { - mirrorchain = tr.mirror_entities[i].chain; - - for( surf = mirrorchain; surf != NULL; surf = surf->texturechain ) - { - RI.currententity = tr.mirror_entities[i].ent; - RI.currentmodel = RI.currententity->model; - - ASSERT( RI.currententity != NULL ); - ASSERT( RI.currentmodel != NULL ); - - R_PlaneForMirror( surf, &plane ); - - d = -2.0f * ( DotProduct( RI.vieworg, plane.normal ) - plane.dist ); - VectorMA( RI.vieworg, d, plane.normal, origin ); - - d = -2.0f * DotProduct( RI.vforward, plane.normal ); - VectorMA( RI.vforward, d, plane.normal, forward ); - VectorNormalize( forward ); - - d = -2.0f * DotProduct( RI.vright, plane.normal ); - VectorMA( RI.vright, d, plane.normal, right ); - VectorNormalize( right ); - - d = -2.0f * DotProduct( RI.vup, plane.normal ); - VectorMA( RI.vup, d, plane.normal, up ); - VectorNormalize( up ); - - VectorsAngles( forward, right, up, angles ); - angles[ROLL] = -angles[ROLL]; - - RI.params = RP_MIRRORVIEW|RP_FLIPFRONTFACE|RP_CLIPPLANE; - if( r_viewleaf ) RI.params |= RP_OLDVIEWLEAF; - - RI.clipPlane = plane; - RI.clipFlags |= ( 1<<5 ); - - RI.frustum[5] = plane; - RI.frustum[5].signbits = SignbitsForPlane( RI.frustum[5].normal ); - RI.frustum[5].type = PLANE_NONAXIAL; - - RI.refdef.viewangles[0] = anglemod( angles[0] ); - RI.refdef.viewangles[1] = anglemod( angles[1] ); - RI.refdef.viewangles[2] = anglemod( angles[2] ); - VectorCopy( origin, RI.refdef.vieworg ); - VectorCopy( origin, RI.pvsorigin ); - VectorCopy( origin, RI.cullorigin ); - - R_RenderScene( &RI.refdef ); - - if( !( RI.params & RP_OLDVIEWLEAF )) - r_oldviewleaf = r_viewleaf = NULL; // force markleafs next frame - - RI = oldRI; // restore ref instance - - // TODO: draw mirror surface here - } - - tr.mirror_entities[i].chain = NULL; // done - tr.mirror_entities[i].ent = NULL; - } - - tr.num_mirror_entities = 0; -} - /* ============================================================= @@ -1696,7 +1501,7 @@ void R_RecursiveWorldNode( mnode_t *node, uint clipflags ) // node is just a decision point, so go down the apropriate sides // find which side of the node we are on - dot = PlaneDiff( modelorg, node->plane ); + dot = PlaneDiff( tr.modelorg, node->plane ); side = (dot >= 0) ? 0 : 1; // recurse down the children, front side first @@ -1714,11 +1519,6 @@ void R_RecursiveWorldNode( mnode_t *node, uint clipflags ) surf->texturechain = skychain; skychain = surf; } - else if( RP_NORMALPASS() && surf->flags & SURF_MIRROR ) - { - surf->texturechain = tr.mirror_entities[0].chain; - tr.mirror_entities[0].chain = surf; - } else { surf->texturechain = surf->texinfo->texture->texturechain; @@ -1931,7 +1731,7 @@ void R_DrawWorld( void ) if( !RI.drawWorld || RI.refdef.onlyClientDraw ) return; - VectorCopy( RI.cullorigin, modelorg ); + VectorCopy( RI.cullorigin, tr.modelorg ); Q_memset( gl_lms.lightmap_surfaces, 0, sizeof( gl_lms.lightmap_surfaces )); Q_memset( fullbright_polys, 0, sizeof( fullbright_polys )); Q_memset( detail_polys, 0, sizeof( detail_polys )); @@ -2079,6 +1879,51 @@ void GL_CreateSurfaceLightmap( msurface_t *surf ) R_BuildLightMap( surf, base, BLOCK_WIDTH * 4 ); } +/* +================== +GL_RebuildLightmaps + +Rebuilds the lightmap texture +when gamma is changed +================== +*/ +void GL_RebuildLightmaps( void ) +{ + int i, j; + model_t *m; + + if( !cl.worldmodel ) return; // wait for worldmodel + vid_gamma->modified = false; + + // release old lightmaps + for( i = 0; i < MAX_LIGHTMAPS; i++ ) + { + if( !tr.lightmapTextures[i] ) break; + GL_FreeTexture( tr.lightmapTextures[i] ); + } + + Q_memset( tr.lightmapTextures, 0, sizeof( tr.lightmapTextures )); + gl_lms.current_lightmap_texture = 0; + + // setup all the lightstyles + R_AnimateLight(); + + LM_InitBlock(); + + for( i = 1; i < MAX_MODELS; i++ ) + { + if(( m = Mod_Handle( i )) == NULL ) + continue; + + if( m->name[0] == '*' || m->type != mod_brush ) + continue; + + for( j = 0; j < m->numsurfaces; j++ ) + GL_CreateSurfaceLightmap( m->surfaces + j ); + } + LM_UploadBlock( false ); +} + /* ================== GL_BuildLightmaps @@ -2099,14 +1944,24 @@ void GL_BuildLightmaps( void ) GL_FreeTexture( tr.lightmapTextures[i] ); } + // release old mirror textures + for( i = 0; i < MAX_MIRRORS; i++ ) + { + if( !tr.mirrorTextures[i] ) break; + GL_FreeTexture( tr.mirrorTextures[i] ); + } + Q_memset( tr.lightmapTextures, 0, sizeof( tr.lightmapTextures )); Q_memset( tr.mirror_entities, 0, sizeof( tr.mirror_entities )); + Q_memset( tr.mirrorTextures, 0, sizeof( tr.mirrorTextures )); Q_memset( visbytes, 0x00, sizeof( visbytes )); skychain = NULL; tr.framecount = tr.visframecount = 1; // no dlight cache gl_lms.current_lightmap_texture = 0; + tr.num_mirror_entities = 0; + tr.num_mirrors_used = 0; // setup all the lightstyles R_AnimateLight(); diff --git a/engine/client/gl_sprite.c b/engine/client/gl_sprite.c index 98e2ad22..6df9ff51 100644 --- a/engine/client/gl_sprite.c +++ b/engine/client/gl_sprite.c @@ -287,7 +287,7 @@ void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size, qboolean if( h < MAPSPRITE_SIZE ) h = MAPSPRITE_SIZE; // resample image if needed - Image_Process( &pix, w, h, IMAGE_FORCE_RGBA|IMAGE_RESAMPLE ); + Image_Process( &pix, w, h, 0.0f, IMAGE_FORCE_RGBA|IMAGE_RESAMPLE ); w = h = MAPSPRITE_SIZE; diff --git a/engine/client/gl_studio.c b/engine/client/gl_studio.c index 0870d81a..81be272f 100644 --- a/engine/client/gl_studio.c +++ b/engine/client/gl_studio.c @@ -252,6 +252,7 @@ static qboolean R_StudioComputeBBox( cl_entity_t *e, vec3_t bbox[8] ) p1[1] = ( i & 2 ) ? tmp_mins[1] : tmp_maxs[1]; p1[2] = ( i & 4 ) ? tmp_mins[2] : tmp_maxs[2]; + // rotate by YAW p2[0] = DotProduct( p1, vectors[0] ); p2[1] = DotProduct( p1, vectors[1] ); p2[2] = DotProduct( p1, vectors[2] ); @@ -2412,7 +2413,7 @@ R_StudioSetChromeOrigin */ void R_StudioSetChromeOrigin( void ) { - VectorNegate( cl.refdef.vieworg, g_chrome_origin ); + VectorNegate( RI.vieworg, g_chrome_origin ); } /* @@ -2998,6 +2999,7 @@ R_DrawStudioModel void R_DrawStudioModelInternal( cl_entity_t *e, qboolean follow_entity ) { int i, flags, result; + float prevFrame; if( RI.params & RP_ENVVIEW ) return; @@ -3017,6 +3019,8 @@ void R_DrawStudioModelInternal( cl_entity_t *e, qboolean follow_entity ) m_fDoInterp = (e->curstate.effects & EF_NOINTERP) ? false : true; else m_fDoInterp = false; + prevFrame = e->latched.prevframe; + // prevent to crash some mods like HLFX in menu Customize if( !RI.drawWorld && !r_customdraw_playermodel->integer ) { @@ -3032,6 +3036,9 @@ void R_DrawStudioModelInternal( cl_entity_t *e, qboolean follow_entity ) else result = pStudioDraw->StudioDrawModel( flags ); } + // old frame must be restored + if( !RP_NORMALPASS( )) e->latched.prevframe = prevFrame; + if( !result || follow_entity ) return; // NOTE: we must draw all followed entities @@ -3067,7 +3074,7 @@ R_RunViewmodelEvents */ void R_RunViewmodelEvents( void ) { - if( cl.refdef.nextView || cl.thirdperson || RI.params & RP_ENVVIEW ) + if( cl.refdef.nextView || cl.thirdperson || RI.params & RP_NONVIEWERREF ) return; if( !Mod_Extradata( clgame.viewent.model )) @@ -3097,7 +3104,7 @@ void R_DrawViewModel( void ) if( cl.thirdperson || cl.refdef.health <= 0 || cl.refdef.viewentity != ( cl.playernum + 1 )) return; - if( RI.params & RP_ENVVIEW ) + if( RI.params & RP_NONVIEWERREF ) return; if( !Mod_Extradata( clgame.viewent.model )) diff --git a/engine/client/gl_vidnt.c b/engine/client/gl_vidnt.c index 3452402d..522b2c23 100644 --- a/engine/client/gl_vidnt.c +++ b/engine/client/gl_vidnt.c @@ -39,6 +39,7 @@ convar_t *gl_showtextures; convar_t *gl_swapInterval; convar_t *gl_check_errors; convar_t *gl_allow_static; +convar_t *gl_allow_mirrors; convar_t *gl_texturemode; convar_t *gl_wireframe; convar_t *gl_round_down; @@ -78,6 +79,7 @@ convar_t *r_fastsky; convar_t *vid_displayfrequency; convar_t *vid_fullscreen; convar_t *vid_gamma; +convar_t *vid_texgamma; convar_t *vid_mode; byte *r_temppool; @@ -549,7 +551,7 @@ void GL_BuildGammaTable( void ) int i, v; double invGamma, div; - invGamma = 1.0 / bound( 0.5, vid_gamma->value, 3.0 ); + invGamma = 1.0 / bound( 0.5, vid_gamma->value, 2.3 ); div = (double) 1.0 / 255.5; Q_memcpy( glState.gammaRamp, glState.stateRamp, sizeof( glState.gammaRamp )); @@ -570,7 +572,6 @@ GL_UpdateGammaRamp */ void GL_UpdateGammaRamp( void ) { - if( gl_ignorehwgamma->integer ) return; if( !glConfig.deviceSupportsGamma ) return; GL_BuildGammaTable(); @@ -737,11 +738,25 @@ void VID_StartupGamma( void ) size_t gamma_size; byte *savedGamma; + glConfig.deviceSupportsGamma = GetDeviceGammaRamp( glw_state.hDC, glState.stateRamp ); + + if( !glConfig.deviceSupportsGamma ) + { + // force to set cvar + Cvar_FullSet( "gl_ignorehwgamma", "1", CVAR_GLCONFIG ); + } + + if( gl_ignorehwgamma->integer ) + { + glConfig.deviceSupportsGamma = false; // even if supported! + BuildGammaTable( vid_gamma->value, vid_texgamma->value ); + MsgDev( D_NOTE, "VID_StartupGamma: software gamma initialized\n" ); + return; + } + // init gamma ramp Q_memset( glState.stateRamp, 0, sizeof( glState.stateRamp )); - glConfig.deviceSupportsGamma = GetDeviceGammaRamp( glw_state.hDC, glState.stateRamp ); - // share this extension so engine can grab them GL_SetExtension( GL_HARDWARE_GAMMA_CONTROL, glConfig.deviceSupportsGamma ); @@ -811,7 +826,7 @@ void VID_StartupGamma( void ) void VID_RestoreGamma( void ) { - if( !glw_state.hDC ) return; + if( !glw_state.hDC || !glConfig.deviceSupportsGamma ) return; SetDeviceGammaRamp( glw_state.hDC, glState.stateRamp ); } @@ -1414,7 +1429,7 @@ void GL_InitCommands( void ) gl_picmip = Cvar_Get( "gl_picmip", "0", CVAR_GLCONFIG, "reduces resolution of textures by powers of 2" ); gl_skymip = Cvar_Get( "gl_skymip", "0", CVAR_GLCONFIG, "reduces resolution of skybox textures by powers of 2" ); - gl_ignorehwgamma = Cvar_Get( "gl_ignorehwgamma", "0", CVAR_ARCHIVE|CVAR_LATCH_VIDEO, "ignore hardware gamma (e.g. not support)" ); + gl_ignorehwgamma = Cvar_Get( "gl_ignorehwgamma", "0", CVAR_GLCONFIG, "ignore hardware gamma" ); gl_allow_software = Cvar_Get( "gl_allow_software", "0", CVAR_ARCHIVE, "allow OpenGL software emulation" ); gl_alphabits = Cvar_Get( "gl_alphabits", "8", CVAR_GLCONFIG, "pixelformat alpha bits (0 - auto)" ); gl_texturemode = Cvar_Get( "gl_texturemode", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE, "texture filter" ); @@ -1429,6 +1444,7 @@ void GL_InitCommands( void ) gl_compress_textures = Cvar_Get( "gl_compress_textures", "0", CVAR_GLCONFIG, "compress textures to safe video memory" ); gl_luminance_textures = Cvar_Get( "gl_luminance_textures", "0", CVAR_GLCONFIG, "force all textures to luminance" ); gl_allow_static = Cvar_Get( "gl_allow_static", "1", CVAR_ARCHIVE, "force to drawing non-moveable brushes as part of world (save FPS)" ); + gl_allow_mirrors = Cvar_Get( "gl_allow_mirrors", "1", CVAR_ARCHIVE, "allow to draw mirror surfaces" ); gl_showtextures = Cvar_Get( "r_showtextures", "0", CVAR_CHEAT, "show all uploaded textures (type values from 1 to 9)" ); gl_finish = Cvar_Get( "gl_finish", "0", CVAR_ARCHIVE, "use glFinish instead of glFlush" ); gl_clear = Cvar_Get( "gl_clear", "0", CVAR_ARCHIVE, "clearing screen after each frame" ); @@ -1443,6 +1459,7 @@ void GL_InitCommands( void ) gl_swapInterval->modified = true; vid_gamma = Cvar_Get( "gamma", "1.0", CVAR_ARCHIVE, "gamma amount" ); + vid_texgamma = Cvar_Get( "texgamma", "2.2", CVAR_GLCONFIG, "texgamma amount (default Half-Life artwork gamma)" ); vid_mode = Cvar_Get( "vid_mode", VID_DEFAULTMODE, CVAR_RENDERINFO, "display resolution mode" ); vid_fullscreen = Cvar_Get( "fullscreen", "0", CVAR_RENDERINFO, "set in 1 to enable fullscreen mode" ); vid_displayfrequency = Cvar_Get ( "vid_displayfrequency", "0", CVAR_RENDERINFO, "fullscreen refresh rate" ); diff --git a/engine/client/gl_warp.c b/engine/client/gl_warp.c index 8fffb0e3..e5df79ca 100644 --- a/engine/client/gl_warp.c +++ b/engine/client/gl_warp.c @@ -307,6 +307,16 @@ void R_AddSkyBoxSurface( msurface_t *fa ) if( r_fastsky->integer ) return; + if( clgame.movevars.skyangle ) + { + // HACK: force full sky to draw when it has angle + for( i = 0; i < 6; i++ ) + { + RI.skyMins[0][i] = RI.skyMins[1][i] = -1; + RI.skyMaxs[0][i] = RI.skyMaxs[1][i] = 1; + } + } + // calculate vertex values for sky box for( p = fa->polys; p; p = p->next ) { @@ -348,6 +358,18 @@ void R_DrawSkyBox( void ) { int i; + if( clgame.movevars.skyangle ) + { + // check for no sky at all + for( i = 0; i < 6; i++ ) + { + if( RI.skyMins[0][i] < RI.skyMaxs[0][i] && RI.skyMins[1][i] < RI.skyMaxs[1][i] ) + break; + } + + if( i == 6 ) return; // nothing visible + } + RI.isSkyVisible = true; // don't fogging skybox (this fix old Half-Life bug) @@ -357,6 +379,16 @@ void R_DrawSkyBox( void ) pglDisable( GL_ALPHA_TEST ); pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); + if( clgame.movevars.skyangle && !VectorIsNull( (float *)&clgame.movevars.skydir_x )) + { + matrix4x4 m; + Matrix4x4_CreateRotate( m, clgame.movevars.skyangle, clgame.movevars.skydir_x, clgame.movevars.skydir_y, clgame.movevars.skydir_z ); + Matrix4x4_ConcatTranslate( m, -RI.vieworg[0], -RI.vieworg[1], -RI.vieworg[2] ); + Matrix4x4_ConcatTransforms( RI.modelviewMatrix, RI.worldviewMatrix, m ); + GL_LoadMatrix( RI.modelviewMatrix ); + tr.modelviewIdentity = false; + } + for( i = 0; i < 6; i++ ) { if( RI.skyMins[0][i] >= RI.skyMaxs[0][i] || RI.skyMins[1][i] >= RI.skyMaxs[1][i] ) @@ -371,6 +403,8 @@ void R_DrawSkyBox( void ) MakeSkyVec( RI.skyMaxs[0][i], RI.skyMins[1][i], i ); pglEnd(); } + + R_LoadIdentity(); } /* diff --git a/engine/client/s_load.c b/engine/client/s_load.c index 2e841478..6871fe01 100644 --- a/engine/client/s_load.c +++ b/engine/client/s_load.c @@ -198,6 +198,7 @@ sfx_t *S_FindName( const char *name, int *pfInCache ) { if( !sfx->name[0] ) break; // free spot } + if( i == s_numSfx ) { if( s_numSfx == MAX_SFX ) diff --git a/engine/common/avikit.c b/engine/common/avikit.c index 079488cc..f112c654 100644 --- a/engine/common/avikit.c +++ b/engine/common/avikit.c @@ -15,6 +15,7 @@ GNU General Public License for more details. #include "common.h" #include "client.h" +#include "gl_local.h" #include // video for windows // msvfw32.dll exports @@ -294,7 +295,8 @@ byte *AVI_GetVideoFrame( movie_state_t *Avi, long frame ) frame_raw = (char *)frame_info + frame_info->biSize + frame_info->biClrUsed * sizeof( RGBQUAD ); pDrawDibDraw( Avi->hDD, Avi->hDC, 0, 0, Avi->video_xres, Avi->video_yres, frame_info, frame_raw, 0, 0, Avi->video_xres, Avi->video_yres, 0 ); - if( Avi->ignore_hwgamma ) + // adjust gamma only if hardware gamma is enabled + if( Avi->ignore_hwgamma && glConfig.deviceSupportsGamma ) { tmp = Avi->pframe_data; diff --git a/engine/common/common.h b/engine/common/common.h index 07f5b03d..09fca756 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -468,6 +468,7 @@ typedef enum IMAGE_FORCE_RGBA = BIT(23), // force image to RGBA buffer IMAGE_MAKE_LUMA = BIT(24), // create luma texture from indexed IMAGE_QUANTIZE = BIT(25), // make indexed image from 24 or 32- bit image + IMAGE_LIGHTGAMMA = BIT(26), // apply gamma for image } imgFlags_t; typedef struct rgbdata_s @@ -491,7 +492,7 @@ rgbdata_t *FS_LoadImage( const char *filename, const byte *buffer, size_t size ) qboolean FS_SaveImage( const char *filename, rgbdata_t *pix ); void FS_FreeImage( rgbdata_t *pack ); extern const bpc_desc_t PFDesc[]; // image get pixelformat -qboolean Image_Process( rgbdata_t **pix, int width, int height, uint flags ); +qboolean Image_Process( rgbdata_t **pix, int width, int height, float gamma, uint flags ); /* ======================================================================== @@ -778,6 +779,11 @@ void S_StopSound( int entnum, int channel, const char *soundname ); int S_GetCurrentStaticSounds( soundlist_t *pout, int size ); void S_StopAllSounds( void ); +// gamma routines +void BuildGammaTable( float gamma, float texGamma ); +byte TextureToTexGamma( byte b ); +byte TextureToGamma( byte b ); + #ifdef __cplusplus } #endif diff --git a/engine/common/gamma.c b/engine/common/gamma.c new file mode 100644 index 00000000..c0632896 --- /dev/null +++ b/engine/common/gamma.c @@ -0,0 +1,68 @@ +/* +gamma.c - gamma 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 "common.h" +#include +#include "gl_local.h" + +//----------------------------------------------------------------------------- +// Gamma conversion support +//----------------------------------------------------------------------------- +static byte gammatable[256]; +static byte texgammatable[256]; // palette is sent through this to convert to screen gamma + +void BuildGammaTable( float gamma, float texGamma ) +{ + int i, inf; + float g1, g = gamma; + double f; + + g = bound( 1.8f, g, 3.0f ); + texGamma = bound( 1.8f, texGamma, 3.0f ); + + g = 1.0f / g; + g1 = texGamma * g; + + for( i = 0; i < 256; i++ ) + { + inf = 255 * pow( i / 255.f, g1 ); + texgammatable[i] = bound( 0, inf, 255 ); + } + + for( i = 0; i < 256; i++ ) + { + f = 255.0 * pow(( float )i / 255.0f, 2.2f / texGamma ); + inf = (int)(f + 0.5f); + gammatable[i] = bound( 0, inf, 255 ); + } +} + +byte TextureToTexGamma( byte b ) +{ + if( glConfig.deviceSupportsGamma ) + return b; // passthrough + + b = bound( 0, b, 255 ); + return texgammatable[b]; +} + +byte TextureToGamma( byte b ) +{ + if( glConfig.deviceSupportsGamma ) + return b; // passthrough + + b = bound( 0, b, 255 ); + return gammatable[b]; +} \ No newline at end of file diff --git a/engine/common/imagelib/img_utils.c b/engine/common/imagelib/img_utils.c index 3ab0d85f..111eb25b 100644 --- a/engine/common/imagelib/img_utils.c +++ b/engine/common/imagelib/img_utils.c @@ -1203,7 +1203,37 @@ rgbdata_t *Image_DecompressInternal( rgbdata_t *pic ) return pic; } -qboolean Image_Process( rgbdata_t **pix, int width, int height, uint flags ) +rgbdata_t *Image_LightGamma( rgbdata_t *pic, float texGamma ) +{ + byte *in = (byte *)pic->buffer; + byte gammatable[256]; + int i, inf; + double f; + + if( pic->type != PF_RGBA_32 ) + return pic; + + texGamma = bound( 1.8f, texGamma, 3.0f ); + + // build the gamma table + for( i = 0; i < 256; i++ ) + { + f = 255.0 * pow(( float )i / 255.0f, 2.2f / texGamma ); + inf = (int)(f + 0.5f); + gammatable[i] = bound( 0, inf, 255 ); + } + + for( i = 0; i < pic->width * pic->height; i++, in += 4 ) + { + in[0] = gammatable[in[0]]; + in[1] = gammatable[in[1]]; + in[2] = gammatable[in[2]]; + } + + return pic; +} + +qboolean Image_Process( rgbdata_t **pix, int width, int height, float gamma, uint flags ) { rgbdata_t *pic = *pix; qboolean result = true; @@ -1227,6 +1257,7 @@ qboolean Image_Process( rgbdata_t **pix, int width, int height, uint flags ) // update format to RGBA if any if( flags & IMAGE_FORCE_RGBA ) pic = Image_DecompressInternal( pic ); + if( flags & IMAGE_LIGHTGAMMA ) pic = Image_LightGamma( pic, gamma ); // quantize image if( flags & IMAGE_QUANTIZE ) pic = Image_Quantize( pic ); diff --git a/engine/common/mathlib.h b/engine/common/mathlib.h index 3625f03f..268daae7 100644 --- a/engine/common/mathlib.h +++ b/engine/common/mathlib.h @@ -149,6 +149,7 @@ void Matrix4x4_ConcatTransforms( matrix4x4 out, const matrix4x4 in1, const matri void Matrix4x4_FromOriginQuat( matrix4x4 out, const vec4_t quaternion, const vec3_t origin ); void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_t origin, float scale ); void Matrix4x4_TransformPositivePlane( const matrix4x4 in, const vec3_t normal, float d, vec3_t out, float *dist ); +void Matrix4x4_TransformStandardPlane( const matrix4x4 in, const vec3_t normal, float d, vec3_t out, float *dist ); void Matrix4x4_SetOrigin( matrix4x4 out, float x, float y, float z ); void Matrix4x4_Invert_Simple( matrix4x4 out, const matrix4x4 in1 ); void Matrix4x4_OriginFromMatrix( const matrix4x4 in, float *out ); diff --git a/engine/common/matrixlib.c b/engine/common/matrixlib.c index 6c8bcdf9..3607b06e 100644 --- a/engine/common/matrixlib.c +++ b/engine/common/matrixlib.c @@ -432,6 +432,17 @@ void Matrix4x4_TransformPositivePlane( const matrix4x4 in, const vec3_t normal, *dist = d * scale + ( out[0] * in[0][3] + out[1] * in[1][3] + out[2] * in[2][3] ); } +void Matrix4x4_TransformStandardPlane( const matrix4x4 in, const vec3_t normal, float d, vec3_t out, float *dist ) +{ + float scale = sqrt( in[0][0] * in[0][0] + in[0][1] * in[0][1] + in[0][2] * in[0][2] ); + float iscale = 1.0f / scale; + + out[0] = (normal[0] * in[0][0] + normal[1] * in[0][1] + normal[2] * in[0][2]) * iscale; + out[1] = (normal[0] * in[1][0] + normal[1] * in[1][1] + normal[2] * in[1][2]) * iscale; + out[2] = (normal[0] * in[2][0] + normal[1] * in[2][1] + normal[2] * in[2][2]) * iscale; + *dist = d * scale - ( out[0] * in[0][3] + out[1] * in[1][3] + out[2] * in[2][3] ); +} + void Matrix4x4_Invert_Simple( matrix4x4 out, const matrix4x4 in1 ) { // we only support uniform scaling, so assume the first row is enough diff --git a/engine/common/mod_local.h b/engine/common/mod_local.h index 52592e20..25672fc3 100644 --- a/engine/common/mod_local.h +++ b/engine/common/mod_local.h @@ -38,6 +38,7 @@ GNU General Public License for more details. #define PLATE_HUE_END 191 #define SURF_INFO( surf, mod ) ((mextrasurf_t *)mod->cache.data + (surf - mod->surfaces)) +#define INFO_SURF( surf, mod ) (mod->surfaces + (surf - (mextrasurf_t *)mod->cache.data)) // model flags (stored in model_t->flags) #define MODEL_CONVEYOR BIT( 0 ) @@ -64,6 +65,7 @@ typedef struct size_t visdatasize; // actual size of the visdata qboolean loading; // true if worldmodel is loading qboolean sky_sphere; // true when quake sky-sphere is used + qboolean has_mirrors; // one or more brush models contain reflective textures vec3_t mins; // real accuracy world bounds vec3_t maxs; diff --git a/engine/common/model.c b/engine/common/model.c index 3d768fdf..bf8ecbc7 100644 --- a/engine/common/model.c +++ b/engine/common/model.c @@ -492,6 +492,7 @@ static void Mod_LoadTextures( const dlump_t *l ) GL_FreeTexture( tr.solidskyTexture ); GL_FreeTexture( tr.alphaskyTexture ); tr.solidskyTexture = tr.alphaskyTexture = 0; + world.has_mirrors = false; world.sky_sphere = false; } @@ -1062,10 +1063,14 @@ static void Mod_LoadSurfaces( const dlump_t *l ) if( !Q_strncmp( tex->name, "scroll", 6 )) out->flags |= SURF_CONVEYOR; -#ifdef MIRROR_TEST - if( !Q_strncmp( tex->name, "glassblue1", 10 )) + + // g-cont this texture from decals.wad he-he + if( !Q_strncmp( tex->name, "reflect", 7 )) + { out->flags |= SURF_MIRROR; -#endif + world.has_mirrors = true; + } + if( tex->name[0] == '{' ) out->flags |= SURF_TRANSPARENT; diff --git a/engine/common/net_encode.c b/engine/common/net_encode.c index 42ce5a8d..603d7f12 100644 --- a/engine/common/net_encode.c +++ b/engine/common/net_encode.c @@ -81,6 +81,10 @@ static const delta_field_t pm_fields[] = { PHYS_DEF( studio_scale ) }, { PHYS_DEF( clienttrace ) }, { PHYS_DEF( wateralpha ) }, +{ PHYS_DEF( skydir_x ) }, +{ PHYS_DEF( skydir_y ) }, +{ PHYS_DEF( skydir_z ) }, +{ PHYS_DEF( skyangle ) }, { NULL }, }; @@ -817,6 +821,10 @@ void Delta_Init( void ) Delta_AddField( "movevars_t", "skyvec_x", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); // 0 - 1 Delta_AddField( "movevars_t", "skyvec_y", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); Delta_AddField( "movevars_t", "skyvec_z", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); + Delta_AddField( "movevars_t", "skydir_x", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); // 0 - 1 + Delta_AddField( "movevars_t", "skydir_y", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); + Delta_AddField( "movevars_t", "skydir_z", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); + Delta_AddField( "movevars_t", "skyangle", DT_ANGLE, 16, 1.0f, 1.0f ); // 0 - 360 Delta_AddField( "movevars_t", "studio_scale", DT_INTEGER, 1, 1.0f, 1.0f ); Delta_AddField( "movevars_t", "clienttrace", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); Delta_AddField( "movevars_t", "wateralpha", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); diff --git a/engine/engine.dsp b/engine/engine.dsp index 5a0cb141..55ab7b5c 100644 --- a/engine/engine.dsp +++ b/engine/engine.dsp @@ -206,6 +206,10 @@ SOURCE=.\common\filesystem.c # End Source File # Begin Source File +SOURCE=.\common\gamma.c +# End Source File +# Begin Source File + SOURCE=.\client\gl_backend.c # End Source File # Begin Source File @@ -230,6 +234,10 @@ SOURCE=.\client\gl_image.c # End Source File # Begin Source File +SOURCE=.\client\gl_mirror.c +# End Source File +# Begin Source File + SOURCE=.\client\gl_refrag.c # End Source File # Begin Source File diff --git a/engine/menu_int.h b/engine/menu_int.h index effa93a4..b8f9b5c2 100644 --- a/engine/menu_int.h +++ b/engine/menu_int.h @@ -153,6 +153,7 @@ typedef struct ui_enginefuncs_s void (*pfnSetCursor)( void *hCursor ); // change cursor int (*pfnIsMapValid)( char *filename ); + void (*pfnProcessImage)( int texnum, float gamma, int topColor, int bottomColor ); } ui_enginefuncs_t; typedef struct diff --git a/engine/server/server.h b/engine/server/server.h index b6769175..5a036154 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -401,6 +401,8 @@ extern convar_t *sv_clienttrace; extern convar_t *sv_send_resources; extern convar_t *sv_send_logos; extern convar_t *sv_sendvelocity; +extern convar_t *sv_skyspeed; +extern convar_t *sv_skyangle; extern convar_t *mp_consistency; extern convar_t *public_server; extern convar_t *physinfo; diff --git a/engine/server/sv_game.c b/engine/server/sv_game.c index 4297e768..7c350319 100644 --- a/engine/server/sv_game.c +++ b/engine/server/sv_game.c @@ -806,7 +806,7 @@ void SV_PlaybackEvent( sizebuf_t *msg, event_info_t *info ) BF_WriteWord( msg, info->index ); // send event index BF_WriteWord( msg, (int)( info->fire_time * 100.0f )); // send event delay - MSG_WriteDeltaEvent( msg, &nullargs, &info->args ); // TODO: use delta-compressing + MSG_WriteDeltaEvent( msg, &nullargs, &info->args ); // reliable events not use delta } const char *SV_ClassName( const edict_t *e ) @@ -3533,18 +3533,17 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex, } } - flags |= FEV_SERVER; // it's a server event + flags |= FEV_SERVER; // it's a server event! - if( delay < 0.0f ) - delay = 0.0f; // fixup negative delays + if( delay < 0.0f ) delay = 0.0f; // fixup negative delays if( SV_IsValidEdict( pInvoker )) invokerIndex = NUM_FOR_EDICT( pInvoker ); if( flags & FEV_RELIABLE ) { - args.ducking = 0; VectorClear( args.velocity ); + args.ducking = 0; } else if( invokerIndex ) { @@ -4520,6 +4519,11 @@ void SV_SpawnEntities( const char *mapname, char *entities ) Cvar_Reset( "sv_skyvec_y" ); Cvar_Reset( "sv_skyvec_z" ); Cvar_Reset( "sv_skyname" ); + Cvar_Reset( "sv_skydir_x" ); + Cvar_Reset( "sv_skydir_y" ); + Cvar_Reset( "sv_skydir_z" ); + Cvar_Reset( "sv_skyangle" ); + Cvar_Reset( "sv_skyspeed" ); ent = EDICT_NUM( 0 ); if( ent->free ) SV_InitEdict( ent ); diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index c5347f68..82c09fe5 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -80,6 +80,11 @@ convar_t *sv_skyvec_y; convar_t *sv_skyvec_z; convar_t *sv_skyname; convar_t *sv_wateralpha; +convar_t *sv_skydir_x; +convar_t *sv_skydir_y; +convar_t *sv_skydir_z; +convar_t *sv_skyangle; +convar_t *sv_skyspeed; void Master_Shutdown( void ); @@ -225,6 +230,10 @@ void SV_UpdateMovevars( void ) svgame.movevars.skyvec_x = sv_skyvec_x->value; svgame.movevars.skyvec_y = sv_skyvec_y->value; svgame.movevars.skyvec_z = sv_skyvec_z->value; + svgame.movevars.skydir_x = sv_skydir_x->value; + svgame.movevars.skydir_y = sv_skydir_y->value; + svgame.movevars.skydir_z = sv_skydir_z->value; + svgame.movevars.skyangle = sv_skyangle->value; svgame.movevars.studio_scale = sv_allow_studio_scaling->integer; svgame.movevars.clienttrace = sv_clienttrace->value; svgame.movevars.wateralpha = sv_wateralpha->value; @@ -645,13 +654,18 @@ void SV_Init( void ) // half-life shared variables sv_zmax = Cvar_Get ("sv_zmax", "4096", CVAR_PHYSICINFO, "zfar server value" ); sv_wateramp = Cvar_Get ("sv_wateramp", "0", CVAR_PHYSICINFO, "global water wave height" ); - sv_skycolor_r = Cvar_Get ("sv_skycolor_r", "255", CVAR_PHYSICINFO, "skycolor red (hl1 compatibility)" ); - sv_skycolor_g = Cvar_Get ("sv_skycolor_g", "255", CVAR_PHYSICINFO, "skycolor green (hl1 compatibility)" ); - sv_skycolor_b = Cvar_Get ("sv_skycolor_b", "255", CVAR_PHYSICINFO, "skycolor blue (hl1 compatibility)" ); - sv_skyvec_x = Cvar_Get ("sv_skyvec_x", "0", CVAR_PHYSICINFO, "sky direction x (hl1 compatibility)" ); - sv_skyvec_y = Cvar_Get ("sv_skyvec_y", "0", CVAR_PHYSICINFO, "sky direction y (hl1 compatibility)" ); - sv_skyvec_z = Cvar_Get ("sv_skyvec_z", "0", CVAR_PHYSICINFO, "sky direction z (hl1 compatibility)" ); + sv_skycolor_r = Cvar_Get ("sv_skycolor_r", "255", CVAR_PHYSICINFO, "skycolor red" ); + sv_skycolor_g = Cvar_Get ("sv_skycolor_g", "255", CVAR_PHYSICINFO, "skycolor green" ); + sv_skycolor_b = Cvar_Get ("sv_skycolor_b", "255", CVAR_PHYSICINFO, "skycolor blue" ); + sv_skyvec_x = Cvar_Get ("sv_skyvec_x", "0", CVAR_PHYSICINFO, "skylight direction x" ); + sv_skyvec_y = Cvar_Get ("sv_skyvec_y", "0", CVAR_PHYSICINFO, "skylight direction y" ); + sv_skyvec_z = Cvar_Get ("sv_skyvec_z", "0", CVAR_PHYSICINFO, "skylight direction z" ); sv_skyname = Cvar_Get ("sv_skyname", "desert", CVAR_PHYSICINFO, "skybox name (can be dynamically changed in-game)" ); + sv_skydir_x = Cvar_Get ("sv_skydir_x", "0", CVAR_PHYSICINFO, "sky rotation direction x" ); + sv_skydir_y = Cvar_Get ("sv_skydir_y", "0", CVAR_PHYSICINFO, "sky rotation direction y" ); + sv_skydir_z = Cvar_Get ("sv_skydir_z", "1", CVAR_PHYSICINFO, "sky rotation direction z" ); // g-cont. add default sky rotate direction + sv_skyangle = Cvar_Get ("sv_skyangle", "0", CVAR_PHYSICINFO, "skybox rotational angle (in degrees)" ); + sv_skyspeed = Cvar_Get ("sv_skyspeed", "0", 0, "skybox rotational speed" ); sv_footsteps = Cvar_Get ("mp_footsteps", "1", CVAR_PHYSICINFO, "can hear footsteps from other players" ); sv_wateralpha = Cvar_Get ("sv_wateralpha", "1", CVAR_PHYSICINFO, "world surfaces water transparency factor. 1.0 - solid, 0.0 - fully transparent" ); diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index e69b875f..5d343f42 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -1707,6 +1707,14 @@ void SV_Physics( void ) // animate lightstyles (used for GetEntityIllum) SV_RunLightStyles (); + if( sv_skyspeed->value ) + { + // evaluate sky rotation. + // FIXME: ignore this feature in multiplayer to save traffic? + float skyAngle = sv_skyangle->value + sv_skyspeed->value * host.frametime; + Cvar_SetFloat( "sv_skyangle", anglemod( skyAngle )); + } + // decrement svgame.numEntities if the highest number entities died for( ; EDICT_NUM( svgame.numEntities - 1 )->free; svgame.numEntities-- ); } diff --git a/engine/server/sv_save.c b/engine/server/sv_save.c index 9691a617..773f466d 100644 --- a/engine/server/sv_save.c +++ b/engine/server/sv_save.c @@ -75,6 +75,11 @@ typedef struct int viewentity; // Xash3D added int serverflags; // converted to float and back float wateralpha; + float skyDir_x; + float skyDir_y; + float skyDir_z; + float skyAngle; + float skySpeed; } SAVE_HEADER; typedef struct @@ -108,6 +113,11 @@ static TYPEDESCRIPTION gSaveHeader[] = DEFINE_FIELD( SAVE_HEADER, viewentity, FIELD_SHORT ), DEFINE_FIELD( SAVE_HEADER, serverflags, FIELD_INTEGER ), DEFINE_FIELD( SAVE_HEADER, wateralpha, FIELD_FLOAT ), + DEFINE_FIELD( SAVE_HEADER, skyDir_x, FIELD_FLOAT ), + DEFINE_FIELD( SAVE_HEADER, skyDir_y, FIELD_FLOAT ), + DEFINE_FIELD( SAVE_HEADER, skyDir_z, FIELD_FLOAT ), + DEFINE_FIELD( SAVE_HEADER, skyAngle, FIELD_FLOAT ), + DEFINE_FIELD( SAVE_HEADER, skySpeed, FIELD_FLOAT ), }; static TYPEDESCRIPTION gAdjacency[] = @@ -697,6 +707,11 @@ void SV_SaveGameStateGlobals( SAVERESTOREDATA *pSaveData ) header.skyVec_x = Cvar_VariableValue( "sv_skyvec_x" ); header.skyVec_y = Cvar_VariableValue( "sv_skyvec_y" ); header.skyVec_z = Cvar_VariableValue( "sv_skyvec_z" ); + header.skyDir_x = Cvar_VariableValue( "sv_skydir_x" ); + header.skyDir_y = Cvar_VariableValue( "sv_skydir_y" ); + header.skyDir_z = Cvar_VariableValue( "sv_skydir_z" ); + header.skyAngle = Cvar_VariableValue( "sv_skyangle" ); + header.skySpeed = Cvar_VariableValue( "sv_skyspeed" ); // save viewentity to allow camera works after save\restore if(( cl = SV_ClientFromEdict( EDICT_NUM( 1 ), true )) != NULL ) @@ -1181,10 +1196,16 @@ int SV_LoadGameState( char const *level, qboolean createPlayers ) Cvar_SetFloat( "sv_skyvec_x", header.skyVec_x ); Cvar_SetFloat( "sv_skyvec_y", header.skyVec_y ); Cvar_SetFloat( "sv_skyvec_z", header.skyVec_z ); + Cvar_SetFloat( "sv_skydir_x", header.skyDir_x ); + Cvar_SetFloat( "sv_skydir_y", header.skyDir_y ); + Cvar_SetFloat( "sv_skydir_z", header.skyDir_z ); + Cvar_SetFloat( "sv_skyangle", header.skyAngle ); + Cvar_SetFloat( "sv_skyspeed", header.skySpeed ); // restore serverflags svgame.globals->serverflags = header.serverflags; + if( header.wateralpha <= 0.0f ) header.wateralpha = 1.0f; // make compatibility with old saves Cvar_SetFloat( "sv_wateralpha", header.wateralpha ); // re-base the savedata since we re-ordered the entity/table / restore fields diff --git a/engine/server/sv_studio.c b/engine/server/sv_studio.c index be277f37..18c08ddc 100644 --- a/engine/server/sv_studio.c +++ b/engine/server/sv_studio.c @@ -1016,11 +1016,11 @@ void SV_StudioGetAttachment( edict_t *e, int iAttachment, float *org, float *ang void SV_GetBonePosition( edict_t *e, int iBone, float *org, float *ang ) { - iBone = bound( 0, iBone, sv_studiohdr->numbones ); - if( !SV_StudioSetupModel( e, iBone, false ) || sv_studiohdr->numbones <= 0 ) return; + iBone = bound( 0, iBone, sv_studiohdr->numbones ); + if( org ) Matrix3x4_OriginFromMatrix( sv_studiobones[iBone], org ); if( ang ) VectorAngles( sv_studiobones[iBone][0], ang ); // bone forward to angles diff --git a/mainui/enginecallback.h b/mainui/enginecallback.h index 785ea681..c0964098 100644 --- a/mainui/enginecallback.h +++ b/mainui/enginecallback.h @@ -31,6 +31,8 @@ GNU General Public License for more details. #define GetGameInfo (*g_engfuncs.pfnGetGameInfo) #define CheckGameDll (*g_engfuncs.pfnCheckGameDll) +#define PIC_SetGamma( x, y ) (*g_engfuncs.pfnProcessImage)( x, y, 0, 0 ) + #define DRAW_LOGO (*g_engfuncs.pfnDrawLogo) #define PRECACHE_LOGO( x ) (*g_engfuncs.pfnDrawLogo)( x, 0, 0, 0, 0 ) #define GetLogoWidth (*g_engfuncs.pfnGetLogoWidth) diff --git a/mainui/menu_vidoptions.cpp b/mainui/menu_vidoptions.cpp index d956b12f..d00b84f9 100644 --- a/mainui/menu_vidoptions.cpp +++ b/mainui/menu_vidoptions.cpp @@ -51,6 +51,8 @@ typedef struct menuSlider_s glareReduction; menuCheckBox_s fastSky; menuCheckBox_s hiTextures; + + HIMAGE hTestImage; } uiVidOptions_t; static uiVidOptions_t uiVidOptions; @@ -64,9 +66,15 @@ UI_VidOptions_GetConfig static void UI_VidOptions_GetConfig( void ) { uiVidOptions.screenSize.curValue = RemapVal( CVAR_GET_FLOAT( "viewsize" ), 30.0f, 120.0f, 0.0f, 1.0f ); - uiVidOptions.gammaIntensity.curValue = RemapVal( CVAR_GET_FLOAT( "gamma" ), 0.5f, 2.3f, 0.0f, 1.0f ); uiVidOptions.glareReduction.curValue = (CVAR_GET_FLOAT( "r_flaresize" ) - 100.0f ) / 200.0f; + if( CVAR_GET_FLOAT( "gl_ignorehwgamma" )) + { + uiVidOptions.gammaIntensity.curValue = RemapVal( CVAR_GET_FLOAT( "gamma" ), 1.8f, 3.0f, 0.0f, 1.0f ); + PIC_SetGamma( uiVidOptions.hTestImage, CVAR_GET_FLOAT( "gamma" )); + } + else uiVidOptions.gammaIntensity.curValue = RemapVal( CVAR_GET_FLOAT( "gamma" ), 0.5f, 3.0f, 0.0f, 1.0f ); + if( CVAR_GET_FLOAT( "r_fastsky" )) uiVidOptions.fastSky.enabled = 1; @@ -85,10 +93,25 @@ UI_VidOptions_UpdateConfig static void UI_VidOptions_UpdateConfig( void ) { CVAR_SET_FLOAT( "viewsize", RemapVal( uiVidOptions.screenSize.curValue, 0.0f, 1.0f, 30.0f, 120.0f )); - CVAR_SET_FLOAT( "gamma", RemapVal( uiVidOptions.gammaIntensity.curValue, 0.0f, 1.0f, 0.5f, 2.3f )); CVAR_SET_FLOAT( "r_flaresize", (uiVidOptions.glareReduction.curValue * 200.0f ) + 100.0f ); CVAR_SET_FLOAT( "r_fastsky", uiVidOptions.fastSky.enabled ); CVAR_SET_FLOAT( "host_allow_materials", uiVidOptions.hiTextures.enabled ); + + if( CVAR_GET_FLOAT( "gl_ignorehwgamma" )) + PIC_SetGamma( uiVidOptions.hTestImage, RemapVal( uiVidOptions.gammaIntensity.curValue, 0.0f, 1.0f, 1.8f, 3.0f )); + else CVAR_SET_FLOAT( "gamma", RemapVal( uiVidOptions.gammaIntensity.curValue, 0.0f, 1.0f, 0.5f, 2.3f )); +} + +static void UI_VidOptions_SetConfig( void ) +{ + CVAR_SET_FLOAT( "viewsize", RemapVal( uiVidOptions.screenSize.curValue, 0.0f, 1.0f, 30.0f, 120.0f )); + CVAR_SET_FLOAT( "r_flaresize", (uiVidOptions.glareReduction.curValue * 200.0f ) + 100.0f ); + CVAR_SET_FLOAT( "r_fastsky", uiVidOptions.fastSky.enabled ); + CVAR_SET_FLOAT( "host_allow_materials", uiVidOptions.hiTextures.enabled ); + + if( CVAR_GET_FLOAT( "gl_ignorehwgamma" )) + CVAR_SET_FLOAT( "gamma", RemapVal( uiVidOptions.gammaIntensity.curValue, 0.0f, 1.0f, 1.8f, 3.0f )); + else CVAR_SET_FLOAT( "gamma", RemapVal( uiVidOptions.gammaIntensity.curValue, 0.0f, 1.0f, 0.5f, 2.3f )); } /* @@ -162,6 +185,7 @@ static void UI_VidOptions_Callback( void *self, int event ) switch( item->id ) { case ID_DONE: + UI_VidOptions_SetConfig(); UI_PopMenu(); break; } @@ -176,6 +200,8 @@ static void UI_VidOptions_Init( void ) { memset( &uiVidOptions, 0, sizeof( uiVidOptions_t )); + uiVidOptions.hTestImage = PIC_Load( ART_GAMMA ); + uiVidOptions.menu.vidInitFunc = UI_VidOptions_Init; uiVidOptions.background.generic.id = ID_BACKGROUND; @@ -293,7 +319,6 @@ void UI_VidOptions_Precache( void ) { PIC_Load( ART_BACKGROUND ); PIC_Load( ART_BANNER ); - PIC_Load( ART_GAMMA ); } /* @@ -306,6 +331,5 @@ void UI_VidOptions_Menu( void ) UI_VidOptions_Precache(); UI_VidOptions_Init(); - UI_VidOptions_UpdateConfig(); UI_PushMenu( &uiVidOptions.menu ); } \ No newline at end of file diff --git a/pm_shared/pm_movevars.h b/pm_shared/pm_movevars.h index a85893f8..9edf2a74 100644 --- a/pm_shared/pm_movevars.h +++ b/pm_shared/pm_movevars.h @@ -43,6 +43,10 @@ struct movevars_s qboolean studio_scale; // Allow engine to scale visible and physic hull of studiomodels float clienttrace; // Studiomodels scale that applied for the clients (visual effect only) float wateralpha; // World water alpha 1.0 - solid 0.0 - transparent + float skydir_x; // skybox rotate direction + float skydir_y; // + float skydir_z; // + float skyangle; // skybox rotate angle }; extern movevars_t movevars;