diff --git a/backup.lst b/backup.lst index a6680914..8ad58c58 100644 --- a/backup.lst +++ b/backup.lst @@ -34,14 +34,15 @@ launch\imagelib\ launch\extragen\ physic\ public\ -render\ server\ server\ents\ server\game\ server\global\ server\monsters\ vprogs\ -vsound\ +snd_al\ +snd_dx\ +vid_gl\ xtools\ xtools\bsplib xtools\ripper diff --git a/baserc/baserc.plg b/baserc/baserc.plg deleted file mode 100644 index a6b1f243..00000000 --- a/baserc/baserc.plg +++ /dev/null @@ -1,16 +0,0 @@ - - -
-

Build Log

-

---------------------Configuration: baserc - Win32 Debug-------------------- -

-

Command Lines

- - - -

Results

-baserc.dll - 0 error(s), 0 warning(s) -
- - diff --git a/client/client.plg b/client/client.plg deleted file mode 100644 index 33666b63..00000000 --- a/client/client.plg +++ /dev/null @@ -1,16 +0,0 @@ - - -
-

Build Log

-

---------------------Configuration: client - Win32 Debug-------------------- -

-

Command Lines

- - - -

Results

-client.dll - 0 error(s), 0 warning(s) -
- - diff --git a/client/hud/hud_msg.cpp b/client/hud/hud_msg.cpp index fc399912..1cee60e6 100644 --- a/client/hud/hud_msg.cpp +++ b/client/hud/hud_msg.cpp @@ -410,7 +410,23 @@ int CHud :: MsgFunc_RoomType( const char *pszName, int iSize, void *pbuf ) int CHud :: MsgFunc_ScreenFade( const char *pszName, int iSize, void *pbuf ) { - // FIXME: implement + BEGIN_READ( pszName, iSize, pbuf ); + + float fadeTime = READ_SHORT() / (1<<12); + float holdTime = READ_SHORT() / (1<<12); + int fadeFlags = READ_SHORT(); + + Vector m_FadeColor; + + m_FadeColor.x = READ_BYTE(); // fade red + m_FadeColor.y = READ_BYTE(); // fade green + m_FadeColor.z = READ_BYTE(); // fade blue + float alpha = READ_BYTE(); // fade alpha + + SetScreenFade( m_FadeColor, alpha, fadeTime, holdTime, fadeFlags ); + + END_READ(); + return 1; } diff --git a/debug.bat b/debug.bat index 8bb7126a..9fef79df 100644 --- a/debug.bat +++ b/debug.bat @@ -23,7 +23,7 @@ if errorlevel 1 set BUILD_ERROR=1 %MSDEV% physic/physic.dsp %CONFIG%"physic - Win32 Debug" %build_target% if errorlevel 1 set BUILD_ERROR=1 -%MSDEV% render/render.dsp %CONFIG%"render - Win32 Debug" %build_target% +%MSDEV% vid_gl/vid_gl.dsp %CONFIG%"vid_gl - Win32 Debug" %build_target% if errorlevel 1 set BUILD_ERROR=1 %MSDEV% server/server.dsp %CONFIG%"server - Win32 Debug" %build_target% @@ -32,7 +32,10 @@ if errorlevel 1 set BUILD_ERROR=1 %MSDEV% vprogs/vprogs.dsp %CONFIG%"vprogs - Win32 Debug" %build_target% if errorlevel 1 set BUILD_ERROR=1 -%MSDEV% vsound/vsound.dsp %CONFIG%"vsound - Win32 Debug" %build_target% +%MSDEV% snd_al/snd_al.dsp %CONFIG%"snd_al - Win32 Debug" %build_target% +if errorlevel 1 set BUILD_ERROR=1 + +%MSDEV% snd_dx/snd_dx.dsp %CONFIG%"snd_dx - Win32 Debug" %build_target% if errorlevel 1 set BUILD_ERROR=1 %MSDEV% xtools/xtools.dsp %CONFIG%"xtools - Win32 Debug" %build_target% @@ -63,10 +66,11 @@ if exist engine\engine.plg del /f /q engine\engine.plg if exist launch\launch.plg del /f /q launch\launch.plg if exist physic\physic.plg del /f /q physic\physic.plg if exist server\server.plg del /f /q server\server.plg -if exist render\render.plg del /f /q render\render.plg +if exist vid_gl\vid_gl.plg del /f /q vid_gl\vid_gl.plg if exist viewer\viewer.plg del /f /q viewer\viewer.plg if exist vprogs\vprogs.plg del /f /q vprogs\vprogs.plg -if exist vsound\vsound.plg del /f /q vsound\vsound.plg +if exist snd_al\snd_al.plg del /f /q snd_al\snd_al.plg +if exist snd_dx\snd_dx.plg del /f /q snd_dx\snd_dx.plg if exist xtools\xtools.plg del /f /q xtools\xtools.plg echo Build succeeded! diff --git a/engine/client/cl_game.c b/engine/client/cl_game.c index 132e7ea5..698facd4 100644 --- a/engine/client/cl_game.c +++ b/engine/client/cl_game.c @@ -31,6 +31,18 @@ edict_t *CL_GetEdictByIndex( int index ) return EDICT_NUM( index ); } +/* +==================== +CL_GetServerTime + +don't clamped time that come from server +==================== +*/ +int CL_GetServerTime( void ) +{ + return cl.frame.servertime; +} + /* ==================== StudioEvent diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index b3615e19..3056ff93 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -57,6 +57,10 @@ extern cvar_t *allow_download; //====================================================================== //====================================================================== +bool CL_CheckKeydest( void ) +{ + return (cls.key_dest != key_game); +} /* ======================================================================= @@ -673,7 +677,8 @@ Call before entering a new level, or after changing dlls void CL_PrepSound( void ) { int i, sndcount; - + + MsgDev( D_LOAD, "CL_PrepSound: %s\n", cl.configstrings[CS_NAME] ); for( i = 0, sndcount = 0; i < MAX_SOUNDS && cl.configstrings[CS_SOUNDS+i+1][0]; i++ ) sndcount++; // total num sounds @@ -707,7 +712,7 @@ void CL_PrepVideo( void ) return; // no map loaded Cvar_SetValue( "scr_loading", 0.0f ); // reset progress bar - MsgDev( D_LOAD, "CL_PrepRefresh: %s\n", cl.configstrings[CS_NAME] ); + MsgDev( D_LOAD, "CL_PrepVideo: %s\n", cl.configstrings[CS_NAME] ); // let the render dll load the map FS_FileBase( cl.configstrings[CS_MODELS+1], mapname ); re->BeginRegistration( mapname, pe->VisData()); // load map @@ -1134,8 +1139,6 @@ void CL_InitLocal( void ) Cmd_AddCommand ("download", CL_Download_f, "download specified resource (by name)" ); CL_InitServerCommands (); - - UI_SetActiveMenu( UI_MAINMENU ); } //============================================================================ @@ -1163,6 +1166,8 @@ CL_Frame */ void CL_Frame( int time ) { + bool clear; + if( host.type == HOST_DEDICATED ) return; @@ -1184,7 +1189,9 @@ void CL_Frame( int time ) CL_SendCommand(); // predict all unacknowledged movements - CL_PredictMovement (); + CL_PredictMovement(); + + Host_CheckChanges(); // allow rendering DLL change if( cls.state == ca_active ) @@ -1198,8 +1205,10 @@ void CL_Frame( int time ) SCR_MakeScreenShot(); + clear = (cls.state > ca_disconnected && cls.state < ca_active) ? true : false; + // update audio - S_Update( cl.playernum + 1, cl.refdef.simorg, cl.refdef.simvel, cl.refdef.forward, cl.refdef.up ); + S_Update( cl.playernum + 1, cl.refdef.simorg, cl.refdef.simvel, cl.axis, clear ); // advance local effects for next frame CL_RunDLights (); @@ -1228,15 +1237,14 @@ void CL_Init( void ) cl_paused = Cvar_Get( "paused", "0", 0, "game paused" ); Con_Init(); - VID_Init(); if( !CL_LoadProgs( "client" )) Host_Error( "CL_InitGame: can't initialize client.dll\n" ); MSG_Init( &net_message, net_message_buffer, sizeof( net_message_buffer )); - UI_Init(); - SCR_Init(); + Host_CheckChanges (); + CL_InitLocal(); cls.initialized = true; } diff --git a/engine/client/cl_phys.c b/engine/client/cl_phys.c index 185e96c9..fbecce16 100644 --- a/engine/client/cl_phys.c +++ b/engine/client/cl_phys.c @@ -339,6 +339,9 @@ void CL_PredictMovement (void) pmove = EDICT_NUM( cl.playernum + 1 )->pvClientData->current; + // unpredicted pure angled values converted into axis + AngleVectors( cl.refdef.cl_viewangles, cl.axis[0], cl.axis[1], cl.axis[2] ); + if( !cl_predict->value || cl.frame.ps.ed_flags & ESF_NO_PREDICTION ) { // just set angles diff --git a/engine/client/cl_scrn.c b/engine/client/cl_scrn.c index d9348f6e..9ad37836 100644 --- a/engine/client/cl_scrn.c +++ b/engine/client/cl_scrn.c @@ -20,6 +20,7 @@ cvar_t *cl_testflashlight; cvar_t *cl_levelshot_name; cvar_t *cl_envshot_size; cvar_t *cl_font; +static bool scr_init = false; void SCR_TimeRefresh_f( void ); void SCR_Loading_f( void ); @@ -393,10 +394,10 @@ void SCR_MakeScreenShot( void ) switch( cls.scrshot_action ) { case scrshot_plaque: - re->ScrShot( cls.shotname, VID_LEVELSHOT ); + if( re ) re->ScrShot( cls.shotname, VID_LEVELSHOT ); break; case scrshot_savegame: - re->ScrShot( cls.shotname, VID_SAVESHOT ); + if( re ) re->ScrShot( cls.shotname, VID_SAVESHOT ); break; } @@ -465,6 +466,12 @@ SCR_Init */ void SCR_Init( void ) { + if( scr_init ) return; + + // must be init before startup video subsystem + scr_width = Cvar_Get( "width", "640", 0, "screen width" ); + scr_height = Cvar_Get( "height", "480", 0, "screen height" ); + scr_showpause = Cvar_Get( "scr_showpause", "1", 0, "show pause picture" ); scr_centertime = Cvar_Get( "scr_centertime", "2.5", 0, "centerprint hold time" ); scr_printspeed = Cvar_Get( "scr_printspeed", "8", 0, "centerprint speed of print" ); @@ -485,8 +492,23 @@ void SCR_Init( void ) Cmd_AddCommand( "viewpos", SCR_Viewpos_f, "prints current player origin" ); SCR_RegisterShaders(); + UI_Init(); + + if( cls.state == ca_disconnected ) + UI_SetActiveMenu( UI_MAINMENU ); + scr_init = true; } void SCR_Shutdown( void ) { + if( !scr_init ) return; + + Cmd_RemoveCommand( "timerefresh" ); + Cmd_RemoveCommand( "loading" ); + Cmd_RemoveCommand( "skyname" ); + Cmd_RemoveCommand( "setfont" ); + Cmd_RemoveCommand( "viewpos" ); + + UI_Shutdown(); + scr_init = false; } \ No newline at end of file diff --git a/engine/client/client.h b/engine/client/client.h index bcdbbb61..a2070da5 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -118,6 +118,7 @@ typedef struct float predicted_step; // for stair up smoothing uint predicted_step_time; + vec3_t axis[3]; // cl_viewangles without applied any view effects vec3_t predicted_origin; // generated by CL_PredictMovement vec3_t predicted_angles; vec3_t prediction_error; @@ -450,6 +451,7 @@ bool CL_LoadProgs( const char *name ); void CL_ParseUserMessage( sizebuf_t *msg, int svc_num ); void CL_LinkUserMessage( char *pszName, const int svc_num ); void CL_SortUserMessages( void ); +int CL_GetServerTime( void ); float CL_GetLerpFrac( void ); edict_t *CL_AllocEdict( void ); void CL_InitEdict( edict_t *pEdict ); @@ -507,7 +509,6 @@ void CL_Download_f( void ); // void SCR_Init( void ); void SCR_UpdateScreen( void ); -void VID_Init( void ); void SCR_Shutdown( void ); void SCR_RegisterShaders( void ); void SCR_AdjustSize( float *x, float *y, float *w, float *h ); diff --git a/engine/common.h b/engine/common.h index d7c12e2a..eb40275a 100644 --- a/engine/common.h +++ b/engine/common.h @@ -121,6 +121,7 @@ int Host_CompareFileTime( long ft1, long ft2 ); void Host_AbortCurrentFrame( void ); void Host_WriteDefaultConfig( void ); void Host_WriteConfig( void ); +void Host_CheckChanges( void ); int Host_Milliseconds( void ); void Host_Print( const char *txt ); void Host_Error( const char *error, ... ); @@ -351,6 +352,7 @@ void CL_MouseEvent( int mx, int my ); void CL_AddLoopingSounds( void ); void CL_RegisterSounds( void ); void CL_Drop( void ); +bool CL_CheckKeydest( void ); char *Info_ValueForKey( char *s, char *key ); void Info_RemoveKey( char *s, char *key ); void Info_SetValueForKey( char *s, char *key, char *value ); diff --git a/engine/common/con_main.c b/engine/common/con_main.c index 9f99276d..ad503497 100644 --- a/engine/common/con_main.c +++ b/engine/common/con_main.c @@ -87,9 +87,6 @@ void Con_ToggleConsole_f( void ) { UI_SetActiveMenu( UI_CLOSEMENU ); cls.key_dest = key_console; - - if( com.atoi(cl.configstrings[CS_MAXCLIENTS]) == 1 && Host_ServerState()) - Cvar_SetValue( "paused", 1 ); } } @@ -659,7 +656,6 @@ void Con_Close( void ) Con_ClearNotify(); con.finalFrac = 0; // none visible con.displayFrac = 0; - Cvar_SetValue( "paused", 0 ); } bool Con_Active( void ) diff --git a/engine/common/input.c b/engine/common/input.c index 05ceaa5b..fad5bbe9 100644 --- a/engine/common/input.c +++ b/engine/common/input.c @@ -132,18 +132,18 @@ void IN_ActivateMouse( void ) width = GetSystemMetrics(SM_CXSCREEN); height = GetSystemMetrics(SM_CYSCREEN); - GetWindowRect( host.hWnd, &window_rect); - if (window_rect.left < 0) window_rect.left = 0; - if (window_rect.top < 0) window_rect.top = 0; - if (window_rect.right >= width) window_rect.right = width - 1; - if (window_rect.bottom >= height-1) window_rect.bottom = height - 1; + GetWindowRect( host.hWnd, &window_rect ); + if( window_rect.left < 0 ) window_rect.left = 0; + if( window_rect.top < 0 ) window_rect.top = 0; + if( window_rect.right >= width ) window_rect.right = width - 1; + if( window_rect.bottom >= height - 1 ) window_rect.bottom = height - 1; - window_center_x = (window_rect.right + window_rect.left)/2; - window_center_y = (window_rect.top + window_rect.bottom)/2; + window_center_x = (window_rect.right + window_rect.left) / 2; + window_center_y = (window_rect.top + window_rect.bottom) / 2; SetCursorPos( window_center_x, window_center_y ); SetCapture( host.hWnd ); - ClipCursor(&window_rect); + ClipCursor( &window_rect ); while( ShowCursor(false) >= 0 ); } @@ -349,16 +349,16 @@ long IN_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam ) RECT r; int xPos, yPos, style; - xPos = (short) LOWORD(lParam); // horizontal position - yPos = (short) HIWORD(lParam); // vertical position + xPos = (short)LOWORD( lParam ); // horizontal position + yPos = (short)HIWORD( lParam ); // vertical position r.left = r.top = 0; r.right = r.bottom = 1; style = GetWindowLong( hWnd, GWL_STYLE ); AdjustWindowRect( &r, style, FALSE ); - Cvar_SetValue( "r_xpos", xPos + r.left); - Cvar_SetValue( "r_ypos", yPos + r.top); + Cvar_SetValue( "r_xpos", xPos + r.left ); + Cvar_SetValue( "r_ypos", yPos + r.top ); scr_xpos->modified = false; scr_ypos->modified = false; } diff --git a/engine/engine.plg b/engine/engine.plg deleted file mode 100644 index 967c1ed8..00000000 --- a/engine/engine.plg +++ /dev/null @@ -1,96 +0,0 @@ - - -
-

Build Log

-

---------------------Configuration: engine - Win32 Debug-------------------- -

-

Command Lines

-Creating temporary file "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1F65.tmp" with contents -[ -/nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "common" /I "server" /I "client" /I "uimenu" /I "../public" /I "../common" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR"..\temp\engine\!debug/" /Fo"..\temp\engine\!debug/" /Fd"..\temp\engine\!debug/" /FD /c -"D:\Xash3D\src_main\engine\client\cl_parse.c" -] -Creating command line "cl.exe @C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1F65.tmp" -Creating temporary file "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1F66.tmp" with contents -[ -user32.lib msvcrtd.lib /nologo /subsystem:windows /dll /incremental:yes /pdb:"..\temp\engine\!debug/engine.pdb" /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"..\temp\engine\!debug/engine.dll" /implib:"..\temp\engine\!debug/engine.lib" /pdbtype:sept -"\Xash3D\src_main\temp\engine\!debug\cinematic.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_cmds.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_demo.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_effects.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_frame.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_game.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_input.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_main.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_parse.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_phys.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_scrn.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_view.obj" -"\Xash3D\src_main\temp\engine\!debug\com_library.obj" -"\Xash3D\src_main\temp\engine\!debug\con_keys.obj" -"\Xash3D\src_main\temp\engine\!debug\con_main.obj" -"\Xash3D\src_main\temp\engine\!debug\con_utils.obj" -"\Xash3D\src_main\temp\engine\!debug\engfuncs.obj" -"\Xash3D\src_main\temp\engine\!debug\engine.obj" -"\Xash3D\src_main\temp\engine\!debug\host.obj" -"\Xash3D\src_main\temp\engine\!debug\infostring.obj" -"\Xash3D\src_main\temp\engine\!debug\input.obj" -"\Xash3D\src_main\temp\engine\!debug\net_chan.obj" -"\Xash3D\src_main\temp\engine\!debug\net_huff.obj" -"\Xash3D\src_main\temp\engine\!debug\net_msg.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_client.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_cmds.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_frame.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_game.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_init.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_main.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_move.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_phys.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_save.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_world.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_advanced.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_audio.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_controls.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_credits.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_defaults.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_demos.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_gameoptions.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_gotosite.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_ingame.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_loadgame.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_main.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_menu.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_mods.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_multiplayer.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_network.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_options.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_performance.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_playersetup.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_qmenu.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_quit.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_savegame.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_singleplayer.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_video.obj" -] -Creating command line "link.exe @C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1F66.tmp" -Creating temporary file "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1F67.bat" with contents -[ -@echo off -copy \Xash3D\src_main\temp\engine\!debug\engine.dll "D:\Xash3D\bin\engine.dll" -] -Creating command line "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1F67.bat" -Compiling... -cl_parse.c -Linking... -

Output Window

-Performing Custom Build Step on \Xash3D\src_main\temp\engine\!debug\engine.dll -Скопировано файлов: 1. - - - -

Results

-engine.dll - 0 error(s), 0 warning(s) -
- - diff --git a/engine/host.c b/engine/host.c index 131c5b70..d41e71dc 100644 --- a/engine/host.c +++ b/engine/host.c @@ -7,6 +7,8 @@ #include "input.h" #include "client.h" +#define MAX_RENDERS 8 + physic_exp_t *pe; render_exp_t *re; vprogs_exp_t *vm; @@ -14,13 +16,17 @@ vsound_exp_t *se; host_parm_t host; // host parms stdlib_api_t com, newcom; -byte *zonepool; -char *buildstring = __TIME__ " " __DATE__; +byte *zonepool; +char *buildstring = __TIME__ " " __DATE__; +string video_dlls[MAX_RENDERS]; +string audio_dlls[MAX_RENDERS]; +int num_audio_dlls; +int num_video_dlls; +dll_info_t render_dll = { "", NULL, "CreateAPI", NULL, NULL, 0, sizeof(render_exp_t), sizeof(stdlib_api_t) }; +dll_info_t vsound_dll = { "", NULL, "CreateAPI", NULL, NULL, 0, sizeof(vsound_exp_t), sizeof(stdlib_api_t) }; dll_info_t physic_dll = { "physic.dll", NULL, "CreateAPI", NULL, NULL, 1, sizeof(physic_exp_t), sizeof(stdlib_api_t) }; -dll_info_t render_dll = { "render.dll", NULL, "CreateAPI", NULL, NULL, 0, sizeof(render_exp_t), sizeof(stdlib_api_t) }; dll_info_t vprogs_dll = { "vprogs.dll", NULL, "CreateAPI", NULL, NULL, 1, sizeof(vprogs_exp_t), sizeof(stdlib_api_t) }; -dll_info_t vsound_dll = { "vsound.dll", NULL, "CreateAPI", NULL, NULL, 0, sizeof(vsound_exp_t), sizeof(stdlib_api_t) }; cvar_t *timescale; cvar_t *host_serverstate; @@ -29,6 +35,8 @@ cvar_t *host_maxfps; cvar_t *host_minfps; cvar_t *host_framerate; cvar_t *host_registered; +cvar_t *host_audio; +cvar_t *host_video; // these cvars will be duplicated on each client across network int Host_ServerState( void ) { return Cvar_VariableInteger( "host_serverstate" ); } @@ -58,7 +66,7 @@ void Host_InitPhysic( void ) pi.ClientMove = SV_PlayerMove; pi.GetModelVerts = SV_GetModelVerts; - Sys_LoadLibrary( &physic_dll ); + Sys_LoadLibrary( NULL, &physic_dll ); CreatePhysic = (void *)physic_dll.main; pe = CreatePhysic( &newcom, &pi ); @@ -76,54 +84,11 @@ void Host_FreePhysic( void ) Sys_FreeLibrary( &physic_dll ); } -void Host_InitRender( void ) -{ - static render_imp_t ri; - launch_t CreateRender; - bool result = false; - - ri.api_size = sizeof(render_imp_t); - - // studio callbacks - ri.UpdateScreen = SCR_UpdateScreen; - ri.StudioEvent = CL_StudioEvent; - ri.StudioFxTransform = CL_StudioFxTransform; - ri.ShowCollision = pe->DrawCollision; - ri.GetClientEdict = CL_GetEdictByIndex; - ri.GetLocalPlayer = CL_GetLocalPlayer; - ri.GetMaxClients = CL_GetMaxClients; - ri.GetLerpFrac = CL_GetLerpFrac; - ri.WndProc = IN_WndProc; - - Sys_LoadLibrary( &render_dll ); - - if( render_dll.link ) - { - CreateRender = (void *)render_dll.main; - re = CreateRender( &newcom, &ri ); - - if( re->Init( true )) result = true; - } - - // video system not started, run dedicated server - if( !result ) Sys_NewInstance( va("#%s", GI->gamedir ), "Host_InitRender: fallback to dedicated mode\n" ); -} - -void Host_FreeRender( void ) -{ - if( render_dll.link ) - { - re->Shutdown( true ); - Mem_Set( &re, 0, sizeof( re )); - } - Sys_FreeLibrary( &render_dll ); -} - void Host_InitVprogs( const int argc, const char **argv ) { launch_t CreateVprogs; - Sys_LoadLibrary( &vprogs_dll ); + Sys_LoadLibrary( NULL, &vprogs_dll ); CreateVprogs = (void *)vprogs_dll.main; vm = CreateVprogs( &newcom, NULL ); // second interface not allowed @@ -136,11 +101,57 @@ void Host_FreeVprogs( void ) if( vprogs_dll.link ) { vm->Free(); - Mem_Set( &vm, 0, sizeof(vm)); + Mem_Set( &vm, 0, sizeof( vm )); } Sys_FreeLibrary( &vprogs_dll ); } +void Host_FreeRender( void ) +{ + if( render_dll.link ) + { + SCR_Shutdown (); + re->Shutdown( true ); + Mem_Set( &re, 0, sizeof( re )); + } + Sys_FreeLibrary( &render_dll ); +} + +bool Host_InitRender( void ) +{ + static render_imp_t ri; + launch_t CreateRender; + bool result = false; + + ri.api_size = sizeof( render_imp_t ); + + // studio callbacks + ri.UpdateScreen = SCR_UpdateScreen; + ri.StudioEvent = CL_StudioEvent; + ri.StudioFxTransform = CL_StudioFxTransform; + ri.ShowCollision = pe->DrawCollision; + ri.GetClientEdict = CL_GetEdictByIndex; + ri.GetLocalPlayer = CL_GetLocalPlayer; + ri.GetMaxClients = CL_GetMaxClients; + ri.GetLerpFrac = CL_GetLerpFrac; + ri.WndProc = IN_WndProc; + + Sys_LoadLibrary( host_video->string, &render_dll ); + + if( render_dll.link ) + { + CreateRender = (void *)render_dll.main; + re = CreateRender( &newcom, &ri ); + + if( re->Init( true )) result = true; + } + + // video system not started, shutdown refresh subsystem + if( !result ) Host_FreeRender(); + + return result; +} + void Host_FreeSound( void ) { if( vsound_dll.link ) @@ -151,19 +162,20 @@ void Host_FreeSound( void ) Sys_FreeLibrary( &vsound_dll ); } -void Host_InitSound( void ) +bool Host_InitSound( void ) { - static vsound_imp_t si; - launch_t CreateSound; - bool result = false; + static vsound_imp_t si; + launch_t CreateSound; + bool result = false; // phys callback - si.api_size = sizeof(vsound_imp_t); + si.api_size = sizeof( vsound_imp_t ); si.GetSoundSpatialization = CL_GetEntitySoundSpatialization; si.PointContents = CL_PointContents; si.AddLoopingSounds = CL_AddLoopingSounds; + si.GetServerTime = CL_GetServerTime; - Sys_LoadLibrary( &vsound_dll ); + Sys_LoadLibrary( host_audio->string, &vsound_dll ); if( vsound_dll.link ) { @@ -175,6 +187,68 @@ void Host_InitSound( void ) // audio system not started, shutdown sound subsystem if( !result ) Host_FreeSound(); + + return result; +} + +void Host_CheckChanges( void ) +{ + int num_changes; + + if( host_video->modified || host_audio->modified ) + { + host.state = HOST_RESTART; + S_StopAllSounds(); // don't let them loop during the restart + + if( host_video->modified ) cl.video_prepped = false; + if( host_audio->modified ) cl.audio_prepped = false; + } + else return; + + num_changes = 0; + + // restart or change renderer + while( host_video->modified ) + { + host_video->modified = false; + + Host_FreeRender(); // release render.dll + if( !Host_InitRender( )) // load it again + { + if( num_changes > num_video_dlls ) + { + Sys_NewInstance( va("#%s", GI->gamefolder ), "fallback to dedicated mode\n" ); + return; + } + if( !com.strcmp( video_dlls[num_changes], host_video->string )) + num_changes++; // already trying - failed + Cvar_FullSet( "host_video", video_dlls[num_changes], CVAR_SYSTEMINFO ); + num_changes++; + } + else SCR_Init (); + } + + num_changes = 0; + + // restart or change sound engine + while( host_audio->modified ) + { + host_audio->modified = false; + + Host_FreeSound(); // release sound.dll + if( !Host_InitSound( )) // load it again + { + if( num_changes > num_audio_dlls ) + { + MsgDev( D_ERROR, "couldn't initialize sound system\n" ); + return; + } + if( !com.strcmp( audio_dlls[num_changes], host_audio->string )) + num_changes++; // already trying - failed + Cvar_FullSet( "host_audio", audio_dlls[num_changes], CVAR_SYSTEMINFO ); + num_changes++; + } + } } /* @@ -208,14 +282,7 @@ Restart the video subsystem */ void Host_VidRestart_f( void ) { - host.state = HOST_RESTART; - S_StopAllSounds(); // don't let them loop during the restart - cl.video_prepped = false; - - Host_FreeRender(); // release render.dll - Host_InitRender(); // load it again - - SCR_RegisterShaders(); // reload 2d-shaders + host_video->modified = true; } /* @@ -227,12 +294,7 @@ Restart the audio subsystem */ void Host_SndRestart_f( void ) { - host.state = HOST_RESTART; - S_StopAllSounds(); // don't let them loop during the restart - cl.audio_prepped = false; - - Host_FreeSound(); // release vsound.dll - Host_InitSound(); // load it again + host_audio->modified = true; } void Host_ChangeGame_f( void ) @@ -263,25 +325,6 @@ void Host_Minimize_f( void ) if( host.hWnd ) ShowWindow( host.hWnd, SW_MINIMIZE ); } -/* -============ -VID_Init -============ -*/ -void VID_Init( void ) -{ - scr_width = Cvar_Get( "width", "640", 0, "screen width" ); - scr_height = Cvar_Get( "height", "480", 0, "screen height" ); - - Cmd_AddCommand( "minimize", Host_Minimize_f, "minimize main window to tray" ); - Cmd_AddCommand( "vid_restart", Host_VidRestart_f, "restarts video system" ); - Cmd_AddCommand( "snd_restart", Host_SndRestart_f, "restarts audio system" ); - Cmd_AddCommand( "game", Host_ChangeGame_f, "change game" ); - - Host_InitRender(); - Host_InitSound(); -} - /* ================= Host_InitEvents @@ -429,7 +472,9 @@ int Host_ModifyTime( int msec ) { // clients of remote servers do not want to clamp time, because // it would skew their view of the server's time temporarily - clamp_time = 5000; + if( cls.state == ca_cinematic ) + clamp_time = (1000 / host_maxfps->integer); + else clamp_time = 5000; } if( msec > clamp_time ) msec = clamp_time; @@ -467,6 +512,9 @@ void Host_Frame( void ) last_time = host.frametime[0]; time = Host_ModifyTime( time ); + if( host.state == HOST_RESTART ) + host.state = HOST_FRAME; + SV_Frame ( time ); // server frame CL_Frame ( time ); // client frame VM_Frame ( time ); // vprogs frame @@ -559,14 +607,17 @@ void Host_Error_f( void ) Host_Crash_f ================= */ -static void Host_Crash_f (void) +static void Host_Crash_f( void ) { *(int *)0 = 0xffffffff; } void Host_InitCommon( const int argc, const char **argv ) { - char dev_level[4]; + char dev_level[4]; + dll_info_t check_vid, check_snd; + search_t *dlls; + int i; newcom = com; @@ -584,6 +635,52 @@ void Host_InitCommon( const int argc, const char **argv ) zonepool = Mem_AllocPool( "Zone Engine" ); IN_Init(); + + // initialize audio\video multi-dlls system + num_video_dlls = num_audio_dlls = 0; + host_video = Cvar_Get( "host_video", "vid_gl.dll", CVAR_SYSTEMINFO, "name of video rendering library" ); + host_audio = Cvar_Get( "host_audio", "snd_al.dll", CVAR_SYSTEMINFO, "name of sound rendering library" ); + + // make sure what global copy has no changed with any dll checking + Mem_Copy( &check_vid, &render_dll, sizeof( dll_info_t )); + Mem_Copy( &check_snd, &vsound_dll, sizeof( dll_info_t )); + + // checking dlls don't invoke crash! + check_vid.crash = false; + check_snd.crash = false; + + dlls = FS_Search( "*.dll", true ); + + // couldn't find any dlls, render is missing (but i'm don't know how laucnher find engine :) + // probably this should never happen + if( !dlls ) Sys_NewInstance( "й", "" ); + + for( i = 0; i < dlls->numfilenames; i++ ) + { + if(!com.strnicmp( "vid_", dlls->filenames[i], 4 )) + { + // make sure what found library is valid + if( Sys_LoadLibrary( dlls->filenames[i], &check_vid )) + { + MsgDev( D_NOTE, "VideoLibrary[%i]: %s\n", num_video_dlls, dlls->filenames[i] ); + com.strncpy( video_dlls[num_video_dlls], dlls->filenames[i], MAX_STRING ); + Sys_FreeLibrary( &check_vid ); + num_video_dlls++; + } + } + else if(!com.strnicmp( "snd_", dlls->filenames[i], 4 )) + { + // make sure what found library is valid + if( Sys_LoadLibrary( dlls->filenames[i], &check_snd )) + { + MsgDev( D_NOTE, "AudioLibrary[%i]: %s\n", num_audio_dlls, dlls->filenames[i] ); + com.strncpy( audio_dlls[num_audio_dlls], dlls->filenames[i], MAX_STRING ); + Sys_FreeLibrary( &check_snd ); + num_audio_dlls++; + } + } + } + Mem_Free( dlls ); } void Host_FreeCommon( void ) @@ -645,6 +742,14 @@ void Host_Init( const int argc, const char **argv ) Cmd_AddCommand( "quit", Sys_Quit, "quit the game" ); Cmd_AddCommand( "exit", Sys_Quit, "quit the game" ); } + else + { + Cmd_AddCommand( "minimize", Host_Minimize_f, "minimize main window to tray" ); + Cmd_AddCommand( "vid_restart", Host_VidRestart_f, "restarts video system" ); + Cmd_AddCommand( "snd_restart", Host_SndRestart_f, "restarts audio system" ); + } + + Cmd_AddCommand( "game", Host_ChangeGame_f, "change game" ); // allow to change game from the console host.frametime[0] = Host_Milliseconds(); host.errorframe = 0; } diff --git a/engine/server/sv_cmds.c b/engine/server/sv_cmds.c index 675be4c9..91a7d968 100644 --- a/engine/server/sv_cmds.c +++ b/engine/server/sv_cmds.c @@ -211,7 +211,7 @@ void SV_Map_f( void ) else spawn_entity = GI->sp_entity; com.strncpy( filename, Cmd_Argv( 1 ), sizeof( filename )); - if( !SV_MapIsValid( filename, spawn_entity )) + if( !SV_MapIsValid( filename, spawn_entity ) && host.developer <= 1 ) { Msg( "SV_NewMap: invalid map %s\n", filename ); return; diff --git a/engine/server/sv_game.c b/engine/server/sv_game.c index 96fcc0e9..5e9d27c9 100644 --- a/engine/server/sv_game.c +++ b/engine/server/sv_game.c @@ -2329,6 +2329,8 @@ pfnIndexOfEdict */ int pfnIndexOfEdict( const edict_t *pEdict ) { + if( !pEdict || pEdict->free ) + return 0; return NUM_FOR_EDICT( pEdict ); } diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index a84e3e56..76011979 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -252,6 +252,8 @@ void SV_SpawnServer( const char *server, const char *startspot ) Msg( "SpawnServer [^2%s^7]\n", server ); + Cmd_ExecuteString( "latch\n" ); + if( sv.state == ss_dead && !sv.loadgame ) SV_InitGame(); // the game is just starting @@ -354,8 +356,6 @@ void SV_InitGame( void ) } MsgDev( D_INFO, "Dll loaded for mod %s\n", svgame.dllFuncs.pfnGetGameDescription() ); - - Cmd_ExecuteString( "latch\n" ); svs.initialized = true; if( Cvar_VariableValue( "coop" ) && Cvar_VariableValue ( "deathmatch" ) && Cvar_VariableValue( "teamplay" )) diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index a935af50..fdfced64 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -241,9 +241,6 @@ bool SV_CheckPaused( void ) int i, count; sv_client_t *cl; - if( !sv_paused->integer ) - return false; - // only pause if there is just a single client connected for( i = count = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) { @@ -259,6 +256,12 @@ bool SV_CheckPaused( void ) return false; } + if( CL_CheckKeydest() ) + return true; + + if( !sv_paused->integer ) + return false; + if( !sv_paused->integer ) Cvar_Set( "paused", "1" ); return true; diff --git a/engine/uimenu/ui_video.c b/engine/uimenu/ui_video.c index 942eca69..2f019913 100644 --- a/engine/uimenu/ui_video.c +++ b/engine/uimenu/ui_video.c @@ -323,7 +323,7 @@ static void UI_Video_UpdateConfig( void ) } uiVideo.glExtensions.generic.name = uiVideoYesNo[(int)uiVideo.glExtensions.curValue]; - uiVideo.videoMode.generic.name = uiVideoModes[(int)uiVideo.videoMode.curValue + 1]; + uiVideo.videoMode.generic.name = uiVideoModes[(int)uiVideo.videoMode.curValue]; uiVideo.fullScreen.generic.name = uiVideoYesNo[(int)uiVideo.fullScreen.curValue]; uiVideo.colorDepth.generic.name = uiVideoBits[(int)uiVideo.colorDepth.curValue]; uiVideo.hardwareGamma.generic.name = uiVideoYesNo[(int)uiVideo.hardwareGamma.curValue]; diff --git a/launch/cmd.c b/launch/cmd.c index b93063d0..4cff13b2 100644 --- a/launch/cmd.c +++ b/launch/cmd.c @@ -45,17 +45,17 @@ Cbuf_AddText Adds command text at the end of the buffer ============ */ -void Cbuf_AddText(const char *text) +void Cbuf_AddText( const char *text ) { int l; - l = com_strlen(text); - if (cmd_text.cursize + l >= cmd_text.maxsize) + l = com.strlen( text ); + if( cmd_text.cursize + l >= cmd_text.maxsize ) { - MsgDev(D_WARN, "Cbuf_AddText: overflow\n"); + MsgDev( D_WARN, "Cbuf_AddText: overflow\n" ); return; } - Mem_Copy(&cmd_text.data[cmd_text.cursize], (char *)text, l); + Mem_Copy( &cmd_text.data[cmd_text.cursize], text, l ); cmd_text.cursize += l; } @@ -73,22 +73,22 @@ void Cbuf_InsertText (const char *text) { int i, len; - len = strlen( text ) + 1; - if ( len + cmd_text.cursize > cmd_text.maxsize ) + len = com.strlen( text ) + 1; + if( len + cmd_text.cursize > cmd_text.maxsize ) { - MsgDev(D_WARN,"Cbuf_InsertText overflowed\n" ); + MsgDev( D_WARN, "Cbuf_InsertText overflowed\n" ); return; } // move the existing command text - for ( i = cmd_text.cursize - 1; i >= 0; i-- ) + for( i = cmd_text.cursize - 1; i >= 0; i-- ) { cmd_text.data[i + len] = cmd_text.data[i]; } // copy the new text in Mem_Copy( cmd_text.data, (char *)text, len - 1 ); - cmd_text.data[ len - 1 ] = '\n'; // add a \n + cmd_text.data[len - 1] = '\n'; // add a \n cmd_text.cursize += len; } @@ -97,23 +97,23 @@ void Cbuf_InsertText (const char *text) Cbuf_ExecuteText ============ */ -void Cbuf_ExecuteText (int exec_when, const char *text) +void Cbuf_ExecuteText( int exec_when, const char *text ) { - switch (exec_when) + switch( exec_when ) { case EXEC_NOW: - if (text && strlen(text)) - Cmd_ExecuteString(text); + if( text && com.strlen( text )) + Cmd_ExecuteString( text ); else Cbuf_Execute(); break; case EXEC_INSERT: - Cbuf_InsertText (text); + Cbuf_InsertText( text ); break; case EXEC_APPEND: - Cbuf_AddText (text); + Cbuf_AddText( text ); break; default: - MsgDev( D_ERROR, "Cbuf_ExecuteText: bad execute target\n"); + MsgDev( D_ERROR, "Cbuf_ExecuteText: bad execute target\n" ); break; } } @@ -143,28 +143,33 @@ void Cbuf_Execute( void ) text = (char *)cmd_text.data; quotes = 0; - for (i = 0; i < cmd_text.cursize; i++) + for( i = 0; i < cmd_text.cursize; i++ ) { - if (text[i] == '"') quotes++; - if ( !(quotes&1) && text[i] == ';') + if( text[i] == '"') quotes++; + if(!( quotes & 1 ) && text[i] == ';' ) break; // don't break if inside a quoted string - if (text[i] == '\n' || text[i] == '\r' ) break; + if( text[i] == '\n' || text[i] == '\r' ) break; } - if( i >= (MAX_CMD_LINE - 1)) i = MAX_CMD_LINE - 1; - Mem_Copy (line, text, i); + if( i >= MAX_CMD_LINE - 1 ) + Sys_Error( "Cbuf_Execute: command string owerflow\n" ); + + Mem_Copy( line, text, i ); line[i] = 0; - + // delete the text from the command buffer and move remaining commands down // this is necessary because commands (exec) can insert data at the // beginning of the text buffer - if (i == cmd_text.cursize) cmd_text.cursize = 0; + if( i == cmd_text.cursize ) + { + cmd_text.cursize = 0; + } else { i++; cmd_text.cursize -= i; - memmove (text, text+i, cmd_text.cursize); + memmove( text, text + i, cmd_text.cursize ); } // execute the command line @@ -195,7 +200,7 @@ void Cmd_StuffCmds_f( void ) if(Cmd_Argc() != 1) { - Msg("stuffcmds : execute command line parameters\n"); + Msg( "stuffcmds : execute command line parameters\n"); return; } @@ -261,26 +266,27 @@ void Cmd_Exec_f (void) { string rcpath; size_t len; - char *f; + if( Cmd_Argc() != 2 ) { - Msg( "exec : execute a script file\n" ); + Msg( "Usage: exec \n" ); return; } - com.snprintf( rcpath, MAX_STRING, "config/%s", Cmd_Argv(1)); + com.snprintf( rcpath, MAX_STRING, "config/%s", Cmd_Argv( 1 )); FS_DefaultExtension( rcpath, ".rc" ); // append as default f = FS_LoadFile(rcpath, &len ); - if (!f) + if( !f ) { - MsgDev( D_WARN, "couldn't exec %s\n", Cmd_Argv(1)); + MsgDev( D_WARN, "couldn't exec %s\n", Cmd_Argv( 1 )); return; } - MsgDev(D_INFO, "execing %s\n",Cmd_Argv(1)); - Cbuf_InsertText(f); - Mem_Free(f); + + MsgDev( D_INFO, "execing %s\n", Cmd_Argv( 1 )); + Cbuf_InsertText( f ); + Mem_Free( f ); } /* @@ -331,10 +337,10 @@ typedef struct cmd_function_s xcommand_t function; } cmd_function_t; -static int cmd_argc; -static char *cmd_argv[MAX_STRING_TOKENS]; -static char cmd_tokenized[MAX_MSGLEN+MAX_STRING_TOKENS]; // will have 0 bytes inserted -static cmd_function_t *cmd_functions; // possible commands to execute +static int cmd_argc; +static char *cmd_argv[MAX_STRING_TOKENS]; +static char cmd_tokenized[MAX_CMD_BUFFER]; // will have 0 bytes inserted +static cmd_function_t *cmd_functions; // possible commands to execute /* ============ @@ -390,7 +396,7 @@ are inserted in the apropriate place, The argv array will point into this temporary buffer. ============ */ -void Cmd_TokenizeString (const char *text_in) +void Cmd_TokenizeString( const char *text_in ) { const char *text; char *textOut; @@ -404,36 +410,37 @@ void Cmd_TokenizeString (const char *text_in) while( 1 ) { // this is usually something malicious - if ( cmd_argc == MAX_STRING_TOKENS ) return; + if( cmd_argc == MAX_STRING_TOKENS ) return; - while ( 1 ) + while( 1 ) { // skip whitespace - while ( *text && *text <= ' ' ) text++; - if ( !*text ) return; // all tokens parsed + while( *text && *text <= ' ' ) text++; + if( !*text ) return; // all tokens parsed // skip // comments - if ( text[0] == '/' && text[1] == '/' ) return; // all tokens parsed + if( text[0] == '/' && text[1] == '/' ) return; // all tokens parsed // skip /* */ comments - if ( text[0] == '/' && text[1] =='*' ) + if( text[0] == '/' && text[1] =='*' ) { - while(*text && ( text[0] != '*' || text[1] != '/' )) text++; - if ( !*text ) return; // all tokens parsed + while( *text && ( text[0] != '*' || text[1] != '/' )) text++; + if( !*text ) return; // all tokens parsed text += 2; } else break; // we are ready to parse a token } // handle quoted strings - if ( *text == '"' ) + if( *text == '"' ) { cmd_argv[cmd_argc] = textOut; cmd_argc++; text++; - while ( *text && *text != '"' ) *textOut++ = *text++; + while( *text && *text != '"' ) + *textOut++ = *text++; *textOut++ = 0; - if ( !*text ) return; // all tokens parsed + if( !*text ) return; // all tokens parsed text++; continue; } @@ -443,12 +450,12 @@ void Cmd_TokenizeString (const char *text_in) cmd_argc++; // skip until whitespace, quote, or command - while ( *text > ' ' ) + while( *text > ' ' ) { - if ( text[0] == '"' ) break; - if ( text[0] == '/' && text[1] == '/' ) break; + if( text[0] == '"' ) break; + if( text[0] == '/' && text[1] == '/' ) break; // skip /* */ comments - if ( text[0] == '/' && text[1] =='*' ) break; + if( text[0] == '/' && text[1] =='*' ) break; *textOut++ = *text++; } @@ -464,7 +471,7 @@ void Cmd_TokenizeString (const char *text_in) Cmd_AddCommand ============ */ -void Cmd_AddCommand (const char *cmd_name, xcommand_t function, const char *cmd_desc) +void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc ) { cmd_function_t *cmd; @@ -559,7 +566,7 @@ void Cmd_ExecuteString( const char *text ) if( !Cmd_Argc()) return; // no tokens // check registered command functions - for ( prev = &cmd_functions; *prev; prev = &cmd->next ) + for( prev = &cmd_functions; *prev; prev = &cmd->next ) { cmd = *prev; if(!com.stricmp( cmd_argv[0], cmd->name )) diff --git a/launch/cvar.c b/launch/cvar.c index 8f22e4e9..ce49e203 100644 --- a/launch/cvar.c +++ b/launch/cvar.c @@ -301,7 +301,7 @@ cvar_t *Cvar_Set2 (const char *var_name, const char *value, bool force) MsgDev(D_INFO, "%s is system variable.\n", var_name); return var; } - if( var->flags & (CVAR_LATCH|CVAR_LATCH_VIDEO)) + if( var->flags & (CVAR_LATCH|CVAR_LATCH_VIDEO|CVAR_LATCH_AUDIO)) { if( var->latched_string ) { @@ -315,26 +315,29 @@ cvar_t *Cvar_Set2 (const char *var_name, const char *value, bool force) return var; } - if( Cvar_VariableInteger( "host_serverstate" )) + if( var->flags & CVAR_LATCH && Cvar_VariableInteger( "host_serverstate" )) { MsgDev( D_INFO, "%s will be changed upon restarting.\n", var->name ); var->latched_string = copystring( value ); } + else if( var->flags & CVAR_LATCH_VIDEO ) + { + MsgDev( D_INFO, "%s will be changed upon restarting video.\n", var->name ); + var->latched_string = copystring( value ); + } + else if( var->flags & CVAR_LATCH_AUDIO ) + { + MsgDev( D_INFO, "%s will be changed upon restarting audio.\n", var->name ); + var->latched_string = copystring( value ); + } else { - if( var->flags & CVAR_LATCH_VIDEO ) - { - MsgDev( D_INFO, "%s will be changed upon restarting video.\n", var->name ); - var->latched_string = copystring( value ); - } - else - { - Mem_Free( var->string ); // free the old value string - var->string = copystring( value ); - var->value = com.atof( var->string ); - var->integer = com.atoi( var->string ); - } + Mem_Free( var->string ); // free the old value string + var->string = copystring( value ); + var->value = com.atof( var->string ); + var->integer = com.atoi( var->string ); } + var->modified = true; var->modificationCount++; return var; @@ -684,28 +687,31 @@ void Cvar_List_f( void ) if( match && !com_stricmpext( match, var->name )) continue; - if( var->flags & CVAR_SERVERINFO ) Msg( "S" ); + if( var->flags & CVAR_SERVERINFO ) Msg( "SV " ); else Msg( " " ); - if( var->flags & CVAR_USERINFO ) Msg( "U" ); + if( var->flags & CVAR_USERINFO ) Msg( "USER " ); else Msg( " " ); - if( var->flags & CVAR_READ_ONLY ) Msg( "R" ); + if( var->flags & CVAR_READ_ONLY ) Msg( "READ " ); else Msg( " " ); - if( var->flags & CVAR_INIT ) Msg( "I" ); + if( var->flags & CVAR_INIT ) Msg( "INIT " ); else Msg( " " ); - if( var->flags & CVAR_ARCHIVE ) Msg( "A" ); + if( var->flags & CVAR_ARCHIVE ) Msg( "ARCH " ); else Msg( " " ); - if( var->flags & CVAR_LATCH ) Msg( "L" ); + if( var->flags & CVAR_LATCH ) Msg( "LATCH" ); else Msg( " " ); - if( var->flags & CVAR_LATCH_VIDEO ) Msg( "V" ); + if( var->flags & CVAR_LATCH_VIDEO ) Msg( "VIDEO" ); else Msg( " " ); - if( var->flags & CVAR_CHEAT ) Msg( "C" ); + if( var->flags & CVAR_LATCH_AUDIO ) Msg( "AUDIO" ); + else Msg( " " ); + + if( var->flags & CVAR_CHEAT ) Msg( "CHEAT" ); else Msg( " " ); Msg(" %s \"%s\"\n", var->name, var->string ); j++; @@ -820,6 +826,35 @@ void Cvar_LatchedVideo_f( void ) } } +/* +============ +Cvar_Latched_f + +Now all latched audio strings is valid +============ +*/ +void Cvar_LatchedAudio_f( void ) +{ + cvar_t *var; + cvar_t **prev; + + prev = &cvar_vars; + + while ( 1 ) + { + var = *prev; + if( !var ) break; + + if( var->flags & CVAR_LATCH_AUDIO && var->latched_string ) + { + Cvar_FullSet( var->name, var->latched_string, var->flags ); + Mem_Free( var->latched_string ); + var->latched_string = NULL; + } + prev = &var->next; + } +} + /* ============ Cvar_Init @@ -842,7 +877,8 @@ void Cvar_Init( void ) Cmd_AddCommand ("seta", Cvar_SetA_f, "create or change the value of a console variable that will be saved to vars.rc"); Cmd_AddCommand ("reset", Cvar_Reset_f, "reset any type variable to initial value" ); Cmd_AddCommand ("latch", Cvar_Latched_f, "apply latched values" ); - Cmd_AddCommand ("vidlatch", Cvar_LatchedVideo_f, "apply latched values for renderer" ); + Cmd_AddCommand ("vidlatch", Cvar_LatchedVideo_f, "apply latched values for video subsystem" ); + Cmd_AddCommand ("sndlatch", Cvar_LatchedAudio_f, "apply latched values for audio subsytem" ); Cmd_AddCommand ("cvarlist", Cvar_List_f, "display all console variables beginning with the specified prefix" ); Cmd_AddCommand ("unsetall", Cvar_Restart_f, "reset all console variables to their default values" ); diff --git a/launch/launch.h b/launch/launch.h index e04d5a7b..5e673880 100644 --- a/launch/launch.h +++ b/launch/launch.h @@ -144,7 +144,7 @@ void Sys_Sleep( int msec ); void Sys_Init( void ); void Sys_Exit( void ); void Sys_Abort( void ); -bool Sys_LoadLibrary ( dll_info_t *dll ); +bool Sys_LoadLibrary( const char *dll_name, dll_info_t *dll ); void* Sys_GetProcAddress ( dll_info_t *dll, const char* name ); void Sys_ShellExecute( const char *path, const char *parms, bool exit ); byte *Sys_LoadRes( const char *filename, size_t *size ); diff --git a/launch/launch.plg b/launch/launch.plg deleted file mode 100644 index 7d3da586..00000000 --- a/launch/launch.plg +++ /dev/null @@ -1,16 +0,0 @@ - - -
-

Build Log

-

---------------------Configuration: launch - Win32 Debug-------------------- -

-

Command Lines

- - - -

Results

-launch.dll - 0 error(s), 0 warning(s) -
- - diff --git a/launch/network.c b/launch/network.c index e53182f0..7589feba 100644 --- a/launch/network.c +++ b/launch/network.c @@ -92,7 +92,7 @@ bool NET_OpenWinSock( void ) { // initialize the Winsock function vectors (we do this instead of statically linking // so we can run on Win 3.1, where there isn't necessarily Winsock) - if( Sys_LoadLibrary( &winsock_dll )) + if( Sys_LoadLibrary( NULL, &winsock_dll )) return true; return false; } diff --git a/launch/system.c b/launch/system.c index f248a196..0d3c3c68 100644 --- a/launch/system.c +++ b/launch/system.c @@ -409,8 +409,8 @@ void Sys_CreateInstance( void ) // export launch_t CreateHost, CreateBaserc; - srand( time( NULL )); // init random generator - Sys_LoadLibrary( Sys.linked_dll ); // loading library if need + srand( time( NULL )); // init random generator + Sys_LoadLibrary( NULL, Sys.linked_dll ); // loading library if need // pre initializations switch( Sys.app_name ) @@ -424,7 +424,7 @@ void Sys_CreateInstance( void ) case HOST_STUDIO: case HOST_WADLIB: case HOST_RIPPER: - Sys_LoadLibrary( &baserc_dll ); // load baserc + Sys_LoadLibrary( NULL, &baserc_dll ); // load baserc CreateHost = (void *)Sys.linked_dll->main; Host = CreateHost( &com, NULL ); // second interface not allowed Sys.Init = Host->Init; @@ -970,7 +970,7 @@ void Sys_Exit( void ) //======================================================================= // DLL'S MANAGER SYSTEM //======================================================================= -bool Sys_LoadLibrary ( dll_info_t *dll ) +bool Sys_LoadLibrary( const char *dll_name, dll_info_t *dll ) { const dllfunc_t *func; bool native_lib = false; @@ -978,9 +978,12 @@ bool Sys_LoadLibrary ( dll_info_t *dll ) // check errors if( !dll ) return false; // invalid desc - if( !dll->name ) return false;// nothing to load if( dll->link ) return true; // already loaded + // check and replace names + if( dll_name && *dll_name ) dll->name = dll_name; + if( !dll->name || !*dll->name ) return false; // nothing to load + MsgDev( D_NOTE, "Sys_LoadLibrary: Loading %s", dll->name ); if( dll->fcts ) @@ -1003,7 +1006,7 @@ bool Sys_LoadLibrary ( dll_info_t *dll ) if( native_lib ) { - if(( dll->main = Sys_GetProcAddress( dll, dll->entry )) == 0) + if(( dll->main = Sys_GetProcAddress( dll, dll->entry )) == 0 ) { com.sprintf( errorstring, "Sys_LoadLibrary: %s has no valid entry point\n", dll->name ); goto error; @@ -1060,19 +1063,19 @@ error: void* Sys_GetProcAddress( dll_info_t *dll, const char* name ) { - if(!dll || !dll->link) // invalid desc + if( !dll || !dll->link ) // invalid desc return NULL; - return (void *)GetProcAddress (dll->link, name); + return (void *)GetProcAddress( dll->link, name ); } bool Sys_FreeLibrary( dll_info_t *dll ) { // invalid desc or alredy freed - if(!dll || !dll->link ) + if( !dll || !dll->link ) return false; - MsgDev(D_NOTE, "Sys_FreeLibrary: Unloading %s\n", dll->name ); + MsgDev( D_NOTE, "Sys_FreeLibrary: Unloading %s\n", dll->name ); FreeLibrary( dll->link ); dll->link = NULL; diff --git a/physic/physic.plg b/physic/physic.plg deleted file mode 100644 index 3835ce2a..00000000 --- a/physic/physic.plg +++ /dev/null @@ -1,16 +0,0 @@ - - -
-

Build Log

-

---------------------Configuration: physic - Win32 Debug-------------------- -

-

Command Lines

- - - -

Results

-physic.dll - 0 error(s), 0 warning(s) -
- - diff --git a/public/launch_api.h b/public/launch_api.h index 554fe75b..435241a2 100644 --- a/public/launch_api.h +++ b/public/launch_api.h @@ -120,6 +120,7 @@ typedef enum CVAR_CHEAT = BIT(9), // can not be changed if cheats are disabled CVAR_NORESTART = BIT(10),// do not clear when a cvar_restart is issued CVAR_LATCH_VIDEO = BIT(11),// save changes until render restart + CVAR_LATCH_AUDIO = BIT(12),// save changes until vsound restart } cvar_flags_t; typedef struct @@ -271,8 +272,9 @@ writes into struct by offsets not names */ typedef struct dll_info_s { + const char *name; // name of library + // generic interface - const char *name; // library name const dllfunc_t *fcts; // list of dll exports const char *entry; // entrypoint name (internal libs only) void *link; // hinstance of loading library @@ -579,7 +581,7 @@ typedef struct stdilib_api_s // filesystem simply user interface byte *(*Com_LoadFile)(const char *path, long *filesize ); // load file into heap bool (*Com_WriteFile)(const char *path, const void *data, long len ); // write file into disk - bool (*Com_LoadLibrary)( dll_info_t *dll ); // load library + bool (*Com_LoadLibrary)( const char *name, dll_info_t *dll ); // load library bool (*Com_FreeLibrary)( dll_info_t *dll ); // free library void*(*Com_GetProcAddress)( dll_info_t *dll, const char* name ); // gpa double (*Com_DoubleTime)( void ); // hi-res timer diff --git a/public/vsound_api.h b/public/vsound_api.h index d2dd28b5..fe362a3c 100644 --- a/public/vsound_api.h +++ b/public/vsound_api.h @@ -41,7 +41,7 @@ typedef struct vsound_exp_s void (*StartStreaming)( void ); void (*StopStreaming)( void ); - void (*Frame)( int entnum, const vec3_t pos, const vec3_t vel, const vec3_t at, const vec3_t up ); + void (*Frame)( int entnum, const vec3_t pos, const vec3_t vel, const vec3_t axis[3], bool clear ); void (*StopAllSounds)( void ); void (*FreeSounds)( void ); @@ -57,7 +57,7 @@ typedef struct vsound_imp_s void (*GetSoundSpatialization)( int entnum, vec3_t origin, vec3_t velocity ); int (*PointContents)( const vec3_t point ); void (*AddLoopingSounds)( void ); - + int (*GetServerTime)( void ); } vsound_imp_t; #endif//VSOUND_API_H \ No newline at end of file diff --git a/release.bat b/release.bat index 663a785d..80e61c91 100644 --- a/release.bat +++ b/release.bat @@ -23,7 +23,7 @@ if errorlevel 1 set BUILD_ERROR=1 %MSDEV% physic/physic.dsp %CONFIG%"physic - Win32 Release" %build_target% if errorlevel 1 set BUILD_ERROR=1 -%MSDEV% render/render.dsp %CONFIG%"render - Win32 Release" %build_target% +%MSDEV% vid_gl/vid_gl.dsp %CONFIG%"vid_gl - Win32 Release" %build_target% if errorlevel 1 set BUILD_ERROR=1 %MSDEV% server/server.dsp %CONFIG%"server - Win32 Release" %build_target% @@ -32,7 +32,10 @@ if errorlevel 1 set BUILD_ERROR=1 %MSDEV% vprogs/vprogs.dsp %CONFIG%"vprogs - Win32 Release" %build_target% if errorlevel 1 set BUILD_ERROR=1 -%MSDEV% vsound/vsound.dsp %CONFIG%"vsound - Win32 Release" %build_target% +%MSDEV% snd_al/snd_al.dsp %CONFIG%"snd_al - Win32 Release" %build_target% +if errorlevel 1 set BUILD_ERROR=1 + +%MSDEV% snd_dx/snd_dx.dsp %CONFIG%"snd_dx - Win32 Release" %build_target% if errorlevel 1 set BUILD_ERROR=1 %MSDEV% xtools/xtools.dsp %CONFIG%"xtools - Win32 Release" %build_target% @@ -62,10 +65,11 @@ if exist client\client.plg del /f /q client\client.plg if exist engine\engine.plg del /f /q engine\engine.plg if exist launch\launch.plg del /f /q launch\launch.plg if exist physic\physic.plg del /f /q physic\physic.plg -if exist render\render.plg del /f /q render\render.plg +if exist vid_gl\vid_gl.plg del /f /q vid_gl\vid_gl.plg if exist server\server.plg del /f /q server\server.plg if exist vprogs\vprogs.plg del /f /q vprogs\vprogs.plg -if exist vsound\vsound.plg del /f /q vsound\vsound.plg +if exist snd_al\snd_al.plg del /f /q snd_al\snd_al.plg +if exist snd_dx\snd_dx.plg del /f /q snd_dx\snd_dx.plg if exist xtools\xtools.plg del /f /q xtools\xtools.plg echo Build succeeded! diff --git a/server/ents/baseentity.cpp b/server/ents/baseentity.cpp index 39b9d120..689148f9 100644 --- a/server/ents/baseentity.cpp +++ b/server/ents/baseentity.cpp @@ -288,8 +288,9 @@ void CBaseEntity :: ResetParent( void ) void CBaseEntity :: SetupPhysics( void ) { //rebuild all parents - if(pFlags & PF_LINKCHILD) LinkChild( this ); - if(m_physinit) return; + if( pFlags & PF_LINKCHILD ) LinkChild( this ); + + if( m_physinit ) return; SetParent(); //set all parents m_physinit = true; PostSpawn();//post spawn diff --git a/server/ents/baseinfo.cpp b/server/ents/baseinfo.cpp index d6a3a77c..29baecc4 100644 --- a/server/ents/baseinfo.cpp +++ b/server/ents/baseinfo.cpp @@ -52,26 +52,31 @@ class CDecal : public CBaseEntity public: void KeyValue( KeyValueData *pkvd ) { - if (FStrEq(pkvd->szKeyName, "texture")) + if( FStrEq( pkvd->szKeyName, "texture" )) { pev->skin = DECAL_INDEX( pkvd->szValue ); - if ( pev->skin >= 0 ) return; + if( pev->skin >= 0 ) return; Msg( "Can't find decal %s\n", pkvd->szValue ); } } - void PostSpawn( void ) { if(FStringNull(pev->targetname))MakeDecal(); } + void PostSpawn( void ) { if( FStringNull( pev->targetname )) MakeDecal(); } void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { MakeDecal(); } void MakeDecal( void ) { if ( pev->skin < 0 ) { REMOVE_ENTITY(ENT(pev)); return; } - TraceResult trace; - int entityIndex, modelIndex; - UTIL_TraceLine( pev->origin - Vector(5,5,5), pev->origin + Vector(5,5,5), ignore_monsters, ENT(pev), &trace ); - entityIndex = (short)ENTINDEX(trace.pHit); - if ( entityIndex ) modelIndex = (int)VARS(trace.pHit)->modelindex; + TraceResult trace; + int entityIndex, modelIndex; + + UTIL_TraceLine( pev->origin - Vector( 5, 5, 5 ), pev->origin + Vector( 5, 5, 5 ), ignore_monsters, ENT( pev ), &trace ); + + entityIndex = (short)ENTINDEX( trace.pHit ); + if ( entityIndex ) modelIndex = (int)VARS( trace.pHit )->modelindex; else modelIndex = 0; - if(FStringNull(pev->targetname)) g_engfuncs.pfnStaticDecal( pev->origin, (int)pev->skin, entityIndex, modelIndex ); + if( FStringNull( pev->targetname )) + { + g_engfuncs.pfnStaticDecal( pev->origin, (int)pev->skin, entityIndex, modelIndex ); + } else { MESSAGE_BEGIN( MSG_BROADCAST, gmsg.TempEntity ); @@ -81,7 +86,7 @@ public: WRITE_COORD( pev->origin.z ); WRITE_SHORT( (int)pev->skin ); WRITE_SHORT( entityIndex ); - if(entityIndex) WRITE_SHORT( modelIndex ); + if( entityIndex ) WRITE_SHORT( modelIndex ); MESSAGE_END(); } diff --git a/server/monsters/player.cpp b/server/monsters/player.cpp index 91471c39..a10ec504 100644 --- a/server/monsters/player.cpp +++ b/server/monsters/player.cpp @@ -402,7 +402,7 @@ void CBasePlayer :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector if(bitsDamageType & DMG_NUCLEAR) { - m_FadeColor = Vector(255, 255, 255); + m_FadeColor = Vector( 255, 255, 255 ); m_FadeAlpha = 240; m_iFadeFlags = 0; m_iFadeTime = 25; diff --git a/server/server.plg b/server/server.plg deleted file mode 100644 index 35b71426..00000000 --- a/server/server.plg +++ /dev/null @@ -1,16 +0,0 @@ - - -
-

Build Log

-

---------------------Configuration: server - Win32 Debug-------------------- -

-

Command Lines

- - - -

Results

-server.dll - 0 error(s), 0 warning(s) -
- - diff --git a/vsound/libogg.lib b/snd_al/libogg.lib similarity index 100% rename from vsound/libogg.lib rename to snd_al/libogg.lib diff --git a/vsound/s_export.c b/snd_al/s_export.c similarity index 100% rename from vsound/s_export.c rename to snd_al/s_export.c diff --git a/vsound/s_load.c b/snd_al/s_load.c similarity index 87% rename from vsound/s_load.c rename to snd_al/s_load.c index 75276201..55a657d8 100644 --- a/vsound/s_load.c +++ b/snd_al/s_load.c @@ -28,6 +28,7 @@ void S_SoundList_f( void ) { sfx_t *sfx; int i, samples = 0; + int totalSfx = 0; Msg("\n"); Msg(" -samples -hz-- -format- -name--------\n"); @@ -35,46 +36,40 @@ void S_SoundList_f( void ) for( i = 0; i < s_numSfx; i++ ) { sfx = &s_knownSfx[i]; - Msg("%4i: ", i); - if( sfx->loaded ) { samples += sfx->samples; - Msg("%8i ", sfx->samples); - Msg("%5i ", sfx->rate); + Msg( "%8i ", sfx->samples ); + Msg( "%5i ", sfx->rate ); switch( sfx->format ) { - case AL_FORMAT_STEREO16: Msg("STEREO16 "); break; - case AL_FORMAT_STEREO8: Msg("STEREO8 "); break; - case AL_FORMAT_MONO16: Msg("MONO16 "); break; - case AL_FORMAT_MONO8: Msg("MONO8 "); break; - default: Msg("???????? "); break; + case AL_FORMAT_STEREO16: Msg( "STEREO16 " ); break; + case AL_FORMAT_STEREO8: Msg( "STEREO8 " ); break; + case AL_FORMAT_MONO16: Msg( "MONO16 " ); break; + case AL_FORMAT_MONO8: Msg( "MONO8 " ); break; + default: Msg( "???????? " ); break; } - if( sfx->name[0] == '#' ) Msg("%s", &sfx->name[1]); - else Msg("sound/%s", sfx->name); + if( sfx->name[0] == '#' ) Msg( "%s", &sfx->name[1] ); + else Msg( "sound/%s", sfx->name ); Msg( "\n" ); - } - else - { - if( sfx->name[0] == '*' ) Msg(" placeholder %s\n", sfx->name); - else Msg(" not loaded %s\n", sfx->name); + totalSfx++; } } Msg("-------------------------------------------\n"); Msg("%i total samples\n", samples ); - Msg("%i total sounds\n", s_numSfx ); + Msg("%i total sounds\n", totalSfx ); Msg("\n"); } /* - ======================================================================= +======================================================================= WAV LOADING - ======================================================================= +======================================================================= */ static byte *iff_data; static byte *iff_dataPtr; @@ -177,7 +172,7 @@ static bool S_LoadWAV( const char *name, byte **wav, wavinfo_t *info ) // dind "RIFF" chunk S_FindChunk( "RIFF" ); - if(!(iff_dataPtr && !com.strncmp(iff_dataPtr+8, "WAVE", 4))) + if( !( iff_dataPtr && !com.strncmp( iff_dataPtr + 8, "WAVE", 4 ))) { MsgDev( D_WARN, "S_LoadWAV: missing 'RIFF/WAVE' chunks (%s)\n", name ); Mem_Free( buffer ); @@ -186,7 +181,7 @@ static bool S_LoadWAV( const char *name, byte **wav, wavinfo_t *info ) // get "fmt " chunk iff_data = iff_dataPtr + 12; - S_FindChunk("fmt "); + S_FindChunk( "fmt " ); if( !iff_dataPtr ) { MsgDev( D_WARN, "S_LoadWAV: missing 'fmt ' chunk (%s)\n", name ); @@ -497,11 +492,11 @@ S_LoadSound */ loadformat_t load_formats[] = { - {"sound/%s.%s", "ogg", S_LoadOGG}, - {"sound/%s.%s", "wav", S_LoadWAV}, - {"%s.%s", "ogg", S_LoadOGG}, - {"%s.%s", "wav", S_LoadWAV}, - {NULL, NULL} +{ "sound/%s.%s", "ogg", S_LoadOGG }, +{ "sound/%s.%s", "wav", S_LoadWAV }, +{ "%s.%s", "ogg", S_LoadOGG }, +{ "%s.%s", "wav", S_LoadWAV }, +{ NULL, NULL } }; bool S_LoadSound( sfx_t *sfx ) @@ -526,7 +521,7 @@ bool S_LoadSound( sfx_t *sfx ) Mem_Set( &info, 0, sizeof( info )); // developer warning - if( !anyformat ) MsgDev(D_NOTE, "Note: %s will be loading only with ext .%s\n", loadname, ext ); + if( !anyformat ) MsgDev( D_NOTE, "Note: %s will be loading only with ext .%s\n", loadname, ext ); // now try all the formats in the selected list for( format = load_formats; format->formatstring; format++ ) @@ -540,7 +535,7 @@ bool S_LoadSound( sfx_t *sfx ) } sfx->default_sound = true; - MsgDev(D_WARN, "FS_LoadSound: couldn't load %s\n", sfx->name ); + MsgDev( D_WARN, "FS_LoadSound: couldn't load %s\n", sfx->name ); S_CreateDefaultSound( &data, &info ); info.loopstart = -1; @@ -576,6 +571,7 @@ sfx_t *S_FindSound( const char *name ) return NULL; } + // see if already loaded for( i = 0; i < s_numSfx; i++ ) { sfx = &s_knownSfx[i]; @@ -647,7 +643,7 @@ void S_EndRegistration( void ) // load everything in for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ ) { - if( !sfx->name[0] )continue; + if( !sfx->name[0] ) continue; S_LoadSound( sfx ); } s_registering = false; diff --git a/vsound/s_main.c b/snd_al/s_main.c similarity index 91% rename from vsound/s_main.c rename to snd_al/s_main.c index 0a8c0e3a..42847773 100644 --- a/vsound/s_main.c +++ b/snd_al/s_main.c @@ -13,8 +13,8 @@ static playSound_t s_playSounds[MAX_PLAYSOUNDS]; static playSound_t s_freePlaySounds; static playSound_t s_pendingPlaySounds; -static channel_t s_channels[MAX_CHANNELS]; -static listener_t s_listener; +static channel_t s_channels[MAX_CHANNELS]; +static listener_t s_listener; const guid_t DSPROPSETID_EAX20_ListenerProperties = {0x306a6a8, 0xb224, 0x11d2, {0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22}}; const guid_t DSPROPSETID_EAX20_BufferProperties = {0x306a6a7, 0xb224, 0x11d2, {0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22}}; @@ -350,6 +350,7 @@ static playSound_t *S_AllocPlaySound( void ) if( ps == &s_freePlaySounds ) return NULL; // No free playSounds + // unlink from freelist ps->prev->next = ps->next; ps->next->prev = ps->prev; @@ -363,6 +364,7 @@ S_FreePlaySound */ static void S_FreePlaySound( playSound_t *ps ) { + // unlink from channel ps->prev->next = ps->next; ps->next->prev = ps->prev; @@ -397,7 +399,7 @@ static void S_IssuePlaySounds( void ) ch = S_PickChannel( ps->entnum, ps->entchannel ); if(!ch) { - if( ps->sfx->name[0] == '#' ) MsgDev(D_ERROR, "dropped sound %s\n", &ps->sfx->name[1] ); + if( ps->sfx->name[0] == '#' ) MsgDev( D_ERROR, "dropped sound %s\n", &ps->sfx->name[1] ); else MsgDev( D_ERROR, "dropped sound \"sound/%s\"\n", ps->sfx->name ); S_FreePlaySound( ps ); continue; @@ -441,16 +443,16 @@ void S_StartSound( const vec3_t pos, int entnum, int channel, sound_t handle, fl playSound_t *ps, *sort; sfx_t *sfx = NULL; - if(!al_state.initialized ) + if( !al_state.initialized ) return; sfx = S_GetSfxByHandle( handle ); if( !sfx ) return; - // Make sure the sound is loaded + // make sure the sound is loaded if( !S_LoadSound( sfx )) return; - // Allocate a playSound + // allocate a playSound ps = S_AllocPlaySound(); if( !ps ) { @@ -570,13 +572,13 @@ S_Update Called once each time through the main loop ================= */ -void S_Update( int clientnum, const vec3_t position, const vec3_t velocity, const vec3_t at, const vec3_t up ) +void S_Update( int clientnum, const vec3_t position, const vec3_t velocity, const vec3_t axis[3], bool clear ) { channel_t *ch; int i; if(!al_state.initialized ) return; - //if( s_pause->integer ) return; +// if( s_pause->integer || clear ) return; // bump frame count al_state.framecount++; @@ -587,12 +589,12 @@ void S_Update( int clientnum, const vec3_t position, const vec3_t velocity, cons VectorSet( s_listener.velocity, velocity[1], velocity[2], -velocity[0] ); // set listener orientation matrix - s_listener.orientation[0] = at[1]; - s_listener.orientation[1] = -at[2]; - s_listener.orientation[2] = -at[0]; - s_listener.orientation[3] = up[1]; - s_listener.orientation[4] = -up[2]; - s_listener.orientation[5] = -up[0]; + s_listener.orientation[0] = axis[0][1]; + s_listener.orientation[1] = -axis[0][2]; + s_listener.orientation[2] = -axis[0][0]; + s_listener.orientation[3] = axis[2][1]; + s_listener.orientation[4] = -axis[2][2]; + s_listener.orientation[5] = -axis[2][0]; palListenerfv(AL_POSITION, s_listener.position); palListenerfv(AL_VELOCITY, s_listener.velocity); @@ -743,9 +745,11 @@ bool S_Init( void *hInst ) { int num_mono_src, num_stereo_src; + Cmd_ExecuteString( "sndlatch\n" ); + host_sound = Cvar_Get("host_sound", "1", CVAR_SYSTEMINFO, "enable sound system" ); - s_alDevice = Cvar_Get("s_device", "Generic Software", CVAR_LATCH|CVAR_ARCHIVE, "OpenAL current device name" ); - s_soundfx = Cvar_Get("s_soundfx", "1", CVAR_LATCH|CVAR_ARCHIVE, "allow OpenAl extensions" ); + s_alDevice = Cvar_Get("s_device", "Generic Software", CVAR_LATCH_AUDIO|CVAR_ARCHIVE, "OpenAL current device name" ); + s_soundfx = Cvar_Get("s_soundfx", "1", CVAR_LATCH_AUDIO|CVAR_ARCHIVE, "allow OpenAl extensions" ); s_check_errors = Cvar_Get("s_check_errors", "1", CVAR_ARCHIVE, "ignore audio engine errors" ); s_volume = Cvar_Get("s_volume", "1.0", CVAR_ARCHIVE, "sound volume" ); s_musicvolume = Cvar_Get("s_musicvolume", "1.0", CVAR_ARCHIVE, "background music volume" ); diff --git a/vsound/s_openal.c b/snd_al/s_openal.c similarity index 96% rename from vsound/s_openal.c rename to snd_al/s_openal.c index 0e8cbd0b..6474b7ef 100644 --- a/vsound/s_openal.c +++ b/snd_al/s_openal.c @@ -160,8 +160,8 @@ failed: // release openal at all Sys_FreeLibrary( &openal_dll ); - Mem_Set(&al_config, 0, sizeof(alconfig_t)); - Mem_Set(&al_state, 0, sizeof(alstate_t)); + Mem_Set( &al_config, 0, sizeof( alconfig_t )); + Mem_Set( &al_state, 0, sizeof( alstate_t )); return false; } @@ -331,7 +331,7 @@ static void S_InitExtensions( void ) bool S_Init_OpenAL( void ) { - Sys_LoadLibrary( &openal_dll ); + Sys_LoadLibrary( NULL, &openal_dll ); if( !openal_dll.link ) { diff --git a/vsound/s_openal.h b/snd_al/s_openal.h similarity index 100% rename from vsound/s_openal.h rename to snd_al/s_openal.h diff --git a/vsound/s_stream.c b/snd_al/s_stream.c similarity index 100% rename from vsound/s_stream.c rename to snd_al/s_stream.c diff --git a/vsound/s_stream.h b/snd_al/s_stream.h similarity index 100% rename from vsound/s_stream.h rename to snd_al/s_stream.h diff --git a/vsound/vsound.dsp b/snd_al/snd_al.dsp similarity index 75% rename from vsound/vsound.dsp rename to snd_al/snd_al.dsp index 8d4e0ac8..db181710 100644 --- a/vsound/vsound.dsp +++ b/snd_al/snd_al.dsp @@ -1,24 +1,24 @@ -# Microsoft Developer Studio Project File - Name="vsound" - Package Owner=<4> +# Microsoft Developer Studio Project File - Name="snd_al" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 -CFG=vsound - Win32 Debug +CFG=snd_al - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE -!MESSAGE NMAKE /f "vsound.mak". +!MESSAGE NMAKE /f "snd_al.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE -!MESSAGE NMAKE /f "vsound.mak" CFG="vsound - Win32 Debug" +!MESSAGE NMAKE /f "snd_al.mak" CFG="snd_al - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE -!MESSAGE "vsound - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "vsound - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "snd_al - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "snd_al - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project @@ -29,7 +29,7 @@ CPP=cl.exe MTL=midl.exe RSC=rc.exe -!IF "$(CFG)" == "vsound - Win32 Release" +!IF "$(CFG)" == "snd_al - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 @@ -38,8 +38,8 @@ RSC=rc.exe # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 -# PROP Output_Dir "..\temp\vsound\!release" -# PROP Intermediate_Dir "..\temp\vsound\!release" +# PROP Output_Dir "..\temp\snd_al\!release" +# PROP Intermediate_Dir "..\temp\snd_al\!release" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PLATFORM_EXPORTS" /YX /FD /c @@ -57,16 +57,16 @@ LINK32=link.exe # ADD LINK32 libogg.lib vorbis.lib /nologo /dll /pdb:none /machine:I386 /nodefaultlib:"libcmt.lib" /opt:nowin98 # SUBTRACT LINK32 /profile # Begin Custom Build -TargetDir=\Xash3D\src_main\temp\vsound\!release -InputPath=\Xash3D\src_main\temp\vsound\!release\vsound.dll +TargetDir=\Xash3D\src_main\temp\snd_al\!release +InputPath=\Xash3D\src_main\temp\snd_al\!release\snd_al.dll SOURCE="$(InputPath)" -"D:\Xash3D\bin\vsound.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\vsound.dll "D:\Xash3D\bin\vsound.dll" +"D:\Xash3D\bin\snd_al.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\snd_al.dll "D:\Xash3D\bin\snd_al.dll" # End Custom Build -!ELSEIF "$(CFG)" == "vsound - Win32 Debug" +!ELSEIF "$(CFG)" == "snd_al - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 @@ -75,8 +75,8 @@ SOURCE="$(InputPath)" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 -# PROP Output_Dir "..\temp\vsound\!debug" -# PROP Intermediate_Dir "..\temp\vsound\!debug" +# PROP Output_Dir "..\temp\snd_al\!debug" +# PROP Intermediate_Dir "..\temp\snd_al\!debug" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PLATFORM_EXPORTS" /YX /FD /GZ /c @@ -94,12 +94,12 @@ LINK32=link.exe # ADD LINK32 libogg.lib vorbis.lib /nologo /dll /debug /machine:I386 /nodefaultlib:"libcmt.lib" /pdbtype:sept # SUBTRACT LINK32 /incremental:no /nodefaultlib # Begin Custom Build -TargetDir=\Xash3D\src_main\temp\vsound\!debug -InputPath=\Xash3D\src_main\temp\vsound\!debug\vsound.dll +TargetDir=\Xash3D\src_main\temp\snd_al\!debug +InputPath=\Xash3D\src_main\temp\snd_al\!debug\snd_al.dll SOURCE="$(InputPath)" -"D:\Xash3D\bin\vsound.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\vsound.dll "D:\Xash3D\bin\vsound.dll" +"D:\Xash3D\bin\snd_al.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\snd_al.dll "D:\Xash3D\bin\snd_al.dll" # End Custom Build @@ -107,8 +107,8 @@ SOURCE="$(InputPath)" # Begin Target -# Name "vsound - Win32 Release" -# Name "vsound - Win32 Debug" +# Name "snd_al - Win32 Release" +# Name "snd_al - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" diff --git a/vsound/sound.h b/snd_al/sound.h similarity index 93% rename from vsound/sound.h rename to snd_al/sound.h index b1231f6a..b18643b9 100644 --- a/vsound/sound.h +++ b/snd_al/sound.h @@ -169,7 +169,7 @@ void S_Activate( bool active ); void S_SoundList_f( void ); bool S_CheckForErrors( void ); void S_StartSound(const vec3_t pos, int ent, int chan, sound_t sfx, float vol, float attn, float pitch, bool use_loop); -void S_Update( int clientnum, const vec3_t pos, const vec3_t vel, const vec3_t at, const vec3_t up ); +void S_Update( int entnum, const vec3_t pos, const vec3_t vel, const vec3_t axis[3], bool clear ); void S_StreamRawSamples( int samples, int rate, int width, int channels, const byte *data ); bool S_AddLoopingSound( int entnum, sound_t handle, float volume, float attn ); void S_StartBackgroundTrack( const char *intro, const char *loop ); diff --git a/vsound/vorbis.lib b/snd_al/vorbis.lib similarity index 100% rename from vsound/vorbis.lib rename to snd_al/vorbis.lib diff --git a/snd_dx/s_direct.c b/snd_dx/s_direct.c new file mode 100644 index 00000000..a187fa0c --- /dev/null +++ b/snd_dx/s_direct.c @@ -0,0 +1,743 @@ +//======================================================================= +// Copyright XashXT Group 2009 й +// s_direct.c - sound hardware output +//======================================================================= + +#include +#include "sound.h" + +#define iDirectSoundCreate( a, b, c ) pDirectSoundCreate( a, b, c ) + +static HRESULT ( _stdcall *pDirectSoundCreate)(GUID* lpGUID, LPDIRECTSOUND* lplpDS, IUnknown* pUnkOuter ); + +static dllfunc_t dsound_funcs[] = +{ +{ "DirectSoundCreate", (void **) &pDirectSoundCreate }, +{ NULL, NULL } +}; + +dll_info_t dsound_dll = { "dsound.dll", dsound_funcs, NULL, NULL, NULL, false, 0, 0 }; + +// 64K is > 1 second at 16-bit, 22050 Hz +#define WAV_BUFFERS 64 +#define WAV_MASK 0x3F +#define WAV_BUFFER_SIZE 0x0400 +#define SECONDARY_BUFFER_SIZE 0x10000 + +typedef enum +{ + SIS_SUCCESS, + SIS_FAILURE, + SIS_NOTAVAIL +} si_state_t; + +cvar_t *s_wavonly; + +static HWND snd_hwnd; +static bool dsound_init; +static bool wav_init; +static bool snd_firsttime = true, snd_isdirect, snd_iswave; +static bool primary_format_set; +static int snd_buffer_count = 0; +static int sample16; +static int snd_sent, snd_completed; + +/* +======================================================================= +Global variables. Must be visible to window-procedure function +so it can unlock and free the data block after it has been played. +======================================================================= +*/ +DWORD locksize; +HANDLE hData; +HPSTR lpData, lpData2; +HGLOBAL hWaveHdr; +LPWAVEHDR lpWaveHdr; +HWAVEOUT hWaveOut; +WAVEOUTCAPS wavecaps; +DWORD gSndBufSize; +MMTIME mmstarttime; +LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf; +LPDIRECTSOUND pDS; + +bool SNDDMA_InitDirect( void *hInst ); +bool SNDDMA_InitWav( void ); +void SNDDMA_FreeSound( void ); + +static const char *DSoundError( int error ) +{ + switch( error ) + { + case DSERR_BUFFERLOST: + return "DSERR_BUFFERLOST"; + case DSERR_INVALIDCALL: + return "DSERR_INVALIDCALLS"; + case DSERR_INVALIDPARAM: + return "DSERR_INVALIDPARAM"; + case DSERR_PRIOLEVELNEEDED: + return "DSERR_PRIOLEVELNEEDED"; + } + return "Unknown Error"; +} + +/* +================== +DS_CreateBuffers +================== +*/ +static bool DS_CreateBuffers( void *hInst ) +{ + DSBUFFERDESC dsbuf; + DSBCAPS dsbcaps; + WAVEFORMATEX pformat, format; + + Mem_Set( &format, 0, sizeof( format )); + + format.wFormatTag = WAVE_FORMAT_PCM; + format.nChannels = dma.channels; + format.wBitsPerSample = dma.samplebits; + format.nSamplesPerSec = dma.speed; + format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; + format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; + format.cbSize = 0; + + MsgDev( D_NOTE, "DS_CreateBuffers: initialize\n" ); + + MsgDev( D_NOTE, "DS_CreateBuffers: setting EXCLUSIVE coop level " ); + if( DS_OK != pDS->lpVtbl->SetCooperativeLevel( pDS, hInst, DSSCL_EXCLUSIVE )) + { + MsgDev( D_NOTE, "- failed\n" ); + SNDDMA_FreeSound(); + return false; + } + MsgDev( D_NOTE, "- ok\n" ); + + // get access to the primary buffer, if possible, so we can set the sound hardware format + Mem_Set( &dsbuf, 0, sizeof( dsbuf )); + dsbuf.dwSize = sizeof( DSBUFFERDESC ); + dsbuf.dwFlags = DSBCAPS_PRIMARYBUFFER; + dsbuf.dwBufferBytes = 0; + dsbuf.lpwfxFormat = NULL; + + Mem_Set( &dsbcaps, 0, sizeof( dsbcaps )); + dsbcaps.dwSize = sizeof( dsbcaps ); + primary_format_set = false; + + MsgDev( D_NOTE, "DS_CreateBuffers: creating primary buffer " ); + if( pDS->lpVtbl->CreateSoundBuffer( pDS, &dsbuf, &pDSPBuf, NULL ) == DS_OK ) + { + pformat = format; + + MsgDev( D_NOTE, "- ok\n" ); + if( pDSPBuf->lpVtbl->SetFormat( pDSPBuf, &pformat ) != DS_OK ) + { + if( snd_firsttime ) + MsgDev( D_NOTE, "DS_CreateBuffers: setting primary sound format - failed\n" ); + } + else + { + if( snd_firsttime ) + MsgDev( D_NOTE, "DS_CreateBuffers: setting primary sound format - ok\n" ); + primary_format_set = true; + } + } + else MsgDev( D_NOTE, "- failed\n" ); + + if( !primary_format_set || !s_primary->integer ) + { + // create the secondary buffer we'll actually work with + Mem_Set( &dsbuf, 0, sizeof( dsbuf )); + dsbuf.dwSize = sizeof( DSBUFFERDESC ); + dsbuf.dwFlags = (DSBCAPS_CTRLFREQUENCY|DSBCAPS_LOCSOFTWARE); + dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE; + dsbuf.lpwfxFormat = &format; + + Mem_Set( &dsbcaps, 0, sizeof( dsbcaps )); + dsbcaps.dwSize = sizeof( dsbcaps ); + + MsgDev( D_NOTE, "DS_CreateBuffers: creating secondary buffer " ); + if( pDS->lpVtbl->CreateSoundBuffer( pDS, &dsbuf, &pDSBuf, NULL ) == DS_OK ) + { + MsgDev( D_NOTE, "- ok\n" ); + } + else + { + // couldn't get hardware, fallback to software. + dsbuf.dwFlags = (DSBCAPS_LOCSOFTWARE|DSBCAPS_GETCURRENTPOSITION2); + if( pDS->lpVtbl->CreateSoundBuffer( pDS, &dsbuf, &pDSBuf, NULL ) != DS_OK ) + { + MsgDev( D_NOTE, "- failed\n" ); + SNDDMA_FreeSound (); + return false; + } + MsgDev( D_INFO, "- failed. forced to software\n" ); + } + + dma.channels = format.nChannels; + dma.samplebits = format.wBitsPerSample; + dma.speed = format.nSamplesPerSec; + + if( pDSBuf->lpVtbl->GetCaps( pDSBuf, &dsbcaps ) != DS_OK ) + { + MsgDev( D_ERROR, "DS_CreateBuffers: GetCaps failed\n"); + SNDDMA_FreeSound (); + return false; + } + MsgDev( D_NOTE, "DS_CreateBuffers: using secondary sound buffer\n" ); + } + else + { + MsgDev( D_NOTE, "DS_CreateBuffers: using primary sound buffer\n" ); + MsgDev( D_NOTE, "DS_CreateBuffers: setting WRITEPRIMARY coop level " ); + if( pDS->lpVtbl->SetCooperativeLevel( pDS, hInst, DSSCL_WRITEPRIMARY ) != DS_OK ) + { + MsgDev( D_NOTE, "- failed\n" ); + SNDDMA_FreeSound (); + return false; + } + MsgDev( D_NOTE, "- ok\n" ); + + if( pDSPBuf->lpVtbl->GetCaps( pDSPBuf, &dsbcaps ) != DS_OK ) + { + MsgDev( D_ERROR, "DS_CreateBuffers: GetCaps failed\n"); + SNDDMA_FreeSound (); + return false; + } + pDSBuf = pDSPBuf; + } + + // make sure mixer is active + if( pDSBuf->lpVtbl->Play( pDSBuf, 0, 0, DSBPLAY_LOOPING ) != DS_OK ) + { + MsgDev( D_ERROR, "DS_CreateBuffers: looped sound play failed\n" ); + SNDDMA_FreeSound (); + return false; + } + + // we don't want anyone to access the buffer directly w/o locking it first + lpData = NULL; + dma.samplepos = 0; + snd_hwnd = (HWND)hInst; + gSndBufSize = dsbcaps.dwBufferBytes; + dma.samples = gSndBufSize / (dma.samplebits / 8 ); + dma.submission_chunk = 1; + dma.buffer = (byte *)lpData; + sample16 = (dma.samplebits / 8) - 1; + + SNDDMA_BeginPainting(); + if( dma.buffer ) Mem_Set( dma.buffer, 0, dma.samples * dma.samplebits / 8 ); + SNDDMA_Submit(); + + return true; +} + +/* +================== +DS_DestroyBuffers +================== +*/ +static void DS_DestroyBuffers( void ) +{ + MsgDev( D_NOTE, "DS_DestroyBuffers: shutdown\n" ); + + if( pDS ) + { + MsgDev( D_NOTE, "DS_DestroyBuffers: setting NORMAL coop level\n" ); + pDS->lpVtbl->SetCooperativeLevel( pDS, snd_hwnd, DSSCL_NORMAL ); + } + + if( pDSBuf ) + { + MsgDev( D_NOTE, "DS_DestroyBuffers: stopping and releasing sound buffer\n" ); + pDSBuf->lpVtbl->Stop( pDSBuf ); + pDSBuf->lpVtbl->Release( pDSBuf ); + } + + // only release primary buffer if it's not also the mixing buffer we just released + if( pDSPBuf && ( pDSBuf != pDSPBuf )) + { + MsgDev( D_NOTE, "DS_DestroyBuffers: releasing primary buffer\n" ); + pDSPBuf->lpVtbl->Release( pDSPBuf ); + } + + pDSBuf = NULL; + pDSPBuf = NULL; + dma.buffer = NULL; +} + +/* +================== +SNDDMA_FreeSound +================== +*/ +void SNDDMA_FreeSound( void ) +{ + int i; + + if( pDS ) + { + DS_DestroyBuffers(); + pDS->lpVtbl->Release( pDS ); + Sys_FreeLibrary( &dsound_dll ); + } + + if( hWaveOut ) + { + waveOutReset( hWaveOut ); + + if( lpWaveHdr ) + { + for( i = 0; i < WAV_BUFFERS; i++ ) + waveOutUnprepareHeader( hWaveOut, lpWaveHdr + i, sizeof( WAVEHDR )); + } + + waveOutClose( hWaveOut ); + + if( hWaveHdr ) + { + GlobalUnlock( hWaveHdr ); + GlobalFree( hWaveHdr ); + } + + if( hData ) + { + GlobalUnlock( hData ); + GlobalFree( hData ); + } + + } + + pDS = NULL; + pDSBuf = NULL; + pDSPBuf = NULL; + hWaveOut = 0; + hData = 0; + hWaveHdr = 0; + lpData = NULL; + lpWaveHdr = NULL; + dsound_init = false; + wav_init = false; +} + +/* +================== +SNDDMA_InitDirect + +Direct-Sound support +================== +*/ +si_state_t SNDDMA_InitDirect( void *hInst ) +{ + DSCAPS dscaps; + HRESULT hresult; + + dma.channels = 2; + dma.samplebits = 16; + + switch( s_khz->integer ) + { + case 44: dma.speed = 44100; break; + case 22: dma.speed = 22050; break; + default: dma.speed = 11025; break; + } + + MsgDev( D_NOTE, "SNDDMA_InitDirect: initializing DirectSound "); + + if ( !dsound_dll.link ) + { + if( !Sys_LoadLibrary( NULL, &dsound_dll )) + { + MsgDev( D_NOTE, "- failed\n" ); + return SIS_FAILURE; + } + MsgDev( D_NOTE, "- ok\n" ); + } + + MsgDev( D_NOTE, "SNDDMA_InitDirect: creating DS object " ); + if(( hresult = iDirectSoundCreate( NULL, &pDS, NULL )) != DS_OK ) + { + if( hresult != DSERR_ALLOCATED ) + { + MsgDev( D_NOTE, "- failed\n" ); + return SIS_FAILURE; + } + + MsgDev( D_NOTE, "- failed, hardware already in use\n" ); + return SIS_NOTAVAIL; + } + + MsgDev( D_NOTE, "- ok\n" ); + dscaps.dwSize = sizeof( dscaps ); + + if( pDS->lpVtbl->GetCaps( pDS, &dscaps ) != DS_OK ) + MsgDev( D_ERROR, "SNDDMA_InitDirect: GetCaps failed\n"); + + if( dscaps.dwFlags & DSCAPS_EMULDRIVER ) + { + MsgDev( D_ERROR, "SNDDMA_InitDirect: no DSound driver found\n" ); + SNDDMA_FreeSound(); + return SIS_FAILURE; + } + + if( !DS_CreateBuffers( hInst )) + return SIS_FAILURE; + + dsound_init = true; + + return SIS_SUCCESS; +} + + +/* +================== +SNDDM_InitWav + +Crappy windows multimedia base +================== +*/ +si_state_t SNDDMA_InitWav( void ) +{ + WAVEFORMATEX format; + HRESULT hr; + int i; + + snd_sent = 0; + snd_completed = 0; + + dma.channels = 2; + dma.samplebits = 16; + + switch( s_khz->integer ) + { + case 44: dma.speed = 44100; break; + case 22: dma.speed = 22050; break; + default: dma.speed = 11025; break; + } + + Mem_Set( &format, 0, sizeof( format )); + format.wFormatTag = WAVE_FORMAT_PCM; + format.nChannels = dma.channels; + format.wBitsPerSample = dma.samplebits; + format.nSamplesPerSec = dma.speed; + format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; + format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; + format.cbSize = 0; + + // open a waveform device for output using window callback. + MsgDev( D_NOTE, "SNDDMA_InitWav: initializing wave sound " ); + if((hr = waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER, &format, 0, 0, CALLBACK_NULL)) != MMSYSERR_NOERROR ) + { + if( hr != MMSYSERR_ALLOCATED ) + { + MsgDev( D_NOTE, "- failed\n" ); + return SIS_FAILURE; + } + + MsgDev( D_NOTE, "- failed, hardware already in use\n" ); + return SIS_NOTAVAIL; + } + + MsgDev( D_NOTE, "- ok\n" ); + + // allocate and lock memory for the waveform data. The memory + // for waveform data must be globally allocated with + // GMEM_MOVEABLE and GMEM_SHARE flags. + + gSndBufSize = WAV_BUFFERS * WAV_BUFFER_SIZE; + hData = GlobalAlloc( GMEM_MOVEABLE|GMEM_SHARE, gSndBufSize ); + if( !hData ) + { + SNDDMA_FreeSound (); + return SIS_FAILURE; + } + + lpData = GlobalLock( hData ); + if( !lpData ) + { + SNDDMA_FreeSound (); + return SIS_FAILURE; + } + + Mem_Set( lpData, 0, gSndBufSize ); + + // Allocate and lock memory for the header. This memory must + // also be globally allocated with GMEM_MOVEABLE and + // GMEM_SHARE flags. + hWaveHdr = GlobalAlloc( GMEM_MOVEABLE|GMEM_SHARE, (DWORD)sizeof( WAVEHDR ) * WAV_BUFFERS ); + + if( hWaveHdr == NULL ) + { + SNDDMA_FreeSound (); + return SIS_FAILURE; + } + + lpWaveHdr = (LPWAVEHDR)GlobalLock( hWaveHdr ); + + if( lpWaveHdr == NULL ) + { + SNDDMA_FreeSound(); + return SIS_FAILURE; + } + + Mem_Set( lpWaveHdr, 0, sizeof( WAVEHDR ) * WAV_BUFFERS ); + + // After allocation, set up and prepare headers. + for( i = 0; i < WAV_BUFFERS; i++ ) + { + lpWaveHdr[i].dwBufferLength = WAV_BUFFER_SIZE; + lpWaveHdr[i].lpData = lpData + i * WAV_BUFFER_SIZE; + + if( waveOutPrepareHeader( hWaveOut, lpWaveHdr+i, sizeof( WAVEHDR )) != MMSYSERR_NOERROR ) + { + SNDDMA_FreeSound(); + return SIS_FAILURE; + } + } + + dma.samplepos = 0; + dma.samples = gSndBufSize / ( dma.samplebits / 8 ); + dma.submission_chunk = 512; + dma.buffer = (byte *)lpData; + sample16 = (dma.samplebits / 8) - 1; + wav_init = true; + + return SIS_SUCCESS; +} + +/* +================== +SNDDMA_Init + +Try to find a sound device to mix for. +Returns false if nothing is found. +================== +*/ +int SNDDMA_Init( void *hInst ) +{ + si_state_t stat = SIS_FAILURE; // assume DirectSound won't initialize + + Mem_Set( &dma, 0, sizeof( dma )); + + s_wavonly = Cvar_Get( "s_wavonly", "0", CVAR_LATCH_AUDIO|CVAR_ARCHIVE, "force to use WaveOutput only" ); + dsound_init = wav_init = 0; + + // init DirectSound + if( !s_wavonly->integer ) + { + if( snd_firsttime || snd_isdirect ) + { + stat = SNDDMA_InitDirect( hInst ); + + if( stat == SIS_SUCCESS ) + { + snd_isdirect = true; + + if( snd_firsttime ) + MsgDev( D_INFO, "Audio: DirectSound\n" ); + } + else snd_isdirect = false; + } + } + + // if DirectSound didn't succeed in initializing, try to initialize + // waveOut sound, unless DirectSound failed because the hardware is + // already allocated (in which case the user has already chosen not + // to have sound) + if( !dsound_init && ( stat != SIS_NOTAVAIL )) + { + if( snd_firsttime || snd_iswave ) + { + stat = SNDDMA_InitWav(); + + if( stat == SIS_SUCCESS ) + { + snd_iswave = true; + if( snd_firsttime ) + MsgDev( D_INFO, "Audio: WaveOutput\n" ); + } + else snd_iswave = false; + } + } + snd_buffer_count = 1; + + if( !dsound_init && !wav_init ) + { + if( snd_firsttime ) + MsgDev( D_ERROR, "SNDDMA_Init: can't initialize sound device\n" ); + return false; + } + + snd_firsttime = false; + return true; +} + +/* +============== +SNDDMA_GetDMAPos + +return the current sample position (in mono samples read) +inside the recirculating dma buffer, so the mixing code will know +how many sample are required to fill it up. +=============== +*/ +int SNDDMA_GetDMAPos( void ) +{ + int s; + + if( dsound_init ) + { + MMTIME mmtime; + DWORD dwWrite; + + mmtime.wType = TIME_SAMPLES; + pDSBuf->lpVtbl->GetCurrentPosition( pDSBuf, &mmtime.u.sample, &dwWrite ); + s = mmtime.u.sample - mmstarttime.u.sample; + } + else if( wav_init ) + { + s = snd_sent * WAV_BUFFER_SIZE; + } + + + s >>= sample16; + s &= (dma.samples - 1); + + return s; +} + +/* +============== +SNDDMA_BeginPainting + +Makes sure dma.buffer is valid +=============== +*/ +void SNDDMA_BeginPainting( void ) +{ + int reps; + DWORD dwSize2; + DWORD *pbuf, *pbuf2; + HRESULT hr; + DWORD dwStatus; + + if( !pDSBuf ) return; + + // if the buffer was lost or stopped, restore it and/or restart it + if( pDSBuf->lpVtbl->GetStatus( pDSBuf, &dwStatus ) != DS_OK ) + MsgDev( D_WARN, "SNDDMA_BeginPainting: couldn't get sound buffer status\n" ); + + if( dwStatus & DSBSTATUS_BUFFERLOST ) + pDSBuf->lpVtbl->Restore( pDSBuf ); + + if(!( dwStatus & DSBSTATUS_PLAYING )) + pDSBuf->lpVtbl->Play( pDSBuf, 0, 0, DSBPLAY_LOOPING ); + + // lock the dsound buffer + dma.buffer = NULL; + reps = 0; + + while(( hr = pDSBuf->lpVtbl->Lock( pDSBuf, 0, gSndBufSize, &pbuf, &locksize, &pbuf2, &dwSize2, 0 )) != DS_OK ) + { + if( hr != DSERR_BUFFERLOST ) + { + MsgDev( D_ERROR, "S_TransferStereo16: lock failed with error '%s'\n", DSoundError( hr )); + S_Shutdown (); + return; + } + else pDSBuf->lpVtbl->Restore( pDSBuf ); + + if( ++reps > 2 ) return; + } + dma.buffer = (byte *)pbuf; +} + +/* +============== +SNDDMA_Submit + +Send sound to device if buffer isn't really the dma buffer +Also unlocks the dsound buffer +=============== +*/ +void SNDDMA_Submit( void ) +{ + LPWAVEHDR h; + int wResult; + + if( !dma.buffer ) + return; + + // unlock the dsound buffer + if( pDSBuf ) pDSBuf->lpVtbl->Unlock( pDSBuf, dma.buffer, locksize, NULL, 0 ); + + if( !wav_init ) return; + + // find which sound blocks have completed + while( 1 ) + { + if( snd_completed == snd_sent ) + break; + + if(!( lpWaveHdr[snd_completed & WAV_MASK].dwFlags & WHDR_DONE )) + break; + snd_completed++; // this buffer has been played + } + + // submit a few new sound blocks + while(((snd_sent - snd_completed) >> sample16 ) < 8 ) + { + h = lpWaveHdr + ( snd_sent & WAV_MASK ); + + if( paintedtime / 256 <= snd_sent ) + break; + snd_sent++; + + // Now the data block can be sent to the output device. The + // waveOutWrite function returns immediately and waveform + // data is sent to the output device in the background. + wResult = waveOutWrite( hWaveOut, h, sizeof( WAVEHDR )); + + if( wResult != MMSYSERR_NOERROR ) + { + MsgDev( D_ERROR, "S_TransferStereo16: failed to write block to device\n" ); + SNDDMA_FreeSound (); + return; + } + } +} + +/* +============== +SNDDMA_Shutdown + +Reset the sound device for exiting +=============== +*/ +void SNDDMA_Shutdown( void ) +{ + SNDDMA_FreeSound(); +} + + +/* +=========== +S_Activate + +Called when the main window gains or loses focus. +The window have been destroyed and recreated +between a deactivate and an activate. +=========== +*/ +void S_Activate( bool active ) +{ + if( active ) + { + if( pDS && snd_hwnd && snd_isdirect ) + DS_CreateBuffers( snd_hwnd ); + } + else + { + if( pDS && snd_hwnd && snd_isdirect ) + DS_DestroyBuffers(); + } +} \ No newline at end of file diff --git a/snd_dx/s_export.c b/snd_dx/s_export.c new file mode 100644 index 00000000..dae202cf --- /dev/null +++ b/snd_dx/s_export.c @@ -0,0 +1,52 @@ +//======================================================================= +// Copyright XashXT Group 2007 й +// s_export.c - sound library main +//======================================================================= + +#include "sound.h" + +vsound_imp_t si; +stdlib_api_t com; +byte *sndpool; + +vsound_exp_t DLLEXPORT *CreateAPI( stdlib_api_t *input, vsound_imp_t *engfuncs ) +{ + static vsound_exp_t snd; + + com = *input; + + // Sys_LoadLibrary can create fake instance, to check + // api version and api size, but second argument will be 0 + // and always make exception, run simply check for avoid it + if( engfuncs ) si = *engfuncs; + + // generic functions + snd.api_size = sizeof( vsound_exp_t ); + snd.com_size = sizeof( stdlib_api_t ); + + snd.Init = S_Init; + snd.Shutdown = S_Shutdown; + + // sound manager + snd.BeginRegistration = S_BeginRegistration; + snd.RegisterSound = S_RegisterSound; + snd.EndRegistration = S_EndRegistration; + + snd.StartSound = S_StartSound; + snd.StreamRawSamples = S_StreamRawSamples; + snd.AddLoopingSound = S_AddLoopingSound; + snd.StartLocalSound = S_StartLocalSound; + snd.StartBackgroundTrack = S_StartBackgroundTrack; + snd.StopBackgroundTrack = S_StopBackgroundTrack; + + snd.StartStreaming = S_StartStreaming; + snd.StopStreaming = S_StopStreaming; + + snd.Frame = S_Update; + snd.StopAllSounds = S_StopAllSounds; + snd.FreeSounds = S_FreeSounds; + + snd.Activate = S_Activate; + + return &snd; +} \ No newline at end of file diff --git a/snd_dx/s_load.c b/snd_dx/s_load.c new file mode 100644 index 00000000..ec46ebe3 --- /dev/null +++ b/snd_dx/s_load.c @@ -0,0 +1,609 @@ +//======================================================================= +// Copyright XashXT Group 2007 й +// s_load.c - sound managment +//======================================================================= + +#include "sound.h" +#include "byteorder.h" + +// during registration it is possible to have more sounds +// than could actually be referenced during gameplay, +// because we don't want to free anything until we are +// sure we won't need it. +#define MAX_SFX 4096 + +static sfx_t s_knownSfx[MAX_SFX]; +static int s_numSfx = 0; +bool s_registering = false; +int s_registration_sequence = 0; + +typedef struct loadformat_s +{ + char *formatstring; + char *ext; + bool (*loadfunc)( const char *name, byte **wav, wavinfo_t *info ); +} loadformat_t; + +/* +================= +S_SoundList_f +================= +*/ +void S_SoundList_f( void ) +{ + int i; + sfx_t *sfx; + sfxcache_t *sc; + int size, totalSfx = 0; + int totalSize = 0; + + for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ ) + { + if( !sfx->registration_sequence ) + continue; + + sc = sfx->cache; + if( sc ) + { + size = sc->length * sc->width * (sc->stereo + 1); + totalSize += size; + if( sc->loopstart >= 0 ) Msg( "L" ); + else Msg( " " ); + + if( sfx->name[0] == '#' ) + Msg( " (%2db) %s : %s\n", sc->width * 8, memprint( size ), &sfx->name[1] ); + else Msg( " (%2db) %s : sound/%s\n", sc->width * 8, memprint( size ), sfx->name ); + totalSfx++; + } + } + + Msg("-------------------------------------------\n"); + Msg("%i total sounds\n", totalSfx ); + Msg("%s total memory\n", memprint( totalSize )); + Msg("\n"); +} + +/* +================ +S_ResampleSfx +================ +*/ +void S_ResampleSfx( sfx_t *sfx, int inrate, int inwidth, byte *data ) +{ + float stepscale; + int outcount, srcsample; + int i, sample, samplefrac, fracstep; + sfxcache_t *sc; + + if( !sfx ) return; + sc = sfx->cache; + if( !sc ) return; + + stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2 + + outcount = sc->length / stepscale; + sc->length = outcount; + if( sc->loopstart != -1 ) + sc->loopstart = sc->loopstart / stepscale; + + sc->speed = dma.speed; + if( s_loadas8bit->integer ) + sc->width = 1; + else sc->width = inwidth; + sc->stereo = 0; + + // resample / decimate to the current source rate + if( stepscale == 1 && inwidth == 1 && sc->width == 1 ) + { + // fast special case + for( i = 0; i < outcount; i++ ) + ((signed char *)sc->data)[i] = (int)((unsigned char)(data[i]) - 128); + } + else + { + // general case + samplefrac = 0; + fracstep = stepscale * 256; + for( i = 0; i < outcount; i++ ) + { + srcsample = samplefrac >> 8; + samplefrac += fracstep; + + if( inwidth == 2 ) sample = LittleShort(((short *)data)[srcsample] ); + else sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8; + + if( sc->width == 2 ) ((short *)sc->data)[i] = sample; + else ((signed char *)sc->data)[i] = sample >> 8; + } + } +} + +/* +=============================================================================== + +WAV loading + +=============================================================================== +*/ +static byte *iff_data; +static byte *iff_dataPtr; +static byte *iff_end; +static byte *iff_lastChunk; +static int iff_chunkLen; + +/* +================= +S_GetLittleShort +================= +*/ +static short S_GetLittleShort( void ) +{ + short val = 0; + + val += (*(iff_dataPtr+0) << 0); + val += (*(iff_dataPtr+1) << 8); + iff_dataPtr += 2; + + return val; +} + +/* +================= +S_GetLittleLong +================= +*/ +static int S_GetLittleLong( void ) +{ + int val = 0; + + val += (*(iff_dataPtr+0) << 0); + val += (*(iff_dataPtr+1) << 8); + val += (*(iff_dataPtr+2) << 16); + val += (*(iff_dataPtr+3) << 24); + iff_dataPtr += 4; + + return val; +} + +/* +================= +S_FindNextChunk +================= +*/ +static void S_FindNextChunk( const char *name ) +{ + while( 1 ) + { + iff_dataPtr = iff_lastChunk; + if( iff_dataPtr >= iff_end ) + { + // didn't find the chunk + iff_dataPtr = NULL; + return; + } + + iff_dataPtr += 4; + iff_chunkLen = S_GetLittleLong(); + if (iff_chunkLen < 0) + { + iff_dataPtr = NULL; + return; + } + + iff_dataPtr -= 8; + iff_lastChunk = iff_dataPtr + 8 + ((iff_chunkLen + 1) & ~1); + if(!com.strncmp( iff_dataPtr, name, 4 )) + return; + } +} + +/* +================= +S_FindChunk +================= +*/ +static void S_FindChunk( const char *name ) +{ + iff_lastChunk = iff_data; + S_FindNextChunk( name ); +} + +/* +================= +S_LoadWAV +================= +*/ +static bool S_LoadWAV( const char *name, byte **wav, wavinfo_t *info ) +{ + byte *buffer, *out; + int length, samples; + + buffer = FS_LoadFile( name, &length ); + if( !buffer ) return false; + + iff_data = buffer; + iff_end = buffer + length; + + // dind "RIFF" chunk + S_FindChunk( "RIFF" ); + if( !( iff_dataPtr && !com.strncmp( iff_dataPtr + 8, "WAVE", 4 ))) + { + MsgDev( D_WARN, "S_LoadWAV: missing 'RIFF/WAVE' chunks (%s)\n", name ); + Mem_Free( buffer ); + return false; + } + + // get "fmt " chunk + iff_data = iff_dataPtr + 12; + S_FindChunk( "fmt " ); + if( !iff_dataPtr ) + { + MsgDev( D_WARN, "S_LoadWAV: missing 'fmt ' chunk (%s)\n", name ); + Mem_Free( buffer ); + return false; + } + + iff_dataPtr += 8; + if( S_GetLittleShort() != 1 ) + { + MsgDev( D_WARN, "S_LoadWAV: microsoft PCM format only (%s)\n", name ); + Mem_Free( buffer ); + return false; + } + + info->channels = S_GetLittleShort(); + if( info->channels != 1 ) + { + MsgDev( D_WARN, "S_LoadWAV: only mono WAV files supported (%s)\n", name ); + Mem_Free( buffer ); + return false; + } + + info->rate = S_GetLittleLong(); + iff_dataPtr += 4+2; + + info->width = S_GetLittleShort() / 8; + if( info->width != 1 && info->width != 2 ) + { + MsgDev( D_WARN, "S_LoadWAV: only 8 and 16 bit WAV files supported (%s)\n", name ); + Mem_Free( buffer ); + return false; + } + + // get cue chunk + S_FindChunk( "cue " ); + if( iff_dataPtr ) + { + iff_dataPtr += 32; + info->loopstart = S_GetLittleLong(); + S_FindNextChunk( "LIST" ); // if the next chunk is a LIST chunk, look for a cue length marker + if( iff_dataPtr ) + { + if( !com.strncmp((const char *)iff_dataPtr + 28, "mark", 4 )) + { + // this is not a proper parse, but it works with CoolEdit... + iff_dataPtr += 24; + info->samples = info->loopstart + S_GetLittleLong(); // samples in loop + } + } + } + else + { + info->loopstart = -1; + info->samples = 0; + } + + // find data chunk + S_FindChunk( "data" ); + if( !iff_dataPtr ) + { + MsgDev( D_WARN, "S_LoadWAV: missing 'data' chunk (%s)\n", name ); + Mem_Free( buffer ); + return false; + } + + iff_dataPtr += 4; + samples = S_GetLittleLong() / info->width; + + if( info->samples ) + { + if( samples < info->samples ) + { + MsgDev( D_ERROR, "S_LoadWAV: %s has a bad loop length\n", name ); + Mem_Free( buffer ); + return false; + } + } + else info->samples = samples; + + if( info->samples <= 0 ) + { + MsgDev( D_WARN, "S_LoadWAV: file with %i samples (%s)\n", info->samples, name ); + Mem_Free( buffer ); + return false; + } + + // Load the data + *wav = out = Z_Malloc( info->samples * info->width ); + Mem_Copy( out, buffer + (iff_dataPtr - buffer), info->samples * info->width ); + Mem_Free( buffer ); + + return true; +} + +/* +================= +S_UploadSound +================= +*/ +static void S_UploadSound( byte *data, wavinfo_t *info, sfx_t *sfx ) +{ + sfxcache_t *sc; + size_t size, samples; + float stepscale; + + // calculate buffer size + stepscale = (float)info->rate / dma.speed; + samples = info->samples / stepscale; + size = samples * info->width * info->channels; + + sc = sfx->cache = Z_Malloc( size + sizeof( sfxcache_t )); + sc->length = info->samples; + sc->loopstart = info->loopstart; + sc->speed = info->rate; + sc->width = info->width; + sc->stereo = info->channels; + + S_ResampleSfx( sfx, sc->speed, sc->width, data + info->dataofs ); +} + +/* +================= +S_CreateDefaultSound +================= +*/ +static void S_CreateDefaultSound( byte **wav, wavinfo_t *info ) +{ + byte *out; + int i; + + info->rate = 22050; + info->width = 2; + info->channels = 1; + info->samples = 11025; + + *wav = out = Z_Malloc( info->samples * info->width ); + + if( s_check_errors->integer ) + { + // create 1 kHz tone as default sound + for( i = 0; i < info->samples; i++ ) + ((short *)out)[i] = com.sin( i * 0.1f ) * 20000; + } + else + { + // create silent sound + for( i = 0; i < info->samples; i++ ) + ((short *)out)[i] = i; + } +} + +/* +================= +S_LoadSound +================= +*/ +loadformat_t load_formats[] = +{ +{ "sound/%s.%s", "wav", S_LoadWAV }, +{ "%s.%s", "wav", S_LoadWAV }, +{ NULL, NULL } +}; + +sfxcache_t *S_LoadSound( sfx_t *sfx ) +{ + byte *data; + wavinfo_t info; + const char *ext; + string loadname, path; + loadformat_t *format; + bool anyformat; + + if( !sfx ) return NULL; + if( sfx->name[0] == '*' ) return NULL; + if( sfx->cache ) return sfx->cache; // see if still in memory + + // load it from disk + ext = FS_FileExtension( sfx->name ); + anyformat = !com.stricmp( ext, "" ) ? true : false; + + com.strncpy( loadname, sfx->name, sizeof( loadname )); + FS_StripExtension( loadname ); // remove extension if needed + Mem_Set( &info, 0, sizeof( info )); + + // developer warning + if( !anyformat ) MsgDev( D_NOTE, "Note: %s will be loading only with ext .%s\n", loadname, ext ); + + // now try all the formats in the selected list + for( format = load_formats; format->formatstring; format++ ) + { + if( anyformat || !com.stricmp( ext, format->ext )) + { + com.sprintf( path, format->formatstring, loadname, format->ext ); + if( format->loadfunc( path, &data, &info )) + goto snd_loaded; + } + } + + sfx->default_sound = true; + MsgDev( D_WARN, "FS_LoadSound: couldn't load %s\n", sfx->name ); + S_CreateDefaultSound( &data, &info ); + info.loopstart = -1; + +snd_loaded: + + // load it in + S_UploadSound( data, &info, sfx ); + Mem_Free( data ); + + return sfx->cache; +} + +// ======================================================================= +// Load a sound +// ======================================================================= +/* +================== +S_FindSound + +================== +*/ +sfx_t *S_FindSound( const char *name ) +{ + int i; + sfx_t *sfx; + + if( !name || !name[0] ) return NULL; + + if( com.strlen( name ) >= MAX_STRING ) + { + MsgDev( D_ERROR, "S_FindSound: sound name too long: %s", name ); + return NULL; + } + + // see if already loaded + for( i = 0; i < s_numSfx; i++ ) + { + sfx = &s_knownSfx[i]; + + if( !com.strcmp( sfx->name, name )) + { + // prolonge registration + sfx->registration_sequence = s_registration_sequence; + return sfx; + } + } + + // find a free sfx slot spot + for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++) + { + if( !sfx->name[0] ) break; // free spot + } + if( i == s_numSfx ) + { + if( s_numSfx == MAX_SFX ) + { + MsgDev( D_ERROR, "S_FindName: MAX_SFX limit exceeded\n" ); + return NULL; + } + s_numSfx++; + } + + sfx = &s_knownSfx[i]; + Mem_Set( sfx, 0, sizeof( *sfx )); + com.strncpy( sfx->name, name, MAX_STRING ); + sfx->registration_sequence = s_registration_sequence; + + return sfx; +} + +/* +===================== +S_BeginRegistration + +===================== +*/ +void S_BeginRegistration( void ) +{ + s_registration_sequence++; + s_registering = true; +} + +/* +===================== +S_EndRegistration + +===================== +*/ +void S_EndRegistration( void ) +{ + sfx_t *sfx; + int i; + + // free any sounds not from this registration sequence + for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ ) + { + if( !sfx->name[0] ) continue; + if( sfx->registration_sequence != s_registration_sequence ) + { + // don't need this sound + if( sfx->cache ) Mem_Free( sfx->cache ); + Mem_Set( sfx, 0, sizeof( *sfx )); + } + } + + // load everything in + for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ ) + { + if( !sfx->name[0] ) continue; + S_LoadSound( sfx ); + } + s_registering = false; +} + +/* +================== +S_RegisterSound + +================== +*/ +sound_t S_RegisterSound( const char *name ) +{ + sfx_t *sfx; + + if( !sound_started ) + return -1; + + sfx = S_FindSound( name ); + if( !sfx ) return -1; + + sfx->registration_sequence = s_registration_sequence; + if( !s_registering ) S_LoadSound( sfx ); + + return sfx - s_knownSfx; +} + +sfx_t *S_GetSfxByHandle( sound_t handle ) +{ + if( handle < 0 || handle >= s_numSfx ) + { + MsgDev( D_ERROR, "S_GetSfxByHandle: handle %i out of range (%i)\n", handle, s_numSfx ); + return NULL; + } + return &s_knownSfx[handle]; +} + +/* +================= +S_FreeSounds +================= +*/ +void S_FreeSounds( void ) +{ + sfx_t *sfx; + int i; + + // stop all sounds + S_StopAllSounds(); + + // free all sounds + for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ ) + { + if( !sfx->name[0] ) continue; + if( sfx->cache ) Mem_Free( sfx->cache ); + Mem_Set( sfx, 0, sizeof( *sfx )); + } + + Mem_Set( s_knownSfx, 0, sizeof(s_knownSfx)); + s_numSfx = 0; +} \ No newline at end of file diff --git a/snd_dx/s_main.c b/snd_dx/s_main.c new file mode 100644 index 00000000..9906f9a1 --- /dev/null +++ b/snd_dx/s_main.c @@ -0,0 +1,748 @@ +//======================================================================= +// Copyright XashXT Group 2009 й +// s_main.c - sound engine +//======================================================================= + +#include "sound.h" + +// only begin attenuating sound volumes when outside the FULLVOLUME range +#define SOUND_FULLVOLUME 80 +#define SOUND_LOOPATTENUATE 0.003 +#define MAX_PLAYSOUNDS 128 + +dma_t dma; +channel_t channels[MAX_CHANNELS]; +bool sound_started = false; +vec3_t listener_origin; +vec3_t listener_velocity; +vec3_t listener_forward; +vec3_t listener_right; +vec3_t listener_up; + +int s_framecount; // for autosounds checking +int s_clientnum; // cl.playernum + 1 +int soundtime; // sample PAIRS +int paintedtime; // sample PAIRS +byte *sndpool; + +playsound_t s_playsounds[MAX_PLAYSOUNDS]; +playsound_t s_freeplays; +playsound_t s_pendingplays; +int s_beginofs; + +cvar_t *host_sound; +cvar_t *s_check_errors; +cvar_t *s_volume; +cvar_t *s_testsound; +cvar_t *s_loadas8bit; +cvar_t *s_khz; +cvar_t *s_show; +cvar_t *s_mixahead; +cvar_t *s_primary; +cvar_t *s_pause; + +/* +============================================================================= + + SOUNDS PROCESSING + +============================================================================= +*/ +/* +================= +S_PickChannel +================= +*/ +channel_t *S_PickChannel( int entnum, int channel ) +{ + int i; + int firstToDie = -1; + int oldestTime = 0x7fffffff; + channel_t *ch; + + if( entnum < 0 || channel < 0 ) return NULL; // invalid channel or entnum + + for( i = 0, ch = channels; i < MAX_CHANNELS; i++, ch++ ) + { + // check if this channel is active + if( channel == CHAN_AUTO && !ch->sfx ) + { + // free channel + firstToDie = i; + break; + } + + // channel 0 never overrides + if( channel != CHAN_AUTO && ( ch->entnum == entnum && ch->entchannel == channel )) + { + // always override sound from same entity + firstToDie = i; + break; + } + + // don't let monster sounds override player sounds + if( entnum != s_clientnum && ch->entnum == s_clientnum && ch->sfx ) + continue; + + // replace the oldest sound + if( ch->end - paintedtime < oldestTime ) + { + oldestTime = ch->end - paintedtime; + firstToDie = i; + } + } + + if( firstToDie == -1 ) + return NULL; + + ch = &channels[firstToDie]; + Mem_Set( ch, 0, sizeof( *ch )); + + return ch; +} + +/* +================= +S_SpatializeOrigin + +Used for spatializing channels and autosounds +================= +*/ +void S_SpatializeOrigin( vec3_t pos, vec3_t vel, float master_vol, float dist_mult, int *left_vol, int *right_vol ) +{ + float dot; + float dist; + float lscale, rscale, scale; + vec3_t source_vec; + vec3_t source_vel; + + // calculate stereo seperation and distance attenuation + VectorSubtract( pos, listener_origin, source_vec ); + VectorCopy( vel, source_vel ); + + dist = VectorNormalizeLength( source_vec ); + dist -= SOUND_FULLVOLUME; + if( dist < 0 ) dist = 0; // close enough to be at full volume + dist *= dist_mult; // different attenuation levels + + dot = DotProduct( listener_right, source_vec ); + + if( dma.channels == 1 || !dist_mult ) + { + // no attenuation = no spatialization + rscale = 1.0f; + lscale = 1.0f; + } + else + { + rscale = 0.5f * (1.0f + dot); + lscale = 0.5f * (1.0f - dot); + } + + // add in distance effect + scale = (1.0f - dist) * rscale; + *right_vol = (int)( master_vol * scale ); + if( *right_vol < 0 ) *right_vol = 0; + + scale = (1.0f - dist) * lscale; + *left_vol = (int)( master_vol * scale ); + if( *left_vol < 0 ) *left_vol = 0; +} + +/* +================= +S_Spatialize +================= +*/ +void S_SpatializeChannel( channel_t *ch ) +{ + vec3_t position, velocity; + + // anything coming from the view entity will always be full volume + if( ch->entnum == s_clientnum || !ch->dist_mult ) + { + ch->leftvol = ch->master_vol; + ch->rightvol = ch->master_vol; + return; + } + + if( ch->fixed_origin ) + { + VectorCopy( ch->origin, position ); + VectorSet( velocity, 0, 0, 0 ); + } + else + { + if( ch->autosound ) si.GetSoundSpatialization( ch->loopnum, position, velocity ); + else si.GetSoundSpatialization( ch->entnum, position, velocity ); + } + + S_SpatializeOrigin( position, velocity, ch->master_vol, ch->dist_mult, &ch->leftvol, &ch->rightvol ); +} + + +/* +================= +S_AllocPlaysound +================= +*/ +playsound_t *S_AllocPlaysound( void ) +{ + playsound_t *ps; + + ps = s_freeplays.next; + if( ps == &s_freeplays ) + return NULL; // no free playsounds + + // unlink from freelist + ps->prev->next = ps->next; + ps->next->prev = ps->prev; + + return ps; +} + + +/* +================= +S_FreePlaysound +================= +*/ +void S_FreePlaysound( playsound_t *ps ) +{ + // unlink from channel + ps->prev->next = ps->next; + ps->next->prev = ps->prev; + + // add to free list + ps->next = s_freeplays.next; + s_freeplays.next->prev = ps; + ps->prev = &s_freeplays; + s_freeplays.next = ps; +} + +/* +=============== +S_IssuePlaysound + +Take the next playsound and begin it on the channel +This is never called directly by S_Play*, but only +by the update loop. +=============== +*/ +void S_IssuePlaysound( playsound_t *ps ) +{ + channel_t *ch; + sfxcache_t *sc; + + if( s_show->value ) MsgDev( D_INFO, "Issue %i\n", ps->begin ); + + // pick a channel to play on + ch = S_PickChannel( ps->entnum, ps->entchannel ); + if( !ch ) + { + if( ps->sfx->name[0] == '#' ) MsgDev( D_ERROR, "dropped sound %s\n", &ps->sfx->name[1] ); + else MsgDev( D_ERROR, "dropped sound \"sound/%s\"\n", ps->sfx->name ); + S_FreePlaysound( ps ); + return; + } + + // spatialize + if( ps->attenuation == ATTN_STATIC ) + ch->dist_mult = ps->attenuation * 0.001; + else ch->dist_mult = ps->attenuation * 0.0005; + + ch->master_vol = ps->volume; + ch->entnum = ps->entnum; + ch->entchannel = ps->entchannel; + ch->sfx = ps->sfx; + ch->use_loop = ps->use_loop; + VectorCopy( ps->origin, ch->origin ); + ch->fixed_origin = ps->fixed_origin; + + S_SpatializeChannel( ch ); + + ch->pos = 0; + sc = S_LoadSound( ch->sfx ); + ch->end = paintedtime + sc->length; + + // free the playsound + S_FreePlaysound( ps ); +} + +// ======================================================================= +// Start a sound effect +// ======================================================================= +/* +==================== +S_StartSound + +Validates the parms and ques the sound up +if pos is NULL, the sound will be dynamically sourced from the entity +Entchannel 0 will never override a playing sound +==================== +*/ +void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fvol, float attn, float pitch, bool loop ) +{ + sfxcache_t *sc; + int vol, start; + playsound_t *ps, *sort; + sfx_t *sfx = NULL; + float timeofs = 0; // FIXME: implement into network protocol + + if( !sound_started ) + return; + + sfx = S_GetSfxByHandle( handle ); + if( !sfx ) return; + + // make sure the sound is loaded + sc = S_LoadSound( sfx ); + if( !sc ) return; // couldn't load the sound's data + + vol = fvol * 255; + + // allocate the playsound_t + ps = S_AllocPlaysound(); + if( !ps ) + { + if( sfx->name[0] == '#' ) MsgDev( D_ERROR, "dropped sound %s\n", &sfx->name[1] ); + else MsgDev( D_ERROR, "dropped sound \"sound/%s\"\n", sfx->name ); + return; + } + + if( pos ) + { + VectorCopy( pos, ps->origin ); + ps->fixed_origin = true; + } + else ps->fixed_origin = false; + + ps->entnum = ent; + ps->entchannel = chan; + ps->attenuation = attn; + ps->use_loop = loop; + ps->volume = vol; + ps->sfx = sfx; + + // drift s_beginofs + start = si.GetServerTime() * 0.001 * dma.speed + s_beginofs; + if( start < paintedtime ) + { + start = paintedtime; + s_beginofs = start - ( si.GetServerTime() * 0.001 * dma.speed ); + } + else if( start > paintedtime + 0.3 * dma.speed ) + { + start = paintedtime + 0.1 * dma.speed; + s_beginofs = start - ( si.GetServerTime() * 0.001 * dma.speed ); + } + else s_beginofs -= 10; + + if( !timeofs ) ps->begin = paintedtime; + else ps->begin = start + timeofs * dma.speed; + + // sort into the pending sound list + for( sort = s_pendingplays.next; sort != &s_pendingplays && sort->begin < ps->begin; sort = sort->next ); + + ps->next = sort; + ps->prev = sort->prev; + ps->next->prev = ps; + ps->prev->next = ps; +} + +/* +================== +S_StartLocalSound +================== +*/ +bool S_StartLocalSound( const char *name, float volume, float pitch, const float *origin ) +{ + sound_t sfxHandle; + + if( !sound_started ) + return false; + + sfxHandle = S_RegisterSound( name ); + S_StartSound( origin, s_clientnum, CHAN_AUTO, sfxHandle, volume, ATTN_NONE, pitch, false ); + + return true; +} + +/* +================== +S_ClearBuffer +================== +*/ +void S_ClearBuffer( void ) +{ + int clear; + + if( !sound_started ) + return; + + s_rawend = 0; + + if( dma.samplebits == 8 ) + clear = 0x80; + else clear = 0; + + SNDDMA_BeginPainting (); + if( dma.buffer ) Mem_Set( dma.buffer, clear, dma.samples * dma.samplebits / 8 ); + SNDDMA_Submit (); +} + +/* +================== +S_StopAllSounds +================== +*/ +void S_StopAllSounds( void ) +{ + int i; + + if( !sound_started ) + return; + + // clear all the playsounds + Mem_Set( s_playsounds, 0, sizeof( s_playsounds )); + s_freeplays.next = s_freeplays.prev = &s_freeplays; + s_pendingplays.next = s_pendingplays.prev = &s_pendingplays; + + for( i = 0; i < MAX_PLAYSOUNDS; i++ ) + { + s_playsounds[i].prev = &s_freeplays; + s_playsounds[i].next = s_freeplays.next; + s_playsounds[i].prev->next = &s_playsounds[i]; + s_playsounds[i].next->prev = &s_playsounds[i]; + } + + // clear all the channels + Mem_Set( channels, 0, sizeof( channels )); + S_ClearBuffer (); + + s_framecount = 0; +} + +/* +================== +S_AddLoopinSound + +Entities with a ->sound field will generated looped sounds +that are automatically started, stopped, and merged together +as the entities are sent to the client +================== +*/ +bool S_AddLoopingSound( int entnum, sound_t handle, float volume, float attn ) +{ + channel_t *ch; + sfx_t *sfx = NULL; + int i; + + if( !sound_started ) + return false; + sfx = S_GetSfxByHandle( handle ); + + // default looped sound it's terrible :) + if( !sfx || sfx->default_sound || !sfx->cache ) + return false; + + // if this entity is already playing the same sound effect on an + // active channel, then simply update it + for( i = 0, ch = channels; i < MAX_CHANNELS; i++, ch++ ) + { + if( ch->sfx != sfx ) continue; + if( !ch->autosound ) continue; + if( ch->loopnum != entnum ) continue; + if( ch->loopframe + 1 != s_framecount ) + continue; + + ch->loopframe = s_framecount; + break; + } + if( i != MAX_CHANNELS ) + return false; + + // otherwise pick a channel and start the sound effect + ch = S_PickChannel( 0, 0 ); + if( !ch ) + { + MsgDev( D_ERROR, "dropped sound \"sound/%s\"\n", sfx->name ); + return false; + } + + ch->sfx = sfx; + ch->use_loop = true; // autosounds never comes from S_StartLocalSound + ch->autosound = true; // remove next frame + ch->loopnum = entnum; + ch->loopframe = s_framecount; + ch->fixed_origin = false; + ch->dist_mult = ATTN_STATIC * 0.001; + ch->pos = paintedtime % sfx->cache->length; + ch->end = paintedtime + sfx->cache->length - ch->pos; + + // now we can spatialize channel + S_SpatializeChannel( ch ); + + return true; +} + +//============================================================================= + +void GetSoundtime( void ) +{ + static int buffers, oldsamplepos; + int samplepos, fullsamples; + + fullsamples = dma.samples / dma.channels; + + // it is possible to miscount buffers + // if it has wrapped twice between + // calls to S_Update. Oh well. + samplepos = SNDDMA_GetDMAPos(); + + if( samplepos < oldsamplepos ) + { + buffers++; // buffer wrapped + + if( paintedtime > 0x40000000 ) + { + // time to chop things off to avoid 32 bit limits + buffers = 0; + paintedtime = fullsamples; + + S_StopAllSounds(); + } + } + + oldsamplepos = samplepos; + soundtime = buffers * fullsamples + samplepos / dma.channels; +} + +void S_UpdateChannels( void ) +{ + uint endtime; + int samps; + + if( !sound_started ) + return; + + SNDDMA_BeginPainting(); + + if( !dma.buffer ) + return; + + // updates DMA time + GetSoundtime(); + + // check to make sure that we haven't overshot + if( paintedtime < soundtime ) paintedtime = soundtime; + + // mix ahead of current position + endtime = soundtime + s_mixahead->value * dma.speed; + + // mix to an even submission block size + endtime = (endtime + dma.submission_chunk - 1) & ~(dma.submission_chunk - 1); + samps = dma.samples >> (dma.channels - 1); + if( endtime - soundtime > samps ) endtime = soundtime + samps; + + S_PaintChannels( endtime ); + SNDDMA_Submit(); +} + +/* +============ +S_Update + +Called once each time through the main loop +============ +*/ +void S_Update( int clientnum, const vec3_t position, const vec3_t velocity, const vec3_t axis[3], bool clear ) +{ + int i, total; + channel_t *ch, *combine = NULL; + + if( !sound_started ) + return; + + // bump frame count + s_framecount++; + + // if the loading plaque is up, clear everything + // out to make sure we aren't looping a dirty + // dma buffer while loading + if( s_pause->integer || clear ) + { + S_ClearBuffer(); + return; + } + + // rebuild scale tables if volume is modified + if( s_volume->modified ) S_InitScaletable(); + + s_clientnum = clientnum; + VectorCopy( position, listener_origin ); + VectorCopy( velocity, listener_velocity ); + VectorCopy( axis[0], listener_forward ); + VectorCopy( axis[1], listener_right ); + VectorCopy( axis[2], listener_up ); + + // Add looping sounds + si.AddLoopingSounds(); + + // update spatialization for dynamic sounds + for( i = 0, ch = channels; i < MAX_CHANNELS; i++, ch++ ) + { + if( !ch->sfx ) continue; + if( ch->autosound ) + { + if( ch->loopframe != s_framecount ) + { + Mem_Set( ch, 0, sizeof( *ch )); // stopped + continue; + } + } + + // respatialize channel + S_SpatializeChannel( ch ); + + if( !ch->leftvol && !ch->rightvol ) + { + Mem_Set( ch, 0, sizeof( *ch )); // not audible + continue; + } + } + + // debugging output + if( s_show->value ) + { + for( i = total = 0, ch = channels; i < MAX_CHANNELS; i++, ch++ ) + { + if( ch->sfx && ( ch->leftvol || ch->rightvol )) + { + MsgDev( D_INFO, "%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name ); + total++; + } + } + Msg( "----(%i)---- painted: %i\n", total, paintedtime ); + } + + // mix some sound + S_UpdateChannels(); +} + +/* +=============================================================================== + +console functions + +=============================================================================== +*/ +void S_Play_f( void ) +{ + if( Cmd_Argc() == 1 ) + { + Msg( "Usage: playsound \n" ); + return; + } + S_StartLocalSound( Cmd_Argv( 1 ), 1.0f, PITCH_NORM, NULL ); +} + +/* +================= +S_StopSound_f +================= +*/ +void S_StopSound_f( void ) +{ + S_StopAllSounds(); +} + +/* +================= +S_SoundInfo_f +================= +*/ +void S_SoundInfo_f( void ) +{ + if( !sound_started ) + { + Msg( "sound system not started\n" ); + return; + } + + Msg( "%5d channel(s)\n", dma.channels ); + Msg( "%5d samples\n", dma.samples ); + Msg( "%5d bits/sample\n", dma.samplebits ); + Msg( "%5d bytes/sec\n", dma.speed ); + + MsgDev( D_NOTE, "%5d samplepos\n", dma.samplepos ); + MsgDev( D_NOTE, "%5d submission_chunk\n", dma.submission_chunk ); + MsgDev( D_NOTE, "0x%x dma buffer\n", dma.buffer ); +} + +/* +================ +S_Init +================ +*/ +bool S_Init( void *hInst ) +{ + Cmd_ExecuteString( "sndlatch\n" ); + + host_sound = Cvar_Get( "host_sound", "1", CVAR_SYSTEMINFO, "enable sound system" ); + s_volume = Cvar_Get( "s_volume", "0.7", CVAR_ARCHIVE, "sound volume" ); + s_khz = Cvar_Get( "s_khz", "11", CVAR_LATCH_AUDIO|CVAR_ARCHIVE, "output sound frequency" ); + s_loadas8bit = Cvar_Get( "s_loadas8bit", "1", CVAR_LATCH_AUDIO|CVAR_ARCHIVE, "resample all sounds to 8-bit" ); + s_mixahead = Cvar_Get( "s_mixahead", "0.2", CVAR_ARCHIVE, "how much sound to mix ahead of time" ); + s_show = Cvar_Get( "s_show", "0", 0, "show playing sounds" ); + s_testsound = Cvar_Get( "s_testsound", "0", 0, "generate sine 1 khz wave to testing audio subsystem" ); + s_primary = Cvar_Get( "s_primary", "0", CVAR_LATCH_AUDIO|CVAR_ARCHIVE, "use direct primary buffer" ); + s_check_errors = Cvar_Get( "s_check_errors", "1", CVAR_ARCHIVE, "ignore audio engine errors" ); + s_pause = Cvar_Get( "paused", "0", 0, "sound engine pause" ); + + Cmd_AddCommand( "playsound", S_Play_f, "playing a specified sound file" ); + Cmd_AddCommand( "stopsound", S_StopSound_f, "stop all sounds" ); + Cmd_AddCommand( "soundlist", S_SoundList_f, "display loaded sounds" ); + Cmd_AddCommand( "s_info", S_SoundInfo_f, "print sound system information" ); + + if( !host_sound->integer ) + { + MsgDev( D_INFO, "Audio: disabled\n" ); + return false; + } + + if( !SNDDMA_Init( hInst )) + { + MsgDev( D_INFO, "S_Init: sound system can't initialized\n" ); + return false; + } + S_InitScaletable(); + + sndpool = Mem_AllocPool( "Sound Zone" ); + sound_started = true; + soundtime = 0; + paintedtime = 0; + + S_StopAllSounds (); + + return true; +} + +// ======================================================================= +// Shutdown sound engine +// ======================================================================= +void S_Shutdown( void ) +{ + Cmd_RemoveCommand( "playsound" ); + Cmd_RemoveCommand( "stopsound" ); + Cmd_RemoveCommand( "soundlist" ); + Cmd_RemoveCommand( "s_info" ); + + if( !sound_started ) return; + sound_started = false; + + SNDDMA_Shutdown(); + + S_FreeSounds(); + Mem_FreePool( &sndpool ); +} \ No newline at end of file diff --git a/snd_dx/s_mix.c b/snd_dx/s_mix.c new file mode 100644 index 00000000..5a1fd32f --- /dev/null +++ b/snd_dx/s_mix.c @@ -0,0 +1,327 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. + +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 2 +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// snd_mix.c -- portable code to mix sounds for snd_dma.c + +#include "sound.h" + +#define PAINTBUFFER_SIZE 2048 +portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE]; +int snd_scaletable[32][256]; +int *snd_p, snd_linear_count, snd_vol; +short *snd_out; + +void S_WriteLinearBlastStereo16( void ) +{ + int i, val; + + for( i = 0; i < snd_linear_count; i += 2 ) + { + val = snd_p[i]>>8; + if( val > 0x7fff ) snd_out[i] = 0x7fff; + else if( val < (short)0x8000 ) + snd_out[i] = (short)0x8000; + else snd_out[i] = val; + + val = snd_p[i+1]>>8; + if( val > 0x7fff ) snd_out[i+1] = 0x7fff; + else if( val < (short)0x8000 ) + snd_out[i+1] = (short)0x8000; + else snd_out[i+1] = val; + } +} + +void S_TransferStereo16( dword *pbuf, int endtime ) +{ + int lpos, lpaintedtime; + + snd_p = (int *)paintbuffer; + lpaintedtime = paintedtime; + + while( lpaintedtime < endtime ) + { + // handle recirculating buffer issues + lpos = lpaintedtime & ((dma.samples >> 1) - 1); + + snd_out = (short *) pbuf + (lpos << 1); + + snd_linear_count = (dma.samples>>1) - lpos; + if( lpaintedtime + snd_linear_count > endtime ) + snd_linear_count = endtime - lpaintedtime; + + snd_linear_count <<= 1; + + // write a linear blast of samples + S_WriteLinearBlastStereo16(); + + snd_p += snd_linear_count; + lpaintedtime += (snd_linear_count >> 1); + } +} + +/* +=================== +S_TransferPaintBuffer + +=================== +*/ +void S_TransferPaintBuffer( int endtime ) +{ + int out_idx, count; + int step, val; + int *p, out_mask; + dword *pbuf; + + pbuf = (dword *)dma.buffer; + + if( s_testsound->integer ) + { + int i, count; + + // write a fixed sine wave + count = (endtime - paintedtime); + for( i = 0; i < count; i++ ) + { + paintbuffer[i].left = com.sin(( paintedtime + i ) * 0.1f ) * 20000 * 256; + paintbuffer[i].right = paintbuffer[i].left; + } + } + + + if( dma.samplebits == 16 && dma.channels == 2 ) + { + // optimized case + S_TransferStereo16( pbuf, endtime ); + } + else + { + // general case + p = (int *)paintbuffer; + count = (endtime - paintedtime) * dma.channels; + out_mask = dma.samples - 1; + out_idx = paintedtime * dma.channels & out_mask; + step = 3 - dma.channels; + + if( dma.samplebits == 16 ) + { + short *out = (short *)pbuf; + + while( count-- ) + { + val = *p >> 8; + p += step; + if( val > 0x7fff ) val = 0x7fff; + else if( val < (short)0x8000 ) + val = (short)0x8000; + out[out_idx] = val; + out_idx = (out_idx + 1) & out_mask; + } + } + else if( dma.samplebits == 8 ) + { + byte *out = (byte *)pbuf; + + while( count-- ) + { + val = *p >> 8; + p += step; + if( val > 0x7fff ) val = 0x7fff; + else if( val < (short)0x8000 ) + val = (short)0x8000; + out[out_idx] = (val>>8) + 128; + out_idx = (out_idx + 1) & out_mask; + } + } + } +} + +/* +=============================================================================== + +CHANNEL MIXING + +=============================================================================== +*/ +void S_PaintChannelFrom8( channel_t *ch, sfxcache_t *sc, int count, int offset ) +{ + int data; + int *lscale, *rscale; + byte *sfx; + portable_samplepair_t *samp; + int i; + + if( ch->leftvol > 255 ) ch->leftvol = 255; + if( ch->rightvol > 255 ) ch->rightvol = 255; + + lscale = snd_scaletable[ch->leftvol>>3]; + rscale = snd_scaletable[ch->rightvol>>3]; + sfx = (signed char *)sc->data + ch->pos; + + samp = &paintbuffer[offset]; + + for( i = 0; i < count; i++, samp++ ) + { + data = sfx[i]; + samp->left += lscale[data]; + samp->right += rscale[data]; + } + ch->pos += count; +} + +void S_PaintChannelFrom16( channel_t *ch, sfxcache_t *sc, int count, int offset ) +{ + int data; + int left, right; + int leftvol, rightvol; + signed short *sfx; + portable_samplepair_t *samp; + int i; + + leftvol = ch->leftvol * snd_vol; + rightvol = ch->rightvol * snd_vol; + sfx = (signed short *)sc->data + ch->pos; + + samp = &paintbuffer[offset]; + + for( i = 0; i < count; i++, samp++ ) + { + data = sfx[i]; + left = ( data * leftvol ) >> 8; + right = (data * rightvol) >> 8; + samp->left += left; + samp->right += right; + } + ch->pos += count; +} + +void S_PaintChannels( int endtime ) +{ + channel_t *ch; + sfxcache_t *sc; + playsound_t *ps; + int i, end, ltime, count; + + snd_vol = s_volume->value * 256; + + while( paintedtime < endtime ) + { + // if paintbuffer is smaller than DMA buffer + end = endtime; + if( endtime - paintedtime > PAINTBUFFER_SIZE ) + end = paintedtime + PAINTBUFFER_SIZE; + + // start any playsounds + while( 1 ) + { + ps = s_pendingplays.next; + if( ps == &s_pendingplays ) + break; // no more pending sounds + if( ps->begin <= paintedtime ) + { + S_IssuePlaysound( ps ); + continue; + } + + if( ps->begin < end ) end = ps->begin; // stop here + break; + } + + // clear the paint buffer + if( s_rawend < paintedtime ) + { + Mem_Set( paintbuffer, 0, (end - paintedtime) * sizeof( portable_samplepair_t )); + } + else + { + int stop; + + // copy from the streaming sound source + stop = (end < s_rawend) ? end : s_rawend; + + for( i = paintedtime; i < stop; i++ ) + paintbuffer[i - paintedtime] = s_rawsamples[i & (MAX_RAW_SAMPLES - 1)]; + + for( ; i < end; i++ ) + paintbuffer[i-paintedtime].left = paintbuffer[i-paintedtime].right = 0; + } + + // paint in the channels. + for( i = 0, ch = channels; i < MAX_CHANNELS; i++, ch++ ) + { + ltime = paintedtime; + + while( ltime < end ) + { + if( !ch->sfx || ( !ch->leftvol && !ch->rightvol )) + break; + + // max painting is to the end of the buffer + count = end - ltime; + + // might be stopped by running out of data + if( ch->end - ltime < count ) count = ch->end - ltime; + + sc = S_LoadSound( ch->sfx ); + if( !sc ) break; + + if( count > 0 && ch->sfx ) + { + if( sc->width == 1 ) + S_PaintChannelFrom8( ch, sc, count, ltime - paintedtime ); + else S_PaintChannelFrom16( ch, sc, count, ltime - paintedtime ); + + ltime += count; + } + + // if at end of loop, restart + if( ltime >= ch->end ) + { + if( ch->autosound && ch->use_loop ) + { // autolooping sounds always go back to start + ch->pos = 0; + ch->end = ltime + sc->length; + } + else if( sc->loopstart >= 0 && ch->use_loop ) + { + ch->pos = sc->loopstart; + ch->end = ltime + sc->length - ch->pos; + } + else ch->sfx = NULL; // channel just stopped + } + } + } + + // transfer out according to DMA format + S_TransferPaintBuffer( end ); + paintedtime = end; + } +} + +void S_InitScaletable( void ) +{ + int i, j; + int scale; + + for( i = 0; i < 32; i++ ) + { + scale = i * 8 * 256 * s_volume->value; + for( j = 0; j < 256; j++ ) snd_scaletable[i][j] = ((signed char)j) * scale; + } + s_volume->modified = false; +} diff --git a/snd_dx/s_stream.c b/snd_dx/s_stream.c new file mode 100644 index 00000000..fb545a45 --- /dev/null +++ b/snd_dx/s_stream.c @@ -0,0 +1,135 @@ +//======================================================================= +// Copyright XashXT Group 2009 й +// s_stream.c - sound streaming +//======================================================================= + +#include "sound.h" +#include "byteorder.h" + +portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES]; +int s_rawend; +static bg_track_t s_bgTrack; + +/* +================= +S_StartBackgroundTrack +================= +*/ +void S_StartBackgroundTrack( const char *introTrack, const char *loopTrack ) +{ + if( !sound_started ) return; + S_StopBackgroundTrack(); + + // start it up + com.snprintf( s_bgTrack.introName, sizeof(s_bgTrack.introName), "media/%s.ogg", introTrack); + com.snprintf( s_bgTrack.loopName, sizeof(s_bgTrack.loopName), "media/%s.ogg", loopTrack ); + + S_StartStreaming(); + + // UNDONE: process streaming +} + +void S_StopBackgroundTrack( void ) +{ + if( !sound_started ) return; + + S_StopStreaming(); + + // UNDONE: close background track + Mem_Set( &s_bgTrack, 0, sizeof( bg_track_t )); +} + +void S_StartStreaming( void ) +{ + // UNDONE: allocate static channel for streaimng +} + +void S_StopStreaming( void ) +{ +} + +/* +============ +S_StreamRawSamples + +Cinematic streaming and voice over network +============ +*/ +void S_StreamRawSamples( int samples, int rate, int width, int channels, const byte *data ) +{ + int i, src, dst; + float scale; + + if( !sound_started ) + return; + + if( s_rawend < paintedtime ) s_rawend = paintedtime; + scale = (float)rate / dma.speed; + + if( channels == 2 && width == 2 ) + { + if( scale == 1.0f ) + { + // optimized case + for( i = 0; i < samples; i++ ) + { + dst = s_rawend & (MAX_RAW_SAMPLES - 1); + s_rawend++; + s_rawsamples[dst].left = LittleShort(((short *)data)[i*2]) << 8; + s_rawsamples[dst].right = LittleShort(((short *)data)[i*2+1]) << 8; + } + } + else + { + for( i = src = 0; src < samples; i++ ) + { + src = i * scale; + if( src >= samples ) break; + + dst = s_rawend & (MAX_RAW_SAMPLES - 1); + s_rawend++; + s_rawsamples[dst].left = LittleShort(((short *)data)[src*2]) << 8; + s_rawsamples[dst].right = LittleShort(((short *)data)[src*2+1]) << 8; + } + } + } + else if( channels == 1 && width == 2 ) + { + for( i = src = 0; src < samples; i++ ) + { + src = i * scale; + if( src >= samples ) break; + + dst = s_rawend & (MAX_RAW_SAMPLES - 1); + s_rawend++; + s_rawsamples[dst].left = LittleShort(((short *)data)[src]) << 8; + s_rawsamples[dst].right = LittleShort(((short *)data)[src]) << 8; + } + } + else if( channels == 2 && width == 1 ) + { + for( i = src = 0; src < samples; i++ ) + { + src = i * scale; + if( src >= samples ) break; + + dst = s_rawend & (MAX_RAW_SAMPLES - 1); + s_rawend++; + s_rawsamples[dst].left = ((char *)data)[src*2] << 16; + s_rawsamples[dst].right = ((char *)data)[src*2+1] << 16; + } + } + else if( channels == 1 && width == 1 ) + { + for( i = src = 0; src < samples; i++ ) + { + src = i * scale; + if( src >= samples ) break; + + dst = s_rawend & (MAX_RAW_SAMPLES - 1); + s_rawend++; + s_rawsamples[dst].left = (((byte *)data)[src]-128) << 16; + s_rawsamples[dst].right = (((byte *)data)[src]-128) << 16; + } + } +} \ No newline at end of file diff --git a/snd_dx/snd_dx.dsp b/snd_dx/snd_dx.dsp new file mode 100644 index 00000000..78cd625e --- /dev/null +++ b/snd_dx/snd_dx.dsp @@ -0,0 +1,153 @@ +# Microsoft Developer Studio Project File - Name="snd_dx" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=snd_dx - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "snd_dx.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "snd_dx.mak" CFG="snd_dx - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "snd_dx - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "snd_dx - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "snd_dx - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\temp\snd_dx\!release" +# PROP Intermediate_Dir "..\temp\snd_dx\!release" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PLATFORM_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "./" /I "../public" /I "../common" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /opt:nowin98 +# ADD LINK32 winmm.lib /nologo /dll /pdb:none /machine:I386 /nodefaultlib:"libcmt.lib" /opt:nowin98 +# SUBTRACT LINK32 /profile +# Begin Custom Build +TargetDir=\Xash3D\src_main\temp\snd_dx\!release +InputPath=\Xash3D\src_main\temp\snd_dx\!release\snd_dx.dll +SOURCE="$(InputPath)" + +"D:\Xash3D\bin\snd_dx.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\snd_dx.dll "D:\Xash3D\bin\snd_dx.dll" + +# End Custom Build + +!ELSEIF "$(CFG)" == "snd_dx - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\temp\snd_dx\!debug" +# PROP Intermediate_Dir "..\temp\snd_dx\!debug" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PLATFORM_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "../public" /I "../common" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 winmm.lib /nologo /dll /debug /machine:I386 /nodefaultlib:"libcmt.lib" /pdbtype:sept +# SUBTRACT LINK32 /incremental:no /nodefaultlib +# Begin Custom Build +TargetDir=\Xash3D\src_main\temp\snd_dx\!debug +InputPath=\Xash3D\src_main\temp\snd_dx\!debug\snd_dx.dll +SOURCE="$(InputPath)" + +"D:\Xash3D\bin\snd_dx.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\snd_dx.dll "D:\Xash3D\bin\snd_dx.dll" + +# End Custom Build + +!ENDIF + +# Begin Target + +# Name "snd_dx - Win32 Release" +# Name "snd_dx - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\s_direct.c +# End Source File +# Begin Source File + +SOURCE=.\s_export.c +# End Source File +# Begin Source File + +SOURCE=.\s_load.c +# End Source File +# Begin Source File + +SOURCE=.\s_main.c +# End Source File +# Begin Source File + +SOURCE=.\s_mix.c +# End Source File +# Begin Source File + +SOURCE=.\s_stream.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\s_openal.h +# End Source File +# Begin Source File + +SOURCE=.\sound.h +# End Source File +# End Group +# End Target +# End Project diff --git a/snd_dx/sound.h b/snd_dx/sound.h new file mode 100644 index 00000000..1d35c090 --- /dev/null +++ b/snd_dx/sound.h @@ -0,0 +1,190 @@ +//======================================================================= +// Copyright XashXT Group 2009 й +// sound.h - sndlib main header +//======================================================================= + +#ifndef SOUND_H +#define SOUND_H + +#include +#include "launch_api.h" +#include "qfiles_ref.h" +#include "vsound_api.h" + +extern stdlib_api_t com; +extern vsound_imp_t si; +extern byte *sndpool; + +#include "mathlib.h" + +typedef struct +{ + int left; + int right; +} portable_samplepair_t; + +typedef struct +{ + int length; + int loopstart; + int speed; // not needed, because converted on load? + int width; + int stereo; + byte data[1]; // variable sized +} sfxcache_t; + +typedef struct sfx_s +{ + string name; + sfxcache_t *cache; + + int registration_sequence; + bool default_sound; +} sfx_t; + +// a playsound_t will be generated by each call to S_StartSound, +// when the mixer reaches playsound->begin, the playsound will +// be assigned to a channel +typedef struct playsound_s +{ + struct playsound_s *prev, *next; + sfx_t *sfx; + float volume; + float attenuation; + int entnum; + int entchannel; + bool fixed_origin; // use origin field instead of entnum's origin + bool use_loop; + vec3_t origin; + uint begin; // begin on this sample +} playsound_t; + +typedef struct +{ + int channels; + int samples; // mono samples in buffer + int submission_chunk; // don't mix less than this # + int samplepos; // in mono samples + int samplebits; + int speed; + byte *buffer; +} dma_t; + +typedef struct +{ + sfx_t *sfx; // sfx number + int leftvol; // 0-255 volume + int rightvol; // 0-255 volume + int end; // end time in global paintsamples + int pos; // sample position in sfx + int looping; // where to loop, -1 = no looping OBSOLETE? + int entnum; // to allow overriding a specific sound + int loopnum; // entity num that playing autosound + int loopframe; // for stopping looping sounds + int entchannel; // + vec3_t origin; // only use if fixed_origin is set + vec_t dist_mult; // distance multiplier (attenuation/clipK) + int master_vol; // 0-255 master volume + bool fixed_origin; // use origin instead of fetching entnum's origin + bool autosound; // from an entity->sound, cleared each frame + bool use_loop; // don't loop default and local sounds +} channel_t; + +typedef struct +{ + int rate; + int width; + int channels; + int loopstart; + int samples; + int dataofs; // chunk starts this many bytes from file start +} wavinfo_t; + +typedef struct +{ + string introName; + string loopName; + bool looping; + file_t *file; + int start; + int rate; + uint format; + void *vorbisFile; +} bg_track_t; + +/* +==================================================================== + + SYSTEM SPECIFIC FUNCTIONS + +==================================================================== +*/ +#define Host_Error com.error +#define Z_Malloc( size ) Mem_Alloc( sndpool, size ) + +// initializes cycling through a DMA buffer and returns information on it +bool SNDDMA_Init( void *hInst ); +int SNDDMA_GetDMAPos( void ); +void SNDDMA_Shutdown( void ); +void SNDDMA_BeginPainting( void ); +void SNDDMA_Submit( void ); + +//==================================================================== + +#define MAX_CHANNELS 64 +#define MAX_RAW_SAMPLES 8192 + +extern channel_t channels[MAX_CHANNELS]; +extern int paintedtime; +extern int s_rawend; +extern vec3_t listener_origin; +extern vec3_t listener_forward; +extern vec3_t listener_right; +extern vec3_t listener_up; +extern dma_t dma; +extern playsound_t s_pendingplays; +extern bool sound_started; + +extern cvar_t *s_check_errors; +extern cvar_t *s_volume; +extern cvar_t *s_nosound; +extern cvar_t *s_loadas8bit; +extern cvar_t *s_khz; +extern cvar_t *s_show; +extern cvar_t *s_mixahead; +extern cvar_t *s_testsound; +extern cvar_t *s_primary; + +extern portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES]; + +void S_InitScaletable( void ); +sfxcache_t *S_LoadSound( sfx_t *sfx ); +void S_IssuePlaysound( playsound_t *ps ); +void S_PaintChannels( int endtime ); + +bool S_Init( void *hInst ); +void S_Shutdown( void ); +void S_Activate( bool active ); +void S_SoundList_f( void ); +void S_SoundInfo_f( void ); + +// if origin is NULL, the sound will be dynamically sourced from the entity +void S_StartSound( const vec3_t pos, int ent, int chan, sound_t sfx, float vol, float attn, float pitch, bool use_loop); +void S_Update( int entnum, const vec3_t pos, const vec3_t vel, const vec3_t axis[3], bool clear ); +void S_StreamRawSamples( int samples, int rate, int width, int channels, const byte *data ); +bool S_AddLoopingSound( int entnum, sound_t handle, float volume, float attn ); +void S_StartBackgroundTrack( const char *intro, const char *loop ); +channel_t *S_PickChannel( int entNum, int entChannel ); +int S_StartLocalSound( const char *name, float volume, float pitch, const float *org ); +sfx_t *S_GetSfxByHandle( sound_t handle ); +void S_StopBackgroundTrack( void ); +void S_StartStreaming( void ); +void S_StopStreaming( void ); +void S_StopAllSounds( void ); +void S_FreeSounds( void ); + +void S_BeginRegistration( void ); +sound_t S_RegisterSound( const char *sample ); +void S_EndRegistration( void ); + +#endif//SOUND_H \ No newline at end of file diff --git a/todo.log b/todo.log index 3593b84c..630b25ea 100644 --- a/todo.log +++ b/todo.log @@ -155,6 +155,10 @@ Beta 13.12.09 128. fixup sprites lerping OK 129. fixup sound orientation OK 130. don't show console on changelevel OK -131. support for doom3-style parsing +131. support for doom3-style materials parsing 132. implement SENTENCE_system -133. rebuild vsound.dll +133. new sound\render system version replacement OK +134. dx sound engine complete OK +135. implement dsp, lypsync and vox +136. re-vision uimenu +137. complete rewriting physic.dll diff --git a/render/cin.c b/vid_gl/cin.c similarity index 100% rename from render/cin.c rename to vid_gl/cin.c diff --git a/render/cin.h b/vid_gl/cin.h similarity index 100% rename from render/cin.h rename to vid_gl/cin.h diff --git a/render/r_aliasq.c b/vid_gl/r_aliasq.c similarity index 100% rename from render/r_aliasq.c rename to vid_gl/r_aliasq.c diff --git a/render/r_aliasq.old b/vid_gl/r_aliasq.old similarity index 100% rename from render/r_aliasq.old rename to vid_gl/r_aliasq.old diff --git a/render/r_backend.c b/vid_gl/r_backend.c similarity index 100% rename from render/r_backend.c rename to vid_gl/r_backend.c diff --git a/render/r_backend.h b/vid_gl/r_backend.h similarity index 100% rename from render/r_backend.h rename to vid_gl/r_backend.h diff --git a/render/r_bloom.c b/vid_gl/r_bloom.c similarity index 100% rename from render/r_bloom.c rename to vid_gl/r_bloom.c diff --git a/render/r_cin.c b/vid_gl/r_cin.c similarity index 100% rename from render/r_cin.c rename to vid_gl/r_cin.c diff --git a/render/r_cull.c b/vid_gl/r_cull.c similarity index 100% rename from render/r_cull.c rename to vid_gl/r_cull.c diff --git a/render/r_draw.c b/vid_gl/r_draw.c similarity index 100% rename from render/r_draw.c rename to vid_gl/r_draw.c diff --git a/render/r_image.c b/vid_gl/r_image.c similarity index 96% rename from render/r_image.c rename to vid_gl/r_image.c index c1a84a57..dfcf6901 100644 --- a/render/r_image.c +++ b/vid_gl/r_image.c @@ -443,7 +443,7 @@ void R_TextureList_f( void ) Msg( "---------------------------------------------------------\n" ); Msg( "%i total textures\n", texCount ); - Msg( "%.2f total megabytes of textures\n", bytes/1048576.0 ); + Msg( "%s total memory used\n", memprint( bytes )); Msg( "\n" ); } diff --git a/render/r_light.c b/vid_gl/r_light.c similarity index 100% rename from render/r_light.c rename to vid_gl/r_light.c diff --git a/render/r_local.h b/vid_gl/r_local.h similarity index 96% rename from render/r_local.h rename to vid_gl/r_local.h index fab8ccc2..baeea7cf 100644 --- a/render/r_local.h +++ b/vid_gl/r_local.h @@ -124,7 +124,7 @@ enum #define FOG_TEXTURE_WIDTH 256 #define FOG_TEXTURE_HEIGHT 32 -#define VID_DEFAULTMODE "4" +#define VID_DEFAULTMODE "0" #define SHADOW_PLANAR 1 #define SHADOW_MAPPING 2 diff --git a/render/r_main.c b/vid_gl/r_main.c similarity index 100% rename from render/r_main.c rename to vid_gl/r_main.c diff --git a/render/r_math.c b/vid_gl/r_math.c similarity index 100% rename from render/r_math.c rename to vid_gl/r_math.c diff --git a/render/r_math.h b/vid_gl/r_math.h similarity index 100% rename from render/r_math.h rename to vid_gl/r_math.h diff --git a/render/r_mesh.c b/vid_gl/r_mesh.c similarity index 100% rename from render/r_mesh.c rename to vid_gl/r_mesh.c diff --git a/render/r_mesh.h b/vid_gl/r_mesh.h similarity index 100% rename from render/r_mesh.h rename to vid_gl/r_mesh.h diff --git a/render/r_model.c b/vid_gl/r_model.c similarity index 100% rename from render/r_model.c rename to vid_gl/r_model.c diff --git a/render/r_model.h b/vid_gl/r_model.h similarity index 100% rename from render/r_model.h rename to vid_gl/r_model.h diff --git a/render/r_opengl.c b/vid_gl/r_opengl.c similarity index 92% rename from render/r_opengl.c rename to vid_gl/r_opengl.c index 30b867f3..c39c2038 100644 --- a/render/r_opengl.c +++ b/vid_gl/r_opengl.c @@ -239,7 +239,7 @@ bool R_SetPixelformat( void ) size_t gamma_size; byte *savedGamma; - Sys_LoadLibrary( &opengl_dll ); // load opengl32.dll + Sys_LoadLibrary( NULL, &opengl_dll ); // load opengl32.dll if( !opengl_dll.link ) return false; glw_state.minidriver = false; // FIXME @@ -490,6 +490,20 @@ bool R_CreateWindow( int width, int height, bool fullscreen ) r_ypos = Cvar_Get( "r_ypos", "22", CVAR_ARCHIVE, "window position by vertical" ); x = r_xpos->integer; y = r_ypos->integer; + + // adjust window coordinates if necessary + // so that the window is completely on screen + if( x < 0 ) x = 0; + if( y < 0 ) y = 0; + + if( Cvar_VariableInteger( "r_mode" ) != glConfig.prev_mode ) + { + if((x + w > glw_state.desktopWidth) || (y + h > glw_state.desktopHeight)) + { + x = ( glw_state.desktopWidth - w ) / 2; + y = ( glw_state.desktopHeight - h ) / 2; + } + } } glw_state.hWnd = CreateWindowEx( exstyle, "Xash Window", wndname, stylebits, x, y, w, h, NULL, NULL, glw_state.hInst, NULL ); @@ -522,13 +536,21 @@ bool R_CreateWindow( int width, int height, bool fullscreen ) rserr_t R_ChangeDisplaySettings( int vid_mode, bool fullscreen ) { - int width, height; - + int width, height; + HDC hDC; + R_SaveVideoMode( vid_mode ); width = r_width->integer; height = r_height->integer; + // check our desktop attributes + hDC = GetDC( GetDesktopWindow() ); + glw_state.desktopBitsPixel = GetDeviceCaps( hDC, BITSPIXEL ); + glw_state.desktopWidth = GetDeviceCaps( hDC, HORZRES ); + glw_state.desktopHeight = GetDeviceCaps( hDC, VERTRES ); + ReleaseDC( GetDesktopWindow(), hDC ); + // destroy the existing window if( glw_state.hWnd ) R_Free_OpenGL(); diff --git a/render/r_opengl.h b/vid_gl/r_opengl.h similarity index 97% rename from render/r_opengl.h rename to vid_gl/r_opengl.h index 02e4fb1b..c764e23a 100644 --- a/render/r_opengl.h +++ b/vid_gl/r_opengl.h @@ -1107,6 +1107,10 @@ typedef struct HINSTANCE hinstOpenGL; // HINSTANCE for the OpenGL library + int desktopBitsPixel; + int desktopWidth; + int desktopHeight; + bool software; // software emulation uses RB_RenderShader() bool initialized; // OpenGL subsystem started bool minidriver; diff --git a/render/r_poly.c b/vid_gl/r_poly.c similarity index 100% rename from render/r_poly.c rename to vid_gl/r_poly.c diff --git a/render/r_program.c b/vid_gl/r_program.c similarity index 100% rename from render/r_program.c rename to vid_gl/r_program.c diff --git a/render/r_register.c b/vid_gl/r_register.c similarity index 97% rename from render/r_register.c rename to vid_gl/r_register.c index 4c50e10a..962c1222 100644 --- a/render/r_register.c +++ b/vid_gl/r_register.c @@ -522,8 +522,8 @@ void GL_InitCommands( void ) r_environment_color = Cvar_Get( "r_environment_color", "128 128 128", CVAR_ARCHIVE, "map environment light color" ); r_ignorehwgamma = Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE|CVAR_LATCH_VIDEO, "ignore hardware gamma (e.g. not support)" ); - r_overbrightbits = Cvar_Get( "r_overbrightbits", "1", CVAR_ARCHIVE|CVAR_LATCH_VIDEO, "renderer overbright bits" ); - r_mapoverbrightbits = Cvar_Get( "r_mapoverbrightbits", "2", CVAR_ARCHIVE|CVAR_LATCH_VIDEO, "current map overbright bits" ); + r_overbrightbits = Cvar_Get( "r_overbrightbits", "0", CVAR_ARCHIVE|CVAR_LATCH_VIDEO, "renderer overbright bits" ); + r_mapoverbrightbits = Cvar_Get( "r_mapoverbrightbits", "0", CVAR_ARCHIVE|CVAR_LATCH_VIDEO, "current map overbright bits" ); r_vertexbuffers = Cvar_Get( "r_vertexbuffers", "0", CVAR_ARCHIVE, "store vertex data in VBOs" ); r_detailtextures = Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE, "enable or disable detail textures" ); diff --git a/render/r_shader.c b/vid_gl/r_shader.c similarity index 100% rename from render/r_shader.c rename to vid_gl/r_shader.c diff --git a/render/r_shader.h b/vid_gl/r_shader.h similarity index 100% rename from render/r_shader.h rename to vid_gl/r_shader.h diff --git a/render/r_shadow.c b/vid_gl/r_shadow.c similarity index 100% rename from render/r_shadow.c rename to vid_gl/r_shadow.c diff --git a/render/r_shadow.h b/vid_gl/r_shadow.h similarity index 100% rename from render/r_shadow.h rename to vid_gl/r_shadow.h diff --git a/render/r_sky.c b/vid_gl/r_sky.c similarity index 100% rename from render/r_sky.c rename to vid_gl/r_sky.c diff --git a/render/r_sprite.c b/vid_gl/r_sprite.c similarity index 100% rename from render/r_sprite.c rename to vid_gl/r_sprite.c diff --git a/render/r_studio.c b/vid_gl/r_studio.c similarity index 100% rename from render/r_studio.c rename to vid_gl/r_studio.c diff --git a/render/r_surf.c b/vid_gl/r_surf.c similarity index 100% rename from render/r_surf.c rename to vid_gl/r_surf.c diff --git a/render/render.plg b/vid_gl/render.plg similarity index 100% rename from render/render.plg rename to vid_gl/render.plg diff --git a/render/render.dsp b/vid_gl/vid_gl.dsp similarity index 79% rename from render/render.dsp rename to vid_gl/vid_gl.dsp index 71c6c097..7aaa702f 100644 --- a/render/render.dsp +++ b/vid_gl/vid_gl.dsp @@ -1,24 +1,24 @@ -# Microsoft Developer Studio Project File - Name="render" - Package Owner=<4> +# Microsoft Developer Studio Project File - Name="vid_gl" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 -CFG=render - Win32 Release +CFG=vid_gl - Win32 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE -!MESSAGE NMAKE /f "render.mak". +!MESSAGE NMAKE /f "vid_gl.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE -!MESSAGE NMAKE /f "render.mak" CFG="render - Win32 Release" +!MESSAGE NMAKE /f "vid_gl.mak" CFG="vid_gl - Win32 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE -!MESSAGE "render - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "render - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "vid_gl - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "vid_gl - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project @@ -29,7 +29,7 @@ CPP=cl.exe MTL=midl.exe RSC=rc.exe -!IF "$(CFG)" == "render - Win32 Release" +!IF "$(CFG)" == "vid_gl - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 @@ -38,8 +38,8 @@ RSC=rc.exe # PROP BASE Target_Dir "." # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 -# PROP Output_Dir "..\temp\render\!release" -# PROP Intermediate_Dir "..\temp\render\!release" +# PROP Output_Dir "..\temp\vid_gl\!release" +# PROP Intermediate_Dir "..\temp\vid_gl\!release" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "." # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c @@ -57,16 +57,16 @@ LINK32=link.exe # ADD LINK32 msvcrt.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /pdb:none /machine:I386 /nodefaultlib:"libc.lib" /libpath:"../public/libs/" # SUBTRACT LINK32 /debug # Begin Custom Build -TargetDir=\Xash3D\src_main\temp\render\!release -InputPath=\Xash3D\src_main\temp\render\!release\render.dll +TargetDir=\Xash3D\src_main\temp\vid_gl\!release +InputPath=\Xash3D\src_main\temp\vid_gl\!release\vid_gl.dll SOURCE="$(InputPath)" -"D:\Xash3D\bin\render.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\render.dll "D:\Xash3D\bin\render.dll" +"D:\Xash3D\bin\vid_gl.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\vid_gl.dll "D:\Xash3D\bin\vid_gl.dll" # End Custom Build -!ELSEIF "$(CFG)" == "render - Win32 Debug" +!ELSEIF "$(CFG)" == "vid_gl - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 @@ -75,8 +75,8 @@ SOURCE="$(InputPath)" # PROP BASE Target_Dir "." # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 -# PROP Output_Dir "..\temp\render\!debug" -# PROP Intermediate_Dir "..\temp\render\!debug" +# PROP Output_Dir "..\temp\vid_gl\!debug" +# PROP Intermediate_Dir "..\temp\vid_gl\!debug" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "." # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c @@ -94,12 +94,12 @@ LINK32=link.exe # ADD LINK32 msvcrtd.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /pdbtype:sept # SUBTRACT LINK32 /profile /incremental:no /map # Begin Custom Build -TargetDir=\Xash3D\src_main\temp\render\!debug -InputPath=\Xash3D\src_main\temp\render\!debug\render.dll +TargetDir=\Xash3D\src_main\temp\vid_gl\!debug +InputPath=\Xash3D\src_main\temp\vid_gl\!debug\vid_gl.dll SOURCE="$(InputPath)" -"D:\Xash3D\bin\render.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\render.dll "D:\Xash3D\bin\render.dll" +"D:\Xash3D\bin\vid_gl.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\vid_gl.dll "D:\Xash3D\bin\vid_gl.dll" # End Custom Build @@ -107,8 +107,8 @@ SOURCE="$(InputPath)" # Begin Target -# Name "render - Win32 Release" -# Name "render - Win32 Debug" +# Name "vid_gl - Win32 Release" +# Name "vid_gl - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" diff --git a/render/warpsin.h b/vid_gl/warpsin.h similarity index 100% rename from render/warpsin.h rename to vid_gl/warpsin.h diff --git a/vprogs/vprogs.plg b/vprogs/vprogs.plg deleted file mode 100644 index d5eb623c..00000000 --- a/vprogs/vprogs.plg +++ /dev/null @@ -1,16 +0,0 @@ - - -
-

Build Log

-

---------------------Configuration: vprogs - Win32 Debug-------------------- -

-

Command Lines

- - - -

Results

-vprogs.dll - 0 error(s), 0 warning(s) -
- - diff --git a/vsound/vsound.plg b/vsound/vsound.plg deleted file mode 100644 index 548624db..00000000 --- a/vsound/vsound.plg +++ /dev/null @@ -1,16 +0,0 @@ - - -
-

Build Log

-

---------------------Configuration: vsound - Win32 Debug-------------------- -

-

Command Lines

- - - -

Results

-vsound.dll - 0 error(s), 0 warning(s) -
- - diff --git a/xash.dsw b/xash.dsw index 55f0de32..940f311e 100644 --- a/xash.dsw +++ b/xash.dsw @@ -87,7 +87,7 @@ Package=<4> ############################################################################### -Project: "render"=".\render\render.dsp" - Package Owner=<4> +Project: "vid_gl"=".\vid_gl\vid_gl.dsp" - Package Owner=<4> Package=<5> {{{ @@ -111,7 +111,19 @@ Package=<4> ############################################################################### -Project: "vsound"=".\vsound\vsound.dsp" - Package Owner=<4> +Project: "snd_al"=".\snd_al\snd_al.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "snd_dx"=".\snd_dx\snd_dx.dsp" - Package Owner=<4> Package=<5> {{{ diff --git a/xtools/bsplib/leakfile.c b/xtools/bsplib/leakfile.c index c0aed17e..b0649734 100644 --- a/xtools/bsplib/leakfile.c +++ b/xtools/bsplib/leakfile.c @@ -73,7 +73,7 @@ void LeakFile( tree_t *tree ) MsgDev( D_NOTE, "--- LeakFile ---\n" ); // write the points to the file - com.sprintf( filename, "%s.lin", source ); + com.sprintf( filename, "maps/%s.lin", source ); linefile = FS_Open( filename, "w" ); if( !linefile ) Sys_Error( "couldn't open %s\n", filename ); diff --git a/xtools/xtools.c b/xtools/xtools.c index 45dcc507..a7b6783e 100644 --- a/xtools/xtools.c +++ b/xtools/xtools.c @@ -77,7 +77,7 @@ void InitCommon( const int argc, const char **argv ) PrepareBSPModel( (int)argc, (char **)argv ); break; case HOST_QCCLIB: - Sys_LoadLibrary( &vprogs_dll ); // load qcclib + Sys_LoadLibrary( NULL, &vprogs_dll ); // load qcclib CreateVprogs = (void *)vprogs_dll.main; PRVM = CreateVprogs( &com, NULL ); // second interface not allowed diff --git a/xtools/xtools.plg b/xtools/xtools.plg deleted file mode 100644 index 2a5b16d7..00000000 --- a/xtools/xtools.plg +++ /dev/null @@ -1,16 +0,0 @@ - - -
-

Build Log

-

---------------------Configuration: xtools - Win32 Debug-------------------- -

-

Command Lines

- - - -

Results

-xtools.dll - 0 error(s), 0 warning(s) -
- -