From de17869a5554853271263264fa7a432a129fb383 Mon Sep 17 00:00:00 2001 From: g-cont Date: Sun, 4 Sep 2011 00:00:00 +0400 Subject: [PATCH] 04 Sep 2011 --- change.log | 14 +- cl_dll/cl_dll.plg | 110 ++++++++ dlls/hl.plg | 16 +- dlls/tripmine.cpp | 2 +- engine/client/cl_cmds.c | 81 +++++- engine/client/cl_frame.c | 32 +++ engine/client/cl_game.c | 102 +++----- engine/client/cl_main.c | 3 + engine/client/cl_parse.c | 9 +- engine/client/cl_pmove.c | 11 +- engine/client/cl_remap.c | 7 +- engine/client/cl_scrn.c | 14 +- engine/client/cl_tent.c | 59 ++++- engine/client/cl_view.c | 13 +- engine/client/client.h | 13 +- engine/client/gl_backend.c | 7 +- engine/client/gl_beams.c | 108 +++++++- engine/client/gl_local.h | 2 +- engine/client/gl_rmain.c | 102 +++++--- engine/client/gl_rmisc.c | 7 +- engine/client/gl_rpart.c | 71 ++++++ engine/client/gl_rsurf.c | 94 ++++--- engine/client/gl_sprite.c | 41 +-- engine/client/gl_studio.c | 38 ++- engine/client/gl_vidnt.c | 9 +- engine/client/s_load.c | 44 +++- engine/client/s_main.c | 166 ++++++++++-- engine/client/s_mix.c | 6 - engine/client/s_vox.c | 1 - engine/client/sound.h | 9 +- engine/client/vgui/vgui_int.cpp | 27 ++ engine/common/common.h | 5 + engine/common/console.c | 28 ++- engine/common/filesystem.c | 15 +- engine/common/host.c | 2 + engine/common/imagelib/img_quant.c | 2 +- engine/common/imagelib/img_quant.old | 363 +++++++++++++++++++++++++++ engine/common/imagelib/img_tga.c | 3 + engine/common/imagelib/img_utils.c | 22 +- engine/common/imagelib/img_wad.c | 4 +- engine/common/keys.c | 7 + engine/common/mod_local.h | 1 + engine/common/model.c | 190 +++++++++++--- engine/common/net_encode.c | 3 +- engine/common/pm_trace.c | 6 +- engine/common/soundlib/snd_mp3.c | 3 - engine/common/soundlib/snd_utils.c | 43 ++++ engine/common/soundlib/snd_wav.c | 32 ++- engine/common/soundlib/soundlib.h | 34 +++ engine/engine.dsp | 22 +- engine/server/server.h | 1 + engine/server/sv_client.c | 11 +- engine/server/sv_game.c | 76 ++---- engine/server/sv_main.c | 5 + engine/server/sv_phys.c | 37 ++- engine/server/sv_save.c | 12 + engine/server/sv_world.c | 8 +- engine/studio.h | 14 +- mainui/menu_creategame.cpp | 2 +- mainui/utils.cpp | 2 +- pm_shared/pm_movevars.h | 1 + 61 files changed, 1791 insertions(+), 381 deletions(-) create mode 100644 engine/common/imagelib/img_quant.old diff --git a/change.log b/change.log index 402e582e..5abc9284 100644 --- a/change.log +++ b/change.log @@ -1,8 +1,20 @@ -build ???? +build 1662 Client: implement StudioRemapColors function Client: add simple shadows for stduiomodels (disabled like in GoldSrc) Client: fix some Paranoia bugs when custom renderer is disabled +Client: implement overview tool (dev_overview) +Client: add debug commands linefile and pointfile +Client: get support for full-color external textures (tga format) - world, studiomodels and decals +Client: fixed some HLFX 0.6 bugs +Client: fixed follow studiomodels (like flags in CTF) +Server: add pfnGetApproxWavePlayLen +Sound: get support for mp3's with wav header +Server: fixed FIND_CLIENT_IN_PVS +Server: fixed PlaybackEvent, use camera PVS point when client see in +Render: enable lightmaps on a transparent surfaces like windows (r_lighting_extended 2) +Server: func_pushable can push players which standing on (sv_fix_pushstep) +Render: partially fix for underwater fog (temporary solution) build 1613 diff --git a/cl_dll/cl_dll.plg b/cl_dll/cl_dll.plg index f9d4a2cd..070f646c 100644 --- a/cl_dll/cl_dll.plg +++ b/cl_dll/cl_dll.plg @@ -6,6 +6,116 @@ --------------------Configuration: cl_dll - Win32 Release--------------------

Command Lines

+Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP266.tmp" with contents +[ +/nologo /MT /W3 /GX /O2 /I "..\utils\vgui\include" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\dlls" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "CLIENT_DLL" /D "CLIENT_WEAPONS" /Fp"..\temp\cl_dll\!release/cl_dll.pch" /YX /Fo"..\temp\cl_dll\!release/" /Fd"..\temp\cl_dll\!release/" /FD /c +"D:\Xash3D\src_main\cl_dll\ev_hldm.cpp" +"D:\Xash3D\src_main\cl_dll\cdll_int.cpp" +"D:\Xash3D\src_main\cl_dll\ev_common.cpp" +"D:\Xash3D\src_main\pm_shared\pm_shared.c" +] +Creating command line "cl.exe @"C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP266.tmp"" +Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP267.tmp" with contents +[ +kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib winmm.lib ../utils/vgui/lib/win32_vc6/vgui.lib wsock32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"..\temp\cl_dll\!release/client.pdb" /machine:I386 /out:"..\temp\cl_dll\!release/client.dll" /implib:"..\temp\cl_dll\!release/client.lib" +"\Xash3D\src_main\temp\cl_dll\!release\crossbow.obj" +"\Xash3D\src_main\temp\cl_dll\!release\crowbar.obj" +"\Xash3D\src_main\temp\cl_dll\!release\egon.obj" +"\Xash3D\src_main\temp\cl_dll\!release\ev_hldm.obj" +"\Xash3D\src_main\temp\cl_dll\!release\gauss.obj" +"\Xash3D\src_main\temp\cl_dll\!release\handgrenade.obj" +"\Xash3D\src_main\temp\cl_dll\!release\hl_baseentity.obj" +"\Xash3D\src_main\temp\cl_dll\!release\hl_events.obj" +"\Xash3D\src_main\temp\cl_dll\!release\hl_objects.obj" +"\Xash3D\src_main\temp\cl_dll\!release\hl_weapons.obj" +"\Xash3D\src_main\temp\cl_dll\!release\hl_wpn_glock.obj" +"\Xash3D\src_main\temp\cl_dll\!release\hornetgun.obj" +"\Xash3D\src_main\temp\cl_dll\!release\mp5.obj" +"\Xash3D\src_main\temp\cl_dll\!release\python.obj" +"\Xash3D\src_main\temp\cl_dll\!release\rpg.obj" +"\Xash3D\src_main\temp\cl_dll\!release\satchel.obj" +"\Xash3D\src_main\temp\cl_dll\!release\shotgun.obj" +"\Xash3D\src_main\temp\cl_dll\!release\squeakgrenade.obj" +"\Xash3D\src_main\temp\cl_dll\!release\tripmine.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_scrollbar2.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_slider2.obj" +"\Xash3D\src_main\temp\cl_dll\!release\voice_banmgr.obj" +"\Xash3D\src_main\temp\cl_dll\!release\voice_status.obj" +"\Xash3D\src_main\temp\cl_dll\!release\ammo.obj" +"\Xash3D\src_main\temp\cl_dll\!release\ammo_secondary.obj" +"\Xash3D\src_main\temp\cl_dll\!release\ammohistory.obj" +"\Xash3D\src_main\temp\cl_dll\!release\battery.obj" +"\Xash3D\src_main\temp\cl_dll\!release\cdll_int.obj" +"\Xash3D\src_main\temp\cl_dll\!release\com_weapons.obj" +"\Xash3D\src_main\temp\cl_dll\!release\death.obj" +"\Xash3D\src_main\temp\cl_dll\!release\demo.obj" +"\Xash3D\src_main\temp\cl_dll\!release\entity.obj" +"\Xash3D\src_main\temp\cl_dll\!release\ev_common.obj" +"\Xash3D\src_main\temp\cl_dll\!release\events.obj" +"\Xash3D\src_main\temp\cl_dll\!release\flashlight.obj" +"\Xash3D\src_main\temp\cl_dll\!release\GameStudioModelRenderer.obj" +"\Xash3D\src_main\temp\cl_dll\!release\geiger.obj" +"\Xash3D\src_main\temp\cl_dll\!release\health.obj" +"\Xash3D\src_main\temp\cl_dll\!release\hud.obj" +"\Xash3D\src_main\temp\cl_dll\!release\hud_msg.obj" +"\Xash3D\src_main\temp\cl_dll\!release\hud_redraw.obj" +"\Xash3D\src_main\temp\cl_dll\!release\hud_servers.obj" +"\Xash3D\src_main\temp\cl_dll\!release\hud_spectator.obj" +"\Xash3D\src_main\temp\cl_dll\!release\hud_update.obj" +"\Xash3D\src_main\temp\cl_dll\!release\in_camera.obj" +"\Xash3D\src_main\temp\cl_dll\!release\input.obj" +"\Xash3D\src_main\temp\cl_dll\!release\inputw32.obj" +"\Xash3D\src_main\temp\cl_dll\!release\menu.obj" +"\Xash3D\src_main\temp\cl_dll\!release\message.obj" +"\Xash3D\src_main\temp\cl_dll\!release\parsemsg.obj" +"\Xash3D\src_main\temp\cl_dll\!release\pm_debug.obj" +"\Xash3D\src_main\temp\cl_dll\!release\pm_math.obj" +"\Xash3D\src_main\temp\cl_dll\!release\pm_shared.obj" +"\Xash3D\src_main\temp\cl_dll\!release\saytext.obj" +"\Xash3D\src_main\temp\cl_dll\!release\status_icons.obj" +"\Xash3D\src_main\temp\cl_dll\!release\statusbar.obj" +"\Xash3D\src_main\temp\cl_dll\!release\studio_util.obj" +"\Xash3D\src_main\temp\cl_dll\!release\StudioModelRenderer.obj" +"\Xash3D\src_main\temp\cl_dll\!release\text_message.obj" +"\Xash3D\src_main\temp\cl_dll\!release\train.obj" +"\Xash3D\src_main\temp\cl_dll\!release\tri.obj" +"\Xash3D\src_main\temp\cl_dll\!release\util.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_checkbutton2.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_ClassMenu.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_ConsolePanel.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_ControlConfigPanel.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_CustomObjects.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_grid.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_helpers.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_int.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_listbox.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_loadtga.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_MOTDWindow.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_SchemeManager.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_ScorePanel.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_ServerBrowser.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_SpectatorPanel.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_TeamFortressViewport.obj" +"\Xash3D\src_main\temp\cl_dll\!release\vgui_teammenu.obj" +"\Xash3D\src_main\temp\cl_dll\!release\view.obj" +] +Creating command line "link.exe @"C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP267.tmp"" +Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP268.bat" with contents +[ +@echo off +copy \Xash3D\src_main\temp\cl_dll\!release\client.dll "D:\Xash3D\valve\cl_dlls\client.dll" +] +Creating command line ""C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP268.bat"" +Compiling... +ev_hldm.cpp +cdll_int.cpp +ev_common.cpp +pm_shared.c +Linking... + Creating library ..\temp\cl_dll\!release/client.lib and object ..\temp\cl_dll\!release/client.exp +

Output Window

+Performing Custom Build Step on \Xash3D\src_main\temp\cl_dll\!release\client.dll +‘ª®¯¨à®¢ ­® ä ©«®¢: 1. diff --git a/dlls/hl.plg b/dlls/hl.plg index 06d48cfd..d11dea49 100644 --- a/dlls/hl.plg +++ b/dlls/hl.plg @@ -6,13 +6,13 @@ --------------------Configuration: hl - Win32 Release--------------------

Command Lines

-Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1B70.tmp" with contents +Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1931.tmp" with contents [ /nologo /G5 /MT /W3 /O2 /I "..\dlls" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\game_shared" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /D "CLIENT_WEAPONS" /Fr"..\temp\dlls\!release/" /Fp"..\temp\dlls\!release/hl.pch" /YX /Fo"..\temp\dlls\!release/" /Fd"..\temp\dlls\!release/" /FD /c -"D:\Xash3D\src_main\dlls\client.cpp" +"D:\Xash3D\src_main\dlls\nodes.cpp" ] -Creating command line "cl.exe @"C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1B70.tmp"" -Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1B71.tmp" with contents +Creating command line "cl.exe @"C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1931.tmp"" +Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1932.tmp" with contents [ kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"..\temp\dlls\!release/hl.pdb" /debug /machine:I386 /def:".\hl.def" /out:"..\temp\dlls\!release/hl.dll" /implib:"..\temp\dlls\!release/hl.lib" "\Xash3D\src_main\temp\dlls\!release\aflock.obj" @@ -117,15 +117,15 @@ kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32 "\Xash3D\src_main\temp\dlls\!release\xen.obj" "\Xash3D\src_main\temp\dlls\!release\zombie.obj" ] -Creating command line "link.exe @"C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1B71.tmp"" -Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1B72.bat" with contents +Creating command line "link.exe @"C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1932.tmp"" +Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1933.bat" with contents [ @echo off copy \Xash3D\src_main\temp\dlls\!release\hl.dll "D:\Xash3D\valve\dlls\hl.dll" ] -Creating command line ""C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1B72.bat"" +Creating command line ""C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP1933.bat"" Compiling... -client.cpp +nodes.cpp Linking... Creating library ..\temp\dlls\!release/hl.lib and object ..\temp\dlls\!release/hl.exp

Output Window

diff --git a/dlls/tripmine.cpp b/dlls/tripmine.cpp index 81ff1044..6b039080 100644 --- a/dlls/tripmine.cpp +++ b/dlls/tripmine.cpp @@ -407,7 +407,7 @@ int CTripmine::GetItemInfo(ItemInfo *p) BOOL CTripmine::Deploy( ) { - //pev->body = 0; + pev->body = 0; return DefaultDeploy( "models/v_tripmine.mdl", "models/p_tripmine.mdl", TRIPMINE_DRAW, "trip" ); } diff --git a/engine/client/cl_cmds.c b/engine/client/cl_cmds.c index 912334a6..6e52c0f3 100644 --- a/engine/client/cl_cmds.c +++ b/engine/client/cl_cmds.c @@ -65,10 +65,13 @@ void CL_PlayCDTrack_f( void ) static int track = 0; static qboolean paused = false; static qboolean looped = false; + static qboolean enabled = true; if( Cmd_Argc() < 2 ) return; command = Cmd_Argv( 1 ); + if( !enabled && Q_stricmp( command, "on" )) return; // CD-player is disabled + if( !Q_stricmp( command, "play" )) { track = bound( 1, Q_atoi( Cmd_Argv( 2 )), MAX_CDTRACKS ); @@ -100,6 +103,14 @@ void CL_PlayCDTrack_f( void ) looped = false; track = 0; } + else if( !Q_stricmp( command, "on" )) + { + enabled = true; + } + else if( !Q_stricmp( command, "off" )) + { + enabled = false; + } else if( !Q_stricmp( command, "info" )) { int i, maxTrack; @@ -128,7 +139,6 @@ void CL_ScreenshotGetName( int lastnum, char *filename ) { int a, b, c, d; - if( !filename ) return; if( lastnum < 0 || lastnum > 9999 ) { // bound @@ -147,6 +157,35 @@ void CL_ScreenshotGetName( int lastnum, char *filename ) Q_sprintf( filename, "scrshots/%s/shot%i%i%i%i.bmp", clgame.mapname, a, b, c, d ); } +/* +================== +CL_SnapshotGetName +================== +*/ +qboolean CL_SnapshotGetName( int lastnum, char *filename ) +{ + int a, b, c, d; + + if( lastnum < 0 || lastnum > 9999 ) + { + MsgDev( D_ERROR, "unable to write snapshot\n" ); + FS_AllowDirectPaths( false ); + return false; + } + + a = lastnum / 1000; + lastnum -= a * 1000; + b = lastnum / 100; + lastnum -= b * 100; + c = lastnum / 10; + lastnum -= c * 10; + d = lastnum; + + Q_sprintf( filename, "../%s%i%i%i%i.bmp", clgame.mapname, a, b, c, d ); + + return true; +} + /* ============================================================================== @@ -189,6 +228,46 @@ void CL_ScreenShot_f( void ) cls.envshot_vieworg = NULL; // no custom view } +/* +================== +CL_SnapShot_f + +save screenshots into root dir +================== +*/ +void CL_SnapShot_f( void ) +{ + int i; + string checkname; + + if( gl_overview->integer == 1 ) + { + // special case for write overview image and script file + Q_snprintf( cls.shotname, sizeof( cls.shotname ), "overviews/%s.bmp", clgame.mapname ); + cls.scrshot_action = scrshot_mapshot; // build new frame for mapshot + } + else + { + FS_AllowDirectPaths( true ); + + // scan for a free filename + for( i = 0; i < 9999; i++ ) + { + if( !CL_SnapshotGetName( i, checkname )) + return; // no namespace + + if( !FS_FileExists( checkname, false )) + break; + } + + FS_AllowDirectPaths( false ); + Q_strncpy( cls.shotname, checkname, sizeof( cls.shotname )); + cls.scrshot_action = scrshot_snapshot; // build new frame for screenshot + } + + cls.envshot_vieworg = NULL; // no custom view +} + /* ================== CL_EnvShot_f diff --git a/engine/client/cl_frame.c b/engine/client/cl_frame.c index a9f9cc36..d5bedd07 100644 --- a/engine/client/cl_frame.c +++ b/engine/client/cl_frame.c @@ -256,6 +256,38 @@ qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType ) dl->radius = 430; else dl->radius = Com_RandomLong( 400, 430 ); } + + if( ent->model->type == mod_studio ) + { + if (ent->model->flags & STUDIO_ROTATE) + ent->angles[1] = anglemod(100 * cl.time); + + if (ent->model->flags & STUDIO_GIB) + CL_RocketTrail (ent->prevstate.origin, ent->curstate.origin, 2); + else if (ent->model->flags & STUDIO_ZOMGIB) + CL_RocketTrail (ent->prevstate.origin, ent->curstate.origin, 4); + else if (ent->model->flags & STUDIO_TRACER) + CL_RocketTrail (ent->prevstate.origin, ent->curstate.origin, 3); + else if (ent->model->flags & STUDIO_TRACER2) + CL_RocketTrail (ent->prevstate.origin, ent->curstate.origin, 5); + else if (ent->model->flags & STUDIO_ROCKET) + { + dlight_t *dl = CL_AllocDlight (ent->curstate.number); + VectorCopy (ent->origin, dl->origin); + dl->color.r = 255; + dl->color.g = 255; + dl->color.b = 255; + dl->radius = 200; + dl->die = cl.time + 0.01; + + CL_RocketTrail (ent->prevstate.origin, ent->curstate.origin, 0); + } + else if (ent->model->flags & STUDIO_GRENADE) + CL_RocketTrail (ent->prevstate.origin, ent->curstate.origin, 1); + else if (ent->model->flags & STUDIO_TRACER3) + CL_RocketTrail (ent->prevstate.origin, ent->curstate.origin, 6); + } + return true; } diff --git a/engine/client/cl_game.c b/engine/client/cl_game.c index 6b6a3f85..a7736cd0 100644 --- a/engine/client/cl_game.c +++ b/engine/client/cl_game.c @@ -276,40 +276,6 @@ void CL_StudioEvent( struct mstudioevent_s *event, cl_entity_t *pEdict ) clgame.dllFuncs.pfnStudioEvent( event, pEdict ); } -/* -================ -CL_FadeAlpha -================ -*/ -void CL_FadeAlpha( int starttime, int endtime, byte *alpha ) -{ - int time, fade_time; - - if( !starttime ) - { - *alpha = 255; - return; - } - - // FIXME: rewrite this code with float values - time = (cl.time * 1000) - starttime; - - if( time >= endtime ) - { - *alpha = 0; - return; - } - - // fade time is 1/4 of endtime - fade_time = endtime / 4; - fade_time = bound( 300, fade_time, 10000 ); - - // fade out - if(( endtime - time ) < fade_time ) - *alpha = bound( 0, (( endtime - time ) * ( 1.0f / fade_time )) * 255, 255 ); - else *alpha = 255; -} - /* ============= CL_AdjustXPos @@ -388,7 +354,7 @@ void CL_CenterPrint( const char *text, float y ) clgame.centerPrint.lines = 1; clgame.centerPrint.totalWidth = 0; - clgame.centerPrint.time = cl.mtime[0] * 1000; // allow pause for centerprint + clgame.centerPrint.time = cl.mtime[0]; // allow pause for centerprint Q_strncpy( clgame.centerPrint.message, text, sizeof( clgame.centerPrint.message )); s = clgame.centerPrint.message; @@ -554,23 +520,23 @@ static void CL_DrawCenterPrint( void ) char *pText; int i, j, x, y; int width, lineLength; - byte line[80]; - byte alpha; + byte *colorDefault, line[80]; + int charWidth, charHeight; if( !clgame.centerPrint.time ) return; - CL_FadeAlpha( clgame.centerPrint.time, scr_centertime->value * 1000, &alpha ); - - if( !alpha ) + if(( cl.time - clgame.centerPrint.time ) >= scr_centertime->value ) { - // faded out - clgame.centerPrint.time = 0; + // time expired + clgame.centerPrint.time = 0.0f; return; } - pText = clgame.centerPrint.message; y = clgame.centerPrint.y; // start y + colorDefault = g_color_table[7]; + pText = clgame.centerPrint.message; + Con_DrawCharacterLen( 0, NULL, &charHeight ); for( i = 0; i < clgame.centerPrint.lines; i++ ) { @@ -581,10 +547,12 @@ static void CL_DrawCenterPrint( void ) { byte c = *pText; line[lineLength] = c; - width += clgame.scrInfo.charWidths[c]; + Con_DrawCharacterLen( c, &charWidth, NULL ); + width += charWidth; lineLength++; pText++; } + pText++; // Skip LineFeed line[lineLength] = 0; @@ -592,17 +560,10 @@ static void CL_DrawCenterPrint( void ) for( j = 0; j < lineLength; j++ ) { - int ch = line[j]; - int next = x + clgame.scrInfo.charWidths[ch]; - - if( x >= 0 && y >= 0 && next <= clgame.scrInfo.iWidth ) - { - pfnPIC_Set( cls.creditsFont.hFontTexture, 255, 255, 255, alpha ); - pfnPIC_DrawAdditive( x, y, -1, -1, &cls.creditsFont.fontRc[ch] ); - } - x = next; + if( x >= 0 && y >= 0 && x <= clgame.scrInfo.iWidth ) + x += Con_DrawCharacter( x, y, line[j], colorDefault ); } - y += clgame.scrInfo.iCharHeight; + y += charHeight; } } @@ -900,19 +861,28 @@ static void CL_DrawLoading( float percent ) width *= xscale; height *= yscale; - pglColor4ub( 128, 128, 128, 255 ); - GL_SetRenderMode( kRenderTransTexture ); - R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, cls.loadingBar ); + if( cl_allow_levelshots->integer ) + { + pglColor4ub( 128, 128, 128, 255 ); + GL_SetRenderMode( kRenderTransTexture ); + R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, cls.loadingBar ); - step = (float)width / 100.0f; - right = (int)ceil( percent * step ); - s2 = (float)right / width; - width = right; + step = (float)width / 100.0f; + right = (int)ceil( percent * step ); + s2 = (float)right / width; + width = right; - pglColor4ub( 208, 152, 0, 255 ); - GL_SetRenderMode( kRenderTransTexture ); - R_DrawStretchPic( x, y, width, height, 0, 0, s2, 1, cls.loadingBar ); - pglColor4ub( 255, 255, 255, 255 ); + pglColor4ub( 208, 152, 0, 255 ); + GL_SetRenderMode( kRenderTransTexture ); + R_DrawStretchPic( x, y, width, height, 0, 0, s2, 1, cls.loadingBar ); + pglColor4ub( 255, 255, 255, 255 ); + } + else + { + pglColor4ub( 255, 255, 255, 255 ); + GL_SetRenderMode( kRenderTransTexture ); + R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, cls.loadingBar ); + } } /* @@ -1972,7 +1942,7 @@ like trigger_multiple message in q1 static void pfnCenterPrint( const char *string ) { if( !string || !*string ) return; // someone stupid joke - CL_CenterPrint( string, -1 ); + CL_CenterPrint( string, 0.25f ); } /* diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 2e01b757..33945ef1 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -1547,11 +1547,14 @@ void CL_InitLocal( void ) Cmd_AddCommand ("stop", CL_Stop_f, "stop playing or recording a demo" ); Cmd_AddCommand ("info", NULL, "collect info about local servers with specified protocol" ); Cmd_AddCommand ("escape", CL_Escape_f, "escape from game to menu" ); + Cmd_AddCommand ("pointfile", CL_ReadPointFile_f, "show leaks on a map (if present of course)" ); + Cmd_AddCommand ("linefile", CL_ReadLineFile_f, "show leaks on a map (if present of course)" ); Cmd_AddCommand ("quit", CL_Quit_f, "quit from game" ); Cmd_AddCommand ("exit", CL_Quit_f, "quit from game" ); Cmd_AddCommand ("screenshot", CL_ScreenShot_f, "takes a screenshot of the next rendered frame" ); + Cmd_AddCommand ("snapshot", CL_SnapShot_f, "takes a snapshot of the next rendered frame" ); Cmd_AddCommand ("envshot", CL_EnvShot_f, "takes a six-sides cubemap shot with specified name" ); Cmd_AddCommand ("skyshot", CL_SkyShot_f, "takes a six-sides envmap (skybox) shot with specified name" ); Cmd_AddCommand ("levelshot", CL_LevelShot_f, "same as \"screenshot\", used for create plaque images" ); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 924c2f2f..ed1c0ad3 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -405,12 +405,7 @@ void CL_ParseStaticDecal( sizebuf_t *msg ) else modelIndex = 0; flags = BF_ReadByte( msg ); - host.decal_loading = true; - if( !cl.decal_index[decalIndex] ) - cl.decal_index[decalIndex] = GL_LoadTexture( host.draw_decals[decalIndex], NULL, 0, TF_DECAL ); - host.decal_loading = false; - - CL_DecalShoot( cl.decal_index[decalIndex], entityIndex, modelIndex, origin, flags ); + CL_DecalShoot( CL_DecalIndex( decalIndex ), entityIndex, modelIndex, origin, flags ); } void CL_ParseSoundFade( sizebuf_t *msg ) @@ -1326,7 +1321,7 @@ void CL_ParseServerMessage( sizebuf_t *msg ) CL_ParseCustomization( msg ); break; case svc_centerprint: - CL_CenterPrint( BF_ReadString( msg ), 0.35f ); + CL_CenterPrint( BF_ReadString( msg ), 0.25f ); break; case svc_event: CL_ParseEvent( msg ); diff --git a/engine/client/cl_pmove.c b/engine/client/cl_pmove.c index 3380357b..24acd4ab 100644 --- a/engine/client/cl_pmove.c +++ b/engine/client/cl_pmove.c @@ -294,22 +294,19 @@ int CL_WaterEntity( const float *rgflPos ) /* ============= -CL_GetWaterModel +CL_GetWaterEntity returns water brush where inside pos ============= */ -model_t *CL_GetWaterModel( const float *rgflPos ) +cl_entity_t *CL_GetWaterEntity( const float *rgflPos ) { - int entnum; - cl_entity_t *clent; + int entnum; entnum = CL_WaterEntity( rgflPos ); if( entnum <= 0 ) return NULL; // world or not water - if(( clent = CL_GetEntityByIndex( entnum )) != NULL ) - return clent->model; - return NULL; + return CL_GetEntityByIndex( entnum ); } static void pfnParticle( float *origin, int color, float life, int zpos, int zvel ) diff --git a/engine/client/cl_remap.c b/engine/client/cl_remap.c index 7728930e..34d832d5 100644 --- a/engine/client/cl_remap.c +++ b/engine/client/cl_remap.c @@ -217,7 +217,7 @@ void CL_UpdateTexture( mstudiotexture_t *ptexture, int topcolor, int bottomcolor gltexture_t *glt; rgbdata_t *pic; texture_t *tx = NULL; - char texname[128], name[128]; + char texname[128], name[128], mdlname[128]; int i, size, index; byte paletteBackup[768]; byte *raw, *pal; @@ -226,8 +226,11 @@ void CL_UpdateTexture( mstudiotexture_t *ptexture, int topcolor, int bottomcolor glt = R_GetTexture( ptexture->index ); // build name of original texture + Q_strncpy( mdlname, RI.currentmodel->name, sizeof( mdlname )); FS_FileBase( ptexture->name, name ); - Q_snprintf( texname, sizeof( texname ), "#%s/%s.mdl", RI.currentmodel->name, name ); + FS_StripExtension( mdlname ); + + Q_snprintf( texname, sizeof( texname ), "#%s/%s.mdl", mdlname, name ); index = GL_FindTexture( texname ); if( !index ) return; // couldn't find texture diff --git a/engine/client/cl_scrn.c b/engine/client/cl_scrn.c index 4b641ded..92b62c14 100644 --- a/engine/client/cl_scrn.c +++ b/engine/client/cl_scrn.c @@ -203,6 +203,9 @@ void SCR_MakeScreenShot( void ) case scrshot_normal: iRet = VID_ScreenShot( cls.shotname, VID_SCREENSHOT ); break; + case scrshot_snapshot: + iRet = VID_ScreenShot( cls.shotname, VID_SNAPSHOT ); + break; case scrshot_plaque: iRet = VID_ScreenShot( cls.shotname, VID_LEVELSHOT ); break; @@ -224,7 +227,12 @@ void SCR_MakeScreenShot( void ) } // report - if( iRet ) MsgDev( D_INFO, "Write %s\n", cls.shotname ); + if( iRet ) + { + // snapshots don't writes message about image + if( cls.scrshot_action != scrshot_snapshot ) + MsgDev( D_INFO, "Write %s\n", cls.shotname ); + } else MsgDev( D_ERROR, "Unable to write %s\n", cls.shotname ); cls.envshot_vieworg = NULL; @@ -390,7 +398,9 @@ void SCR_RegisterShaders( void ) // register gfx.wad images cls.pauseIcon = GL_LoadTexture( "gfx.wad/paused.lmp", NULL, 0, TF_IMAGE ); - cls.loadingBar = GL_LoadTexture( "gfx.wad/lambda.lmp", NULL, 0, TF_IMAGE|TF_LUMINANCE ); + if( cl_allow_levelshots->integer ) + cls.loadingBar = GL_LoadTexture( "gfx.wad/lambda.lmp", NULL, 0, TF_IMAGE|TF_LUMINANCE ); + else cls.loadingBar = GL_LoadTexture( "gfx.wad/lambda.lmp", NULL, 0, TF_IMAGE ); cls.creditsFont.hFontTexture = GL_LoadTexture( "gfx.wad/creditsfont.fnt", NULL, 0, TF_IMAGE ); cls.hChromeSprite = pfnSPR_Load( "sprites/shellchrome.spr" ); diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 00759085..cee296dc 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -22,6 +22,7 @@ GNU General Public License for more details. #include "pm_local.h" #include "gl_local.h" #include "studio.h" +#include "wadfile.h" // acess decal size /* ============================================================== @@ -824,6 +825,8 @@ void CL_BloodSprite( const vec3_t org, int colorIndex, int modelIndex, int model VectorSet( forward, 0.0f, 0.0f, 1.0f ); // up-vector VectorVectors( forward, right, up ); + Mod_GetFrames( modelIndex2, &frameCount ); + // create blood drops for( i = 0; i < 14; i++ ) { @@ -835,7 +838,7 @@ void CL_BloodSprite( const vec3_t org, int colorIndex, int modelIndex, int model pTemp = CL_TempEntAlloc( org, Mod_Handle( modelIndex2 )); if( !pTemp ) return; - pTemp->flags = FTENT_SPRANIMATELOOP|FTENT_COLLIDEWORLD|FTENT_SLOWGRAVITY; + pTemp->flags = FTENT_COLLIDEWORLD|FTENT_SLOWGRAVITY; pTemp->entity.curstate.rendermode = kRenderTransTexture; pTemp->entity.curstate.renderfx = kRenderFxClampMinScale; @@ -843,17 +846,17 @@ void CL_BloodSprite( const vec3_t org, int colorIndex, int modelIndex, int model pTemp->entity.curstate.rendercolor.r = clgame.palette[colorIndex][0]; pTemp->entity.curstate.rendercolor.g = clgame.palette[colorIndex][1]; pTemp->entity.curstate.rendercolor.b = clgame.palette[colorIndex][2]; - pTemp->entity.curstate.framerate = frameCount * 4; // Finish in 0.250 seconds + pTemp->entity.curstate.frame = Com_RandomLong( 0, frameCount - 1 ); pTemp->die = cl.time + Com_RandomFloat( 1.0f, 3.0f ); pTemp->entity.angles[2] = Com_RandomLong( 0, 360 ); pTemp->bounceFactor = 0; - dir[0] = forward[0] + Com_RandomFloat( -0.3f, 0.3f ); - dir[1] = forward[1] + Com_RandomFloat( -0.3f, 0.3f ); - dir[2] = forward[2] + Com_RandomFloat( -0.3f, 0.3f ); + dir[0] = forward[0] + Com_RandomFloat( -0.8f, 0.8f ); + dir[1] = forward[1] + Com_RandomFloat( -0.8f, 0.8f ); + dir[2] = forward[2]; - VectorScale( dir, Com_RandomFloat( 4.0f * size, 16.0f * size ), pTemp->entity.baseline.origin ); + VectorScale( dir, Com_RandomFloat( 8.0f * size, 20.0f * size ), pTemp->entity.baseline.origin ); pTemp->entity.baseline.origin[2] += Com_RandomFloat( 4.0f, 16.0f ) * size; } } @@ -2384,12 +2387,12 @@ update client flashlight */ void CL_UpdateFlashlight( cl_entity_t *pEnt ) { + int key, traceFlags; vec3_t vecSrc, vecEnd; vec3_t forward, view_ofs; float falloff; pmtrace_t trace; dlight_t *dl; - int key; if(( pEnt->index - 1 ) == cl.playernum ) { @@ -2416,7 +2419,12 @@ void CL_UpdateFlashlight( cl_entity_t *pEnt ) VectorAdd( pEnt->origin, view_ofs, vecSrc ); VectorMA( vecSrc, FLASHLIGHT_DISTANCE, forward, vecEnd ); - trace = PM_PlayerTrace( clgame.pmove, vecSrc, vecEnd, PM_GLASS_IGNORE|PM_STUDIO_BOX, 2, -1, NULL ); + traceFlags = PM_STUDIO_BOX; + + if( r_lighting_extended->integer < 2 ) + traceFlags |= PM_GLASS_IGNORE; + + trace = PM_PlayerTrace( clgame.pmove, vecSrc, vecEnd, traceFlags, 2, -1, NULL ); falloff = trace.fraction * FLASHLIGHT_DISTANCE; if( falloff < 250.0f ) falloff = 1.0f; @@ -2538,7 +2546,40 @@ int CL_DecalIndex( int id ) host.decal_loading = true; if( !cl.decal_index[id] ) - cl.decal_index[id] = GL_LoadTexture( host.draw_decals[id], NULL, 0, TF_DECAL ); + { + qboolean load_external = false; + + if( host_allow_materials->integer ) + { + char decalname[64]; + int gl_texturenum = 0; + + Q_snprintf( decalname, sizeof( decalname ), "materials/decals/%s.tga", host.draw_decals[id] ); + + if( FS_FileExists( decalname, false )) + gl_texturenum = GL_LoadTexture( decalname, NULL, 0, TF_DECAL ); + + if( gl_texturenum ) + { + byte *fin; + mip_t *mip; + + // find real decal dimensions and store it into texture srcWidth\srcHeight + if(( fin = FS_LoadFile( va( "decals.wad/%s", host.draw_decals[id] ), NULL, false )) != NULL ) + { + mip = (mip_t *)fin; + R_GetTexture( gl_texturenum )->srcWidth = mip->width; + R_GetTexture( gl_texturenum )->srcHeight = mip->height; + Mem_Free( fin ); // release low-quality decal + } + + cl.decal_index[id] = gl_texturenum; + load_external = true; // sucessfully loaded + } + } + + if( !load_external ) cl.decal_index[id] = GL_LoadTexture( host.draw_decals[id], NULL, 0, TF_DECAL ); + } host.decal_loading = false; return cl.decal_index[id]; diff --git a/engine/client/cl_view.c b/engine/client/cl_view.c index 6355012e..452461b9 100644 --- a/engine/client/cl_view.c +++ b/engine/client/cl_view.c @@ -327,6 +327,8 @@ V_PostRender */ void V_PostRender( void ) { + qboolean draw_2d = false; + R_Set2DMode( true ); if( cls.state == ca_active ) @@ -335,7 +337,16 @@ void V_PostRender( void ) VGui_Paint(); } - if( cls.scrshot_action == scrshot_inactive || cls.scrshot_action == scrshot_normal ) + switch( cls.scrshot_action ) + { + case scrshot_inactive: + case scrshot_normal: + case scrshot_snapshot: + draw_2d = true; + break; + } + + if( draw_2d ) { SCR_RSpeeds(); SCR_NetSpeeds(); diff --git a/engine/client/client.h b/engine/client/client.h index 0f97d3bd..a2f0f369 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -40,6 +40,7 @@ GNU General Public License for more details. #define VID_LEVELSHOT 1 #define VID_MINISHOT 2 #define VID_MAPSHOT 3 // special case for overview layer +#define VID_SNAPSHOT 4 // save screenshot into root dir and no gamma correction typedef int sound_t; @@ -171,6 +172,7 @@ typedef enum { scrshot_inactive, scrshot_normal, // in-game screenshot + scrshot_snapshot, // in-game snapshot scrshot_plaque, // levelshot scrshot_savegame, // saveshot scrshot_demoshot, // for demos preview @@ -256,8 +258,8 @@ typedef struct typedef struct { // centerprint stuff - int lines; - int y, time; + float time; + int y, lines; char message[2048]; int totalWidth; int totalHeight; @@ -550,6 +552,7 @@ void CL_PrepSound( void ); // void CL_Quit_f( void ); void CL_ScreenShot_f( void ); +void CL_SnapShot_f( void ); void CL_PlayCDTrack_f( void ); void CL_EnvShot_f( void ); void CL_SkyShot_f( void ); @@ -664,7 +667,7 @@ qboolean CL_IsPredicted( void ); int CL_TruePointContents( const vec3_t p ); int CL_PointContents( const vec3_t p ); int CL_WaterEntity( const float *rgflPos ); -model_t *CL_GetWaterModel( const float *rgflPos ); +cl_entity_t *CL_GetWaterEntity( const float *rgflPos ); void CL_SetupPMove( playermove_t *pmove, clientdata_t *cd, entity_state_t *state, usercmd_t *ucmd ); void CL_ClearPhysEnts( void ); @@ -722,6 +725,8 @@ void CL_AddCustomBeam( cl_entity_t *pEnvBeam ); void CL_KillDeadBeams( cl_entity_t *pDeadEntity ); void CL_ParseViewBeam( sizebuf_t *msg, int beamType ); void CL_RegisterMuzzleFlashes( void ); +void CL_ReadPointFile_f( void ); +void CL_ReadLineFile_f( void ); // // console.c @@ -737,6 +742,8 @@ void Con_DrawConsole( void ); void Con_DrawVersion( void ); void Con_DrawStringLen( const char *pText, int *length, int *height ); int Con_DrawString( int x, int y, const char *string, rgba_t setColor ); +int Con_DrawCharacter( int x, int y, int number, rgba_t color ); +void Con_DrawCharacterLen( int number, int *width, int *height ); void Con_DefaultColor( int r, int g, int b ); void Con_CharEvent( int key ); void Key_Console( int key ); diff --git a/engine/client/gl_backend.c b/engine/client/gl_backend.c index ddfe2356..493fab70 100644 --- a/engine/client/gl_backend.c +++ b/engine/client/gl_backend.c @@ -430,7 +430,11 @@ qboolean VID_ScreenShot( const char *filename, int shot_type ) switch( shot_type ) { case VID_SCREENSHOT: - VID_ImageAdjustGamma( r_shot->buffer, r_shot->width, r_shot->height ); // adjust brightness + if( !gl_overview->integer ) + VID_ImageAdjustGamma( r_shot->buffer, r_shot->width, r_shot->height ); // scrshot gamma + break; + case VID_SNAPSHOT: + FS_AllowDirectPaths( true ); break; case VID_LEVELSHOT: flags |= IMAGE_RESAMPLE; @@ -454,6 +458,7 @@ qboolean VID_ScreenShot( const char *filename, int shot_type ) // write image result = FS_SaveImage( filename, r_shot ); + FS_AllowDirectPaths( false ); // always reset after store screenshot FS_FreeImage( r_shot ); return result; diff --git a/engine/client/gl_beams.c b/engine/client/gl_beams.c index 0bdfb902..58ce63a6 100644 --- a/engine/client/gl_beams.c +++ b/engine/client/gl_beams.c @@ -162,6 +162,19 @@ static void ComputeNormal( const vec3_t vStartPos, const vec3_t vNextPos, vec3_t VectorNormalizeFast( pNormal ); } +static void SetBeamRenderMode( int rendermode ) +{ + if( rendermode == kRenderTransAdd ) + { + pglEnable( GL_BLEND ); + pglBlendFunc( GL_SRC_ALPHA, GL_ONE ); + } + else pglDisable( GL_BLEND ); // solid mode + + pglDisable( GL_ALPHA_TEST ); + pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); +} + /* ================ CL_DrawSegs @@ -250,7 +263,7 @@ static void CL_DrawSegs( int modelIndex, float frame, int rendermode, const vec3 segs_drawn = 0; total_segs = segments; - GL_SetRenderMode( rendermode ); + SetBeamRenderMode( rendermode ); GL_Bind( GL_TEXTURE0, m_hSprite ); pglBegin( GL_TRIANGLE_STRIP ); @@ -421,7 +434,7 @@ static void CL_DrawDisk( int modelIndex, float frame, int rendermode, const vec3 w = freq * delta[2]; - GL_SetRenderMode( rendermode ); + SetBeamRenderMode( rendermode ); GL_Bind( GL_TEXTURE0, m_hSprite ); pglBegin( GL_TRIANGLE_STRIP ); @@ -491,7 +504,7 @@ static void CL_DrawCylinder( int modelIndex, float frame, int rendermode, const scale = scale * length; GL_Cull( GL_NONE ); // draw both sides - GL_SetRenderMode( rendermode ); + SetBeamRenderMode( rendermode ); GL_Bind( GL_TEXTURE0, m_hSprite ); pglBegin( GL_TRIANGLE_STRIP ); @@ -606,7 +619,7 @@ void CL_DrawRing( int modelIndex, float frame, int rendermode, const vec3_t sour j = segments / 8; - GL_SetRenderMode( rendermode ); + SetBeamRenderMode( rendermode ); GL_Bind( GL_TEXTURE0, m_hSprite ); pglBegin( GL_TRIANGLE_STRIP ); @@ -780,7 +793,7 @@ static void DrawBeamFollow( int modelIndex, particle_t *pHead, int frame, int re nColor[1] = (byte)bound( 0, (int)(scaledColor[1] * 255.0f), 255 ); nColor[2] = (byte)bound( 0, (int)(scaledColor[2] * 255.0f), 255 ); - GL_SetRenderMode( rendermode ); + SetBeamRenderMode( rendermode ); GL_Bind( GL_TEXTURE0, m_hSprite ); pglBegin( GL_QUADS ); @@ -1412,7 +1425,7 @@ void CL_DrawBeam( BEAM *pbeam ) } frame = ((int)( pbeam->frame + cl.time * pbeam->frameRate ) % pbeam->frameCount ); - rendermode = ( pbeam->flags & FBEAM_SOLID ) ? kRenderTransColor : kRenderTransAdd; + rendermode = ( pbeam->flags & FBEAM_SOLID ) ? kRenderNormal : kRenderTransAdd; // set color VectorSet( srcColor, pbeam->r, pbeam->g, pbeam->b ); @@ -1632,8 +1645,6 @@ void CL_BeamKill( int deadEntity ) CL_KillDeadBeams( pDeadEntity ); } - - /* ============== CL_BeamEnts @@ -2114,4 +2125,85 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType ) CL_BeamKill( startEnt ); break; } +} + +/* +=============== +CL_ReadLineFile_f + +Optimized version of pointfile - use beams instead of particles +=============== +*/ +void CL_ReadLineFile_f( void ) +{ + char *afile, *pfile; + vec3_t p1, p2; + int count, modelIndex; + char filename[64]; + string token; + + Q_snprintf( filename, sizeof( filename ), "maps/%s.lin", clgame.mapname ); + afile = FS_LoadFile( filename, NULL, false ); + + if( !afile ) + { + MsgDev( D_ERROR, "couldn't open %s\n", filename ); + return; + } + + Msg( "Reading %s...\n", filename ); + + count = 0; + pfile = afile; + modelIndex = CL_FindModelIndex( "sprites/laserbeam.spr" ); + + while( 1 ) + { + pfile = COM_ParseFile( pfile, token ); + if( !pfile ) break; + p1[0] = Q_atof( token ); + + pfile = COM_ParseFile( pfile, token ); + if( !pfile ) break; + p1[1] = Q_atof( token ); + + pfile = COM_ParseFile( pfile, token ); + if( !pfile ) break; + p1[2] = Q_atof( token ); + + pfile = COM_ParseFile( pfile, token ); + if( !pfile ) break; + + if( token[0] != '-' ) + { + MsgDev( D_ERROR, "%s is corrupted\n" ); + break; + } + + pfile = COM_ParseFile( pfile, token ); + if( !pfile ) break; + p2[0] = Q_atof( token ); + + pfile = COM_ParseFile( pfile, token ); + if( !pfile ) break; + p2[1] = Q_atof( token ); + + pfile = COM_ParseFile( pfile, token ); + if( !pfile ) break; + p2[2] = Q_atof( token ); + + count++; + + if( !CL_BeamPoints( p1, p2, modelIndex, 99999, 2, 0, 255, 0, 0, 0, 255.0f, 0.0f, 0.0f )) + { + if( !modelIndex ) MsgDev( D_ERROR, "CL_ReadLineFile: no beam sprite!\n" ); + else MsgDev( D_ERROR, "CL_ReadLineFile: not enough free beams!\n" ); + break; + } + } + + Mem_Free( afile ); + + if( count ) Msg( "%i lines read\n", count ); + else Msg( "map %s has no leaks!\n", clgame.mapname ); } \ No newline at end of file diff --git a/engine/client/gl_local.h b/engine/client/gl_local.h index 4480e907..2ef65792 100644 --- a/engine/client/gl_local.h +++ b/engine/client/gl_local.h @@ -168,6 +168,7 @@ typedef struct float fogDensity; float fogStart; float fogEnd; + int cached_contents; // in water float waveHeight; // global waveHeight float currentWaveHeight; // current entity waveHeight @@ -626,7 +627,6 @@ extern convar_t *r_novis; extern convar_t *r_nocull; extern convar_t *r_lockpvs; extern convar_t *r_lockcull; -extern convar_t *r_wateralpha; extern convar_t *r_dynamic; extern convar_t *r_lightmap; extern convar_t *r_fastsky; diff --git a/engine/client/gl_rmain.c b/engine/client/gl_rmain.c index 0c7f04de..02ad2511 100644 --- a/engine/client/gl_rmain.c +++ b/engine/client/gl_rmain.c @@ -18,6 +18,8 @@ GNU General Public License for more details. #include "gl_local.h" #include "mathlib.h" +#define IsLiquidContents( cnt ) ( cnt == CONTENTS_WATER || cnt == CONTENTS_SLIME || cnt == CONTENTS_LAVA ) + msurface_t *r_debug_surface; const char *r_debug_hitbox; float gldepthmin, gldepthmax; @@ -840,65 +842,89 @@ static void R_EndGL( void ) R_CheckFog check for underwater fog +FIXME: this code is wrong, we need to compute fog volumes (as water volumes) +and get fog params from texture water on a surface. ============= */ static void R_CheckFog( void ) { - model_t *model; + cl_entity_t *ent; gltexture_t *tex; - int i, count; + int i, cnt, count; RI.fogEnabled = false; - if( RI.refdef.waterlevel < 3 || !RI.drawWorld || !r_viewleaf ) + if( RI.refdef.waterlevel < 2 || !RI.drawWorld || !r_viewleaf ) return; - model = CL_GetWaterModel( cl.refdef.vieworg ); - tex = NULL; + ent = CL_GetWaterEntity( cl.refdef.vieworg ); + if( ent && ent->model && ent->model->type == mod_brush && ent->curstate.skin < 0 ) + cnt = ent->curstate.skin; + else cnt = r_viewleaf->contents; - // check for water texture - if( model && model->type == mod_brush ) + if( IsLiquidContents( RI.cached_contents ) && !IsLiquidContents( cnt )) { - msurface_t *surf; - - count = model->nummodelsurfaces; + RI.cached_contents = CONTENTS_EMPTY; + return; + } - for( i = 0, surf = &model->surfaces[model->firstmodelsurface]; i < count; i++, surf++ ) + if( RI.refdef.waterlevel < 3 ) return; + + if( !IsLiquidContents( RI.cached_contents ) && IsLiquidContents( cnt )) + { + tex = NULL; + + // check for water texture + if( ent && ent->model && ent->model->type == mod_brush ) { - if( surf->flags & SURF_DRAWTURB && surf->texinfo && surf->texinfo->texture ) + msurface_t *surf; + + count = ent->model->nummodelsurfaces; + + for( i = 0, surf = &ent->model->surfaces[ent->model->firstmodelsurface]; i < count; i++, surf++ ) { - tex = R_GetTexture( surf->texinfo->texture->gl_texturenum ); - break; + if( surf->flags & SURF_DRAWTURB && surf->texinfo && surf->texinfo->texture ) + { + tex = R_GetTexture( surf->texinfo->texture->gl_texturenum ); + RI.cached_contents = ent->curstate.skin; + break; + } } } + else + { + msurface_t **surf; + + count = r_viewleaf->nummarksurfaces; + + for( i = 0, surf = r_viewleaf->firstmarksurface; i < count; i++, surf++ ) + { + if((*surf)->flags & SURF_DRAWTURB && (*surf)->texinfo && (*surf)->texinfo->texture ) + { + tex = R_GetTexture( (*surf)->texinfo->texture->gl_texturenum ); + RI.cached_contents = r_viewleaf->contents; + break; + } + } + } + + if( i == count || !tex ) + return; // no valid fogs + + // copy fog params + RI.fogColor[0] = tex->fogParams[0] / 255.0f; + RI.fogColor[1] = tex->fogParams[1] / 255.0f; + RI.fogColor[2] = tex->fogParams[2] / 255.0f; + RI.fogDensity = tex->fogParams[3] * 0.000025f; + RI.fogStart = RI.fogEnd = 0.0f; + RI.fogCustom = false; + RI.fogEnabled = true; } else { - msurface_t **surf; - - count = r_viewleaf->nummarksurfaces; - - for( i = 0, surf = r_viewleaf->firstmarksurface; i < count; i++, surf++ ) - { - if((*surf)->flags & SURF_DRAWTURB && (*surf)->texinfo && (*surf)->texinfo->texture ) - { - tex = R_GetTexture( (*surf)->texinfo->texture->gl_texturenum ); - break; - } - } + RI.fogCustom = false; + RI.fogEnabled = true; } - - if( i == count || !tex ) - return; // no valid fogs - - // copy fog params - RI.fogColor[0] = tex->fogParams[0] / 255.0f; - RI.fogColor[1] = tex->fogParams[1] / 255.0f; - RI.fogColor[2] = tex->fogParams[2] / 255.0f; - RI.fogDensity = tex->fogParams[3] * 0.000025f; - RI.fogStart = RI.fogEnd = 0.0f; - RI.fogCustom = false; - RI.fogEnabled = true; } /* diff --git a/engine/client/gl_rmisc.c b/engine/client/gl_rmisc.c index 04d76954..9adc8841 100644 --- a/engine/client/gl_rmisc.c +++ b/engine/client/gl_rmisc.c @@ -264,6 +264,7 @@ void R_ParseDetailTextures( const char *filename ) void R_NewMap( void ) { + texture_t *tx; int i; R_ClearDecals(); // clear all level decals @@ -284,10 +285,12 @@ void R_NewMap( void ) if( !cl.worldmodel->textures[i] ) continue; - if( world.version == Q1BSP_VERSION && !Q_strncmp( cl.worldmodel->textures[i]->name, "sky", 3 )) + tx = cl.worldmodel->textures[i]; + + if( !Q_strncmp( tx->name, "sky", 3 ) && tx->width == 256 && tx->height == 128) tr.skytexturenum = i; - cl.worldmodel->textures[i]->texturechain = NULL; + tx->texturechain = NULL; } // upload detailtextures diff --git a/engine/client/gl_rpart.c b/engine/client/gl_rpart.c index d2256d96..6861578f 100644 --- a/engine/client/gl_rpart.c +++ b/engine/client/gl_rpart.c @@ -1602,4 +1602,75 @@ void CL_Implosion( const vec3_t end, float radius, int count, float life ) // die right when you get there p->die += ( life != 0.0f ) ? life : ( radius / vel ); } +} + +/* +=============== +CL_ReadPointFile_f + +=============== +*/ +void CL_ReadPointFile_f( void ) +{ + char *afile, *pfile; + vec3_t org; + int count; + particle_t *p; + char filename[64]; + string token; + + Q_snprintf( filename, sizeof( filename ), "maps/%s.pts", clgame.mapname ); + afile = FS_LoadFile( filename, NULL, false ); + + if( !afile ) + { + MsgDev( D_ERROR, "couldn't open %s\n", filename ); + return; + } + + Msg( "Reading %s...\n", filename ); + + count = 0; + pfile = afile; + + while( 1 ) + { + pfile = COM_ParseFile( pfile, token ); + if( !pfile ) break; + org[0] = Q_atof( token ); + + pfile = COM_ParseFile( pfile, token ); + if( !pfile ) break; + org[1] = Q_atof( token ); + + pfile = COM_ParseFile( pfile, token ); + if( !pfile ) break; + org[2] = Q_atof( token ); + + count++; + + if( !cl_free_particles ) + { + MsgDev( D_ERROR, "CL_ReadPointFile: not enough free particles!\n" ); + break; + } + + // NOTE: can't use CL_AllocateParticles because running from the console + p = cl_free_particles; + cl_free_particles = p->next; + p->next = cl_active_particles; + cl_active_particles = p; + + p->ramp = 0; + p->die = 99999; + p->color = (-count) & 15; + p->type = pt_static; + VectorClear( p->vel ); + VectorCopy( org, p->org ); + } + + Mem_Free( afile ); + + if( count ) Msg( "%i points read\n", count ); + else Msg( "map %s has no leaks!\n", clgame.mapname ); } \ No newline at end of file diff --git a/engine/client/gl_rsurf.c b/engine/client/gl_rsurf.c index 9ea5540a..d1ab0b02 100644 --- a/engine/client/gl_rsurf.c +++ b/engine/client/gl_rsurf.c @@ -357,7 +357,7 @@ texture_t *R_TextureAnimation( texture_t *base, int surfacenum ) return base; // GoldSrc and Quake1 has different animating speed - if( world.version == Q1BSP_VERSION ) + if( world.sky_sphere || world.version == Q1BSP_VERSION ) speed = 10; else speed = 20; @@ -733,6 +733,8 @@ void R_BlendLightmaps( void ) switch( RI.currententity->curstate.rendermode ) { case kRenderTransTexture: + if( r_lighting_extended->integer == 2 ) + break; case kRenderTransColor: case kRenderTransAdd: case kRenderGlow: @@ -746,8 +748,14 @@ void R_BlendLightmaps( void ) if( !r_lightmap->integer ) { pglEnable( GL_BLEND ); - pglDepthMask( GL_FALSE ); - pglDepthFunc( GL_EQUAL ); + + if( !glState.drawTrans ) + { + // lightmapped solid surfaces + pglDepthMask( GL_FALSE ); + pglDepthFunc( GL_EQUAL ); + } + pglDisable( GL_ALPHA_TEST ); pglBlendFunc( GL_ZERO, GL_SRC_COLOR ); pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); @@ -849,8 +857,14 @@ void R_BlendLightmaps( void ) if( !r_lightmap->integer ) { pglDisable( GL_BLEND ); - pglDepthMask( GL_TRUE ); - pglDepthFunc( GL_LEQUAL ); + + if( !glState.drawTrans ) + { + // restore depth state + pglDepthMask( GL_TRUE ); + pglDepthFunc( GL_LEQUAL ); + } + pglDisable( GL_ALPHA_TEST ); pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); } @@ -960,7 +974,7 @@ void R_RenderBrushPoly( msurface_t *fa ) if( fa->flags & SURF_DRAWSKY ) { - if( world.version == Q1BSP_VERSION ) + if( world.sky_sphere ) { // warp texture, no lightmaps EmitSkyLayers( fa ); @@ -1086,11 +1100,14 @@ void R_DrawTextureChains( void ) if( i == tr.skytexturenum ) { - if( world.version == Q1BSP_VERSION ) + if( world.sky_sphere ) R_DrawSkyChain( s ); } else { + if(( s->flags & SURF_DRAWTURB ) && RI.refdef.movevars->wateralpha < 1.0f ) + continue; // draw translucent water later + for( ; s != NULL; s = s->texturechain ) R_RenderBrushPoly( s ); } @@ -1113,7 +1130,7 @@ void R_DrawWaterSurfaces( void ) return; // non-transparent water is already drawed - if( r_wateralpha->value >= 1.0f ) + if( RI.refdef.movevars->wateralpha >= 1.0f ) return; // go back to the world matrix @@ -1125,7 +1142,7 @@ void R_DrawWaterSurfaces( void ) pglDisable( GL_ALPHA_TEST ); pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); - pglColor4f( 1.0f, 1.0f, 1.0f, r_wateralpha->value ); + pglColor4f( 1.0f, 1.0f, 1.0f, RI.refdef.movevars->wateralpha ); for( i = 0; i < cl.worldmodel->numtextures; i++ ) { @@ -1684,7 +1701,7 @@ void R_RecursiveWorldNode( mnode_t *node, uint clipflags ) if( R_CullSurface( surf, clipflags )) continue; - if( surf->flags & SURF_DRAWSKY && world.version == HLBSP_VERSION ) + if( surf->flags & SURF_DRAWSKY && !world.sky_sphere ) { // make sky chain to right clip the skybox surf->texturechain = skychain; @@ -1958,41 +1975,50 @@ void R_MarkLeaves( void ) int i; if( !RI.drawWorld ) return; + + if( r_novis->modified ) + { + // force recalc viewleaf + r_novis->modified = false; + r_viewleaf = NULL; + } + if( r_viewleaf == r_oldviewleaf && r_viewleaf2 == r_oldviewleaf2 && !r_novis->integer && r_viewleaf != NULL ) return; // development aid to let you run around // and see exactly where the pvs ends - if( r_lockpvs->integer ) - return; + if( r_lockpvs->integer ) return; tr.visframecount++; r_oldviewleaf = r_viewleaf; r_oldviewleaf2 = r_viewleaf2; - + if( r_novis->integer || RI.drawOrtho || !r_viewleaf || !cl.worldmodel->visdata ) { - // force to get full visibility - vis = Mod_LeafPVS( NULL, NULL ); + // mark everything + for( i = 0; i < cl.worldmodel->numleafs; i++ ) + cl.worldmodel->leafs[i+1].visframe = tr.visframecount; + for( i = 0; i < cl.worldmodel->numnodes; i++ ) + cl.worldmodel->nodes[i].visframe = tr.visframecount; + return; } - else + + // may have to combine two clusters + // because of solid water boundaries + vis = Mod_LeafPVS( r_viewleaf, cl.worldmodel ); + + if( r_viewleaf != r_viewleaf2 ) { - // may have to combine two clusters - // because of solid water boundaries - vis = Mod_LeafPVS( r_viewleaf, cl.worldmodel ); + int longs = ( cl.worldmodel->numleafs + 31 ) >> 5; - if( r_viewleaf != r_viewleaf2 ) - { - int longs = ( cl.worldmodel->numleafs + 31 ) >> 5; + Q_memcpy( visbytes, vis, longs << 2 ); + vis = Mod_LeafPVS( r_viewleaf2, cl.worldmodel ); - Q_memcpy( visbytes, vis, longs << 2 ); - vis = Mod_LeafPVS( r_viewleaf2, cl.worldmodel ); + for( i = 0; i < longs; i++ ) + ((int *)visbytes)[i] |= ((int *)vis)[i]; - for( i = 0; i < longs; i++ ) - ((int *)visbytes)[i] |= ((int *)vis)[i]; - - vis = visbytes; - } + vis = visbytes; } for( i = 0; i < cl.worldmodel->numleafs; i++ ) @@ -2098,14 +2124,20 @@ void GL_BuildLightmaps( void ) GL_CreateSurfaceLightmap( m->surfaces + j ); - if( m->surfaces[i].flags & SURF_DRAWTURB ) + if( m->surfaces[j].flags & SURF_DRAWTURB ) continue; - if( m->surfaces[i].flags & SURF_DRAWSKY && world.version == Q1BSP_VERSION ) + if( m->surfaces[j].flags & SURF_DRAWSKY && world.sky_sphere ) continue; GL_BuildPolygonFromSurface( m->surfaces + j ); } + + // clearing visframe + for( j = 0; j < m->numleafs; j++ ) + m->leafs[j+1].visframe = 0; + for( j = 0; j < m->numnodes; j++ ) + m->nodes[j].visframe = 0; } loadmodel = NULL; diff --git a/engine/client/gl_sprite.c b/engine/client/gl_sprite.c index de35b6a6..98e2ad22 100644 --- a/engine/client/gl_sprite.c +++ b/engine/client/gl_sprite.c @@ -830,7 +830,7 @@ static _inline qboolean R_SpriteHasLightmap( cl_entity_t *e, int texFormat ) if( e->curstate.effects & EF_FULLBRIGHT ) return false; - if( e->curstate.renderamt != 255 ) + if( e->curstate.renderamt <= 127 ) return false; switch( e->curstate.rendermode ) @@ -856,10 +856,10 @@ void R_DrawSpriteModel( cl_entity_t *e ) mspriteframe_t *frame, *oldframe; msprite_t *psprite; model_t *model; - int i, alpha; + int i, alpha, type; float angle, dot, sr, cr, flAlpha; float lerp = 1.0f, ilerp, scale; - vec3_t v_forward, v_right, v_up; + vec3_t v_forward, v_right, v_up, tmp; vec3_t origin, color, color2; if( RI.params & RP_ENVVIEW ) @@ -959,16 +959,27 @@ void R_DrawSpriteModel( cl_entity_t *e ) frame = oldframe = R_GetSpriteFrame( model, e->curstate.frame, e->angles[YAW] ); else lerp = R_GetSpriteFrameInterpolant( e, &oldframe, &frame ); - switch( psprite->type ) + type = psprite->type; + + // automatically roll parallel sprites if requested + if( e->angles[ROLL] != 0.0f && type == SPR_FWD_PARALLEL ) + type = SPR_FWD_PARALLEL_ORIENTED; + + switch( type ) { case SPR_ORIENTED: AngleVectors( e->angles, v_forward, v_right, v_up ); - VectorScale( v_forward, 0.01f, v_forward ); // to avoid z-fighting + VectorScale( v_forward, 0.01f, v_forward ); // to avoid z-fighting VectorSubtract( origin, v_forward, origin ); break; case SPR_FACING_UPRIGHT: - VectorSet( v_right, origin[1] - RI.vieworg[1], -(origin[0] - RI.vieworg[0]), 0.0f ); - VectorSet( v_up, 0.0f, 0.0f, 1.0f ); + VectorNegate( e->origin, tmp ); + VectorNormalize( tmp ); + dot = tmp[2]; + if(( dot > 0.999848 ) || ( dot < -0.999848 )) // cos(1 degree) = 0.999848 + return; // invisible + VectorSet( v_up, 0.0f, 0.0f, 1.0f ); + VectorSet( v_right, tmp[1], -tmp[0], 0.0f ); VectorNormalize( v_right ); break; case SPR_FWD_PARALLEL_UPRIGHT: @@ -989,19 +1000,9 @@ void R_DrawSpriteModel( cl_entity_t *e ) } break; case SPR_FWD_PARALLEL: // normal sprite - default: // gold src support rotating sprites - angle = e->angles[ROLL]; - - if( angle != 0.0f ) - { - RotatePointAroundVector( v_up, RI.vforward, RI.vright, angle-90.0f ); // make up - CrossProduct( RI.vforward, v_up, v_right ); // make right - } - else - { - VectorCopy( RI.vright, v_right ); - VectorCopy( RI.vup, v_up ); - } + default: + VectorCopy( RI.vright, v_right ); + VectorCopy( RI.vup, v_up ); break; } diff --git a/engine/client/gl_studio.c b/engine/client/gl_studio.c index 4e076996..958ab981 100644 --- a/engine/client/gl_studio.c +++ b/engine/client/gl_studio.c @@ -3108,7 +3108,8 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture { size_t size; int flags = 0; - char texname[128], name[128]; + qboolean load_external = false; + char texname[128], name[128], mdlname[128]; texture_t *tx = NULL; if( ptexture->flags & STUDIO_NF_TRANSPARENT ) @@ -3165,15 +3166,38 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture mod->numtextures++; // done } - // NOTE: replace index with pointer to start of imagebuffer, ImageLib expected it - ptexture->index = (int)((byte *)phdr) + ptexture->index; - size = sizeof( mstudiotexture_t ) + ptexture->width * ptexture->height + 768; + Q_strncpy( mdlname, mod->name, sizeof( mdlname )); FS_FileBase( ptexture->name, name ); + FS_StripExtension( mdlname ); - // build the texname - Q_snprintf( texname, sizeof( texname ), "#%s/%s.mdl", mod->name, name ); - ptexture->index = GL_LoadTexture( texname, (byte *)ptexture, size, flags ); + // NOTE: colormaps must have the palette for properly work. Ignore it. + if( host_allow_materials->integer && !( ptexture->flags & STUDIO_NF_COLORMAP )) + { + int gl_texturenum = 0; + Q_snprintf( texname, sizeof( texname ), "materials/%s/%s.tga", mdlname, name ); + + if( FS_FileExists( texname, false )) + gl_texturenum = GL_LoadTexture( texname, NULL, 0, flags ); + + if( gl_texturenum ) + { + ptexture->index = gl_texturenum; + load_external = true; // sucessfully loaded + } + } + + if( !load_external ) + { + // NOTE: replace index with pointer to start of imagebuffer, ImageLib expected it + ptexture->index = (int)((byte *)phdr) + ptexture->index; + size = sizeof( mstudiotexture_t ) + ptexture->width * ptexture->height + 768; + + // build the texname + Q_snprintf( texname, sizeof( texname ), "#%s/%s.mdl", mdlname, name ); + ptexture->index = GL_LoadTexture( texname, (byte *)ptexture, size, flags ); + } + if( !ptexture->index ) { MsgDev( D_WARN, "%s has null texture %s\n", mod->name, ptexture->name ); diff --git a/engine/client/gl_vidnt.c b/engine/client/gl_vidnt.c index dc385347..533f0b71 100644 --- a/engine/client/gl_vidnt.c +++ b/engine/client/gl_vidnt.c @@ -73,7 +73,6 @@ convar_t *r_novis; convar_t *r_nocull; convar_t *r_lockpvs; convar_t *r_lockcull; -convar_t *r_wateralpha; convar_t *r_dynamic; convar_t *r_lightmap; convar_t *r_fastsky; @@ -1254,6 +1253,13 @@ check vid modes and fullscreen */ void VID_CheckChanges( void ) { + if( cl_allow_levelshots->modified ) + { + GL_FreeTexture( cls.loadingBar ); + SCR_RegisterShaders(); // reload 'lambda' image + cl_allow_levelshots->modified = false; + } + if( renderinfo->modified ) { if( !VID_SetMode()) @@ -1424,7 +1430,6 @@ void GL_InitCommands( void ) r_detailtextures = Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE, "enable detail textures support, use \"2\" for auto-generate mapname_detail.txt" ); r_lockpvs = Cvar_Get( "r_lockpvs", "0", CVAR_CHEAT, "lockpvs area at current point (pvs test)" ); r_lockcull = Cvar_Get( "r_lockcull", "0", CVAR_CHEAT, "lock frustrum area at current point (cull test)" ); - r_wateralpha = Cvar_Get( "r_wateralpha", "1", CVAR_ARCHIVE, "world water transparency factor" ); r_dynamic = Cvar_Get( "r_dynamic", "1", CVAR_ARCHIVE, "allow dynamic lighting (dlights, lightstyles)" ); r_lightmap = Cvar_Get( "r_lightmap", "0", CVAR_CHEAT, "lightmap debugging tool" ); r_fastsky = Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE, "enable algorhytm fo fast sky rendering (for old machines)" ); diff --git a/engine/client/s_load.c b/engine/client/s_load.c index 484cb1cb..2e841478 100644 --- a/engine/client/s_load.c +++ b/engine/client/s_load.c @@ -121,17 +121,32 @@ S_LoadSound */ wavdata_t *S_LoadSound( sfx_t *sfx ) { - wavdata_t *sc; + wavdata_t *sc = NULL; if( !sfx ) return NULL; if( sfx->cache ) return sfx->cache; // see if still in memory - // load it from disk - if( sfx->name[0] == '*' ) - sc = FS_LoadSound( sfx->name + 1, NULL, 0 ); - else sc = FS_LoadSound( sfx->name, NULL, 0 ); + if( Q_stricmp( sfx->name, "*default" )) + { + // load it from disk + if( sfx->name[0] == '*' ) + sc = FS_LoadSound( sfx->name + 1, NULL, 0 ); + else sc = FS_LoadSound( sfx->name, NULL, 0 ); + } if( !sc ) sc = S_CreateDefaultSound(); + + if( sc->rate < SOUND_11k ) // some bad sounds + Sound_Process( &sc, SOUND_11k, sc->width, SOUND_RESAMPLE ); +#if SOUND_DMA_SPEED > SOUND_11k + else if( sc->rate > SOUND_11k && sc->rate < SOUND_22k ) // some bad sounds + Sound_Process( &sc, SOUND_22k, sc->width, SOUND_RESAMPLE ); +#endif + +#if SOUND_DMA_SPEED > SOUND_32k + else if( sc->rate > SOUND_22k && sc->rate <= SOUND_32k ) // some bad sounds + Sound_Process( &sc, SOUND_44k, sc->width, SOUND_RESAMPLE ); +#endif sfx->cache = sc; return sfx->cache; @@ -247,8 +262,27 @@ S_BeginRegistration */ void S_BeginRegistration( void ) { + int i; + s_registration_sequence++; s_registering = true; + + // create unused 0-entry + S_RegisterSound( "*default" ); + + snd_ambient = false; + + // check for automatic ambient sounds + for( i = 0; i < NUM_AMBIENTS; i++ ) + { + if( !GI->ambientsound[i][0] ) + continue; // empty slot + + if( !ambient_sfx[i] ) + MsgDev( D_NOTE, "Loading ambient[%i]: ^2%s^7\n", i, GI->ambientsound[i] ); + ambient_sfx[i] = S_RegisterSound( GI->ambientsound[i] ); + if( ambient_sfx[i] ) snd_ambient = true; // allow auto-ambients + } } /* diff --git a/engine/client/s_main.c b/engine/client/s_main.c index 0f38fd01..63242803 100644 --- a/engine/client/s_main.c +++ b/engine/client/s_main.c @@ -26,18 +26,23 @@ dma_t dma; byte *sndpool; static soundfade_t soundfade; channel_t channels[MAX_CHANNELS]; +sound_t ambient_sfx[NUM_AMBIENTS]; +qboolean snd_ambient = false; listener_t s_listener; int total_channels; int soundtime; // sample PAIRS int paintedtime; // sample PAIRS -convar_t *s_check_errors; convar_t *s_volume; convar_t *s_musicvolume; convar_t *s_show; convar_t *s_mixahead; convar_t *s_primary; convar_t *s_lerping; +convar_t *s_ambient_level; +convar_t *s_ambient_fade; +convar_t *s_combine_sounds; +convar_t *s_test; // cvar for testing new effects convar_t *dsp_off; // set to 1 to disable all dsp processing /* @@ -176,7 +181,7 @@ channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx ) first_to_die = -1; life_left = 0x7fffffff; - for( ch_idx = 0; ch_idx < MAX_DYNAMIC_CHANNELS; ch_idx++ ) + for( ch_idx = NUM_AMBIENTS; ch_idx < MAX_DYNAMIC_CHANNELS; ch_idx++ ) { channel_t *ch = &channels[ch_idx]; @@ -315,7 +320,7 @@ int S_AlterChannel( int entnum, int channel, sfx_t *sfx, int vol, int pitch, int // at a time, so we can just shut off // any channel that has ch->isSentence >= 0 and matches the entnum. - for( i = 0, ch = channels; i < total_channels; i++, ch++ ) + for( i = NUM_AMBIENTS, ch = channels + NUM_AMBIENTS; i < total_channels; i++, ch++ ) { if( ch->entnum == entnum && ch->entchannel == channel && ch->sfx && ch->isSentence ) { @@ -337,7 +342,7 @@ int S_AlterChannel( int entnum, int channel, sfx_t *sfx, int vol, int pitch, int } // regular sound or streaming sound - for( i = 0, ch = channels; i < total_channels; i++, ch++ ) + for( i = NUM_AMBIENTS, ch = channels + NUM_AMBIENTS; i < total_channels; i++, ch++ ) { if( ch->entnum == entnum && ch->entchannel == channel && ch->sfx == sfx ) { @@ -428,13 +433,12 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv channel_t *target_chan, *check; int vol, ch_idx; - if( pitch <= 1 ) pitch = PITCH_NORM; // Invasion issues - if( !dma.initialized ) return; sfx = S_GetSfxByHandle( handle ); if( !sfx ) return; vol = bound( 0, fvol * 255, 255 ); + if( pitch <= 1 ) pitch = PITCH_NORM; // Invasion issues if( flags & ( SND_STOP|SND_CHANGE_VOL|SND_CHANGE_PITCH )) { @@ -527,7 +531,7 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv // Init client entity mouth movement vars SND_InitMouth( ent, chan ); - for( ch_idx = 0, check = channels; ch_idx < MAX_DYNAMIC_CHANNELS; ch_idx++, check++ ) + for( ch_idx = NUM_AMBIENTS, check = channels + NUM_AMBIENTS; ch_idx < MAX_DYNAMIC_CHANNELS; ch_idx++, check++) { if( check == target_chan ) continue; @@ -570,6 +574,7 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa if( !sfx ) return; vol = bound( 0, fvol * 255, 255 ); + if( pitch <= 1 ) pitch = PITCH_NORM; // Invasion issues if( flags & (SND_STOP|SND_CHANGE_VOL|SND_CHANGE_PITCH)) { @@ -684,6 +689,79 @@ int S_GetCurrentStaticSounds( soundlist_t *pout, int size ) return ( size - sounds_left ); } +/* +=================== +S_InitAmbientChannels +=================== +*/ +void S_InitAmbientChannels( void ) +{ + int ambient_channel; + channel_t *chan; + + for( ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++ ) + { + chan = &channels[ambient_channel]; + + chan->staticsound = true; + chan->use_loop = true; + chan->dist_mult = (ATTN_NONE / SND_CLIP_DISTANCE); + chan->basePitch = PITCH_NORM; + } +} + +/* +=================== +S_UpdateAmbientSounds +=================== +*/ +void S_UpdateAmbientSounds( void ) +{ + mleaf_t *leaf; + float vol; + int ambient_channel; + channel_t *chan; + + if( !snd_ambient ) return; + + // calc ambient sound levels + if( !cl.worldmodel ) return; + + leaf = Mod_PointInLeaf( s_listener.origin, cl.worldmodel->nodes ); + + if( !leaf || !s_ambient_level->value ) + { + for( ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++ ) + channels[ambient_channel].sfx = NULL; + return; + } + + for( ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++ ) + { + chan = &channels[ambient_channel]; + chan->sfx = S_GetSfxByHandle( ambient_sfx[ambient_channel] ); + + if( !chan->sfx ) continue; + + vol = s_ambient_level->value * leaf->ambient_sound_level[ambient_channel]; + if( vol < 8 ) vol = 0; + + // don't adjust volume too fast + if( chan->master_vol < vol ) + { + chan->master_vol += s_listener.frametime * s_ambient_fade->value; + if( chan->master_vol > vol ) chan->master_vol = vol; + } + else if( chan->master_vol > vol ) + { + chan->master_vol -= s_listener.frametime * s_ambient_fade->value; + if( chan->master_vol < vol ) chan->master_vol = vol; + } + + chan->leftvol = chan->rightvol = chan->master_vol; + } +} + /* ================== S_ClearBuffer @@ -739,6 +817,9 @@ void S_StopAllSounds( void ) // clear all the channels Q_memset( channels, 0, sizeof( channels )); + // restart the ambient sounds + S_InitAmbientChannels (); + S_ClearBuffer (); // clear any remaining soundfade @@ -769,8 +850,8 @@ void S_UpdateChannels( void ) if(( endtime - paintedtime ) & 0x3 ) { - // The difference between endtime and painted time should align on - // boundaries of 4 samples. This is important when upsampling from 11khz -> 44khz. + // the difference between endtime and painted time should align on + // boundaries of 4 samples. this is important when upsampling from 11khz -> 44khz. endtime -= ( endtime - paintedtime ) & 0x3; } @@ -801,9 +882,9 @@ Called once each time through the main loop */ void S_RenderFrame( ref_params_t *fd ) { - int i, total; + int i, j, total; con_nprint_t info; - channel_t *ch; + channel_t *ch, *combine; if( !dma.initialized ) return; if( !fd ) return; // too early @@ -825,11 +906,58 @@ void S_RenderFrame( ref_params_t *fd ) VectorCopy( fd->simvel, s_listener.velocity ); AngleVectors( fd->viewangles, s_listener.forward, s_listener.right, s_listener.up ); + // update general area ambient sound sources + S_UpdateAmbientSounds(); + + combine = NULL; + // update spatialization for static and dynamic sounds - for( i = 0, ch = channels; i < total_channels; i++, ch++ ) + for( i = NUM_AMBIENTS, ch = channels + NUM_AMBIENTS; i < total_channels; i++, ch++ ) { if( !ch->sfx ) continue; SND_Spatialize( ch ); // respatialize channel + + if( !ch->leftvol && !ch->rightvol ) + continue; + + // try to combine static sounds with a previous channel of the same + // sound effect so we don't mix five torches every frame + // g-cont: perfomance option, probably kill stereo effect in most cases + if( i >= MAX_DYNAMIC_CHANNELS && s_combine_sounds->integer ) + { + // see if it can just use the last one + if( combine && combine->sfx == ch->sfx ) + { + combine->leftvol += ch->leftvol; + combine->rightvol += ch->rightvol; + ch->leftvol = ch->rightvol = 0; + continue; + } + + // search for one + combine = channels + MAX_DYNAMIC_CHANNELS; + + for( j = MAX_DYNAMIC_CHANNELS; j < i; j++, combine++ ) + { + if( combine->sfx == ch->sfx ) + break; + } + + if( j == total_channels ) + { + combine = NULL; + } + else + { + if( combine != ch ) + { + combine->leftvol += ch->leftvol; + combine->rightvol += ch->rightvol; + ch->leftvol = ch->rightvol = 0; + } + continue; + } + } } // debugging output @@ -845,7 +973,8 @@ void S_RenderFrame( ref_params_t *fd ) if( ch->sfx && ( ch->leftvol || ch->rightvol )) { info.index = total; - Con_NXPrintf( &info, "%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name ); + Con_NXPrintf( &info, "chan %i, lv%3i rv%3i %s\n", + i, ch->leftvol, ch->rightvol, ch->sfx->name ); total++; } } @@ -870,9 +999,10 @@ void S_Play_f( void ) { if( Cmd_Argc() == 1 ) { - Msg( "Usage: playsound \n" ); + Msg( "Usage: play \n" ); return; } + S_StartLocalSound( Cmd_Argv( 1 )); } @@ -969,9 +1099,12 @@ qboolean S_Init( void ) s_musicvolume = Cvar_Get( "musicvolume", "1.0", CVAR_ARCHIVE, "background music volume" ); s_mixahead = Cvar_Get( "_snd_mixahead", "0.1", CVAR_ARCHIVE, "how much sound to mix ahead of time" ); s_show = Cvar_Get( "s_show", "0", CVAR_ARCHIVE, "show playing sounds" ); - s_check_errors = Cvar_Get( "s_check_errors", "1", CVAR_ARCHIVE, "ignore audio engine errors" ); s_lerping = Cvar_Get( "s_lerping", "0", CVAR_ARCHIVE, "apply interpolation to sound output" ); dsp_off = Cvar_Get( "dsp_off", "0", CVAR_ARCHIVE, "set to 1 to disable all dsp processing" ); + s_ambient_level = Cvar_Get( "ambient_level", "0.3", 0, "volume of environment noises (water and wind)" ); + s_ambient_fade = Cvar_Get( "ambient_fade", "100", 0, "rate of volume fading when client is moving" ); + s_combine_sounds = Cvar_Get( "s_combine", "0", CVAR_ARCHIVE, "combine the channels with same sounds" ); + s_test = Cvar_Get( "s_test", "0", 0, "engine developer cvar for quick testing new features" ); Cmd_AddCommand( "play", S_Play_f, "playing a specified sound file" ); Cmd_AddCommand( "stopsound", S_StopSound_f, "stop all sounds" ); @@ -989,6 +1122,9 @@ qboolean S_Init( void ) soundtime = 0; paintedtime = 0; + // clear ambient sounds + Q_memset( ambient_sfx, 0, sizeof( ambient_sfx )); + MIX_InitAllPaintbuffers (); S_InitScaletable (); diff --git a/engine/client/s_mix.c b/engine/client/s_mix.c index 5a39d514..cb067a2e 100644 --- a/engine/client/s_mix.c +++ b/engine/client/s_mix.c @@ -601,7 +601,6 @@ void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate ) { case SOUND_11k: case SOUND_22k: - case SOUND_32k: case SOUND_44k: if( rate != pSource->rate ) continue; @@ -1005,11 +1004,6 @@ void MIX_UpsampleAllPaintbuffers( int end, int count ) MIX_SetCurrentPaintbuffer( IROOMBUFFER ); S_MixUpsample( count / ( SOUND_DMA_SPEED / SOUND_22k ), FILTERTYPE_LINEAR ); #endif - -#if (SOUND_DMA_SPEED >= SOUND_32k) - // mix 32khz sounds: - MIX_MixChannelsToPaintbuffer( end, SOUND_32k, SOUND_DMA_SPEED ); -#endif // mix all 44khz sounds to all active paintbuffers MIX_MixChannelsToPaintbuffer( end, SOUND_44k, SOUND_DMA_SPEED ); diff --git a/engine/client/s_vox.c b/engine/client/s_vox.c index 7dc060bd..b0a9f18d 100644 --- a/engine/client/s_vox.c +++ b/engine/client/s_vox.c @@ -114,7 +114,6 @@ char *VOX_LookupString( const char *pSentenceName, int *psentencenum ) return (g_Sentences[i].pName + Q_strlen( g_Sentences[i].pName ) + 1 ); } - for( i = 0; i < g_numSentences; i++ ) { if( !Q_stricmp( pSentenceName, g_Sentences[i].pName )) diff --git a/engine/client/sound.h b/engine/client/sound.h index 27dc3102..eeeffaf0 100644 --- a/engine/client/sound.h +++ b/engine/client/sound.h @@ -27,6 +27,7 @@ extern byte *sndpool; // sound engine rate defines #define SOUND_DMA_SPEED 44100 // hardware playback rate #define SOUND_11k 11025 // 11khz sample rate +#define SOUND_16k 16000 // 16khz sample rate #define SOUND_22k 22050 // 22khz sample rate #define SOUND_32k 32000 // 32khz sample rate #define SOUND_44k 44100 // 44khz sample rate @@ -135,7 +136,6 @@ typedef struct qboolean use_loop; // don't loop default and local sounds qboolean staticsound; // use origin instead of fetching entnum's origin qboolean localsound; // it's a local menu sound (not looped, not paused) - qboolean bdry; // if true, bypass all dsp processing for this sound (ie: music) mixer_t pMixer; // sentence mixer @@ -186,10 +186,12 @@ void SNDDMA_Submit( void ); //==================================================================== -#define MAX_DYNAMIC_CHANNELS 28 +#define MAX_DYNAMIC_CHANNELS (28 + NUM_AMBIENTS) #define MAX_CHANNELS 128 #define MAX_RAW_SAMPLES 8192 +extern sound_t ambient_sfx[NUM_AMBIENTS]; +extern qboolean snd_ambient; extern channel_t channels[MAX_CHANNELS]; extern int total_channels; extern int paintedtime; @@ -199,13 +201,13 @@ extern dma_t dma; extern listener_t s_listener; extern int idsp_room; -extern convar_t *s_check_errors; extern convar_t *s_volume; extern convar_t *s_musicvolume; extern convar_t *s_show; extern convar_t *s_mixahead; extern convar_t *s_lerping; extern convar_t *dsp_off; +extern convar_t *s_test; extern portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES]; @@ -232,6 +234,7 @@ void MIX_PaintChannels( int endtime ); qboolean S_TestSoundChar( const char *pch, char c ); char *S_SkipSoundChar( const char *pch ); sfx_t *S_FindName( const char *name, int *pfInCache ); +sound_t S_RegisterSound( const char *name ); void S_FreeSound( sfx_t *sfx ); // s_dsp.c diff --git a/engine/client/vgui/vgui_int.cpp b/engine/client/vgui/vgui_int.cpp index c45310eb..9f6f9d27 100644 --- a/engine/client/vgui/vgui_int.cpp +++ b/engine/client/vgui/vgui_int.cpp @@ -18,6 +18,7 @@ GNU General Public License for more details. #include "const.h" #include "vgui_draw.h" #include "vgui_main.h" +#include CEnginePanel *rootpanel = NULL; CEngineSurface *surface = NULL; @@ -59,6 +60,32 @@ void CEngineApp :: getCursorPos( int &x,int &y ) void VGui_RunFrame( void ) { + PROCESSENTRY32 pe32; + HANDLE hSnapshot; + + host.force_draw_version = false; + + if(( hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 )) == INVALID_HANDLE_VALUE ) + return; + + pe32.dwSize = sizeof( PROCESSENTRY32 ); + + if( !Process32First( hSnapshot, &pe32 )) + { + CloseHandle( hSnapshot ); + return; + } + + do + { + if( Q_stristr( pe32.szExeFile, "fraps.exe" )) + { + host.force_draw_version = true; + break; + } + } while( Process32Next( hSnapshot, &pe32 )); + + CloseHandle( hSnapshot ); } void VGui_Startup( void ) diff --git a/engine/common/common.h b/engine/common/common.h index 29806ab7..9e51baa5 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -124,6 +124,7 @@ extern convar_t *scr_height; extern convar_t *scr_loading; extern convar_t *scr_download; extern convar_t *cl_allow_levelshots; +extern convar_t *host_allow_materials; extern convar_t *host_limitlocal; extern convar_t *host_maxfps; @@ -173,6 +174,8 @@ typedef struct gameinfo_s float client_mins[4][3]; // 4 hulls allowed float client_maxs[4][3]; // 4 hulls allowed + char ambientsound[NUM_AMBIENTS][64];// quake ambient sounds + int max_edicts; // min edicts is 600, max edicts is 4096 int max_tents; // min temp ents is 300, max is 2048 int max_beams; // min beams is 64, max beams is 512 @@ -304,6 +307,7 @@ typedef struct host_parm_s qboolean shutdown_issued; // engine is shutting down qboolean decal_loading; // nasty hack to tell imagelib about decal qboolean overview_loading; // another nasty hackk to tell imagelib about ovierview + qboolean force_draw_version; // used when fraps is loaded char rootdir[256]; // member root directory char gamefolder[64]; // it's a default gamefolder @@ -539,6 +543,7 @@ wavdata_t *FS_StreamInfo( stream_t *stream ); long FS_ReadStream( stream_t *stream, int bytes, void *buffer ); void FS_FreeStream( stream_t *stream ); qboolean Sound_Process( wavdata_t **wav, int rate, int width, uint flags ); +uint Sound_GetApproxWavePlayLen( const char *filepath ); // // build.c diff --git a/engine/common/console.c b/engine/common/console.c index b04a6d9e..c863cd14 100644 --- a/engine/common/console.c +++ b/engine/common/console.c @@ -309,7 +309,7 @@ void Con_CheckResize( void ) width = ( scr_width->integer / charWidth ) - 2; - // FIXME: Con_CheckResize is totally wrong :-( + // NOTE: Con_CheckResize is totally wrong :-( // g-cont. i've just used fixed width on all resolutions width = 90; @@ -346,7 +346,6 @@ void Con_CheckResize( void ) for( i = 0; i < CON_TEXTSIZE; i++ ) con.text[i] = ( ColorIndex( COLOR_DEFAULT ) << 8 ) | ' '; - // FIXME: should we consider '\n' when counting the actual lines? for( i = 0; i < numlines; i++ ) { for( j = 0; j < numchars; j++ ) @@ -517,12 +516,18 @@ static int Con_DrawGenericChar( int x, int y, int number, rgba_t color ) return con.charWidths[number]; } -static int Con_DrawCharacter( int x, int y, int number, rgba_t color ) +int Con_DrawCharacter( int x, int y, int number, rgba_t color ) { GL_SetRenderMode( kRenderTransTexture ); return Con_DrawGenericChar( x, y, number, color ); } +void Con_DrawCharacterLen( int number, int *width, int *height ) +{ + if( width ) *width = con.charWidths[number]; + if( height ) *height = con.charHeight; +} + void Con_DrawStringLen( const char *pText, int *length, int *height ) { int curLength = 0; @@ -1799,11 +1804,24 @@ void Con_DrawVersion( void ) byte *color = g_color_table[7]; int i, stringLen, width = 0, charH; int start, height = scr_height->integer; + qboolean draw_version = false; string curbuild; - if( cls.key_dest != key_menu && cls.scrshot_action != scrshot_normal ) return; + switch( cls.scrshot_action ) + { + case scrshot_normal: + case scrshot_snapshot: + draw_version = true; + break; + } - if( cls.scrshot_action == scrshot_normal ) + if( !host.force_draw_version ) + { + if(( cls.key_dest != key_menu && !draw_version ) || gl_overview->integer == 2 ) + return; + } + + if( host.force_draw_version || draw_version ) Q_snprintf( curbuild, MAX_STRING, "Xash3D v%i/%g (build %i)", PROTOCOL_VERSION, XASH_VERSION, Q_buildnum( )); else Q_snprintf( curbuild, MAX_STRING, "v%i/%g (build %i)", PROTOCOL_VERSION, XASH_VERSION, Q_buildnum( )); Con_DrawStringLen( curbuild, &stringLen, &charH ); diff --git a/engine/common/filesystem.c b/engine/common/filesystem.c index e948b28e..02a2e9a0 100644 --- a/engine/common/filesystem.c +++ b/engine/common/filesystem.c @@ -1355,7 +1355,7 @@ static qboolean FS_ParseGameInfo( const char *gamedir, gameinfo_t *GameInfo ) else if( !Q_stricmp( token, "max_particles" )) { pfile = COM_ParseFile( pfile, token ); - GameInfo->max_particles = bound( 1024, Q_atoi( token ), 32768 ); + GameInfo->max_particles = bound( 1024, Q_atoi( token ), 131072 ); } else if( !Q_stricmp( token, "gamemode" )) { @@ -1379,6 +1379,19 @@ static qboolean FS_ParseGameInfo( const char *gamedir, gameinfo_t *GameInfo ) FS_ParseVector( &pfile, GameInfo->client_maxs[hullNum], 3 ); } } + else if( !Q_strnicmp( token, "ambient", 7 )) + { + int ambientNum = Q_atoi( token + 7 ); + + if( ambientNum < 0 || ambientNum > ( NUM_AMBIENTS - 1 )) + { + MsgDev( D_ERROR, "FS_ParseGameInfo: Invalid ambient number %i. Ignored.\n", ambientNum ); + } + else + { + pfile = COM_ParseFile( pfile, GameInfo->ambientsound[ambientNum] ); + } + } } Mem_Free( afile ); diff --git a/engine/common/host.c b/engine/common/host.c index 30565208..089fcd8b 100644 --- a/engine/common/host.c +++ b/engine/common/host.c @@ -33,6 +33,7 @@ sysinfo_t SI; convar_t *host_serverstate; convar_t *host_gameloaded; convar_t *host_clientloaded; +convar_t *host_allow_materials; convar_t *host_limitlocal; convar_t *host_cheats; convar_t *host_maxfps; @@ -691,6 +692,7 @@ int EXPORT Host_Main( const char *progname, int bChangeGame, pfnChangeGame func host_gameloaded = Cvar_Get( "host_gameloaded", "0", CVAR_INIT, "inidcates a loaded game.dll" ); host_clientloaded = Cvar_Get( "host_clientloaded", "0", CVAR_INIT, "inidcates a loaded client.dll" ); host_limitlocal = Cvar_Get( "host_limitlocal", "0", 0, "apply cl_cmdrate and rate to loopback connection" ); + host_allow_materials = Cvar_Get( "host_allow_materials", "1", CVAR_LATCH|CVAR_ARCHIVE, "allow HD textures" ); con_gamemaps = Cvar_Get( "con_gamemaps", "1", CVAR_ARCHIVE, "when true show only maps in game folder" ); // content control diff --git a/engine/common/imagelib/img_quant.c b/engine/common/imagelib/img_quant.c index b4c25299..6ebc0336 100644 --- a/engine/common/imagelib/img_quant.c +++ b/engine/common/imagelib/img_quant.c @@ -1,5 +1,5 @@ /* -img_quant.c - image quantizer. based on hl2 beta original code +img_quant.c - image quantizer. based on Antony Dekker original code Copyright (C) 2011 Uncle Mike This program is free software: you can redistribute it and/or modify diff --git a/engine/common/imagelib/img_quant.old b/engine/common/imagelib/img_quant.old new file mode 100644 index 00000000..22a794a7 --- /dev/null +++ b/engine/common/imagelib/img_quant.old @@ -0,0 +1,363 @@ +/* +img_quant.c - image quantizer. based on hl2 beta original code +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 "imagelib.h" + +#define MAX_PAL_SIZE 256 +#define MAX_NUM_NODES ( MAX_PAL_SIZE * 8 + 1 ) + +typedef struct quantnode_s +{ + qboolean isLeaf; + int timesUsed; + vec3_t cumulativeColor; + int paletteIndex; + struct quantnode_s *children[8]; + struct quantnode_s *parent; + struct quantnode_s *next; // next in the priority list for this level of the tree. + // also next for the free list. +} quantnode_t; + +static quantnode_t nodePool[MAX_NUM_NODES]; +static int nextFreeID; +static quantnode_t *freeList; +static quantnode_t *root; +static int numColorsUsed; +static int desiredNumColors; +static byte insertColor[3]; +static int currNumPalIndices; +static byte *pal; +static int debugNumNodes = 0; +static quantnode_t *priorityQueues[9]; // not prioritized for now. + +static quantnode_t *AllocNode() +{ + quantnode_t *node; + + debugNumNodes++; + + if( nextFreeID < MAX_NUM_NODES ) + { + node = &nodePool[nextFreeID]; + nextFreeID++; + } + else + { + node = freeList; + if( !node ) + { + ASSERT( node ); + return NULL; + } + + freeList = freeList->next; + } + + Q_memset( node, 0, sizeof( quantnode_t )); + return node; +} + +static void FreeNode( quantnode_t *node ) +{ + debugNumNodes--; + node->next = freeList; + freeList = node; +} + +static void InitNodeAllocation( void ) +{ + freeList = NULL; + nextFreeID = 0; +} + +static void RemoveFromPriorityQueue( int level, quantnode_t *node ) +{ + quantnode_t *searchNode, *prev; + quantnode_t dummy; + + dummy.next = priorityQueues[level]; + prev = &dummy; + + for( searchNode = dummy.next; searchNode; searchNode = searchNode->next ) + { + if( searchNode == node ) + { + prev->next = node->next; + FreeNode( node ); + priorityQueues[level] = dummy.next; + return; + } + + prev = searchNode; + } + + ASSERT( 0 ); +} + +static void ReduceNode( quantnode_t *node, int nodeLevel ) +{ + int childNum; + + if( node->timesUsed == 0 ) + { + numColorsUsed++; + } + + for( childNum = 0; childNum < 8; childNum++ ) + { + quantnode_t *child; + + child = node->children[childNum]; + + if( child ) + { + node->cumulativeColor[0] += child->cumulativeColor[0]; + node->cumulativeColor[1] += child->cumulativeColor[1]; + node->cumulativeColor[2] += child->cumulativeColor[2]; + node->timesUsed += child->timesUsed; + + RemoveFromPriorityQueue( nodeLevel + 1, child ); + numColorsUsed--; + node->children[childNum] = NULL; + } + } + + if( !node->isLeaf ) + { + node->next = priorityQueues[nodeLevel]; + priorityQueues[nodeLevel] = node; + } + + node->isLeaf = true; +} + +static void ReduceTree( void ) +{ + int i; + + for( i = 8; i > 0; i-- ) + { + if( priorityQueues[i] ) + { + ReduceNode( priorityQueues[i]->parent, i - 1 ); + return; + } + } + + ASSERT( 0 ); +} + +static void AddToNode( quantnode_t *node, int depth, byte *color ) +{ + node->timesUsed++; + node->cumulativeColor[0] += ( 1.0f / 255.0f ) * color[0]; + node->cumulativeColor[1] += ( 1.0f / 255.0f ) * color[1]; + node->cumulativeColor[2] += ( 1.0f / 255.0f ) * color[2]; + node->isLeaf = true; + + // insert into priority queue if not already there. + if( node->timesUsed == 1 ) + { + node->next = priorityQueues[depth]; + priorityQueues[depth] = node; + numColorsUsed++; + } +} + +static void Insert( quantnode_t *node, quantnode_t *parent, int depth, uint r, uint g, uint b ) +{ + int childNum; + + if( depth == 8 || node->isLeaf ) + { + if( numColorsUsed < desiredNumColors ) + { + // just add it and go since we have pal entries to use. + AddToNode( node, depth, insertColor ); + } + else + { + // make space and try again. + while( numColorsUsed >= desiredNumColors ) + { + ReduceTree(); + } + Insert( root, NULL, 0, insertColor[0], insertColor[1], insertColor[2] ); + } + return; + } + + // figure out which child to go to. + childNum = (( r & ( 1 << 7 )) >> 5 ) | (( g & ( 1 << 7 )) >> 6 ) | (( b & ( 1 << 7 )) >> 7 ); + + ASSERT( childNum >= 0 && childNum < 8 ); + + // does the child already exist? + if( !node->children[childNum] ) + { + // before allocating anything new, make sure we have + // space for something new and start over + if( numColorsUsed >= desiredNumColors ) + { + do + { + ReduceTree(); + } while( numColorsUsed >= desiredNumColors ); + Insert( root, NULL, 0, insertColor[0], insertColor[1], insertColor[2] ); + return; + } + + node->children[childNum] = AllocNode(); + node->children[childNum]->parent = node; + } + + Insert( node->children[childNum], node, depth + 1, ( r << 1 ) & 0xff, ( g << 1 ) & 0xff, ( b << 1 ) & 0xff ); +} + +void Quantize( byte *image, int numPixels, int bytesPerPixel, int numPalEntries, byte *palette ) +{ + int i; + + pal = palette; + desiredNumColors = numPalEntries; + root = AllocNode(); + + ASSERT( root ); + + numColorsUsed = 0; + desiredNumColors = numPalEntries; + + for( i = 0; i < 9; i++ ) + { + priorityQueues[i] = NULL; + } + + for( i = 0; i < numPixels; i++ ) + { + Q_memcpy( insertColor, &image[i*bytesPerPixel], 3 ); + Insert( root, NULL, 0, (uint)insertColor[0], (uint)insertColor[1], (uint)insertColor[2] ); + } +} + +static void AverageColorsAndBuildPalette( quantnode_t *node ) +{ + vec3_t fColor; + float ooTimesUsed; + int i; + + if( !node ) return; + + if( node->isLeaf ) + { + ooTimesUsed = 1.0f / node->timesUsed; + + for( i = 0; i < 3; i++ ) + { + fColor[i] = node->cumulativeColor[i] * ooTimesUsed; + if( fColor[i] > 1.0f ) fColor[i] = 1.0f; + pal[currNumPalIndices*3+i] = (byte)( fColor[i] * 255 ); + } + + node->paletteIndex = currNumPalIndices; + currNumPalIndices++; + return; + } + + for( i = 0; i < 8; i++ ) + { + AverageColorsAndBuildPalette( node->children[i] ); + } +} + +static void RemapPixel( quantnode_t *node, int depth, int pixel, uint r, uint g, uint b ) +{ + int childNum; + + if( !node ) return; + + if( node->isLeaf ) + { + image.tempbuffer[pixel] = node->paletteIndex; + return; + } + + // figure out which child to go to. + childNum = (( r & ( 1 << 7 )) >> 5 ) | (( g & ( 1 << 7 )) >> 6 ) | (( b & ( 1 << 7 )) >> 7 ); + + ASSERT( childNum >= 0 && childNum < 8 ); + + RemapPixel( node->children[childNum], depth + 1, pixel, ( r << 1 ) & 0xff, ( g << 1 ) & 0xff, ( b << 1 ) & 0xff ); +} + +static void MapImageToPalette( byte *in, int numPixels, int bpp ) +{ + int i; + + for( i = 0; i < numPixels; i++ ) + { + RemapPixel( root, 0, i, (uint)in[i*bpp+0], (uint)in[i*bpp+1], (uint)in[i*bpp+2] ); + } +} + +// returns the actual number of palette entries. +rgbdata_t *Image_Quantize( rgbdata_t *pic ) +{ + byte palette[768]; + int bpp; + + // quick case to reject unneeded conversions + if( pic->type == PF_INDEXED_24 || pic->type == PF_INDEXED_32 ) + return pic; + + // get image description + switch( pic->type ) + { + case PF_RGB_24: + case PF_BGR_24: + bpp = 3; + break; + case PF_RGBA_32: + case PF_BGRA_32: + bpp = 4; + break; + default: + MsgDev( D_ERROR, "Image_Quantize: unsupported image type %s\n", PFDesc[pic->type].name ); + return pic; + } + + Image_CopyParms( pic ); + image.size = image.width * image.height; + image.palette = palette; + image.ptr = 0; + + // allocate 8-bit buffer + image.tempbuffer = Mem_Realloc( host.imagepool, image.tempbuffer, image.size ); + + InitNodeAllocation(); + Quantize( pic->buffer, image.size, bpp, 256, palette ); + currNumPalIndices = 0; + AverageColorsAndBuildPalette( root ); + MapImageToPalette( pic->buffer, image.size, bpp ); + + pic->buffer = Mem_Realloc( host.imagepool, pic->buffer, image.size ); + Q_memcpy( pic->buffer, image.tempbuffer, image.size ); + pic->palette = Mem_Alloc( host.imagepool, sizeof( palette )); + Q_memcpy( pic->palette, palette, sizeof( palette )); + pic->type = PF_INDEXED_24; + pic->size = image.size; + image.palette = NULL; + + return pic; +} \ No newline at end of file diff --git a/engine/common/imagelib/img_tga.c b/engine/common/imagelib/img_tga.c index 3079bb95..fc5e63f4 100644 --- a/engine/common/imagelib/img_tga.c +++ b/engine/common/imagelib/img_tga.c @@ -116,6 +116,9 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, size_t filesize ) } } + // HACKHACK: detect luma textures by name + if( Q_stristr( name, "_luma" )) image.flags |= IMAGE_HAS_LUMA; + columns = targa_header.width; rows = targa_header.height; diff --git a/engine/common/imagelib/img_utils.c b/engine/common/imagelib/img_utils.c index 243d7584..3ab0d85f 100644 --- a/engine/common/imagelib/img_utils.c +++ b/engine/common/imagelib/img_utils.c @@ -1035,7 +1035,7 @@ byte *Image_FlipInternal( const byte *in, word *srcwidth, word *srcheight, int t return image.tempbuffer; } -byte *Image_CreateLumaInternal( const byte *fin, int width, int height, int type, int flags ) +byte *Image_CreateLumaInternal( byte *fin, int width, int height, int type, int flags ) { byte *out; int i; @@ -1054,6 +1054,26 @@ byte *Image_CreateLumaInternal( const byte *fin, int width, int height, int type for( i = 0; i < width * height; i++ ) *out++ = fin[i] >= 224 ? fin[i] : 0; break; + case PF_RGB_24: + case PF_BGR_24: + // clearing any gray pixels + for( i = 0; i < width * height; i++ ) + { + if( fin[i*3+0] < 32 ) fin[i*3+0] = 0; + if( fin[i*3+1] < 32 ) fin[i*3+1] = 0; + if( fin[i*3+2] < 32 ) fin[i*3+2] = 0; + } + return (byte *)fin; + case PF_RGBA_32: + case PF_BGRA_32: + // clearing any gray pixels + for( i = 0; i < width * height; i++ ) + { + if( fin[i*4+0] < 32 ) fin[i*4+0] = 0; + if( fin[i*4+1] < 32 ) fin[i*4+1] = 0; + if( fin[i*4+2] < 32 ) fin[i*4+2] = 0; + } + return (byte *)fin; default: // another formats does ugly result :( MsgDev( D_WARN, "Image_MakeLuma: unsupported format %s\n", PFDesc[type].name ); diff --git a/engine/common/imagelib/img_wad.c b/engine/common/imagelib/img_wad.c index 8121e950..3eefbb76 100644 --- a/engine/common/imagelib/img_wad.c +++ b/engine/common/imagelib/img_wad.c @@ -404,8 +404,8 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, size_t filesize ) // this is a good reason for using fullbright pixels pal_type = Image_ComparePalette( pal ); - // check for luma pixels - if( pal_type == PAL_QUAKE1 ) + // check for luma pixels (but ignore liquid textures, this a Xash3D limitation) + if( mip.name[0] != '!' && pal_type == PAL_QUAKE1 ) { for( i = 0; i < image.width * image.height; i++ ) { diff --git a/engine/common/keys.c b/engine/common/keys.c index 30f30b2f..f33b0f3a 100644 --- a/engine/common/keys.c +++ b/engine/common/keys.c @@ -587,6 +587,13 @@ void Key_Event( int key, qboolean down ) // distribute the key down event to the apropriate handler if( cls.key_dest == key_game ) { + if( cls.state == ca_cinematic && ( key != K_ESCAPE || !down )) + { + // only escape passed when cinematic is playing + // HLFX 0.6 bug: crash in vgui3.dll while press +attack during movie playback + return; + } + // send the bound action kb = keys[key].binding; if( !kb ) diff --git a/engine/common/mod_local.h b/engine/common/mod_local.h index 8e91bfbc..52592e20 100644 --- a/engine/common/mod_local.h +++ b/engine/common/mod_local.h @@ -63,6 +63,7 @@ typedef struct int max_surfaces; // max surfaces per submodel (for all models) 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 vec3_t mins; // real accuracy world bounds vec3_t maxs; diff --git a/engine/common/model.c b/engine/common/model.c index 42c5bced..dd364903 100644 --- a/engine/common/model.c +++ b/engine/common/model.c @@ -30,7 +30,8 @@ static model_t cm_models[MAX_MODELS]; static int cm_nummodels = 0; static byte visdata[MAX_MAP_LEAFS/8]; // intermediate buffer int bmodel_version; // global stuff to detect bsp version - +char modelname[64]; // short model name (without path and ext) + model_t *loadmodel; model_t *worldmodel; @@ -326,7 +327,7 @@ qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbi { int leafnum = leafList[i]; - if( visbits[leafnum>>3] & (1<<( leafnum & 7 ))) + if( leafnum != -1 && visbits[leafnum>>3] & (1<<( leafnum & 7 ))) return true; } return false; @@ -456,7 +457,7 @@ static void Mod_LoadSubmodels( const dlump_t *l ) if( VectorIsNull( out->origin )) { // NOTE: zero origin after recalculating is indicated included origin brush - VectorAverage( out->mins, out->maxs, out->origin ); +// VectorAverage( out->mins, out->maxs, out->origin ); } if( i == 0 || !world.loading ) @@ -481,7 +482,7 @@ static void Mod_LoadTextures( const dlump_t *l ) texture_t *anims[10]; texture_t *altanims[10]; int num, max, altmax; - char texname[32]; + char texname[64]; mip_t *mt; int i, j; @@ -491,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.sky_sphere = false; } if( !l->filelen ) @@ -507,6 +509,9 @@ static void Mod_LoadTextures( const dlump_t *l ) for( i = 0; i < loadmodel->numtextures; i++ ) { + qboolean load_external = false; + qboolean load_external_luma = false; + if( in->dataofs[i] == -1 ) { // create default texture (some mods requires this) @@ -533,51 +538,166 @@ static void Mod_LoadTextures( const dlump_t *l ) // convert to lowercase Q_strnlwr( mt->name, mt->name, sizeof( mt->name )); Q_strncpy( tx->name, mt->name, sizeof( tx->name )); - Q_snprintf( texname, sizeof( texname ), "%s%s.mip", ( mt->offsets[0] > 0 ) ? "#" : "", mt->name ); tx->width = mt->width; tx->height = mt->height; - // check for sky texture (quake1 only!) - if( world.loading && world.version == Q1BSP_VERSION && !Q_strncmp( mt->name, "sky", 3 )) + // check for multi-layered sky texture + if( world.loading && !Q_strncmp( mt->name, "sky", 3 ) && mt->width == 256 && mt->height == 128 ) { - R_InitSky( mt, tx ); - } - else if( mt->offsets[0] > 0 ) - { - // NOTE: imagelib detect miptex version by size - // 770 additional bytes is indicated custom palette - int size = (int)sizeof( mip_t ) + ((mt->width * mt->height * 85)>>6); - if( bmodel_version == HLBSP_VERSION ) size += sizeof( short ) + 768; + if( host_allow_materials->integer ) + { + // build standard path: "materials/mapname/texname_solid.tga" + Q_snprintf( texname, sizeof( texname ), "materials/%s/%s_solid.tga", modelname, mt->name ); - tx->gl_texturenum = GL_LoadTexture( texname, (byte *)mt, size, 0 ); - } - else - { - // okay, loading it from wad - tx->gl_texturenum = GL_LoadTexture( texname, NULL, 0, 0 ); - } + if( !FS_FileExists( texname, false )) + { + // build common path: "materials/mapname/texname_solid.tga" + Q_snprintf( texname, sizeof( texname ), "materials/common/%s_solid.tga", mt->name ); - // set the emo-texture for missed - if( !tx->gl_texturenum ) tx->gl_texturenum = tr.defaultTexture; + if( FS_FileExists( texname, false )) + load_external = true; + } + else load_external = true; - // check for luma texture - if( R_GetTexture( tx->gl_texturenum )->flags & TF_HAS_LUMA ) + if( load_external ) + { + tr.solidskyTexture = GL_LoadTexture( texname, NULL, 0, TF_UNCOMPRESSED|TF_NOMIPMAP ); + GL_SetTextureType( tr.solidskyTexture, TEX_BRUSH ); + load_external = false; + } + + if( tr.solidskyTexture ) + { + // build standard path: "materials/mapname/texname_alpha.tga" + Q_snprintf( texname, sizeof( texname ), "materials/%s/%s_alpha.tga", modelname, mt->name ); + + if( !FS_FileExists( texname, false )) + { + // build common path: "materials/mapname/texname_alpha.tga" + Q_snprintf( texname, sizeof( texname ), "materials/common/%s_alpha.tga", mt->name ); + + if( FS_FileExists( texname, false )) + load_external = true; + } + else load_external = true; + + if( load_external ) + { + tr.alphaskyTexture = GL_LoadTexture( texname, NULL, 0, TF_UNCOMPRESSED|TF_NOMIPMAP ); + GL_SetTextureType( tr.alphaskyTexture, TEX_BRUSH ); + load_external = false; + } + } + + if( !tr.solidskyTexture || !tr.alphaskyTexture ) + { + // couldn't find one of layer + GL_FreeTexture( tr.solidskyTexture ); + GL_FreeTexture( tr.alphaskyTexture ); + tr.solidskyTexture = tr.alphaskyTexture = 0; + } + } + + if( !tr.solidskyTexture && !tr.alphaskyTexture ) + R_InitSky( mt, tx ); // fallback to standard sky + + if( tr.solidskyTexture && tr.alphaskyTexture ) + world.sky_sphere = true; + } + else { - Q_snprintf( texname, sizeof( texname ), "%s%s_luma.mip", mt->offsets[0] > 0 ? "#" : "", mt->name ); - if( mt->offsets[0] > 0 ) + if( host_allow_materials->integer ) + { + if( mt->name[0] == '*' ) mt->name[0] = '!'; // replace unexpected symbol + + // build standard path: "materials/mapname/texname.tga" + Q_snprintf( texname, sizeof( texname ), "materials/%s/%s.tga", modelname, mt->name ); + + if( !FS_FileExists( texname, false )) + { + // build common path: "materials/mapname/texname.tga" + Q_snprintf( texname, sizeof( texname ), "materials/common/%s.tga", mt->name ); + + if( FS_FileExists( texname, false )) + load_external = true; + } + else load_external = true; + } +load_wad_textures: + if( !load_external ) + Q_snprintf( texname, sizeof( texname ), "%s%s.mip", ( mt->offsets[0] > 0 ) ? "#" : "", mt->name ); + else MsgDev( D_NOTE, "loading HQ: %s\n", texname ); + + if( mt->offsets[0] > 0 && !load_external ) { // NOTE: imagelib detect miptex version by size // 770 additional bytes is indicated custom palette int size = (int)sizeof( mip_t ) + ((mt->width * mt->height * 85)>>6); if( bmodel_version == HLBSP_VERSION ) size += sizeof( short ) + 768; - tx->fb_texturenum = GL_LoadTexture( texname, (byte *)mt, size, TF_MAKELUMA|TF_NOMIPMAP ); + tx->gl_texturenum = GL_LoadTexture( texname, (byte *)mt, size, 0 ); } else { // okay, loading it from wad - tx->fb_texturenum = GL_LoadTexture( texname, NULL, 0, TF_MAKELUMA|TF_NOMIPMAP ); + tx->gl_texturenum = GL_LoadTexture( texname, NULL, 0, 0 ); + + if( !tx->gl_texturenum && load_external ) + { + // in case we failed to loading 32-bit texture + MsgDev( D_ERROR, "Couldn't load %s\n", texname ); + load_external = false; + goto load_wad_textures; + } + } + } + + // set the emo-texture for missed + if( !tx->gl_texturenum ) tx->gl_texturenum = tr.defaultTexture; + + if( load_external ) + { + // build standard luma path: "materials/mapname/texname_luma.tga" + Q_snprintf( texname, sizeof( texname ), "materials/%s/%s_luma.tga", modelname, mt->name ); + + if( !FS_FileExists( texname, false )) + { + // build common path: "materials/mapname/texname_luma.tga" + Q_snprintf( texname, sizeof( texname ), "materials/common/%s_luma.tga", mt->name ); + + if( FS_FileExists( texname, false )) + load_external_luma = true; + } + else load_external_luma = true; + } + + // check for luma texture + if( R_GetTexture( tx->gl_texturenum )->flags & TF_HAS_LUMA || load_external_luma ) + { + if( !load_external_luma ) + Q_snprintf( texname, sizeof( texname ), "%s%s_luma.mip", mt->offsets[0] > 0 ? "#" : "", mt->name ); + else MsgDev( D_NOTE, "loading luma HQ: %s\n", texname ); + + if( mt->offsets[0] > 0 && !load_external_luma ) + { + // NOTE: imagelib detect miptex version by size + // 770 additional bytes is indicated custom palette + int size = (int)sizeof( mip_t ) + ((mt->width * mt->height * 85)>>6); + if( bmodel_version == HLBSP_VERSION ) size += sizeof( short ) + 768; + + tx->fb_texturenum = GL_LoadTexture( texname, (byte *)mt, size, TF_NOMIPMAP|TF_MAKELUMA ); + } + else + { + // okay, loading it from wad + tx->fb_texturenum = GL_LoadTexture( texname, NULL, 0, TF_NOMIPMAP|TF_MAKELUMA ); + + if( !tx->fb_texturenum && load_external_luma ) + { + // in case we failed to loading 32-bit luma texture + MsgDev( D_ERROR, "Couldn't load %s\n", texname ); + } } } @@ -937,13 +1057,13 @@ static void Mod_LoadSurfaces( const dlump_t *l ) if(( tex->name[0] == '*' && Q_stricmp( tex->name, "*default" )) || tex->name[0] == '!' ) out->flags |= (SURF_DRAWTURB|SURF_DRAWTILED); - if( !Q_strnicmp( tex->name, "water", 5 ) || !Q_strnicmp( tex->name, "laser", 5 )) + if( !Q_strncmp( tex->name, "water", 5 ) || !Q_strnicmp( tex->name, "laser", 5 )) out->flags |= (SURF_DRAWTURB|SURF_DRAWTILED|SURF_NOCULL); - if( !Q_strnicmp( tex->name, "scroll", 6 )) + if( !Q_strncmp( tex->name, "scroll", 6 )) out->flags |= SURF_CONVEYOR; #ifdef MIRROR_TEST - if( !Q_strnicmp( tex->name, "glassblue1", 10 )) + if( !Q_strncmp( tex->name, "glassblue1", 10 )) out->flags |= SURF_MIRROR; #endif if( tex->name[0] == '{' ) @@ -965,7 +1085,7 @@ static void Mod_LoadSurfaces( const dlump_t *l ) for( j = 0; j < MAXLIGHTMAPS; j++ ) out->styles[j] = in->styles[j]; - if( world.loading && out->flags & SURF_DRAWSKY && world.version == Q1BSP_VERSION ) + if( out->flags & SURF_DRAWSKY && world.loading && world.sky_sphere ) GL_SubdivideSurface( out ); // cut up polygon for warps if( out->flags & SURF_DRAWTURB ) @@ -1759,6 +1879,8 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash ) return NULL; } + FS_FileBase( mod->name, modelname ); + MsgDev( D_NOTE, "Mod_LoadModel: %s\n", mod->name ); mod->needload = world.load_sequence; // register mod mod->type = mod_bad; diff --git a/engine/common/net_encode.c b/engine/common/net_encode.c index 6e553ff8..42ce5a8d 100644 --- a/engine/common/net_encode.c +++ b/engine/common/net_encode.c @@ -80,6 +80,7 @@ static const delta_field_t pm_fields[] = { PHYS_DEF( skyvec_z ) }, { PHYS_DEF( studio_scale ) }, { PHYS_DEF( clienttrace ) }, +{ PHYS_DEF( wateralpha ) }, { NULL }, }; @@ -818,7 +819,7 @@ void Delta_Init( void ) Delta_AddField( "movevars_t", "skyvec_z", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); 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 ); // now done dt->bInitialized = true; } diff --git a/engine/common/pm_trace.c b/engine/common/pm_trace.c index f56e5903..61d16992 100644 --- a/engine/common/pm_trace.c +++ b/engine/common/pm_trace.c @@ -131,9 +131,9 @@ hull_t *PM_HullForEntity( physent_t *pe, vec3_t mins, vec3_t maxs, vec3_t offset } else { - if( size[0] <= 36.0f ) + if( size[0] <= world.hull_sizes[1][0] ) { - if( size[2] <= 36.0f ) + if( size[2] <= world.hull_sizes[3][2] ) hull = &pe->model->hulls[3]; else hull = &pe->model->hulls[1]; } @@ -460,7 +460,7 @@ pmtrace_t PM_PlayerTrace( playermove_t *pmove, vec3_t start, vec3_t end, int fla if( pmFilter && pmFilter( pe )) continue; - if(( i > 0 ) && !VectorIsNull( mins ) && VectorIsNull( pe->mins )) + if(( i > 0 ) && usehull != 2 && VectorIsNull( pe->mins ) && VectorIsNull( pe->maxs )) continue; // points never interact // might intersect, so do an exact clip diff --git a/engine/common/soundlib/snd_mp3.c b/engine/common/soundlib/snd_mp3.c index d4e7d642..30f66403 100644 --- a/engine/common/soundlib/snd_mp3.c +++ b/engine/common/soundlib/snd_mp3.c @@ -113,10 +113,7 @@ qboolean Sound_LoadMPG( const char *name, const byte *buffer, size_t filesize ) } if( bytesWrite + mpeg.outsize > sound.size ) - { outsize = ( sound.size - bytesWrite ); - Msg( "merge size from %i, to %i\n", mpeg.outsize, outsize ); - } else outsize = mpeg.outsize; Q_memcpy( &sound.wav[bytesWrite], mpeg.out, outsize ); diff --git a/engine/common/soundlib/snd_utils.c b/engine/common/soundlib/snd_utils.c index fe763b5f..ce3e7032 100644 --- a/engine/common/soundlib/snd_utils.c +++ b/engine/common/soundlib/snd_utils.c @@ -92,6 +92,49 @@ byte *Sound_Copy( size_t size ) return out; } +uint Sound_GetApproxWavePlayLen( const char *filepath ) +{ + file_t *f; + wavehdr_t wav; + size_t filesize; + float seconds; + uint samples; + + f = FS_Open( filepath, "rb", false ); + if( !f ) return 0; + + if( FS_Read( f, &wav, sizeof( wav )) != sizeof( wav )) + { + FS_Close( f ); + return 0; + } + + filesize = FS_FileLength( f ); + filesize -= ( sizeof( wavehdr_t ) + sizeof( chunkhdr_t )); + + FS_Close( f ); + + // is real wav file ? + if( wav.riff_id != RIFFHEADER || wav.wave_id != WAVEHEADER || wav.fmt_id != FORMHEADER ) + return 0; + + if( wav.wFormatTag != 1 ) + return 0; + + if( wav.nChannels != 1 && wav.nChannels != 2 ) + return 0; + + if( wav.nBitsPerSample != 8 && wav.nBitsPerSample != 16 ) + return 0; + + // calc samplecount + seconds = (float)filesize / wav.nAvgBytesPerSec / wav.nChannels; + samples = (uint)(( wav.nSamplesPerSec * wav.nChannels ) * seconds ); + + // g-cont. this function returns samplecount or time in milliseconds ??? + return (uint)(seconds * 1000); +} + /* ================ Sound_ConvertToSigned diff --git a/engine/common/soundlib/snd_wav.c b/engine/common/soundlib/snd_wav.c index 25cdca39..4f442dc9 100644 --- a/engine/common/soundlib/snd_wav.c +++ b/engine/common/soundlib/snd_wav.c @@ -139,7 +139,8 @@ Sound_LoadWAV */ qboolean Sound_LoadWAV( const char *name, const byte *buffer, size_t filesize ) { - int samples; + int samples, fmt; + qboolean mpeg_stream = false; if( !buffer || filesize <= 0 ) return false; @@ -164,10 +165,15 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, size_t filesize ) } iff_dataPtr += 8; - if( GetLittleShort() != 1 ) + fmt = GetLittleShort(); + if( fmt != 1 ) { - MsgDev( D_ERROR, "Sound_LoadWAV: %s not a microsoft PCM format\n", name ); - return false; + if( fmt != 85 ) + { + MsgDev( D_ERROR, "Sound_LoadWAV: %s not a microsoft PCM format\n", name ); + return false; + } + else mpeg_stream = true; } sound.channels = GetLittleShort(); @@ -181,6 +187,8 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, size_t filesize ) iff_dataPtr += 6; sound.width = GetLittleShort() / 8; + if( mpeg_stream ) sound.width = 2; // mp3 always 16bit + if( sound.width != 1 && sound.width != 2 ) { MsgDev( D_WARN, "Sound_LoadWAV: only 8 and 16 bit WAV files supported (%s)\n", name ); @@ -242,6 +250,22 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, size_t filesize ) sound.type = WF_PCMDATA; sound.samples /= sound.channels; + // g-cont. get support for mp3 streams packed in wav container + // e.g. CAd menu sounds + if( mpeg_stream ) + { + int hdr_size = (iff_dataPtr - buffer); + + if(( filesize - hdr_size ) < 16384 ) + { + sound.tempbuffer = (byte *)Mem_Realloc( host.soundpool, sound.tempbuffer, 16384 ); + Q_memcpy( sound.tempbuffer, buffer + (iff_dataPtr - buffer), filesize - hdr_size ); + return Sound_LoadMPG( name, sound.tempbuffer, 16384 ); + } + + return Sound_LoadMPG( name, buffer + hdr_size, filesize - hdr_size ); + } + // Load the data sound.size = sound.samples * sound.width * sound.channels; sound.wav = Mem_Alloc( host.soundpool, sound.size ); diff --git a/engine/common/soundlib/soundlib.h b/engine/common/soundlib/soundlib.h index 793232f2..4c16e54b 100644 --- a/engine/common/soundlib/soundlib.h +++ b/engine/common/soundlib/soundlib.h @@ -70,6 +70,40 @@ typedef struct stream_s void *ptr; }; +/* +======================================================================== + +.WAV sound format + +======================================================================== +*/ + +#define RIFFHEADER (('F'<<24)+('F'<<16)+('I'<<8)+'R') // little-endian "RIFF" +#define WAVEHEADER (('E'<<24)+('V'<<16)+('A'<<8)+'W') // little-endian "WAVE" +#define FORMHEADER ((' '<<24)+('t'<<16)+('m'<<8)+'f') // little-endian "fmt " +#define DATAHEADER (('a'<<24)+('t'<<16)+('a'<<8)+'d') // little-endian "data" + +typedef struct +{ + int riff_id; // 'RIFF' + long rLen; + int wave_id; // 'WAVE' + int fmt_id; // 'fmt ' + long pcm_header_len; // varies... + short wFormatTag; + short nChannels; // 1,2 for stereo data is (l,r) pairs + long nSamplesPerSec; + long nAvgBytesPerSec; + short nBlockAlign; + short nBitsPerSample; +} wavehdr_t; + +typedef struct +{ + int data_id; // 'data' or 'fact' + long dLen; +} chunkhdr_t; + extern sndlib_t sound; // // formats load diff --git a/engine/engine.dsp b/engine/engine.dsp index 5a0cb141..1243a3de 100644 --- a/engine/engine.dsp +++ b/engine/engine.dsp @@ -61,9 +61,16 @@ TargetDir=\Xash3D\src_main\temp\engine\!release InputPath=\Xash3D\src_main\temp\engine\!release\xash.dll SOURCE="$(InputPath)" -"D:\Xash3D\xash.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\xash.dll "D:\Xash3D\xash.dll" +BuildCmds= \ + copy $(TargetDir)\xash.dll "D:\Xash3D\xash.dll" \ + copy $(TargetDir)\xash.dll "D:\Area51\xash.dll" \ + +"D:\Xash3D\xash.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) + +"D:\Area51\xash.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "engine - Win32 Debug" @@ -98,9 +105,16 @@ TargetDir=\Xash3D\src_main\temp\engine\!debug InputPath=\Xash3D\src_main\temp\engine\!debug\xash.dll SOURCE="$(InputPath)" -"D:\Xash3D\xash.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\xash.dll "D:\Xash3D\xash.dll" +BuildCmds= \ + copy $(TargetDir)\xash.dll "D:\Xash3D\xash.dll" \ + copy $(TargetDir)\xash.dll "D:\Area51\xash.dll" \ + +"D:\Xash3D\xash.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) + +"D:\Area51\xash.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) # End Custom Build !ENDIF diff --git a/engine/server/server.h b/engine/server/server.h index bd044075..510fafb6 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -395,6 +395,7 @@ extern convar_t *sv_allow_download; extern convar_t *sv_allow_studio_scaling; extern convar_t *sv_allow_studio_attachment_angles; extern convar_t *sv_allow_rotate_pushables; +extern convar_t *sv_fix_pushstep; extern convar_t *sv_clienttrace; extern convar_t *sv_send_resources; extern convar_t *sv_send_logos; diff --git a/engine/server/sv_client.c b/engine/server/sv_client.c index 894f505e..297de623 100644 --- a/engine/server/sv_client.c +++ b/engine/server/sv_client.c @@ -215,10 +215,10 @@ gotnewcl: newcl->frames = (client_frame_t *)Z_Malloc( sizeof( client_frame_t ) * SV_UPDATE_BACKUP ); newcl->userid = g_userid++; // create unique userid newcl->authentication_method = 2; - -// FIXME: g-cont. i'm don't know how spectators interact with server -// newcl->spectator = spectator; - +#if 0 + // g-cont. i'm don't know how spectators interact with server. disabled + newcl->spectator = spectator; +#endif // get the game a chance to reject this connection or modify the userinfo if( !( SV_ClientConnect( ent, userinfo ))) { @@ -1056,7 +1056,8 @@ void SV_New_f( sv_client_t *cl ) ent = EDICT_NUM( playernum + 1 ); cl->edict = ent; - if( sv_maxclients->integer == 1 ) + // NOTE: custom resources download is disabled until is done + if( /*sv_maxclients->integer ==*/ 1 ) { Q_memset( &cl->lastcmd, 0, sizeof( cl->lastcmd )); diff --git a/engine/server/sv_game.c b/engine/server/sv_game.c index 717d83b4..340099a9 100644 --- a/engine/server/sv_game.c +++ b/engine/server/sv_game.c @@ -319,7 +319,7 @@ qboolean SV_Send( int dest, const vec3_t origin, const edict_t *ent ) // -1 is because pvs rows are 1 based, not 0 based like leafs leafnum = Mod_PointLeafnum( viewOrg ) - 1; - if( mask && (!(mask[leafnum>>3] & (1<<( leafnum & 7 ))))) + if( leafnum != -1 && (!(mask[leafnum>>3] & (1<<( leafnum & 7 ))))) continue; } @@ -385,7 +385,7 @@ static qboolean SV_OriginIn( int mode, const vec3_t v1, const vec3_t v2 ) // -1 is because pvs rows are 1 based, not 0 based like leafs leafnum = Mod_PointLeafnum( v2 ) - 1; - if( mask && (!( mask[leafnum>>3] & (1<<( leafnum & 7 ))))) + if( mask && leafnum != -1 && (!( mask[leafnum>>3] & (1<<( leafnum & 7 ))))) return false; return true; } @@ -805,7 +805,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 ); // FIXME: use delta-compressing + MSG_WriteDeltaEvent( msg, &nullargs, &info->args ); // TODO: use delta-compressing } const char *SV_ClassName( const edict_t *e ) @@ -1309,15 +1309,17 @@ pfnFindClientInPVS edict_t* pfnFindClientInPVS( edict_t *pEdict ) { edict_t *pClient; - mleaf_t *leaf; vec3_t view; + float delta; int i; if( !SV_IsValidEdict( pEdict )) return svgame.edicts; + delta = ( sv.time - sv.lastchecktime ); + // find a new check if on a new frame - if(( sv.time - sv.lastchecktime ) >= 0.1 ) + if( delta < 0.0f || delta >= 0.1f ) { sv.lastcheck = SV_CheckClientPVS( sv.lastcheck ); sv.lastchecktime = sv.time; @@ -1329,8 +1331,11 @@ edict_t* pfnFindClientInPVS( edict_t *pEdict ) return svgame.edicts; VectorAdd( pEdict->v.origin, pEdict->v.view_ofs, view ); - leaf = Mod_PointInLeaf( view, sv.worldmodel->nodes ); - i = (leaf - sv.worldmodel->leafs) - 1; + + if( pEdict->v.effects & EF_INVLIGHT ) + view[2] -= 1.0f; // HACK for barnacle + + i = Mod_PointLeafnum( view ) - 1; if( i < 0 || !((clientpvs[i>>3]) & (1 << (i & 7)))) return svgame.edicts; @@ -3562,7 +3567,7 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex, continue; } - if(!( flags & FEV_GLOBAL )) + if( mask && !( flags & FEV_GLOBAL )) { int clientnum; @@ -3575,7 +3580,7 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex, // -1 is because pvs rows are 1 based, not 0 based like leafs leafnum = Mod_PointLeafnum( viewOrg ) - 1; - if( mask && (!( mask[leafnum>>3] & (1<<( leafnum & 7 ))))) + if( leafnum != -1 && (!( mask[leafnum>>3] & (1<<( leafnum & 7 ))))) continue; } @@ -4032,18 +4037,6 @@ int pfnGetFileSize( char *filename ) return FS_FileSize( filename, false ); } -/* -============= -pfnGetApproxWavePlayLen - -returns the wave length in samples -============= -*/ -uint pfnGetApproxWavePlayLen( const char *filepath ) -{ - return 0; -} - /* ============= pfnIsCareerMatch @@ -4290,7 +4283,7 @@ static enginefuncs_t gEngfuncs = pfnSequenceGet, pfnSequencePickSentence, pfnGetFileSize, - pfnGetApproxWavePlayLen, + Sound_GetApproxWavePlayLen, pfnIsCareerMatch, pfnGetLocalizedStringLength, pfnRegisterTutorMessageShown, @@ -4428,10 +4421,7 @@ parsing textual entity definitions out of an ent file. void SV_LoadFromFile( char *entities ) { string token; - int inhibited, spawned, died; - int current_skill = Cvar_VariableInteger( "skill" ); // lock skill level - qboolean inhibits_ents = (world.version == Q1BSP_VERSION) ? true : false; - qboolean deathmatch = Cvar_VariableInteger( "deathmatch" ); + int inhibited, spawned; qboolean create_world = true; edict_t *ent; @@ -4439,7 +4429,6 @@ void SV_LoadFromFile( char *entities ) inhibited = 0; spawned = 0; - died = 0; // parse ents while(( entities = COM_ParseFile( entities, token )) != NULL ) @@ -4457,41 +4446,23 @@ void SV_LoadFromFile( char *entities ) if( !SV_ParseEdict( &entities, ent )) continue; - // remove things from different skill levels or deathmatch - if( inhibits_ents && deathmatch ) + if( svgame.dllFuncs.pfnSpawn( ent ) == -1 ) { - if( ent->v.spawnflags & (1<<11)) + // game rejected the spawn + if( !( ent->v.flags & FL_KILLME )) { SV_FreeEdict( ent ); inhibited++; - continue; } } - else if( inhibits_ents && current_skill == 0 && ent->v.spawnflags & (1<<8)) - { - SV_FreeEdict( ent ); - inhibited++; - continue; - } - else if( inhibits_ents && current_skill == 1 && ent->v.spawnflags & (1<<9)) - { - SV_FreeEdict( ent ); - inhibited++; - continue; - } - else if( inhibits_ents && current_skill >= 2 && ent->v.spawnflags & (1<<10)) - { - SV_FreeEdict( ent ); - inhibited++; - continue; - } - - if( svgame.dllFuncs.pfnSpawn( ent ) == -1 ) - died++; else spawned++; } MsgDev( D_INFO, "\n%i entities inhibited\n", inhibited ); + + // reset world origin and angles + VectorClear( svgame.edicts->v.origin ); + VectorClear( svgame.edicts->v.angles ); } /* @@ -4511,6 +4482,7 @@ void SV_SpawnEntities( const char *mapname, char *entities ) // reset misc parms Cvar_Reset( "sv_zmax" ); Cvar_Reset( "sv_wateramp" ); + Cvar_Reset( "sv_wateralpha" ); // reset sky parms Cvar_Reset( "sv_skycolor_r" ); diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index f5f3c405..34dc380a 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -65,6 +65,7 @@ convar_t *sv_send_resources; convar_t *sv_send_logos; convar_t *sv_sendvelocity; convar_t *sv_airmove; +convar_t *sv_fix_pushstep; convar_t *mp_consistency; convar_t *serverinfo; convar_t *physinfo; @@ -78,6 +79,7 @@ convar_t *sv_skyvec_x; convar_t *sv_skyvec_y; convar_t *sv_skyvec_z; convar_t *sv_skyname; +convar_t *sv_wateralpha; void Master_Shutdown( void ); @@ -225,6 +227,7 @@ void SV_UpdateMovevars( void ) svgame.movevars.skyvec_z = sv_skyvec_z->value; svgame.movevars.studio_scale = sv_allow_studio_scaling->integer; svgame.movevars.clienttrace = sv_clienttrace->value; + svgame.movevars.wateralpha = sv_wateralpha->value; if( MSG_WriteDeltaMovevars( &sv.reliable_datagram, &svgame.oldmovevars, &svgame.movevars )) Q_memcpy( &svgame.oldmovevars, &svgame.movevars, sizeof( movevars_t )); // oldstate changed @@ -650,6 +653,7 @@ void SV_Init( void ) sv_skyvec_z = Cvar_Get ("sv_skyvec_z", "0", CVAR_PHYSICINFO, "sky direction z (hl1 compatibility)" ); sv_skyname = Cvar_Get ("sv_skyname", "desert", CVAR_PHYSICINFO, "skybox name (can be dynamically changed in-game)" ); 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" ); rcon_password = Cvar_Get( "rcon_password", "", 0, "remote connect password" ); sv_stepsize = Cvar_Get( "sv_stepsize", "18", CVAR_ARCHIVE|CVAR_PHYSICINFO, "how high you can step up" ); @@ -693,6 +697,7 @@ void SV_Init( void ) sv_send_logos = Cvar_Get( "sv_send_logos", "1", 0, "send custom player decals to other clients" ); sv_send_resources = Cvar_Get( "sv_send_resources", "1", 0, "send generic resources that specified in 'mapname.res'" ); sv_sendvelocity = Cvar_Get( "sv_sendvelocity", "1", CVAR_ARCHIVE, "force to send velocity for event_t structure across network" ); + sv_fix_pushstep = Cvar_Get( "sv_fix_pushstep", "0", CVAR_ARCHIVE, "allow the 'func_pushable' push the clients which standing on when the entity is floating in water" ); mp_consistency = Cvar_Get( "mp_consistency", "1", CVAR_SERVERNOTIFY, "enbale consistency check in multiplayer" ); clockwindow = Cvar_Get( "clockwindow", "0.5", 0, "timewindow to execute client moves" ); sv_novis = Cvar_Get( "sv_novis", "0", 0, "force to ignore server visibility" ); diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 38fa1d8c..e69b875f 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -1119,11 +1119,10 @@ void SV_Physics_Follow( edict_t *ent ) parent = ent->v.aiment; if( !SV_IsValidEdict( parent )) return; - VectorAdd( parent->v.origin, parent->v.view_ofs, ent->v.origin ); + VectorAdd( parent->v.origin, parent->v.view_ofs, ent->v.v_angle ); VectorCopy( parent->v.angles, ent->v.angles ); - // noclip ents never touch triggers - SV_LinkEdict( ent, false ); + SV_LinkEdict( ent, true ); } /* @@ -1145,7 +1144,9 @@ void SV_Physics_Compound( edict_t *ent ) parent = ent->v.aiment; if( !SV_IsValidEdict( parent )) return; - ent->v.solid = SOLID_NOT; + + if( ent->v.solid != SOLID_TRIGGER ) + ent->v.solid = SOLID_NOT; switch( parent->v.movetype ) { @@ -1185,8 +1186,8 @@ void SV_Physics_Compound( edict_t *ent ) VectorAdd( ent->v.angles, amove, ent->v.angles ); VectorAdd( ent->v.origin, lmove, ent->v.origin ); - // noclip ents never touch triggers - SV_LinkEdict( ent, false ); + // notsolid ents never touch triggers + SV_LinkEdict( ent, (ent->v.solid == SOLID_NOT) ? false : true ); // shuffle states VectorCopy( parent->v.origin, ent->v.oldorigin ); @@ -1430,7 +1431,12 @@ void SV_Physics_Step( edict_t *ent ) if( inwater && ( ent->v.flags & FL_FLOAT )) { + vec3_t lmove; + int e, block; + edict_t *check; + ent->v.flags |= FL_INWATER; + VectorClear( lmove ); // floating pushables if( ent->v.waterlevel >= 2 ) @@ -1445,6 +1451,25 @@ void SV_Physics_Step( edict_t *ent ) { ent->v.velocity[2] -= (ent->v.skin * host.frametime); } + + if( sv_fix_pushstep->integer ) + { + lmove[2] = (ent->v.skin * host.frametime); + + // push the clients to avoid sticking in float items + for( e = 1; e < svgame.globals->maxClients + 1; e++ ) + { + check = EDICT_NUM( e ); + if( !SV_IsValidEdict( check )) continue; + + if(( check->v.flags & FL_ONGROUND ) && check->v.groundentity == ent ) + { + SV_PushEntity( check, lmove, vec3_origin, &block ); + check->v.groundentity = NULL; + check->v.flags &= ~FL_ONGROUND; + } + } + } } else if( !wasonground ) { diff --git a/engine/server/sv_save.c b/engine/server/sv_save.c index f5ff950a..9691a617 100644 --- a/engine/server/sv_save.c +++ b/engine/server/sv_save.c @@ -73,6 +73,8 @@ typedef struct float skyVec_y; float skyVec_z; int viewentity; // Xash3D added + int serverflags; // converted to float and back + float wateralpha; } SAVE_HEADER; typedef struct @@ -104,6 +106,8 @@ static TYPEDESCRIPTION gSaveHeader[] = DEFINE_FIELD( SAVE_HEADER, skyVec_y, FIELD_FLOAT ), DEFINE_FIELD( SAVE_HEADER, skyVec_z, FIELD_FLOAT ), DEFINE_FIELD( SAVE_HEADER, viewentity, FIELD_SHORT ), + DEFINE_FIELD( SAVE_HEADER, serverflags, FIELD_INTEGER ), + DEFINE_FIELD( SAVE_HEADER, wateralpha, FIELD_FLOAT ), }; static TYPEDESCRIPTION gAdjacency[] = @@ -703,6 +707,9 @@ void SV_SaveGameStateGlobals( SAVERESTOREDATA *pSaveData ) } else header.viewentity = 1; + header.serverflags = (int)svgame.globals->serverflags; + header.wateralpha = Cvar_VariableValue( "sv_wateralpha" ); + pSaveData->time = 0; // prohibits rebase of header.time (why not just save time as a field_float and ditch this hack?) svgame.dllFuncs.pfnSaveWriteFields( pSaveData, "Save Header", &header, gSaveHeader, ARRAYSIZE( gSaveHeader )); pSaveData->time = header.time; @@ -1175,6 +1182,11 @@ int SV_LoadGameState( char const *level, qboolean createPlayers ) Cvar_SetFloat( "sv_skyvec_y", header.skyVec_y ); Cvar_SetFloat( "sv_skyvec_z", header.skyVec_z ); + // restore serverflags + svgame.globals->serverflags = header.serverflags; + + Cvar_SetFloat( "sv_wateralpha", header.wateralpha ); + // re-base the savedata since we re-ordered the entity/table / restore fields SaveRestore_Rebase( pSaveData ); diff --git a/engine/server/sv_world.c b/engine/server/sv_world.c index 6e11f23f..164d731d 100644 --- a/engine/server/sv_world.c +++ b/engine/server/sv_world.c @@ -81,6 +81,7 @@ void SV_InitBoxHull( void ) box_planes[i].type = i>>1; box_planes[i].normal[i>>1] = 1; + box_planes[i].signbits = 0; } } @@ -176,9 +177,9 @@ hull_t *SV_HullForEntity( edict_t *ent, int hullNumber, vec3_t mins, vec3_t maxs } else { - if( size[0] <= 36.0f ) + if( size[0] <= world.hull_sizes[1][0] ) { - if( size[2] <= 36.0f ) + if( size[2] <= world.hull_sizes[3][2] ) hull = &model->hulls[3]; else hull = &model->hulls[1]; } @@ -920,8 +921,7 @@ trace_t SV_TraceHull( edict_t *ent, int hullNum, const vec3_t start, vec3_t mins VectorLerp( start, trace.fraction, end, trace.endpos ); VectorCopy( trace.plane.normal, temp ); - Matrix4x4_TransformPositivePlane( matrix, temp, trace.plane.dist, - trace.plane.normal, &trace.plane.dist ); + Matrix4x4_TransformPositivePlane( matrix, temp, trace.plane.dist, trace.plane.normal, &trace.plane.dist ); } } else diff --git a/engine/studio.h b/engine/studio.h index df189950..2029f9a3 100644 --- a/engine/studio.h +++ b/engine/studio.h @@ -48,11 +48,15 @@ Studio models are position independent, so the cache manager can move them. #define MAXSTUDIOCONTROLLERS 8 // max controllers per model #define MAXSTUDIOATTACHMENTS 4 // max attachments per model -// model global flags -#define STUDIO_STATIC 0x0001 // model without anims -#define STUDIO_RAGDOLL 0x0002 // ragdoll animation pose -#define STUDIO_HAS_CHROME 0x0008 // if any of the textures have chrome on them - +// client-side model flags +#define STUDIO_ROCKET 0x0001 // leave a trail +#define STUDIO_GRENADE 0x0002 // leave a trail +#define STUDIO_GIB 0x0004 // leave a trail +#define STUDIO_ROTATE 0x0008 // rotate (bonus items) +#define STUDIO_TRACER 0x0010 // green split trail +#define STUDIO_ZOMGIB 0x0020 // small blood trail +#define STUDIO_TRACER2 0x0040 // orange split trail + rotate +#define STUDIO_TRACER3 0x0080 // purple trail #define STUDIO_DYNAMIC_LIGHT 0x0100 // dynamically get lighting from floor or ceil (flying monsters) #define STUDIO_TRACE_HITBOX 0x0200 // always use hitbox trace instead of bbox diff --git a/mainui/menu_creategame.cpp b/mainui/menu_creategame.cpp index b9715b1d..a1d097f4 100644 --- a/mainui/menu_creategame.cpp +++ b/mainui/menu_creategame.cpp @@ -92,7 +92,7 @@ static void UI_CreateGame_Begin( void ) if( CVAR_GET_FLOAT( "host_serverstate" ) && CVAR_GET_FLOAT( "maxplayers" ) == 1 ) HOST_ENDGAME( "end of the game" ); - CVAR_SET_FLOAT( "deathmatch", 1.0f ); // FIXME + CVAR_SET_FLOAT( "deathmatch", 1.0f ); // start deathmatch as default CVAR_SET_FLOAT( "maxplayers", atoi( uiCreateGame.maxClients.buffer )); CVAR_SET_STRING( "hostname", uiCreateGame.hostName.buffer ); CVAR_SET_STRING( "defaultmap", uiCreateGame.mapName[uiCreateGame.mapsList.curItem] ); diff --git a/mainui/utils.cpp b/mainui/utils.cpp index 2d48a23d..25eb764e 100644 --- a/mainui/utils.cpp +++ b/mainui/utils.cpp @@ -235,7 +235,7 @@ int UI_FadeAlpha( int starttime, int endtime ) return 0xFFFFFFFF; } - time = ( gpGlobals->time * 1000 ) - starttime; // FIXME; convert it to float properly + time = ( gpGlobals->time * 1000 ) - starttime; if( time >= endtime ) { diff --git a/pm_shared/pm_movevars.h b/pm_shared/pm_movevars.h index 7df8a907..a85893f8 100644 --- a/pm_shared/pm_movevars.h +++ b/pm_shared/pm_movevars.h @@ -42,6 +42,7 @@ struct movevars_s float skyvec_z; // 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 }; extern movevars_t movevars;