/* ======================== idLobby::PickNewHostInternal ======================== */ void idLobby::PickNewHostInternal( bool forceMe, bool inviteOldHost ) { if( migrationInfo.state == MIGRATE_PICKING_HOST ) { return; // Already picking new host } idLib::Printf( "PickNewHost: Started picking new host %s.\n", GetLobbyName() ); if( IsHost() ) { idLib::Printf( "PickNewHost: Already host of session %s\n", GetLobbyName() ); return; } // Find the user with the lowest ping int bestUserIndex = -1; int bestPingMs = 0; lobbyUserID_t bestUserId; for( int i = 0; i < GetNumLobbyUsers(); i++ ) { lobbyUser_t* user = GetLobbyUser( i ); if( !verify( user != NULL ) ) { continue; } if( user->IsDisconnected() ) { continue; } if( user->peerIndex == -1 ) { continue; // Don't try and pick old host } if( bestUserIndex == -1 || IsBetterHost( user->pingMs, user->lobbyUserID, bestPingMs, bestUserId ) ) { bestUserIndex = i; bestPingMs = user->pingMs; bestUserId = user->lobbyUserID; } if( user->peerIndex == net_migration_forcePeerAsHost.GetInteger() ) { bestUserIndex = i; bestPingMs = user->pingMs; bestUserId = user->lobbyUserID; break; } } // Remember when we first started picking a new host migrationInfo.state = MIGRATE_PICKING_HOST; migrationInfo.migrationStartTime = Sys_Milliseconds(); migrationInfo.persistUntilGameEndsData.wasMigratedGame = sessionCB->GetState() == idSession::INGAME; if( bestUserIndex == -1 ) // This can happen if we call PickNewHost on an lobby that was Shutdown { NET_VERBOSE_PRINT( "MIGRATION: PickNewHost was called on an lobby that was Shutdown\n" ); BecomeHost(); return; } NET_VERBOSE_PRINT( "MIGRATION: Chose user index %d (%s) for new host\n", bestUserIndex, GetLobbyUser( bestUserIndex )->gamertag ); bool bestWasLocal = IsSessionUserIndexLocal( bestUserIndex ); // Check before shutting down the lobby migrateMsgFlags = parms.matchFlags; // Save off match parms // Build invite list BuildMigrationInviteList( inviteOldHost ); // If the best user is on this machine, then we become the host now, otherwise, wait for a new host to contact us if( forceMe || bestWasLocal ) { BecomeHost(); } }
/* ======================== idSnapShot::ReadDeltaForJob ======================== */ bool idSnapShot::ReadDeltaForJob( const char* deltaMem, int deltaSize, int visIndex, idSnapShot* templateStates ) { bool report = net_verboseSnapshotReport.GetBool(); net_verboseSnapshotReport.SetBool( false ); lzwCompressionData_t lzwData; idZeroRunLengthCompressor rleCompressor; idLZWCompressor lzwCompressor( &lzwData ); int bytesRead = 0; // how many uncompressed bytes we read in. Used to figure out compression ratio lzwCompressor.Start( ( uint8* )deltaMem, deltaSize ); // Skip past sequence and baseSequence int sequence = 0; int baseSequence = 0; lzwCompressor.ReadAgnostic( sequence ); lzwCompressor.ReadAgnostic( baseSequence ); lzwCompressor.ReadAgnostic( time ); bytesRead += sizeof( int ) * 3; int objectNum = 0; uint16 delta = 0; while( lzwCompressor.ReadAgnostic( delta, true ) == sizeof( delta ) ) { bytesRead += sizeof( delta ); objectNum += delta; if( objectNum >= 0xFFFF ) { // full delta if( net_verboseSnapshotCompression.GetBool() ) { float compRatio = static_cast<float>( deltaSize ) / static_cast<float>( bytesRead ); idLib::Printf( "Snapshot (%d/%d). ReadSize: %d DeltaSize: %d Ratio: %.3f\n", sequence, baseSequence, bytesRead, deltaSize, compRatio ); } return true; } objectState_t& state = FindOrCreateObjectByID( objectNum ); objectSize_t newsize = 0; lzwCompressor.ReadAgnostic( newsize ); bytesRead += sizeof( newsize ); if( newsize == SIZE_STALE ) { NET_VERBOSESNAPSHOT_PRINT( "read delta: object %d goes stale\n", objectNum ); // sanity bool oldVisible = ( state.visMask & ( 1 << visIndex ) ) != 0; if( !oldVisible ) { NET_VERBOSESNAPSHOT_PRINT( "ERROR: unexpected already stale\n" ); } state.visMask &= ~( 1 << visIndex ); state.stale = true; // We need to make sure we haven't freed stale objects. assert( state.buffer.Size() > 0 ); // no more data continue; } else if( newsize == SIZE_NOT_STALE ) { NET_VERBOSESNAPSHOT_PRINT( "read delta: object %d no longer stale\n", objectNum ); // sanity bool oldVisible = ( state.visMask & ( 1 << visIndex ) ) != 0; if( oldVisible ) { NET_VERBOSESNAPSHOT_PRINT( "ERROR: unexpected not stale\n" ); } state.visMask |= ( 1 << visIndex ); state.stale = false; // the latest state is packed in, get the new size and continue reading the new state lzwCompressor.ReadAgnostic( newsize ); bytesRead += sizeof( newsize ); } objectState_t* objTemplateState = templateStates->FindObjectByID( objectNum ); if( newsize == 0 ) { // object deleted: reset state now so next one to use it doesn't have old data state.deleted = false; state.stale = false; state.changedCount = 0; state.expectedSequence = 0; state.visMask = 0; state.buffer._Release(); state.createdFromTemplate = false; if( objTemplateState != NULL && objTemplateState->buffer.Size() && objTemplateState->expectedSequence < baseSequence ) { idLib::PrintfIf( net_ssTemplateDebug.GetBool(), "Clearing old template state[%d] [%d<%d]\n", objectNum, objTemplateState->expectedSequence, baseSequence ); objTemplateState->deleted = false; objTemplateState->stale = false; objTemplateState->changedCount = 0; objTemplateState->expectedSequence = 0; objTemplateState->visMask = 0; objTemplateState->buffer._Release(); } } else { // new state? bool debug = false; if( state.buffer.Size() == 0 ) { state.createdFromTemplate = true; // Brand new state if( objTemplateState != NULL && objTemplateState->buffer.Size() > 0 && sequence >= objTemplateState->expectedSequence ) { idLib::PrintfIf( net_ssTemplateDebug.GetBool(), "\nAdding basestate for new object %d (for SS %d/%d. obj base created in ss %d) deltaSize: %d\n", objectNum, sequence, baseSequence, objTemplateState->expectedSequence, deltaSize ); state.buffer = objTemplateState->buffer; if( net_ssTemplateDebug.GetBool() ) { state.Print( "SPAWN STATE" ); debug = true; PrintAlign( "DELTA STATE" ); } } else if( net_ssTemplateDebug.GetBool() ) { idLib::Printf( "\nNew snapobject[%d] in snapshot %d/%d but no basestate found locally so creating new\n", objectNum, sequence, baseSequence ); } } else { state.createdFromTemplate = false; } // the buffer shrank or stayed the same objectBuffer_t newbuffer( newsize ); rleCompressor.Start( NULL, &lzwCompressor, newsize ); objectSize_t compareSize = Min( state.buffer.Size(), newsize ); for( objectSize_t i = 0; i < compareSize; i++ ) { byte b = rleCompressor.ReadByte(); newbuffer[i] = state.buffer[i] + b; if( debug && InDebugRange( i ) ) { idLib::Printf( "%02X", b ); } } // Catch leftover if( newsize > compareSize ) { rleCompressor.ReadBytes( newbuffer.Ptr() + compareSize, newsize - compareSize ); if( debug ) { for( objectSize_t i = compareSize; i < newsize; i++ ) { if( InDebugRange( i ) ) { idLib::Printf( "%02X", newbuffer[i] ); } } } } state.buffer = newbuffer; state.changedCount = sequence; bytesRead += sizeof( byte ) * newsize; if( debug ) { idLib::Printf( "\n" ); state.Print( "NEW STATE" ); } if( report ) { idLib::Printf( " Obj %d Compressed: Size %d \n", objectNum, rleCompressor.CompressedSize() ); } } #ifdef SNAPSHOT_CHECKSUMS extern uint32 SnapObjChecksum( const uint8 * data, int length ); if( state.buffer.Size() > 0 ) { uint32 checksum = 0; lzwCompressor.ReadAgnostic( checksum ); bytesRead += sizeof( checksum ); if( !verify( checksum == SnapObjChecksum( state.buffer.Ptr(), state.buffer.Size() ) ) ) { idLib::Error( " Invalid snapshot checksum" ); } } #endif } // partial delta return false; }
/* ======================== idMenuScreen_Shell_SystemOptions::idMenuDataSource_SystemSettings::AdjustField ======================== */ void idMenuScreen_Shell_SystemOptions::idMenuDataSource_SystemSettings::AdjustField( const int fieldIndex, const int adjustAmount ) { switch( fieldIndex ) { case SYSTEM_FIELD_FRAMERATE: { static const int numValues = 2; static const int values[numValues] = { 60, 120 }; com_engineHz.SetInteger( AdjustOption( com_engineHz.GetInteger(), values, numValues, adjustAmount ) ); break; } case SYSTEM_FIELD_VSYNC: { static const int numValues = 3; static const int values[numValues] = { 0, 1, 2 }; r_swapInterval.SetInteger( AdjustOption( r_swapInterval.GetInteger(), values, numValues, adjustAmount ) ); break; } case SYSTEM_FIELD_ANTIALIASING: { // RB: disabled 16x MSAA static const int numValues = 4; static const int values[numValues] = { 0, 2, 4, 8 }; // RB end r_multiSamples.SetInteger( AdjustOption( r_multiSamples.GetInteger(), values, numValues, adjustAmount ) ); break; } case SYSTEM_FIELD_MOTIONBLUR: { static const int numValues = 5; static const int values[numValues] = { 0, 2, 3, 4, 5 }; r_motionBlur.SetInteger( AdjustOption( r_motionBlur.GetInteger(), values, numValues, adjustAmount ) ); break; } // RB begin case SYSTEM_FIELD_SHADOWMAPPING: { static const int numValues = 2; static const int values[numValues] = { 0, 1 }; r_useShadowMapping.SetInteger( AdjustOption( r_useShadowMapping.GetInteger(), values, numValues, adjustAmount ) ); break; } /*case SYSTEM_FIELD_LODBIAS: { const float percent = LinearAdjust( r_lodBias.GetFloat(), -1.0f, 1.0f, 0.0f, 100.0f ); const float adjusted = percent + ( float )adjustAmount * 5.0f; const float clamped = idMath::ClampFloat( 0.0f, 100.0f, adjusted ); r_lodBias.SetFloat( LinearAdjust( clamped, 0.0f, 100.0f, -1.0f, 1.0f ) ); break; }*/ // RB end case SYSTEM_FIELD_BRIGHTNESS: { const float percent = LinearAdjust( r_lightScale.GetFloat(), 2.0f, 4.0f, 0.0f, 100.0f ); const float adjusted = percent + ( float )adjustAmount; const float clamped = idMath::ClampFloat( 0.0f, 100.0f, adjusted ); r_lightScale.SetFloat( LinearAdjust( clamped, 0.0f, 100.0f, 2.0f, 4.0f ) ); break; } case SYSTEM_FIELD_VOLUME: { const float percent = 100.0f * Square( 1.0f - ( s_volume_dB.GetFloat() / DB_SILENCE ) ); const float adjusted = percent + ( float )adjustAmount; const float clamped = idMath::ClampFloat( 0.0f, 100.0f, adjusted ); s_volume_dB.SetFloat( DB_SILENCE - ( idMath::Sqrt( clamped / 100.0f ) * DB_SILENCE ) ); break; } } cvarSystem->ClearModifiedFlags( CVAR_ARCHIVE ); }
namespace BFG { idCVar in_nograb( "in_nograb", "0", CVAR_SYSTEM | CVAR_NOCHEAT, "prevents input grabbing" ); // RB: FIXME this shit. We need the OpenGL alpha channel for advanced rendering effects idCVar r_waylandcompat( "r_waylandcompat", "0", CVAR_SYSTEM | CVAR_NOCHEAT | CVAR_ARCHIVE, "wayland compatible framebuffer" ); // RB: only relevant if using SDL 2.0 #if defined(__APPLE__) // only core profile is supported on OS X idCVar r_useOpenGL32( "r_useOpenGL32", "2", CVAR_INTEGER, "0 = OpenGL 3.x, 1 = OpenGL 3.2 compatibility profile, 2 = OpenGL 3.2 core profile", 0, 2 ); #elif defined(__linux__) // Linux open source drivers suck idCVar r_useOpenGL32( "r_useOpenGL32", "0", CVAR_INTEGER, "0 = OpenGL 3.x, 1 = OpenGL 3.2 compatibility profile, 2 = OpenGL 3.2 core profile", 0, 2 ); #else idCVar r_useOpenGL32( "r_useOpenGL32", "1", CVAR_INTEGER, "0 = OpenGL 3.x, 1 = OpenGL 3.2 compatibility profile, 2 = OpenGL 3.2 core profile", 0, 2 ); #endif // RB end #if SDL_VERSION_ATLEAST(2, 0, 0) static SDL_Window* window = NULL; static SDL_GLContext context = NULL; #else static SDL_Surface* window = NULL; #define SDL_WINDOW_OPENGL SDL_OPENGL #define SDL_WINDOW_FULLSCREEN SDL_FULLSCREEN #define SDL_WINDOW_RESIZABLE SDL_RESIZABLE #endif /* =================== GLimp_PreInit R_GetModeListForDisplay is called before GLimp_Init(), but SDL needs SDL_Init() first. So do that in GLimp_PreInit() Calling that function more than once doesn't make a difference =================== */ void GLimp_PreInit() // DG: added this function for SDL compatibility { if( !SDL_WasInit( SDL_INIT_VIDEO ) ) { if( SDL_Init( SDL_INIT_VIDEO ) ) common->Error( "Error while initializing SDL: %s", SDL_GetError() ); } } /* =================== GLimp_Init =================== */ bool GLimp_Init( glimpParms_t parms ) { common->Printf( "Initializing OpenGL subsystem\n" ); GLimp_PreInit(); // DG: make sure SDL is initialized // DG: make window resizable Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; // DG end if( parms.fullScreen ) flags |= SDL_WINDOW_FULLSCREEN; int colorbits = 24; int depthbits = 24; int stencilbits = 8; for( int i = 0; i < 16; i++ ) { // 0 - default // 1 - minus colorbits // 2 - minus depthbits // 3 - minus stencil if( ( i % 4 ) == 0 && i ) { // one pass, reduce switch( i / 4 ) { case 2 : if( colorbits == 24 ) colorbits = 16; break; case 1 : if( depthbits == 24 ) depthbits = 16; else if( depthbits == 16 ) depthbits = 8; case 3 : if( stencilbits == 24 ) stencilbits = 16; else if( stencilbits == 16 ) stencilbits = 8; } } int tcolorbits = colorbits; int tdepthbits = depthbits; int tstencilbits = stencilbits; if( ( i % 4 ) == 3 ) { // reduce colorbits if( tcolorbits == 24 ) tcolorbits = 16; } if( ( i % 4 ) == 2 ) { // reduce depthbits if( tdepthbits == 24 ) tdepthbits = 16; else if( tdepthbits == 16 ) tdepthbits = 8; } if( ( i % 4 ) == 1 ) { // reduce stencilbits if( tstencilbits == 24 ) tstencilbits = 16; else if( tstencilbits == 16 ) tstencilbits = 8; else tstencilbits = 0; } int channelcolorbits = 4; if( tcolorbits == 24 ) channelcolorbits = 8; SDL_GL_SetAttribute( SDL_GL_RED_SIZE, channelcolorbits ); SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, channelcolorbits ); SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, channelcolorbits ); SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, tdepthbits ); SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, tstencilbits ); if( r_waylandcompat.GetBool() ) SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 0 ); else SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, channelcolorbits ); SDL_GL_SetAttribute( SDL_GL_STEREO, parms.stereo ? 1 : 0 ); SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, parms.multiSamples ? 1 : 0 ); SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, parms.multiSamples ); #if SDL_VERSION_ATLEAST(2, 0, 0) // RB begin if( r_useOpenGL32.GetInteger() > 0 ) { glConfig.driverType = GLDRV_OPENGL32_COMPATIBILITY_PROFILE; SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 ); SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 2 ); } if( r_debugContext.GetBool() ) { SDL_GL_SetAttribute( SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG ); } if( r_useOpenGL32.GetInteger() > 1 ) { glConfig.driverType = GLDRV_OPENGL32_CORE_PROFILE; SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE ); } // RB end // DG: set display num for fullscreen int windowPos = SDL_WINDOWPOS_UNDEFINED; if( parms.fullScreen > 0 ) { if( parms.fullScreen > SDL_GetNumVideoDisplays() ) { common->Warning( "Couldn't set display to num %i because we only have %i displays", parms.fullScreen, SDL_GetNumVideoDisplays() ); } else { // -1 because SDL starts counting displays at 0, while parms.fullScreen starts at 1 windowPos = SDL_WINDOWPOS_UNDEFINED_DISPLAY( ( parms.fullScreen - 1 ) ); } } // TODO: if parms.fullScreen == -1 there should be a borderless window spanning multiple displays /* * NOTE that this implicitly handles parms.fullScreen == -2 (from r_fullscreen -2) meaning * "do fullscreen, but I don't care on what monitor", at least on my box it's the monitor with * the mouse cursor. */ window = SDL_CreateWindow( GAME_NAME, windowPos, windowPos, parms.width, parms.height, flags ); // DG end context = SDL_GL_CreateContext( window ); if( !window ) { common->DPrintf( "Couldn't set GL mode %d/%d/%d: %s", channelcolorbits, tdepthbits, tstencilbits, SDL_GetError() ); continue; } if( SDL_GL_SetSwapInterval( r_swapInterval.GetInteger() ) < 0 ) common->Warning( "SDL_GL_SWAP_CONTROL not supported" ); // RB begin SDL_GetWindowSize( window, &glConfig.nativeScreenWidth, &glConfig.nativeScreenHeight ); // RB end glConfig.isFullscreen = ( SDL_GetWindowFlags( window ) & SDL_WINDOW_FULLSCREEN ) == SDL_WINDOW_FULLSCREEN; #else glConfig.driverType = GLDRV_OPENGL3X; SDL_WM_SetCaption( GAME_NAME, GAME_NAME ); if( SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, r_swapInterval.GetInteger() ) < 0 ) common->Warning( "SDL_GL_SWAP_CONTROL not supported" ); window = SDL_SetVideoMode( parms.width, parms.height, colorbits, flags ); if( !window ) { common->DPrintf( "Couldn't set GL mode %d/%d/%d: %s", channelcolorbits, tdepthbits, tstencilbits, SDL_GetError() ); continue; } glConfig.nativeScreenWidth = window->w; glConfig.nativeScreenHeight = window->h; glConfig.isFullscreen = ( window->flags & SDL_FULLSCREEN ) == SDL_FULLSCREEN; #endif common->Printf( "Using %d color bits, %d depth, %d stencil display\n", channelcolorbits, tdepthbits, tstencilbits ); glConfig.colorBits = tcolorbits; glConfig.depthBits = tdepthbits; glConfig.stencilBits = tstencilbits; // RB begin glConfig.displayFrequency = 60; glConfig.isStereoPixelFormat = parms.stereo; glConfig.multisamples = parms.multiSamples; glConfig.pixelAspect = 1.0f; // FIXME: some monitor modes may be distorted // should side-by-side stereo modes be consider aspect 0.5? // RB end break; } if( !window ) { common->Printf( "No usable GL mode found: %s", SDL_GetError() ); return false; } #ifdef __APPLE__ glewExperimental = GL_TRUE; #endif GLenum glewResult = glewInit(); if( GLEW_OK != glewResult ) { // glewInit failed, something is seriously wrong common->Printf( "^3GLimp_Init() - GLEW could not load OpenGL subsystem: %s", glewGetErrorString( glewResult ) ); } else { common->Printf( "Using GLEW %s\n", glewGetString( GLEW_VERSION ) ); } // DG: disable cursor, we have two cursors in menu (because mouse isn't grabbed in menu) SDL_ShowCursor( SDL_DISABLE ); // DG end return true; } /* =================== Helper functions for GLimp_SetScreenParms() =================== */ #if SDL_VERSION_ATLEAST(2, 0, 0) // SDL1 doesn't support multiple displays, so the source is much shorter and doesn't need separate functions // makes sure the window will be full-screened on the right display and returns the SDL display index static int ScreenParmsHandleDisplayIndex( glimpParms_t parms ) { int displayIdx; if( parms.fullScreen > 0 ) { displayIdx = parms.fullScreen - 1; // first display for SDL is 0, in parms it's 1 } else // -2 == use current display { displayIdx = SDL_GetWindowDisplayIndex( window ); if( displayIdx < 0 ) // for some reason the display for the window couldn't be detected displayIdx = 0; } if( parms.fullScreen > SDL_GetNumVideoDisplays() ) { common->Warning( "Can't set fullscreen mode to display number %i, because SDL2 only knows about %i displays!", parms.fullScreen, SDL_GetNumVideoDisplays() ); return -1; } if( parms.fullScreen != glConfig.isFullscreen ) { // we have to switch to another display if( glConfig.isFullscreen ) { // if we're already in fullscreen mode but want to switch to another monitor // we have to go to windowed mode first to move the window.. SDL-oddity. SDL_SetWindowFullscreen( window, SDL_FALSE ); } // select display ; SDL_WINDOWPOS_UNDEFINED_DISPLAY() doesn't work. int x = SDL_WINDOWPOS_CENTERED_DISPLAY( displayIdx ); // move window to the center of selected display SDL_SetWindowPosition( window, x, x ); } return displayIdx; } static bool SetScreenParmsFullscreen( glimpParms_t parms ) { SDL_DisplayMode m = {0}; int displayIdx = ScreenParmsHandleDisplayIndex( parms ); if( displayIdx < 0 ) return false; // get current mode of display the window should be full-screened on SDL_GetCurrentDisplayMode( displayIdx, &m ); // change settings in that display mode according to parms // FIXME: check if refreshrate, width and height are supported? // m.refresh_rate = parms.displayHz; m.w = parms.width; m.h = parms.height; // set that displaymode if( SDL_SetWindowDisplayMode( window, &m ) < 0 ) { common->Warning( "Couldn't set window mode for fullscreen, reason: %s", SDL_GetError() ); return false; } // if we're currently not in fullscreen mode, we need to switch to fullscreen if( !( SDL_GetWindowFlags( window ) & SDL_WINDOW_FULLSCREEN ) ) { if( SDL_SetWindowFullscreen( window, SDL_TRUE ) < 0 ) { common->Warning( "Couldn't switch to fullscreen mode, reason: %s!", SDL_GetError() ); return false; } } return true; } static bool SetScreenParmsWindowed( glimpParms_t parms ) { SDL_SetWindowSize( window, parms.width, parms.height ); SDL_SetWindowPosition( window, parms.x, parms.y ); // if we're currently in fullscreen mode, we need to disable that if( SDL_GetWindowFlags( window ) & SDL_WINDOW_FULLSCREEN ) { if( SDL_SetWindowFullscreen( window, SDL_FALSE ) < 0 ) { common->Warning( "Couldn't switch to windowed mode, reason: %s!", SDL_GetError() ); return false; } } return true; } #endif // SDL_VERSION_ATLEAST(2, 0, 0) /* =================== GLimp_SetScreenParms =================== */ bool GLimp_SetScreenParms( glimpParms_t parms ) { #if SDL_VERSION_ATLEAST(2, 0, 0) if( parms.fullScreen > 0 || parms.fullScreen == -2 ) { if( !SetScreenParmsFullscreen( parms ) ) return false; } else if( parms.fullScreen == 0 ) // windowed mode { if( !SetScreenParmsWindowed( parms ) ) return false; } else { common->Warning( "GLimp_SetScreenParms: fullScreen -1 (borderless window for multiple displays) currently unsupported!" ); return false; } #else // SDL 1.2 - so much shorter, but doesn't handle multiple displays SDL_Surface* s = SDL_GetVideoSurface(); if( s == NULL ) { common->Warning( "GLimp_SetScreenParms: Couldn't get video information, reason: %s", SDL_GetError() ); return false; } int bitsperpixel = 24; if( s->format ) bitsperpixel = s->format->BitsPerPixel; Uint32 flags = s->flags; if( parms.fullScreen ) flags |= SDL_FULLSCREEN; else flags &= ~SDL_FULLSCREEN; s = SDL_SetVideoMode( parms.width, parms.height, bitsperpixel, flags ); if( s == NULL ) { common->Warning( "GLimp_SetScreenParms: Couldn't set video information, reason: %s", SDL_GetError() ); return false; } #endif // SDL_VERSION_ATLEAST(2, 0, 0) // Note: the following stuff would also work with SDL1.2 SDL_GL_SetAttribute( SDL_GL_STEREO, parms.stereo ? 1 : 0 ); SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, parms.multiSamples ? 1 : 0 ); SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, parms.multiSamples ); glConfig.isFullscreen = parms.fullScreen; glConfig.isStereoPixelFormat = parms.stereo; glConfig.nativeScreenWidth = parms.width; glConfig.nativeScreenHeight = parms.height; glConfig.displayFrequency = parms.displayHz; glConfig.multisamples = parms.multiSamples; return true; } /* =================== GLimp_Shutdown =================== */ void GLimp_Shutdown() { common->Printf( "Shutting down OpenGL subsystem\n" ); #if SDL_VERSION_ATLEAST(2, 0, 0) if( context ) { SDL_GL_DeleteContext( context ); context = NULL; } if( window ) { SDL_DestroyWindow( window ); window = NULL; } #endif } /* =================== GLimp_SwapBuffers =================== */ void GLimp_SwapBuffers() { #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_GL_SwapWindow( window ); #else SDL_GL_SwapBuffers(); #endif } /* ================= GLimp_SetGamma ================= */ void GLimp_SetGamma( unsigned short red[256], unsigned short green[256], unsigned short blue[256] ) { if( !window ) { common->Warning( "GLimp_SetGamma called without window" ); return; } #if SDL_VERSION_ATLEAST(2, 0, 0) if( SDL_SetWindowGammaRamp( window, red, green, blue ) ) #else if( SDL_SetGammaRamp( red, green, blue ) ) #endif common->Warning( "Couldn't set gamma ramp: %s", SDL_GetError() ); } /* =================== GLimp_ExtensionPointer =================== */ /* GLExtension_t GLimp_ExtensionPointer(const char *name) { assert(SDL_WasInit(SDL_INIT_VIDEO)); return (GLExtension_t)SDL_GL_GetProcAddress(name); } */ /* =============== Sys_GrabMouseCursor =============== */ void Sys_GrabMouseCursor( bool grab ) { static bool grabbed = false; if( in_nograb.GetBool() ) grab = false; if( grabbed != grab ) { grabbed = grab; #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_SetRelativeMouseMode( grab ? SDL_TRUE : SDL_FALSE ); SDL_SetWindowGrab( window, grab ? SDL_TRUE : SDL_FALSE ); #else SDL_WM_GrabInput( grab ? SDL_GRAB_ON : SDL_GRAB_OFF ); #endif } } /* ==================== DumpAllDisplayDevices ==================== */ void DumpAllDisplayDevices() { common->DPrintf( "TODO: DumpAllDisplayDevices\n" ); } class idSort_VidMode : public idSort_Quick< vidMode_t, idSort_VidMode > { public: int Compare( const vidMode_t& a, const vidMode_t& b ) const { int wd = a.width - b.width; int hd = a.height - b.height; int fd = a.displayHz - b.displayHz; return ( hd != 0 ) ? hd : ( wd != 0 ) ? wd : fd; } }; // RB: resolutions supported by XreaL static void FillStaticVidModes( idList<vidMode_t>& modeList ) { modeList.AddUnique( vidMode_t( 320, 240, 60 ) ); modeList.AddUnique( vidMode_t( 400, 300, 60 ) ); modeList.AddUnique( vidMode_t( 512, 384, 60 ) ); modeList.AddUnique( vidMode_t( 640, 480, 60 ) ); modeList.AddUnique( vidMode_t( 800, 600, 60 ) ); modeList.AddUnique( vidMode_t( 960, 720, 60 ) ); modeList.AddUnique( vidMode_t( 1024, 768, 60 ) ); modeList.AddUnique( vidMode_t( 1152, 864, 60 ) ); modeList.AddUnique( vidMode_t( 1280, 720, 60 ) ); modeList.AddUnique( vidMode_t( 1280, 768, 60 ) ); modeList.AddUnique( vidMode_t( 1280, 800, 60 ) ); modeList.AddUnique( vidMode_t( 1280, 1024, 60 ) ); modeList.AddUnique( vidMode_t( 1360, 768, 60 ) ); modeList.AddUnique( vidMode_t( 1440, 900, 60 ) ); modeList.AddUnique( vidMode_t( 1680, 1050, 60 ) ); modeList.AddUnique( vidMode_t( 1600, 1200, 60 ) ); modeList.AddUnique( vidMode_t( 1920, 1080, 60 ) ); modeList.AddUnique( vidMode_t( 1920, 1200, 60 ) ); modeList.AddUnique( vidMode_t( 2048, 1536, 60 ) ); modeList.AddUnique( vidMode_t( 2560, 1600, 60 ) ); modeList.SortWithTemplate( idSort_VidMode() ); } /* ==================== R_GetModeListForDisplay ==================== */ bool R_GetModeListForDisplay( const int requestedDisplayNum, idList<vidMode_t>& modeList ) { assert( requestedDisplayNum >= 0 ); modeList.Clear(); #if SDL_VERSION_ATLEAST(2, 0, 0) // DG: SDL2 implementation if( requestedDisplayNum >= SDL_GetNumVideoDisplays() ) { // requested invalid displaynum return false; } int numModes = SDL_GetNumDisplayModes( requestedDisplayNum ); if( numModes > 0 ) { for( int i = 0; i < numModes; i++ ) { SDL_DisplayMode m; int ret = SDL_GetDisplayMode( requestedDisplayNum, i, &m ); if( ret != 0 ) { common->Warning( "Can't get video mode no %i, because of %s\n", i, SDL_GetError() ); continue; } vidMode_t mode; mode.width = m.w; mode.height = m.h; mode.displayHz = m.refresh_rate ? m.refresh_rate : 60; // default to 60 if unknown (0) modeList.AddUnique( mode ); } if( modeList.Num() < 1 ) { common->Warning( "Couldn't get a single video mode for display %i, using default ones..!\n", requestedDisplayNum ); FillStaticVidModes( modeList ); } // sort with lowest resolution first modeList.SortWithTemplate( idSort_VidMode() ); } else { common->Warning( "Can't get Video Info, using default modes...\n" ); if( numModes < 0 ) { common->Warning( "Reason was: %s\n", SDL_GetError() ); } FillStaticVidModes( modeList ); } return true; // DG end #else // SDL 1 // DG: SDL1 only knows of one display - some functions rely on // R_GetModeListForDisplay() returning false for invalid displaynum to iterate all displays if( requestedDisplayNum >= 1 ) { return false; } // DG end const SDL_VideoInfo* videoInfo = SDL_GetVideoInfo(); if( videoInfo == NULL ) { // DG: yes, this can actually fail, e.g. if SDL_Init( SDL_INIT_VIDEO ) wasn't called common->Warning( "Can't get Video Info, using default modes...\n" ); FillStaticVidModes( modeList ); return true; } SDL_Rect** modes = SDL_ListModes( videoInfo->vfmt, SDL_OPENGL | SDL_FULLSCREEN ); if( !modes ) { common->Warning( "Can't get list of available modes, using default ones...\n" ); FillStaticVidModes( modeList ); return true; } if( modes == ( SDL_Rect** ) - 1 ) { common->Printf( "Display supports any resolution\n" ); FillStaticVidModes( modeList ); return true; } int numModes; for( numModes = 0; modes[numModes]; numModes++ ); if( numModes > 1 ) { for( int i = 0; i < numModes; i++ ) { vidMode_t mode; mode.width = modes[i]->w; mode.height = modes[i]->h; mode.displayHz = 60; // FIXME; modeList.AddUnique( mode ); } // sort with lowest resolution first modeList.SortWithTemplate( idSort_VidMode() ); return true; } return false; #endif } } // namespace BFG
/* ================= idRenderModelManagerLocal::GetModel ================= */ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool createIfNotFound ) { if( !_modelName || !_modelName[0] ) { return NULL; } idStrStatic< MAX_OSPATH > canonical = _modelName; canonical.ToLower(); idStrStatic< MAX_OSPATH > extension; canonical.ExtractFileExtension( extension ); // see if it is already present int key = hash.GenerateKey( canonical, false ); for( int i = hash.First( key ); i != -1; i = hash.Next( i ) ) { idRenderModel* model = models[i]; if( canonical.Icmp( model->Name() ) == 0 ) { if( !model->IsLoaded() ) { // reload it if it was purged idStr generatedFileName = "generated/rendermodels/"; generatedFileName.AppendPath( canonical ); generatedFileName.SetFileExtension( va( "b%s", extension.c_str() ) ); if( model->SupportsBinaryModel() && r_binaryLoadRenderModels.GetBool() ) { idFileLocal file( fileSystem->OpenFileReadMemory( generatedFileName ) ); model->PurgeModel(); if( !model->LoadBinaryModel( file, 0 ) ) { model->LoadModel(); } } else { model->LoadModel(); } } else if( insideLevelLoad && !model->IsLevelLoadReferenced() ) { // we are reusing a model already in memory, but // touch all the materials to make sure they stay // in memory as well model->TouchData(); } model->SetLevelLoadReferenced( true ); return model; } } // see if we can load it // determine which subclass of idRenderModel to initialize idRenderModel* model = NULL; if( ( extension.Icmp( "ase" ) == 0 ) || ( extension.Icmp( "lwo" ) == 0 ) || ( extension.Icmp( "flt" ) == 0 ) || ( extension.Icmp( "ma" ) == 0 ) ) { model = new( TAG_MODEL ) idRenderModelStatic; } else if( extension.Icmp( MD5_MESH_EXT ) == 0 ) { model = new( TAG_MODEL ) idRenderModelMD5; } else if( extension.Icmp( "md3" ) == 0 ) { model = new( TAG_MODEL ) idRenderModelMD3; } else if( extension.Icmp( "prt" ) == 0 ) { model = new( TAG_MODEL ) idRenderModelPrt; } else if( extension.Icmp( "liquid" ) == 0 ) { model = new( TAG_MODEL ) idRenderModelLiquid; } idStrStatic< MAX_OSPATH > generatedFileName; if( model != NULL ) { generatedFileName = "generated/rendermodels/"; generatedFileName.AppendPath( canonical ); generatedFileName.SetFileExtension( va( "b%s", extension.c_str() ) ); // Get the timestamp on the original file, if it's newer than what is stored in binary model, regenerate it ID_TIME_T sourceTimeStamp = fileSystem->GetTimestamp( canonical ); idFileLocal file( fileSystem->OpenFileReadMemory( generatedFileName ) ); if( !model->SupportsBinaryModel() || !r_binaryLoadRenderModels.GetBool() ) { model->InitFromFile( canonical ); } else { if( !model->LoadBinaryModel( file, sourceTimeStamp ) ) { model->InitFromFile( canonical ); idFileLocal outputFile( fileSystem->OpenFileWrite( generatedFileName, "fs_basepath" ) ); idLib::Printf( "Writing %s\n", generatedFileName.c_str() ); model->WriteBinaryModel( outputFile ); } /* else { idLib::Printf( "loaded binary model %s from file %s\n", model->Name(), generatedFileName.c_str() ); } */ } } // Not one of the known formats if( model == NULL ) { if( extension.Length() ) { common->Warning( "unknown model type '%s'", canonical.c_str() ); } if( !createIfNotFound ) { return NULL; } idRenderModelStatic* smodel = new( TAG_MODEL ) idRenderModelStatic; smodel->InitEmpty( canonical ); smodel->MakeDefaultModel(); model = smodel; } if( cvarSystem->GetCVarBool( "fs_buildresources" ) ) { fileSystem->AddModelPreload( canonical ); } model->SetLevelLoadReferenced( true ); if( !createIfNotFound && model->IsDefaultModel() ) { delete model; model = NULL; return NULL; } if( cvarSystem->GetCVarBool( "fs_buildgame" ) ) { fileSystem->AddModelPreload( model->Name() ); } AddModel( model ); return model; }
/* ======================== ConvertCG2GLSL ======================== */ idStr ConvertCG2GLSL( const idStr & in, const char * name, bool isVertexProgram, idStr & uniforms ) { idStr program; program.ReAllocate( in.Length() * 2, false ); idList< inOutVariable_t, TAG_RENDERPROG > varsIn; idList< inOutVariable_t, TAG_RENDERPROG > varsOut; idList< idStr > uniformList; idLexer src( LEXFL_NOFATALERRORS ); src.LoadMemory( in.c_str(), in.Length(), name ); bool inMain = false; const char * uniformArrayName = isVertexProgram ? VERTEX_UNIFORM_ARRAY_NAME : FRAGMENT_UNIFORM_ARRAY_NAME; char newline[128] = { "\n" }; idToken token; while ( src.ReadToken( &token ) ) { // check for uniforms while ( token == "uniform" && src.CheckTokenString( "float4" ) ) { src.ReadToken( &token ); uniformList.Append( token ); // strip ': register()' from uniforms if ( src.CheckTokenString( ":" ) ) { if ( src.CheckTokenString( "register" ) ) { src.SkipUntilString( ";" ); } } src.ReadToken( & token ); } // convert the in/out structs if ( token == "struct" ) { if ( src.CheckTokenString( "VS_IN" ) ) { ParseInOutStruct( src, AT_VS_IN, varsIn ); program += "\n\n"; for ( int i = 0; i < varsIn.Num(); i++ ) { if ( varsIn[i].declareInOut ) { program += "in " + varsIn[i].type + " " + varsIn[i].nameGLSL + ";\n"; } } continue; } else if ( src.CheckTokenString( "VS_OUT" ) ) { ParseInOutStruct( src, AT_VS_OUT, varsOut ); program += "\n"; for ( int i = 0; i < varsOut.Num(); i++ ) { if ( varsOut[i].declareInOut ) { program += "out " + varsOut[i].type + " " + varsOut[i].nameGLSL + ";\n"; } } continue; } else if ( src.CheckTokenString( "PS_IN" ) ) { ParseInOutStruct( src, AT_PS_IN, varsIn ); program += "\n\n"; for ( int i = 0; i < varsIn.Num(); i++ ) { if ( varsIn[i].declareInOut ) { program += "in " + varsIn[i].type + " " + varsIn[i].nameGLSL + ";\n"; } } inOutVariable_t var; var.type = "vec4"; var.nameCg = "position"; var.nameGLSL = "gl_FragCoord"; varsIn.Append( var ); continue; } else if ( src.CheckTokenString( "PS_OUT" ) ) { ParseInOutStruct( src, AT_PS_OUT, varsOut ); program += "\n"; for ( int i = 0; i < varsOut.Num(); i++ ) { if ( varsOut[i].declareInOut ) { program += "out " + varsOut[i].type + " " + varsOut[i].nameGLSL + ";\n"; } } continue; } } // strip 'static' if ( token == "static" ) { program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" ); src.SkipWhiteSpace( true ); // remove white space between 'static' and the next token continue; } // strip ': register()' from uniforms if ( token == ":" ) { if ( src.CheckTokenString( "register" ) ) { src.SkipUntilString( ";" ); program += ";"; continue; } } // strip in/program parameters from main if ( token == "void" && src.CheckTokenString( "main" ) ) { src.ExpectTokenString( "(" ); while( src.ReadToken( &token ) ) { if ( token == ")" ) { break; } } program += "\nvoid main()"; inMain = true; continue; } // strip 'const' from local variables in main() if ( token == "const" && inMain ) { program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" ); src.SkipWhiteSpace( true ); // remove white space between 'const' and the next token continue; } // maintain indentation if ( token == "{" ) { program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" ); program += "{"; int len = Min( idStr::Length( newline ) + 1, (int)sizeof( newline ) - 1 ); newline[len - 1] = '\t'; newline[len - 0] = '\0'; continue; } if ( token == "}" ) { int len = Max( idStr::Length( newline ) - 1, 0 ); newline[len] = '\0'; program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" ); program += "}"; continue; } // check for a type conversion bool foundType = false; for ( int i = 0; typeConversion[i].typeCG != NULL; i++ ) { if ( token.Cmp( typeConversion[i].typeCG ) == 0 ) { program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" ); program += typeConversion[i].typeGLSL; foundType = true; break; } } if ( foundType ) { continue; } if ( r_useUniformArrays.GetBool() ) { // check for uniforms that need to be converted to the array bool isUniform = false; for ( int i = 0; i < uniformList.Num(); i++ ) { if ( token == uniformList[i] ) { program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" ); program += va( "%s[%d /* %s */]", uniformArrayName, i, uniformList[i].c_str() ); isUniform = true; break; } } if ( isUniform ) { continue; } } // check for input/output parameters if ( src.CheckTokenString( "." ) ) { if ( token == "vertex" || token == "fragment" ) { idToken member; src.ReadToken( &member ); bool foundInOut = false; for ( int i = 0; i < varsIn.Num(); i++ ) { if ( member.Cmp( varsIn[i].nameCg ) == 0 ) { program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" ); program += varsIn[i].nameGLSL; foundInOut = true; break; } } if ( !foundInOut ) { src.Error( "invalid input parameter %s.%s", token.c_str(), member.c_str() ); program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" ); program += token; program += "."; program += member; } continue; } if ( token == "result" ) { idToken member; src.ReadToken( &member ); bool foundInOut = false; for ( int i = 0; i < varsOut.Num(); i++ ) { if ( member.Cmp( varsOut[i].nameCg ) == 0 ) { program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" ); program += varsOut[i].nameGLSL; foundInOut = true; break; } } if ( !foundInOut ) { src.Error( "invalid output parameter %s.%s", token.c_str(), member.c_str() ); program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" ); program += token; program += "."; program += member; } continue; } program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" ); program += token; program += "."; continue; } // check for a function conversion bool foundFunction = false; for ( int i = 0; builtinConversion[i].nameCG != NULL; i++ ) { if ( token.Cmp( builtinConversion[i].nameCG ) == 0 ) { program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" ); program += builtinConversion[i].nameGLSL; foundFunction = true; break; } } if ( foundFunction ) { continue; } program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" ); program += token; } idStr out; if ( isVertexProgram ) { out.ReAllocate( idStr::Length( vertexInsert ) + in.Length() * 2, false ); out += vertexInsert; } else { out.ReAllocate( idStr::Length( fragmentInsert ) + in.Length() * 2, false ); out += fragmentInsert; } if ( uniformList.Num() > 0 ) { if ( r_useUniformArrays.GetBool() ) { out += va( "\nuniform vec4 %s[%d];\n", uniformArrayName, uniformList.Num() ); } else { out += "\n"; for ( int i = 0; i < uniformList.Num(); i++ ) { out += "uniform vec4 "; out += uniformList[i]; out += ";\n"; } } } out += program; for ( int i = 0; i < uniformList.Num(); i++ ) { uniforms += uniformList[i]; uniforms += "\n"; } uniforms += "\n"; return out; }
/* ======================== idSoundSample_XAudio2::Load ======================== */ void idSoundSample_XAudio2::LoadResource() { FreeData(); if( idStr::Icmpn( GetName(), "_default", 8 ) == 0 ) { MakeDefault(); return; } if( s_noSound.GetBool() ) { MakeDefault(); return; } loaded = false; for( int i = 0; i < 2; i++ ) { idStrStatic< MAX_OSPATH > sampleName = GetName(); if( ( i == 0 ) && !sampleName.Replace( "/vo/", va( "/vo/%s/", sys_lang.GetString() ) ) ) { i++; } idStrStatic< MAX_OSPATH > generatedName = "generated/"; generatedName.Append( sampleName ); { if( s_useCompression.GetBool() ) { sampleName.Append( ".msadpcm" ); } else { sampleName.Append( ".wav" ); } generatedName.Append( ".idwav" ); } loaded = LoadGeneratedSample( generatedName ) || LoadWav( sampleName ); if( !loaded && s_useCompression.GetBool() ) { sampleName.SetFileExtension( "wav" ); loaded = LoadWav( sampleName ); } if( loaded ) { if( cvarSystem->GetCVarBool( "fs_buildresources" ) ) { fileSystem->AddSamplePreload( GetName() ); WriteAllSamples( GetName() ); if( sampleName.Find( "/vo/" ) >= 0 ) { for( int i = 0; i < Sys_NumLangs(); i++ ) { const char* lang = Sys_Lang( i ); if( idStr::Icmp( lang, ID_LANG_ENGLISH ) == 0 ) { continue; } idStrStatic< MAX_OSPATH > locName = GetName(); locName.Replace( "/vo/", va( "/vo/%s/", Sys_Lang( i ) ) ); WriteAllSamples( locName ); } } } return; } } if( !loaded ) { // make it default if everything else fails MakeDefault(); } return; }
/* ======================== idSoundHardware_XAudio2::Init ======================== */ void idSoundHardware_XAudio2::Init() { cmdSystem->AddCommand( "listDevices", listDevices_f, 0, "Lists the connected sound devices", NULL ); DWORD xAudioCreateFlags = 0; // RB: not available on Windows 8 SDK #if !defined(USE_WINRT) && defined(_DEBUG) xAudioCreateFlags |= XAUDIO2_DEBUG_ENGINE; #endif // RB end XAUDIO2_PROCESSOR xAudioProcessor = XAUDIO2_DEFAULT_PROCESSOR; // RB: not available on Windows 8 SDK if ( FAILED( XAudio2Create( &pXAudio2, xAudioCreateFlags, xAudioProcessor ) ) ){ #if !defined(USE_WINRT) && defined(_DEBUG) if ( xAudioCreateFlags & XAUDIO2_DEBUG_ENGINE ) { // in case the debug engine isn't installed xAudioCreateFlags &= ~XAUDIO2_DEBUG_ENGINE; if ( FAILED( XAudio2Create( &pXAudio2, xAudioCreateFlags, xAudioProcessor ) ) ) { idLib::FatalError( "Failed to create XAudio2 engine. Try installing the latest DirectX." ); return; } } else #endif // RB end { idLib::FatalError( "Failed to create XAudio2 engine. Try installing the latest DirectX." ); return; } } #ifdef _DEBUG XAUDIO2_DEBUG_CONFIGURATION debugConfiguration = { 0 }; debugConfiguration.TraceMask = XAUDIO2_LOG_WARNINGS; debugConfiguration.BreakMask = XAUDIO2_LOG_ERRORS; pXAudio2->SetDebugConfiguration( &debugConfiguration ); #endif // Register the sound engine callback pXAudio2->RegisterForCallbacks( &soundEngineCallback ); soundEngineCallback.hardware = this; DWORD outputSampleRate = 44100; // Max( (DWORD)XAUDIO2FX_REVERB_MIN_FRAMERATE, Min( (DWORD)XAUDIO2FX_REVERB_MAX_FRAMERATE, deviceDetails.OutputFormat.Format.nSamplesPerSec ) ); idCmdArgs args; listDevices_f( args ); // RB: not available on Windows 8 SDK #if defined(USE_WINRT) //(_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) AudioDevice defaultDevice; std::vector<AudioDevice> vAudioDevices = EnumerateAudioDevices(&defaultDevice); if (!vAudioDevices.empty()) { AudioDevice selectedDevice; int preferredDevice = s_device.GetInteger(); bool validPreference = (preferredDevice >= 0 && preferredDevice < (int)vAudioDevices.size()); // Do we select a device automatically? if (validPreference) { // Use the user's selected device selectedDevice = vAudioDevices[preferredDevice]; } else if (!defaultDevice.id.empty()) { // Fall back to the default device if there is one selectedDevice = defaultDevice; } else { // Fall back to first device selectedDevice = vAudioDevices[0]; } if (SUCCEEDED(pXAudio2->CreateMasteringVoice(&pMasterVoice, XAUDIO2_DEFAULT_CHANNELS, outputSampleRate, 0, selectedDevice.id.c_str(), NULL, AudioCategory_GameEffects))) { XAUDIO2_VOICE_DETAILS deviceDetails; pMasterVoice->GetVoiceDetails(&deviceDetails); pMasterVoice->SetVolume(DBtoLinear(s_volume_dB.GetFloat())); outputChannels = deviceDetails.InputChannels; DWORD win8_channelMask; pMasterVoice->GetChannelMask(&win8_channelMask); channelMask = (unsigned int)win8_channelMask; idLib::Printf( "Using device %S\n", selectedDevice.name ); } else { idLib::Warning("Failed to create master voice"); pXAudio2->Release(); pXAudio2 = NULL; return; } } #else UINT32 deviceCount = 0; if( pXAudio2->GetDeviceCount( &deviceCount ) != S_OK || deviceCount == 0 ) { idLib::Warning( "No audio devices found" ); pXAudio2->Release(); pXAudio2 = NULL; return; } int preferredDevice = s_device.GetInteger(); if( preferredDevice < 0 || preferredDevice >= ( int )deviceCount ) { int preferredChannels = 0; for( unsigned int i = 0; i < deviceCount; i++ ) { XAUDIO2_DEVICE_DETAILS deviceDetails; if( pXAudio2->GetDeviceDetails( i, &deviceDetails ) != S_OK ) { continue; } if( deviceDetails.Role & DefaultGameDevice ) { // if we find a device the user marked as their preferred 'game' device, then always use that preferredDevice = i; preferredChannels = deviceDetails.OutputFormat.Format.nChannels; break; } if( deviceDetails.OutputFormat.Format.nChannels > preferredChannels ) { preferredDevice = i; preferredChannels = deviceDetails.OutputFormat.Format.nChannels; } } } idLib::Printf( "Using device %d\n", preferredDevice ); XAUDIO2_DEVICE_DETAILS deviceDetails; if( pXAudio2->GetDeviceDetails( preferredDevice, &deviceDetails ) != S_OK ) { // One way this could happen is if a device is removed between the loop and this line of code // Highly unlikely but possible idLib::Warning( "Failed to get device details" ); pXAudio2->Release(); pXAudio2 = NULL; return; } if( FAILED( pXAudio2->CreateMasteringVoice( &pMasterVoice, XAUDIO2_DEFAULT_CHANNELS, outputSampleRate, 0, preferredDevice, NULL ) ) ) { idLib::Warning( "Failed to create master voice" ); pXAudio2->Release(); pXAudio2 = NULL; return; } pMasterVoice->SetVolume( DBtoLinear( s_volume_dB.GetFloat() ) ); outputChannels = deviceDetails.OutputFormat.Format.nChannels; channelMask = deviceDetails.OutputFormat.dwChannelMask; #endif // #if (_WIN32_WINNT < 0x0602 /*_WIN32_WINNT_WIN8*/) idSoundVoice::InitSurround( outputChannels, channelMask ); // --------------------- // Initialize the Doom classic sound system. // --------------------- I_InitSoundHardware( outputChannels, channelMask ); // --------------------- // Create VU Meter Effect // --------------------- IUnknown * vuMeter = NULL; XAudio2CreateVolumeMeter( &vuMeter, 0 ); XAUDIO2_EFFECT_DESCRIPTOR descriptor; descriptor.InitialState = true; descriptor.OutputChannels = outputChannels; descriptor.pEffect = vuMeter; XAUDIO2_EFFECT_CHAIN chain; chain.EffectCount = 1; chain.pEffectDescriptors = &descriptor; pMasterVoice->SetEffectChain( &chain ); vuMeter->Release(); // --------------------- // Create VU Meter Graph // --------------------- vuMeterRMS = console->CreateGraph( outputChannels ); vuMeterPeak = console->CreateGraph( outputChannels ); vuMeterRMS->Enable( false ); vuMeterPeak->Enable( false ); memset( vuMeterPeakTimes, 0, sizeof( vuMeterPeakTimes ) ); vuMeterPeak->SetFillMode( idDebugGraph::GRAPH_LINE ); vuMeterPeak->SetBackgroundColor( idVec4( 0.0f, 0.0f, 0.0f, 0.0f ) ); vuMeterRMS->AddGridLine( 0.500f, idVec4( 0.5f, 0.5f, 0.5f, 1.0f ) ); vuMeterRMS->AddGridLine( 0.250f, idVec4( 0.5f, 0.5f, 0.5f, 1.0f ) ); vuMeterRMS->AddGridLine( 0.125f, idVec4( 0.5f, 0.5f, 0.5f, 1.0f ) ); const char * channelNames[] = { "L", "R", "C", "S", "Lb", "Rb", "Lf", "Rf", "Cb", "Ls", "Rs" }; for ( int i = 0, ci = 0; ci < sizeof( channelNames ) / sizeof( channelNames[0] ); ci++ ) { if ( ( channelMask & BIT( ci ) ) == 0 ) { continue; } vuMeterRMS->SetLabel( i, channelNames[ ci ] ); i++; } // --------------------- // Create submix buffer // --------------------- if ( FAILED( pXAudio2->CreateSubmixVoice( &pSubmixVoice, 1, outputSampleRate, 0, 0, NULL, NULL ) ) ) { idLib::FatalError( "Failed to create submix voice" ); } // XAudio doesn't really impose a maximum number of voices voices.SetNum( voices.Max() ); freeVoices.SetNum( voices.Max() ); zombieVoices.SetNum( 0 ); for ( int i = 0; i < voices.Num(); i++ ) { freeVoices[i] = &voices[i]; } // RB end }
/* ================= idUsercmdGenLocal::MouseMove ================= */ void idUsercmdGenLocal::MouseMove( void ) { float mx, my, strafeMx, strafeMy; static int history[8][2]; static int historyCounter; int i; history[historyCounter&7][0] = mouseDx; history[historyCounter&7][1] = mouseDy; // allow mouse movement to be smoothed together int smooth = m_smooth.GetInteger(); if ( smooth < 1 ) { smooth = 1; } if ( smooth > 8 ) { smooth = 8; } mx = 0; my = 0; for ( i = 0 ; i < smooth ; i++ ) { mx += history[ ( historyCounter - i + 8 ) & 7 ][0]; my += history[ ( historyCounter - i + 8 ) & 7 ][1]; } mx /= smooth; my /= smooth; // use a larger smoothing for strafing smooth = m_strafeSmooth.GetInteger(); if ( smooth < 1 ) { smooth = 1; } if ( smooth > 8 ) { smooth = 8; } strafeMx = 0; strafeMy = 0; for ( i = 0 ; i < smooth ; i++ ) { strafeMx += history[ ( historyCounter - i + 8 ) & 7 ][0]; strafeMy += history[ ( historyCounter - i + 8 ) & 7 ][1]; } strafeMx /= smooth; strafeMy /= smooth; historyCounter++; if ( idMath::Fabs( mx ) > 1000 || idMath::Fabs( my ) > 1000 ) { Sys_DebugPrintf( "idUsercmdGenLocal::MouseMove: Ignoring ridiculous mouse delta.\n" ); mx = my = 0; } mx *= sensitivity.GetFloat(); my *= sensitivity.GetFloat(); if ( m_showMouseRate.GetBool() ) { Sys_DebugPrintf( "[%3i %3i = %5.1f %5.1f = %5.1f %5.1f] ", mouseDx, mouseDy, mx, my, strafeMx, strafeMy ); } mouseDx = 0; mouseDy = 0; if ( !strafeMx && !strafeMy ) { return; } if ( ButtonState( UB_STRAFE ) || !( cmd.buttons & BUTTON_MLOOK ) ) { // add mouse X/Y movement to cmd strafeMx *= m_strafeScale.GetFloat(); strafeMy *= m_strafeScale.GetFloat(); // clamp as a vector, instead of separate floats float len = sqrt( strafeMx * strafeMx + strafeMy * strafeMy ); if ( len > 127 ) { strafeMx = strafeMx * 127 / len; strafeMy = strafeMy * 127 / len; } } if ( !ButtonState( UB_STRAFE ) ) { viewangles[YAW] -= m_yaw.GetFloat() * mx; } else { cmd.rightmove = idMath::ClampChar( (int)(cmd.rightmove + strafeMx) ); } if ( !ButtonState( UB_STRAFE ) && ( cmd.buttons & BUTTON_MLOOK ) ) { viewangles[PITCH] += m_pitch.GetFloat() * my; } else { cmd.forwardmove = idMath::ClampChar( (int)(cmd.forwardmove - strafeMy) ); } }
/* ======================== idAimAssist::FindAimAssistTarget ======================== */ idEntity* idAimAssist::FindAimAssistTarget( idVec3& targetPos ) { if ( player == NULL ) { return NULL; } //TO DO: Make this faster //TO DO: Defer Traces idEntity * optimalTarget = NULL; float currentBestScore = -idMath::INFINITY; targetPos = vec3_zero; idVec3 cameraPos; idMat3 cameraAxis; player->GetViewPos( cameraPos, cameraAxis ); float maxDistanceSquared = Square( aa_targetMaxDistance.GetFloat() ); idVec3 dirToTarget; float distanceToTargetSquared; idVec3 primaryTargetPos; idVec3 secondaryTargetPos; for ( idEntity * entity = gameLocal.aimAssistEntities.Next(); entity != NULL; entity = entity->aimAssistNode.Next() ) { if ( !entity->IsActive() ) { continue; } if ( entity->IsHidden() ) { continue; } if ( entity->IsType( idActor::Type ) ) { idActor * actor = static_cast<idActor *>( entity ); if ( actor->team == player->team ) { // In DM, LMS, and Tourney, all players are on the same team if ( gameLocal.gameType == GAME_CTF || gameLocal.gameType == GAME_TDM || gameLocal.gameType == GAME_SP ) { continue; } } } if ( entity->IsType( idAI::Type ) ) { idAI * aiEntity = static_cast<idAI *>( entity ); if ( aiEntity->ReactionTo( player ) == ATTACK_IGNORE ) { continue; } } // check whether we have a valid target position for this entity - skip it if we don't if ( !ComputeTargetPos( entity, primaryTargetPos, secondaryTargetPos ) ) { continue; } // is it close enough to us dirToTarget = primaryTargetPos-cameraPos; distanceToTargetSquared = dirToTarget.LengthSqr(); if ( distanceToTargetSquared > maxDistanceSquared ) { continue; } // Compute a score in the range of 0..1 for how much are looking towards the target. idVec3 forward = cameraAxis[ 0 ]; forward.Normalize(); dirToTarget.Normalize(); float ViewDirDotTargetDir = idMath::ClampFloat( -1.0f, 1.0f, forward * dirToTarget ); // compute the dot and clamp to account for floating point error // throw out anything thats outside of weapon's global FOV. if ( ViewDirDotTargetDir < 0.0f ) { continue; } // to be consistent we always use the primaryTargetPos to compute the score for this entity float computedScore = ComputeEntityAimAssistScore( primaryTargetPos, cameraPos, cameraAxis ); // check if the current score beats our current best score and we have line of sight to it. if ( computedScore > currentBestScore ) { // determine if the current target is in our line of sight trace_t tr; gameLocal.clip.TracePoint( tr, cameraPos, primaryTargetPos, MASK_MONSTERSOLID, player ); // did our trace fail? if ( ( ( tr.fraction < 1.0f ) && ( tr.c.entityNum != entity->entityNumber ) ) || ( tr.fraction >= 1.0f ) ) { // if the collision test failed for the primary position -- check the secondary position trace_t tr2; gameLocal.clip.TracePoint( tr2, cameraPos, secondaryTargetPos, MASK_MONSTERSOLID, player ); if ( ( ( tr2.fraction < 1.0f ) && ( tr2.c.entityNum != entity->entityNumber ) ) || ( tr2.fraction >= 1.0f ) ) { // if the secondary position is also not visible then give up continue; } // we can see the secondary target position so we should consider this entity but use // the secondary position as the target position targetPos = secondaryTargetPos; } else { targetPos = primaryTargetPos; } // if we got here then this is our new best score optimalTarget = entity; currentBestScore = computedScore; } } return optimalTarget; }
/* ================ idServerScan::IsFiltered ================ */ bool idServerScan::IsFiltered( const networkServer_t server ) { int i; const idKeyValue *keyval; // OS support filter #if 0 // filter out pure servers that won't provide checksumed game code for client OS keyval = server.serverInfo.FindKey( "si_pure" ); if ( keyval && !idStr::Cmp( keyval->GetValue(), "1" ) ) { if ( ( server.OSMask & ( 1 << BUILD_OS_ID ) ) == 0 ) { return true; } } #else if ( ( server.OSMask & ( 1 << BUILD_OS_ID ) ) == 0 ) { return true; } #endif // password filter keyval = server.serverInfo.FindKey( "si_usePass" ); if ( keyval && gui_filter_password.GetInteger() == 1 ) { // show passworded only if ( keyval->GetValue()[ 0 ] == '0' ) { return true; } } else if ( keyval && gui_filter_password.GetInteger() == 2 ) { // show no password only if ( keyval->GetValue()[ 0 ] != '0' ) { return true; } } // players filter keyval = server.serverInfo.FindKey( "si_maxPlayers" ); if ( keyval ) { if ( gui_filter_players.GetInteger() == 1 && server.clients == atoi( keyval->GetValue() ) ) { return true; } else if ( gui_filter_players.GetInteger() == 2 && ( !server.clients || server.clients == atoi( keyval->GetValue() ) ) ) { return true; } } // gametype filter keyval = server.serverInfo.FindKey( "si_gameType" ); if ( keyval && gui_filter_gameType.GetInteger() ) { i = 0; while ( l_gameTypes[ i ] ) { if ( !keyval->GetValue().Icmp( l_gameTypes[ i ] ) ) { break; } i++; } if ( l_gameTypes[ i ] && i != gui_filter_gameType.GetInteger() -1 ) { return true; } } // idle server filter keyval = server.serverInfo.FindKey( "si_idleServer" ); if ( keyval && !gui_filter_idle.GetInteger() ) { if ( !keyval->GetValue().Icmp( "1" ) ) { return true; } } // autofilter D3XP games if the user does not has the XP installed if(!fileSystem->HasD3XP() && !idStr::Icmp(server.serverInfo.GetString( "fs_game" ), "d3xp")) { return true; } // filter based on the game doom or XP if(gui_filter_game.GetInteger() == 1) { //Only Doom if(idStr::Icmp(server.serverInfo.GetString("fs_game"), "")) { return true; } } else if(gui_filter_game.GetInteger() == 2) { //Only D3XP if(idStr::Icmp(server.serverInfo.GetString("fs_game"), "d3xp")) { return true; } } return false; }
/* =============== idSoundShader::ParseShader =============== */ bool idSoundShader::ParseShader( idLexer &src ) { idToken token; parms.minDistance = 1; parms.maxDistance = 10; parms.volume = 1; parms.shakes = 0; parms.soundShaderFlags = 0; parms.soundClass = 0; speakerMask = 0; altSound = NULL; entries.Clear(); while ( 1 ) { if ( !src.ExpectAnyToken( &token ) ) { return false; } // end of definition else if ( token == "}" ) { break; } // minimum number of sounds else if ( !token.Icmp( "minSamples" ) ) { src.ParseInt(); } // description else if ( !token.Icmp( "description" ) ) { src.ReadTokenOnLine( &token ); } // mindistance else if ( !token.Icmp( "mindistance" ) ) { parms.minDistance = src.ParseFloat(); } // maxdistance else if ( !token.Icmp( "maxdistance" ) ) { parms.maxDistance = src.ParseFloat(); } // shakes screen else if ( !token.Icmp( "shakes" ) ) { src.ExpectAnyToken( &token ); if ( token.type == TT_NUMBER ) { parms.shakes = token.GetFloatValue(); } else { src.UnreadToken( &token ); parms.shakes = 1.0f; } } // reverb else if ( !token.Icmp( "reverb" ) ) { src.ParseFloat(); if ( !src.ExpectTokenString( "," ) ) { src.FreeSource(); return false; } src.ParseFloat(); // no longer supported } // volume else if ( !token.Icmp( "volume" ) ) { parms.volume = src.ParseFloat(); } // leadinVolume is used to allow light breaking leadin sounds to be much louder than the broken loop else if ( !token.Icmp( "leadinVolume" ) ) { leadinVolume = src.ParseFloat(); leadin = true; } // speaker mask else if ( !token.Icmp( "mask_center" ) ) { speakerMask |= 1<<SPEAKER_CENTER; } // speaker mask else if ( !token.Icmp( "mask_left" ) ) { speakerMask |= 1<<SPEAKER_LEFT; } // speaker mask else if ( !token.Icmp( "mask_right" ) ) { speakerMask |= 1<<SPEAKER_RIGHT; } // speaker mask else if ( !token.Icmp( "mask_backright" ) ) { speakerMask |= 1<<SPEAKER_BACKRIGHT; } // speaker mask else if ( !token.Icmp( "mask_backleft" ) ) { speakerMask |= 1<<SPEAKER_BACKLEFT; } // speaker mask else if ( !token.Icmp( "mask_lfe" ) ) { speakerMask |= 1<<SPEAKER_LFE; } // soundClass else if ( !token.Icmp( "soundClass" ) ) { parms.soundClass = src.ParseInt(); if ( parms.soundClass < 0 || parms.soundClass >= SOUND_MAX_CLASSES ) { src.Warning( "SoundClass out of range" ); return false; } } // altSound else if ( !token.Icmp( "altSound" ) ) { if ( !src.ExpectAnyToken( &token ) ) { return false; } altSound = declManager->FindSound( token.c_str() ); } // ordered else if ( !token.Icmp( "ordered" ) ) { // no longer supported } // no_dups else if ( !token.Icmp( "no_dups" ) ) { parms.soundShaderFlags |= SSF_NO_DUPS; } // no_flicker else if ( !token.Icmp( "no_flicker" ) ) { parms.soundShaderFlags |= SSF_NO_FLICKER; } // plain else if ( !token.Icmp( "plain" ) ) { // no longer supported } // looping else if ( !token.Icmp( "looping" ) ) { parms.soundShaderFlags |= SSF_LOOPING; } // no occlusion else if ( !token.Icmp( "no_occlusion" ) ) { parms.soundShaderFlags |= SSF_NO_OCCLUSION; } // private else if ( !token.Icmp( "private" ) ) { parms.soundShaderFlags |= SSF_PRIVATE_SOUND; } // antiPrivate else if ( !token.Icmp( "antiPrivate" ) ) { parms.soundShaderFlags |= SSF_ANTI_PRIVATE_SOUND; } // once else if ( !token.Icmp( "playonce" ) ) { parms.soundShaderFlags |= SSF_PLAY_ONCE; } // global else if ( !token.Icmp( "global" ) ) { parms.soundShaderFlags |= SSF_GLOBAL; } // unclamped else if ( !token.Icmp( "unclamped" ) ) { parms.soundShaderFlags |= SSF_UNCLAMPED; } // omnidirectional else if ( !token.Icmp( "omnidirectional" ) ) { parms.soundShaderFlags |= SSF_OMNIDIRECTIONAL; } else if ( !token.Icmp( "onDemand" ) ) { // no longer loading sounds on demand } // the wave files else if ( !token.Icmp( "leadin" ) ) { leadin = true; } else if ( token.Find( ".wav", false ) != -1 || token.Find( ".ogg", false ) != -1 ) { if ( token.IcmpPrefixPath( "sound/vo/" ) == 0 || token.IcmpPrefixPath( "sound/guis/" ) == 0 ) { parms.soundShaderFlags |= SSF_VO; } if ( token.IcmpPrefixPath( "sound/musical/" ) == 0 ) { parms.soundShaderFlags |= SSF_MUSIC; } // add to the wav list if ( s_maxSamples.GetInteger() == 0 || ( s_maxSamples.GetInteger() > 0 && entries.Num() < s_maxSamples.GetInteger() ) ) { entries.Append( soundSystemLocal.LoadSample( token.c_str() ) ); } } else { src.Warning( "unknown token '%s'", token.c_str() ); return false; } } return true; }
/* ========== idAudioHardwareOSX::Initialize ========== */ bool idAudioHardwareOSX::Initialize( ) { UInt32 size; OSStatus status; int i, deviceCount; AudioDeviceID *deviceList; char buf[ 1024 ]; status = AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices, &size, NULL ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioHardwareGetPropertyInfo kAudioHardwarePropertyDevices failed. status: %s", ExtractStatus( status ) ); InitFailed(); return false; } deviceCount = size / sizeof( AudioDeviceID ); if ( !deviceCount ) { common->Printf( "No sound device found\n" ); InitFailed(); return false; } deviceList = (AudioDeviceID*)malloc( size ); status = AudioHardwareGetProperty( kAudioHardwarePropertyDevices, &size, deviceList ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioHardwareGetProperty kAudioHardwarePropertyDevices failed. status: %s", ExtractStatus( status ) ); free( deviceList ); InitFailed(); return false; } common->Printf( "%d sound device(s)\n", deviceCount ); for( i = 0; i < deviceCount; i++ ) { size = 1024; status = AudioDeviceGetProperty( deviceList[ i ], 0, false, kAudioDevicePropertyDeviceName, &size, buf ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceGetProperty kAudioDevicePropertyDeviceName %d failed. status: %s", i, ExtractStatus( status ) ); free( deviceList ); InitFailed(); return false; } common->Printf( " %d: ID %d, %s - ", i, deviceList[ i ], buf ); size = 1024; status = AudioDeviceGetProperty( deviceList[ i ], 0, false, kAudioDevicePropertyDeviceManufacturer, &size, buf ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceGetProperty kAudioDevicePropertyDeviceManufacturer %d failed. status: %s", i, ExtractStatus( status ) ); free( deviceList ); InitFailed(); return false; } common->Printf( "%s\n", buf ); } if ( s_device.GetInteger() != -1 && s_device.GetInteger() < deviceCount ) { selectedDevice = deviceList[ s_device.GetInteger() ]; common->Printf( "s_device: device ID %d\n", selectedDevice ); } else { size = sizeof( selectedDevice ); status = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice, &size, &selectedDevice ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioHardwareGetProperty kAudioHardwarePropertyDefaultOutputDevice failed. status: %s", ExtractStatus( status ) ); free( deviceList ); InitFailed(); return false; } common->Printf( "select default device, ID %d\n", selectedDevice ); } free( deviceList ); deviceList = NULL; /* // setup a listener to watch for changes to properties status = AudioDeviceAddPropertyListener( selectedDevice, 0, false, kAudioDeviceProcessorOverload, DeviceListener, this ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceAddPropertyListener kAudioDeviceProcessorOverload failed. status: %s", ExtractStatus( status ) ); InitFailed(); return; } */ Float64 sampleRate; size = sizeof( sampleRate ); status = AudioDeviceGetProperty( selectedDevice, 0, false, kAudioDevicePropertyNominalSampleRate, &size, &sampleRate ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceGetProperty %d kAudioDevicePropertyNominalSampleRate failed. status: %s", selectedDevice, ExtractStatus( status ) ); InitFailed(); return false; } common->Printf( "current nominal rate: %g\n", sampleRate ); if ( sampleRate != PRIMARYFREQ ) { GetAvailableNominalSampleRates(); sampleRate = PRIMARYFREQ; common->Printf( "setting rate to: %g\n", sampleRate ); status = AudioDeviceSetProperty( selectedDevice, NULL, 0, false, kAudioDevicePropertyNominalSampleRate, size, &sampleRate ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceSetProperty %d kAudioDevicePropertyNominalSampleRate %g failed. status: %s", selectedDevice, sampleRate, ExtractStatus( status ) ); InitFailed(); return false; } } UInt32 frameSize; size = sizeof( UInt32 ); status = AudioDeviceGetProperty( selectedDevice, 0, false, kAudioDevicePropertyBufferFrameSize, &size, &frameSize ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceGetProperty %d kAudioDevicePropertyBufferFrameSize failed.status: %s", selectedDevice, ExtractStatus( status ) ); InitFailed(); return false; } common->Printf( "current frame size: %d\n", frameSize ); // get the allowed frame size range AudioValueRange frameSizeRange; size = sizeof( AudioValueRange ); status = AudioDeviceGetProperty( selectedDevice, 0, false, kAudioDevicePropertyBufferFrameSizeRange, &size, &frameSizeRange ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceGetProperty %d kAudioDevicePropertyBufferFrameSizeRange failed. status: %s", selectedDevice, ExtractStatus( status ) ); InitFailed(); return false; } common->Printf( "frame size allowed range: %g %g\n", frameSizeRange.mMinimum, frameSizeRange.mMaximum ); if ( frameSizeRange.mMaximum < MIXBUFFER_SAMPLES ) { common->Warning( "can't obtain the required frame size of %d bits", MIXBUFFER_SAMPLES ); InitFailed(); return false; } if ( frameSize != (unsigned int)MIXBUFFER_SAMPLES ) { frameSize = MIXBUFFER_SAMPLES; common->Printf( "setting frame size to: %d\n", frameSize ); size = sizeof( frameSize ); status = AudioDeviceSetProperty( selectedDevice, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, size, &frameSize ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceSetProperty %d kAudioDevicePropertyBufferFrameSize failed. status: %s", selectedDevice, ExtractStatus( status ) ); InitFailed(); return false; } } if ( idSoundSystemLocal::s_numberOfSpeakers.GetInteger() != 2 ) { common->Warning( "only stereo sound currently supported" ); idSoundSystemLocal::s_numberOfSpeakers.SetInteger( 2 ); } UInt32 channels[ 2 ]; size = 2 * sizeof( UInt32 ); status = AudioDeviceGetProperty( selectedDevice, 0, false, kAudioDevicePropertyPreferredChannelsForStereo, &size, &channels ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceGetProperty %d kAudioDevicePropertyPreferredChannelsForStereo failed. status: %s", selectedDevice, ExtractStatus( status ) ); InitFailed(); return false; } common->Printf( "using stereo channel IDs %d %d\n", channels[ 0 ], channels[ 1 ] ); status = AudioDeviceAddIOProc( selectedDevice, DeviceIOProc, NULL ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceAddIOProc failed. status: %s", ExtractStatus( status ) ); InitFailed(); return false; } activeIOProc = true; status = AudioDeviceStart( selectedDevice, DeviceIOProc ); if ( status != kAudioHardwareNoError ) { common->Warning( "AudioDeviceStart failed. status: %s", ExtractStatus( status ) ); InitFailed(); return false; } /* // allocate the mix buffer // it has the space for ROOM_SLICES_IN_BUFFER DeviceIOProc loops mixBufferSize = dwSpeakers * dwSampleSize * dwPrimaryBitRate * ROOM_SLICES_IN_BUFFER / 8; mixBuffer = malloc( mixBufferSize ); memset( mixBuffer, 0, mixBufferSize ); */ return true; }
/* ======================== idLobby::SendMigrationGameData ======================== */ void idLobby::SendMigrationGameData() { if( net_migration_disable.GetBool() ) { return; } if( sessionCB->GetState() != idSession::INGAME ) { return; } if( !migrationInfo.persistUntilGameEndsData.hasGameData ) { // Haven't been given any migration game data yet return; } const int now = Sys_Milliseconds(); if( nextSendMigrationGameTime > now ) { return; } byte packetData[ idPacketProcessor::MAX_MSG_SIZE ]; idBitMsg msg( packetData, sizeof( packetData ) ); // Write global data msg.WriteData( &migrationInfo.persistUntilGameEndsData.gameData, sizeof( migrationInfo.persistUntilGameEndsData.gameData ) ); msg.WriteByte( GetNumLobbyUsers() ); // Write user data for( int userIndex = 0; userIndex < GetNumLobbyUsers(); ++userIndex ) { lobbyUser_t* u = GetLobbyUser( userIndex ); if( u->IsDisconnected() || u->migrationGameData < 0 ) { continue; } u->lobbyUserID.WriteToMsg( msg ); msg.WriteData( migrationInfo.persistUntilGameEndsData.gameDataUser[ u->migrationGameData ], sizeof( migrationInfo.persistUntilGameEndsData.gameDataUser[ u->migrationGameData ] ) ); } // Send to 1 peer for( int i = 0; i < peers.Num(); i++ ) { int peerToSend = ( nextSendMigrationGamePeer + i ) % peers.Num(); if( peers[ peerToSend ].IsConnected() && peers[ peerToSend ].loaded ) { if( peers[ peerToSend ].packetProc->NumQueuedReliables() > idPacketProcessor::MAX_RELIABLE_QUEUE / 2 ) { // This is kind of a hack for development so we don't DC clients by sending them too many reliable migration messages // when they aren't responding. Doesn't seem like a horrible thing to have in a shipping product but is not necessary. NET_VERBOSE_PRINT( "NET: Skipping reliable game migration data msg because client reliable queue is > half full\n" ); } else { if( net_migration_debug.GetBool() ) { idLib::Printf( "NET: Sending migration game data to peer %d. size: %d\n", peerToSend, msg.GetSize() ); } QueueReliableMessage( peerToSend, RELIABLE_MIGRATION_GAME_DATA, msg.GetReadData(), msg.GetSize() ); } break; } } // Increment next send time / next send peer nextSendMigrationGamePeer++; if( nextSendMigrationGamePeer >= peers.Num() ) { nextSendMigrationGamePeer = 0; } nextSendMigrationGameTime = now + MIGRATION_GAME_DATA_INTERVAL_MS; }
/* ================================================================================================ idRenderProgManager::LoadGLSLProgram ================================================================================================ */ void idRenderProgManager::LoadGLSLProgram( const int programIndex, const int vertexShaderIndex, const int fragmentShaderIndex ) { glslProgram_t & prog = glslPrograms[programIndex]; if ( prog.progId != INVALID_PROGID ) { return; // Already loaded } GLuint vertexProgID = ( vertexShaderIndex != -1 ) ? vertexShaders[ vertexShaderIndex ].progId : INVALID_PROGID; GLuint fragmentProgID = ( fragmentShaderIndex != -1 ) ? fragmentShaders[ fragmentShaderIndex ].progId : INVALID_PROGID; const GLuint program = qglCreateProgram(); if ( program ) { if ( vertexProgID != INVALID_PROGID ) { qglAttachShader( program, vertexProgID ); } if ( fragmentProgID != INVALID_PROGID ) { qglAttachShader( program, fragmentProgID ); } // bind vertex attribute locations for ( int i = 0; attribsPC[i].glsl != NULL; i++ ) { if ( ( attribsPC[i].flags & AT_VS_IN ) != 0 ) { qglBindAttribLocation( program, attribsPC[i].bind, attribsPC[i].glsl ); } } qglLinkProgram( program ); int infologLength = 0; qglGetProgramiv( program, GL_INFO_LOG_LENGTH, &infologLength ); if ( infologLength > 1 ) { char * infoLog = (char *)malloc( infologLength ); int charsWritten = 0; qglGetProgramInfoLog( program, infologLength, &charsWritten, infoLog ); // catch the strings the ATI and Intel drivers output on success if ( strstr( infoLog, "Vertex shader(s) linked, fragment shader(s) linked." ) != NULL || strstr( infoLog, "No errors." ) != NULL ) { //idLib::Printf( "render prog %s from %s linked\n", GetName(), GetFileName() ); } else { idLib::Printf( "While linking GLSL program %d with vertexShader %s and fragmentShader %s\n", programIndex, ( vertexShaderIndex >= 0 ) ? vertexShaders[vertexShaderIndex].name.c_str() : "<Invalid>", ( fragmentShaderIndex >= 0 ) ? fragmentShaders[ fragmentShaderIndex ].name.c_str() : "<Invalid>" ); idLib::Printf( "%s\n", infoLog ); } free( infoLog ); } } int linked = GL_FALSE; qglGetProgramiv( program, GL_LINK_STATUS, &linked ); if ( linked == GL_FALSE ) { qglDeleteProgram( program ); idLib::Error( "While linking GLSL program %d with vertexShader %s and fragmentShader %s\n", programIndex, ( vertexShaderIndex >= 0 ) ? vertexShaders[vertexShaderIndex].name.c_str() : "<Invalid>", ( fragmentShaderIndex >= 0 ) ? fragmentShaders[ fragmentShaderIndex ].name.c_str() : "<Invalid>" ); return; } if ( r_useUniformArrays.GetBool() ) { prog.vertexUniformArray = qglGetUniformLocation( program, VERTEX_UNIFORM_ARRAY_NAME ); prog.fragmentUniformArray = qglGetUniformLocation( program, FRAGMENT_UNIFORM_ARRAY_NAME ); assert( prog.vertexUniformArray != -1 || vertexShaderIndex < 0 || vertexShaders[vertexShaderIndex].uniforms.Num() == 0 ); assert( prog.fragmentUniformArray != -1 || fragmentShaderIndex < 0 || fragmentShaders[fragmentShaderIndex].uniforms.Num() == 0 ); } else { // store the uniform locations after we have linked the GLSL program prog.uniformLocations.Clear(); for ( int i = 0; i < RENDERPARM_TOTAL; i++ ) { const char * parmName = GetGLSLParmName( i ); GLint loc = qglGetUniformLocation( program, parmName ); if ( loc != -1 ) { glslUniformLocation_t uniformLocation; uniformLocation.parmIndex = i; uniformLocation.uniformIndex = loc; prog.uniformLocations.Append( uniformLocation ); } } // store the USER uniform locations for ( int i = 0; i < MAX_GLSL_USER_PARMS; i++ ) { const char * parmName = GetGLSLParmName( RENDERPARM_USER + i ); GLint loc = qglGetUniformLocation( program, parmName ); if ( loc != -1 ) { glslUniformLocation_t uniformLocation; uniformLocation.parmIndex = RENDERPARM_USER + i; uniformLocation.uniformIndex = loc; prog.uniformLocations.Append( uniformLocation ); } } // sort the uniforms based on index prog.uniformLocations.SortWithTemplate( idSort_QuickUniforms() ); } // get the uniform buffer binding for skinning joint matrices GLint blockIndex = qglGetUniformBlockIndex( program, "matrices_ubo" ); if ( blockIndex != -1 ) { qglUniformBlockBinding( program, blockIndex, 0 ); } // set the texture unit locations once for the render program. We only need to do this once since we only link the program once qglUseProgram( program ); for ( int i = 0; i < MAX_PROG_TEXTURE_PARMS; ++i ) { GLint loc = qglGetUniformLocation( program, va( "samp%d", i ) ); if ( loc != -1 ) { qglUniform1i( loc, i ); } } idStr programName = vertexShaders[ vertexShaderIndex ].name; programName.StripFileExtension(); prog.name = programName; prog.progId = program; prog.fragmentShaderIndex = fragmentShaderIndex; prog.vertexShaderIndex = vertexShaderIndex; }
/* ======================== idSoundVoice_OpenAL::Start ======================== */ void idSoundVoice_OpenAL::Start( int offsetMS, int ssFlags ) { if( s_debugHardware.GetBool() ) { idLib::Printf( "%dms: %i starting %s @ %dms\n", Sys_Milliseconds(), openalSource, leadinSample ? leadinSample->GetName() : "<null>", offsetMS ); } if( !leadinSample ) { return; } if( !alIsSource( openalSource ) ) { return; } if( leadinSample->IsDefault() ) { idLib::Warning( "Starting defaulted sound sample %s", leadinSample->GetName() ); } bool flicker = ( ssFlags & SSF_NO_FLICKER ) == 0; if( flicker != hasVUMeter ) { hasVUMeter = flicker; /* if( flicker ) { IUnknown* vuMeter = NULL; if( XAudio2CreateVolumeMeter( &vuMeter, 0 ) == S_OK ) { XAUDIO2_EFFECT_DESCRIPTOR descriptor; descriptor.InitialState = true; descriptor.OutputChannels = leadinSample->NumChannels(); descriptor.pEffect = vuMeter; XAUDIO2_EFFECT_CHAIN chain; chain.EffectCount = 1; chain.pEffectDescriptors = &descriptor; pSourceVoice->SetEffectChain( &chain ); vuMeter->Release(); } } else { pSourceVoice->SetEffectChain( NULL ); } */ } assert( offsetMS >= 0 ); int offsetSamples = MsecToSamples( offsetMS, leadinSample->SampleRate() ); if( loopingSample == NULL && offsetSamples >= leadinSample->playLength ) { return; } RestartAt( offsetSamples ); Update(); UnPause(); }
/* ======================== StripDeadCode ======================== */ idStr StripDeadCode( const idStr & in, const char * name ) { if ( r_skipStripDeadCode.GetBool() ) { return in; } //idLexer src( LEXFL_NOFATALERRORS ); idParser src( LEXFL_NOFATALERRORS ); src.LoadMemory( in.c_str(), in.Length(), name ); src.AddDefine("PC"); idList< idCGBlock, TAG_RENDERPROG > blocks; blocks.SetNum( 100 ); idToken token; while ( !src.EndOfFile() ) { idCGBlock & block = blocks.Alloc(); // read prefix while ( src.ReadToken( &token ) ) { bool found = false; for ( int i = 0; i < numPrefixes; i++ ) { if ( token == prefixes[i] ) { found = true; break; } } if ( !found ) { for ( int i = 0; i < numTypes; i++ ) { if ( token == types[i] ) { found = true; break; } int typeLen = idStr::Length( types[i] ); if ( token.Cmpn( types[i], typeLen ) == 0 ) { for ( int j = 0; j < numTypePosts; j++ ) { if ( idStr::Cmp( token.c_str() + typeLen, typePosts[j] ) == 0 ) { found = true; break; } } if ( found ) { break; } } } } if ( found ) { if ( block.prefix.Length() > 0 && token.WhiteSpaceBeforeToken() ) { block.prefix += ' '; } block.prefix += token; } else { src.UnreadToken( &token ); break; } } if ( !src.ReadToken( &token ) ) { blocks.SetNum( blocks.Num() - 1 ); break; } block.name = token; if ( src.PeekTokenString( "=" ) || src.PeekTokenString( ":" ) || src.PeekTokenString( "[" ) ) { src.ReadToken( &token ); block.postfix = token; while ( src.ReadToken( &token ) ) { if ( token == ";" ) { block.postfix += ';'; break; } else { if ( token.WhiteSpaceBeforeToken() ){ block.postfix += ' '; } block.postfix += token; } } } else if ( src.PeekTokenString( "(" ) ) { idStr parms, body; src.ParseBracedSection( parms, -1, true, '(', ')' ); if ( src.CheckTokenString( ";" ) ) { block.postfix = parms + ";"; } else { src.ParseBracedSection( body, -1, true, '{', '}' ); block.postfix = parms + " " + body; } } else if ( src.PeekTokenString( "{" ) ) { src.ParseBracedSection( block.postfix, -1, true, '{', '}' ); if ( src.CheckTokenString( ";" ) ) { block.postfix += ';'; } } else if ( src.CheckTokenString( ";" ) ) { block.postfix = idStr( ';' ); } else { src.Warning( "Could not strip dead code -- unknown token %s\n", token.c_str() ); return in; } } idList<int, TAG_RENDERPROG> stack; for ( int i = 0; i < blocks.Num(); i++ ) { blocks[i].used = ( ( blocks[i].name == "main" ) || blocks[i].name.Right( 4 ) == "_ubo" ); if ( blocks[i].name == "include" ) { blocks[i].used = true; blocks[i].name = ""; // clear out the include tag } if ( blocks[i].used ) { stack.Append( i ); } } while ( stack.Num() > 0 ) { int i = stack[stack.Num() - 1]; stack.SetNum( stack.Num() - 1 ); idLexer src( LEXFL_NOFATALERRORS ); src.LoadMemory( blocks[i].postfix.c_str(), blocks[i].postfix.Length(), name ); while ( src.ReadToken( &token ) ) { for ( int j = 0; j < blocks.Num(); j++ ) { if ( !blocks[j].used ) { if ( token == blocks[j].name ) { blocks[j].used = true; stack.Append( j ); } } } } } idStr out; for ( int i = 0; i < blocks.Num(); i++ ) { if ( blocks[i].used ) { out += blocks[i].prefix; out += ' '; out += blocks[i].name; out += ' '; out += blocks[i].postfix; out += '\n'; } } return out; }
/* ======================== idSoundVoice_OpenAL::Create ======================== */ void idSoundVoice_OpenAL::Create( const idSoundSample* leadinSample_, const idSoundSample* loopingSample_ ) { if( IsPlaying() ) { // This should never hit Stop(); return; } triggered = true; leadinSample = ( idSoundSample_OpenAL* )leadinSample_; loopingSample = ( idSoundSample_OpenAL* )loopingSample_; if( alIsSource( openalSource ) && CompatibleFormat( leadinSample ) ) { sampleRate = leadinSample->format.basic.samplesPerSec; } else { DestroyInternal(); formatTag = leadinSample->format.basic.formatTag; numChannels = leadinSample->format.basic.numChannels; sampleRate = leadinSample->format.basic.samplesPerSec; //soundSystemLocal.hardware.pXAudio2->CreateSourceVoice( &pSourceVoice, ( const WAVEFORMATEX* )&leadinSample->format, XAUDIO2_VOICE_USEFILTER, 4.0f, &streamContext ); CheckALErrors(); alGenSources( 1, &openalSource ); if( CheckALErrors() != AL_NO_ERROR ) //if( pSourceVoice == NULL ) { // If this hits, then we are most likely passing an invalid sample format, which should have been caught by the loader (and the sample defaulted) return; } alSourcef( openalSource, AL_ROLLOFF_FACTOR, 0.0f ); //if( ( loopingSample == NULL && leadinSample->openalBuffer != 0 ) || ( loopingSample != NULL && soundShader->entries[0]->hardwareBuffer ) ) if( leadinSample->openalBuffer != 0 ) { alSourcei( openalSource, AL_BUFFER, 0 ); // handle uncompressed (non streaming) single shot and looping sounds /* if( triggered ) { alSourcei( openalSource, AL_BUFFER, looping ? chan->soundShader->entries[0]->openalBuffer : leadinSample->openalBuffer ); } */ } else { //if( triggered ) // handle streaming sounds (decode on the fly) both single shot AND looping alSourcei( openalSource, AL_BUFFER, 0 ); alDeleteBuffers( 3, &lastopenalStreamingBuffer[0] ); lastopenalStreamingBuffer[0] = openalStreamingBuffer[0]; lastopenalStreamingBuffer[1] = openalStreamingBuffer[1]; lastopenalStreamingBuffer[2] = openalStreamingBuffer[2]; alGenBuffers( 3, &openalStreamingBuffer[0] ); /* if( soundSystemLocal.alEAXSetBufferMode ) { soundSystemLocal.alEAXSetBufferMode( 3, &chan->openalStreamingBuffer[0], alGetEnumValue( ID_ALCHAR "AL_STORAGE_ACCESSIBLE" ) ); } */ openalStreamingBuffer[0]; openalStreamingBuffer[1]; openalStreamingBuffer[2]; } if( s_debugHardware.GetBool() ) { if( loopingSample == NULL || loopingSample == leadinSample ) { idLib::Printf( "%dms: %i created for %s\n", Sys_Milliseconds(), openalSource, leadinSample ? leadinSample->GetName() : "<null>" ); } else { idLib::Printf( "%dms: %i created for %s and %s\n", Sys_Milliseconds(), openalSource, leadinSample ? leadinSample->GetName() : "<null>", loopingSample ? loopingSample->GetName() : "<null>" ); } } } sourceVoiceRate = sampleRate; //pSourceVoice->SetSourceSampleRate( sampleRate ); //pSourceVoice->SetVolume( 0.0f ); alSourcei( openalSource, AL_SOURCE_RELATIVE, AL_TRUE ); alSource3f( openalSource, AL_POSITION, 0.0f, 0.0f, 0.0f ); // RB: FIXME 0.0f ? alSourcef( openalSource, AL_GAIN, 1.0f ); //OnBufferStart( leadinSample, 0 ); }
/* ================================================================================================ idRenderProgManager::LoadGLSLShader ================================================================================================ */ GLuint idRenderProgManager::LoadGLSLShader( GLenum target, const char * name, idList<int> & uniforms ) { idStr inFile; idStr outFileHLSL; idStr outFileGLSL; idStr outFileUniforms; inFile.Format( "renderprogs\\%s", name ); inFile.StripFileExtension(); outFileHLSL.Format( "renderprogs\\glsl\\%s", name ); outFileHLSL.StripFileExtension(); outFileGLSL.Format( "renderprogs\\glsl\\%s", name ); outFileGLSL.StripFileExtension(); outFileUniforms.Format( "renderprogs\\glsl\\%s", name ); outFileUniforms.StripFileExtension(); if ( target == GL_FRAGMENT_SHADER ) { inFile += ".pixel"; outFileHLSL += "_fragment.hlsl"; outFileGLSL += "_fragment.glsl"; outFileUniforms += "_fragment.uniforms"; } else { inFile += ".vertex"; outFileHLSL += "_vertex.hlsl"; outFileGLSL += "_vertex.glsl"; outFileUniforms += "_vertex.uniforms"; } // first check whether we already have a valid GLSL file and compare it to the hlsl timestamp; ID_TIME_T hlslTimeStamp; int hlslFileLength = fileSystem->ReadFile( inFile.c_str(), NULL, &hlslTimeStamp ); ID_TIME_T glslTimeStamp; int glslFileLength = fileSystem->ReadFile( outFileGLSL.c_str(), NULL, &glslTimeStamp ); // if the glsl file doesn't exist or we have a newer HLSL file we need to recreate the glsl file. idStr programGLSL; idStr programUniforms; if ( ( glslFileLength <= 0 ) || ( hlslTimeStamp > glslTimeStamp ) ) { if ( hlslFileLength <= 0 ) { // hlsl file doesn't even exist bail out return false; } void * hlslFileBuffer = NULL; int len = fileSystem->ReadFile( inFile.c_str(), &hlslFileBuffer ); if ( len <= 0 ) { return false; } idStr hlslCode( ( const char* ) hlslFileBuffer ); idStr programHLSL = StripDeadCode( hlslCode, inFile ); programGLSL = ConvertCG2GLSL( programHLSL, inFile, target == GL_VERTEX_SHADER, programUniforms ); fileSystem->WriteFile( outFileHLSL, programHLSL.c_str(), programHLSL.Length(), "fs_basepath" ); fileSystem->WriteFile( outFileGLSL, programGLSL.c_str(), programGLSL.Length(), "fs_basepath" ); if ( r_useUniformArrays.GetBool() ) { fileSystem->WriteFile( outFileUniforms, programUniforms.c_str(), programUniforms.Length(), "fs_basepath" ); } } else { // read in the glsl file void * fileBufferGLSL = NULL; int lengthGLSL = fileSystem->ReadFile( outFileGLSL.c_str(), &fileBufferGLSL ); if ( lengthGLSL <= 0 ) { idLib::Error( "GLSL file %s could not be loaded and may be corrupt", outFileGLSL.c_str() ); } programGLSL = ( const char * ) fileBufferGLSL; Mem_Free( fileBufferGLSL ); if ( r_useUniformArrays.GetBool() ) { // read in the uniform file void * fileBufferUniforms = NULL; int lengthUniforms = fileSystem->ReadFile( outFileUniforms.c_str(), &fileBufferUniforms ); if ( lengthUniforms <= 0 ) { idLib::Error( "uniform file %s could not be loaded and may be corrupt", outFileUniforms.c_str() ); } programUniforms = ( const char* ) fileBufferUniforms; Mem_Free( fileBufferUniforms ); } } // find the uniforms locations in either the vertex or fragment uniform array if ( r_useUniformArrays.GetBool() ) { uniforms.Clear(); idLexer src( programUniforms, programUniforms.Length(), "uniforms" ); idToken token; while ( src.ReadToken( &token ) ) { int index = -1; for ( int i = 0; i < RENDERPARM_TOTAL && index == -1; i++ ) { const char * parmName = GetGLSLParmName( i ); if ( token == parmName ) { index = i; } } for ( int i = 0; i < MAX_GLSL_USER_PARMS && index == -1; i++ ) { const char * parmName = GetGLSLParmName( RENDERPARM_USER + i ); if ( token == parmName ) { index = RENDERPARM_USER + i; } } if ( index == -1 ) { idLib::Error( "couldn't find uniform %s for %s", token.c_str(), outFileGLSL.c_str() ); } uniforms.Append( index ); } } // create and compile the shader const GLuint shader = qglCreateShader( target ); if ( shader ) { const char * source[1] = { programGLSL.c_str() }; qglShaderSource( shader, 1, source, NULL ); qglCompileShader( shader ); int infologLength = 0; qglGetShaderiv( shader, GL_INFO_LOG_LENGTH, &infologLength ); if ( infologLength > 1 ) { idTempArray<char> infoLog( infologLength ); int charsWritten = 0; qglGetShaderInfoLog( shader, infologLength, &charsWritten, infoLog.Ptr() ); // catch the strings the ATI and Intel drivers output on success if ( strstr( infoLog.Ptr(), "successfully compiled to run on hardware" ) != NULL || strstr( infoLog.Ptr(), "No errors." ) != NULL ) { //idLib::Printf( "%s program %s from %s compiled to run on hardware\n", typeName, GetName(), GetFileName() ); } else if ( r_displayGLSLCompilerMessages.GetBool() ) { idLib::Printf( "While compiling %s program %s\n", ( target == GL_FRAGMENT_SHADER ) ? "fragment" : "vertex" , inFile.c_str() ); const char separator = '\n'; idList<idStr> lines; lines.Clear(); idStr source( programGLSL ); lines.Append( source ); for ( int index = 0, ofs = lines[index].Find( separator ); ofs != -1; index++, ofs = lines[index].Find( separator ) ) { lines.Append( lines[index].c_str() + ofs + 1 ); lines[index].CapLength( ofs ); } idLib::Printf( "-----------------\n" ); for ( int i = 0; i < lines.Num(); i++ ) { idLib::Printf( "%3d: %s\n", i+1, lines[i].c_str() ); } idLib::Printf( "-----------------\n" ); idLib::Printf( "%s\n", infoLog.Ptr() ); } } GLint compiled = GL_FALSE; qglGetShaderiv( shader, GL_COMPILE_STATUS, &compiled ); if ( compiled == GL_FALSE ) { qglDeleteShader( shader ); return INVALID_PROGID; } } return shader; }
/* ======================== idAchievementManager::EventCompletesAchievement ======================== */ void idAchievementManager::EventCompletesAchievement( const achievement_t eventId ) { if( g_demoMode.GetBool() ) { return; } idLocalUser* localUser = GetLocalUser(); if( localUser == NULL || localUser->GetProfile() == NULL ) { // Send a Reliable Message to the User that needs to unlock this. if( owner != NULL ) { int playerId = owner->entityNumber; const int bufferSize = sizeof( playerId ) + sizeof( eventId ); byte buffer[ bufferSize ]; idBitMsg msg; msg.InitWrite( buffer, bufferSize ); msg.WriteByte( playerId ); msg.WriteByte( eventId ); msg.WriteByteAlign(); idLib::Printf( "Host Sending Achievement\n" ); session->GetActingGameStateLobbyBase().SendReliableToLobbyUser( gameLocal.lobbyUserIDs[ owner->entityNumber ], GAME_RELIABLE_MESSAGE_ACHIEVEMENT_UNLOCK, msg ); } return; // Remote user or build game } // Check to see if we've already given the achievement. // If so, don't do again because we don't want to autosave every time a trigger is hit if( localUser->GetProfile()->GetAchievement( eventId ) ) { return; } #ifdef ID_RETAIL if( common->GetConsoleUsed() ) { if( !cheatingDialogShown ) { common->Dialog().AddDialog( GDM_ACHIEVEMENTS_DISABLED_DUE_TO_CHEATING, DIALOG_ACCEPT, NULL, NULL, true ); cheatingDialogShown = true; } return; } #endif counts[eventId]++; if( counts[eventId] >= achievementInfo[eventId].required ) { session->GetAchievementSystem().AchievementUnlock( localUser, eventId ); } else { if( achievementInfo[eventId].lifetime ) { localUser->SetStatInt( eventId, counts[eventId] ); } } }
/* =================== GLimp_Init =================== */ bool GLimp_Init( glimpParms_t parms ) { common->Printf( "Initializing OpenGL subsystem\n" ); GLimp_PreInit(); // DG: make sure SDL is initialized // DG: make window resizable Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; // DG end if( parms.fullScreen ) flags |= SDL_WINDOW_FULLSCREEN; int colorbits = 24; int depthbits = 24; int stencilbits = 8; for( int i = 0; i < 16; i++ ) { // 0 - default // 1 - minus colorbits // 2 - minus depthbits // 3 - minus stencil if( ( i % 4 ) == 0 && i ) { // one pass, reduce switch( i / 4 ) { case 2 : if( colorbits == 24 ) colorbits = 16; break; case 1 : if( depthbits == 24 ) depthbits = 16; else if( depthbits == 16 ) depthbits = 8; case 3 : if( stencilbits == 24 ) stencilbits = 16; else if( stencilbits == 16 ) stencilbits = 8; } } int tcolorbits = colorbits; int tdepthbits = depthbits; int tstencilbits = stencilbits; if( ( i % 4 ) == 3 ) { // reduce colorbits if( tcolorbits == 24 ) tcolorbits = 16; } if( ( i % 4 ) == 2 ) { // reduce depthbits if( tdepthbits == 24 ) tdepthbits = 16; else if( tdepthbits == 16 ) tdepthbits = 8; } if( ( i % 4 ) == 1 ) { // reduce stencilbits if( tstencilbits == 24 ) tstencilbits = 16; else if( tstencilbits == 16 ) tstencilbits = 8; else tstencilbits = 0; } int channelcolorbits = 4; if( tcolorbits == 24 ) channelcolorbits = 8; SDL_GL_SetAttribute( SDL_GL_RED_SIZE, channelcolorbits ); SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, channelcolorbits ); SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, channelcolorbits ); SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, tdepthbits ); SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, tstencilbits ); if( r_waylandcompat.GetBool() ) SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 0 ); else SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, channelcolorbits ); SDL_GL_SetAttribute( SDL_GL_STEREO, parms.stereo ? 1 : 0 ); SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, parms.multiSamples ? 1 : 0 ); SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, parms.multiSamples ); #if SDL_VERSION_ATLEAST(2, 0, 0) // RB begin if( r_useOpenGL32.GetInteger() > 0 ) { glConfig.driverType = GLDRV_OPENGL32_COMPATIBILITY_PROFILE; SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 ); SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 2 ); } if( r_debugContext.GetBool() ) { SDL_GL_SetAttribute( SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG ); } if( r_useOpenGL32.GetInteger() > 1 ) { glConfig.driverType = GLDRV_OPENGL32_CORE_PROFILE; SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE ); } // RB end // DG: set display num for fullscreen int windowPos = SDL_WINDOWPOS_UNDEFINED; if( parms.fullScreen > 0 ) { if( parms.fullScreen > SDL_GetNumVideoDisplays() ) { common->Warning( "Couldn't set display to num %i because we only have %i displays", parms.fullScreen, SDL_GetNumVideoDisplays() ); } else { // -1 because SDL starts counting displays at 0, while parms.fullScreen starts at 1 windowPos = SDL_WINDOWPOS_UNDEFINED_DISPLAY( ( parms.fullScreen - 1 ) ); } } // TODO: if parms.fullScreen == -1 there should be a borderless window spanning multiple displays /* * NOTE that this implicitly handles parms.fullScreen == -2 (from r_fullscreen -2) meaning * "do fullscreen, but I don't care on what monitor", at least on my box it's the monitor with * the mouse cursor. */ window = SDL_CreateWindow( GAME_NAME, windowPos, windowPos, parms.width, parms.height, flags ); // DG end context = SDL_GL_CreateContext( window ); if( !window ) { common->DPrintf( "Couldn't set GL mode %d/%d/%d: %s", channelcolorbits, tdepthbits, tstencilbits, SDL_GetError() ); continue; } if( SDL_GL_SetSwapInterval( r_swapInterval.GetInteger() ) < 0 ) common->Warning( "SDL_GL_SWAP_CONTROL not supported" ); // RB begin SDL_GetWindowSize( window, &glConfig.nativeScreenWidth, &glConfig.nativeScreenHeight ); // RB end glConfig.isFullscreen = ( SDL_GetWindowFlags( window ) & SDL_WINDOW_FULLSCREEN ) == SDL_WINDOW_FULLSCREEN; #else glConfig.driverType = GLDRV_OPENGL3X; SDL_WM_SetCaption( GAME_NAME, GAME_NAME ); if( SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, r_swapInterval.GetInteger() ) < 0 ) common->Warning( "SDL_GL_SWAP_CONTROL not supported" ); window = SDL_SetVideoMode( parms.width, parms.height, colorbits, flags ); if( !window ) { common->DPrintf( "Couldn't set GL mode %d/%d/%d: %s", channelcolorbits, tdepthbits, tstencilbits, SDL_GetError() ); continue; } glConfig.nativeScreenWidth = window->w; glConfig.nativeScreenHeight = window->h; glConfig.isFullscreen = ( window->flags & SDL_FULLSCREEN ) == SDL_FULLSCREEN; #endif common->Printf( "Using %d color bits, %d depth, %d stencil display\n", channelcolorbits, tdepthbits, tstencilbits ); glConfig.colorBits = tcolorbits; glConfig.depthBits = tdepthbits; glConfig.stencilBits = tstencilbits; // RB begin glConfig.displayFrequency = 60; glConfig.isStereoPixelFormat = parms.stereo; glConfig.multisamples = parms.multiSamples; glConfig.pixelAspect = 1.0f; // FIXME: some monitor modes may be distorted // should side-by-side stereo modes be consider aspect 0.5? // RB end break; } if( !window ) { common->Printf( "No usable GL mode found: %s", SDL_GetError() ); return false; } #ifdef __APPLE__ glewExperimental = GL_TRUE; #endif GLenum glewResult = glewInit(); if( GLEW_OK != glewResult ) { // glewInit failed, something is seriously wrong common->Printf( "^3GLimp_Init() - GLEW could not load OpenGL subsystem: %s", glewGetErrorString( glewResult ) ); } else { common->Printf( "Using GLEW %s\n", glewGetString( GLEW_VERSION ) ); } // DG: disable cursor, we have two cursors in menu (because mouse isn't grabbed in menu) SDL_ShowCursor( SDL_DISABLE ); // DG end return true; }
/* ======================== idResolutionScale::InitForMap ======================== */ void idResolutionScale::InitForMap( const char* mapName ) { dropMilliseconds = rs_dropMilliseconds.GetFloat(); raiseMilliseconds = rs_raiseMilliseconds.GetFloat(); }
/* ============= R_CheckCvars See if some cvars that we watch have changed ============= */ static void R_CheckCvars() { // gamma stuff if( r_gamma.IsModified() || r_brightness.IsModified() ) { r_gamma.ClearModified(); r_brightness.ClearModified(); R_SetColorMappings(); } // filtering if( r_maxAnisotropicFiltering.IsModified() || r_useTrilinearFiltering.IsModified() || r_lodBias.IsModified() ) { idLib::Printf( "Updating texture filter parameters.\n" ); r_maxAnisotropicFiltering.ClearModified(); r_useTrilinearFiltering.ClearModified(); r_lodBias.ClearModified(); for( int i = 0 ; i < globalImages->images.Num() ; i++ ) { if( globalImages->images[i] ) { globalImages->images[i]->Bind(); globalImages->images[i]->SetTexParameters(); } } } extern idCVar r_useSeamlessCubeMap; if( r_useSeamlessCubeMap.IsModified() ) { r_useSeamlessCubeMap.ClearModified(); if( glConfig.seamlessCubeMapAvailable ) { if( r_useSeamlessCubeMap.GetBool() ) { qglEnable( GL_TEXTURE_CUBE_MAP_SEAMLESS ); } else { qglDisable( GL_TEXTURE_CUBE_MAP_SEAMLESS ); } } } extern idCVar r_useSRGB; if( r_useSRGB.IsModified() ) { r_useSRGB.ClearModified(); if( glConfig.sRGBFramebufferAvailable ) { if( r_useSRGB.GetBool() ) { qglEnable( GL_FRAMEBUFFER_SRGB ); } else { qglDisable( GL_FRAMEBUFFER_SRGB ); } } } if( r_multiSamples.IsModified() ) { if( r_multiSamples.GetInteger() > 0 ) { qglEnable( GL_MULTISAMPLE_ARB ); } else { qglDisable( GL_MULTISAMPLE_ARB ); } } // check for changes to logging state GLimp_EnableLogging( r_logFile.GetInteger() != 0 ); }
/* ============================= idGameBearShootWindow::UpdateGame ============================= */ void idGameBearShootWindow::UpdateGame() { int i; if ( onNewGame ) { ResetGameState(); if ( goal ) { goal->position.x = 550; goal->position.y = 164; goal->velocity.Zero(); } if ( helicopter ) { helicopter->position.x = 550; helicopter->position.y = 100; helicopter->velocity.Zero(); } if ( bear ) { bear->SetVisible( false ); } bearTurretAngle.SetFloat( 0.f ); bearTurretForce.SetFloat( 200.f ); gamerunning = true; } if ( onContinue ) { gameOver = false; timeRemaining = 60.f; onContinue = false; } if(gamerunning == true) { int current_time = gui->GetTime(); idRandom rnd( current_time ); // Check for button presses UpdateButtons(); if ( bear ) { UpdateBear(); } if ( helicopter && goal ) { UpdateHelicopter(); } // Update Wind if ( windUpdateTime < current_time ) { float scale; int width; windForce = rnd.CRandomFloat() * ( MAX_WINDFORCE * 0.75f ); if (windForce > 0) { windForce += ( MAX_WINDFORCE * 0.25f ); wind->rotation = 0; } else { windForce -= ( MAX_WINDFORCE * 0.25f ); wind->rotation = 180; } scale = 1.f - (( MAX_WINDFORCE - idMath::Fabs(windForce) ) / MAX_WINDFORCE); width = 100*scale; if ( windForce < 0 ) { wind->position.x = 500 - width + 1; } else { wind->position.x = 500; } wind->SetSize( width, 40 ); windUpdateTime = current_time + 7000 + rnd.RandomInt(5000); } // Update turret rotation angle if ( turret ) { turretAngle = bearTurretAngle.GetFloat(); turret->rotation = turretAngle; } for( i = 0; i < entities.Num(); i++ ) { entities[i]->Update( timeSlice ); } // Update countdown timer timeRemaining -= timeSlice; timeRemaining = idMath::ClampFloat( 0.f, 99999.f, timeRemaining ); gui->SetStateString( "time_remaining", va("%2.1f", timeRemaining ) ); if ( timeRemaining <= 0.f && !gameOver ) { gameOver = true; updateScore = true; } if ( updateScore ) { UpdateScore(); updateScore = false; } } }
/* ================= idRenderModelManagerLocal::Preload ================= */ void idRenderModelManagerLocal::Preload( const idPreloadManifest& manifest ) { if( preload_MapModels.GetBool() ) { // preload this levels images int start = Sys_Milliseconds(); int numLoaded = 0; idList< preloadSort_t > preloadSort; preloadSort.Resize( manifest.NumResources() ); for( int i = 0; i < manifest.NumResources(); i++ ) { const preloadEntry_s& p = manifest.GetPreloadByIndex( i ); idResourceCacheEntry rc; idStrStatic< MAX_OSPATH > filename; if( p.resType == PRELOAD_MODEL ) { filename = "generated/rendermodels/"; filename += p.resourceName; idStrStatic< 16 > ext; filename.ExtractFileExtension( ext ); filename.SetFileExtension( va( "b%s", ext.c_str() ) ); } if( p.resType == PRELOAD_PARTICLE ) { filename = "generated/particles/"; filename += p.resourceName; filename += ".bprt"; } if( !filename.IsEmpty() ) { if( fileSystem->GetResourceCacheEntry( filename, rc ) ) { preloadSort_t ps = {}; ps.idx = i; ps.ofs = rc.offset; preloadSort.Append( ps ); } } } preloadSort.SortWithTemplate( idSort_Preload() ); for( int i = 0; i < preloadSort.Num(); i++ ) { const preloadSort_t& ps = preloadSort[ i ]; const preloadEntry_s& p = manifest.GetPreloadByIndex( ps.idx ); if( p.resType == PRELOAD_MODEL ) { idRenderModel* model = FindModel( p.resourceName ); if( model != NULL ) { model->SetLevelLoadReferenced( true ); } } else if( p.resType == PRELOAD_PARTICLE ) { declManager->FindType( DECL_PARTICLE, p.resourceName ); } numLoaded++; } int end = Sys_Milliseconds(); common->Printf( "%05d models preloaded ( or were already loaded ) in %5.1f seconds\n", numLoaded, ( end - start ) * 0.001 ); common->Printf( "----------------------------------------\n" ); } }
/* ======================== idSoundHardware_OpenAL::Update ======================== */ void idSoundHardware_OpenAL::Update() { if( openalDevice == NULL ) { int nowTime = Sys_Milliseconds(); if( lastResetTime + 1000 < nowTime ) { lastResetTime = nowTime; Init(); } return; } if( soundSystem->IsMuted() ) { alListenerf( AL_GAIN, 0.0f ); } else { alListenerf( AL_GAIN, DBtoLinear( s_volume_dB.GetFloat() ) ); } // IXAudio2SourceVoice::Stop() has been called for every sound on the // zombie list, but it is documented as asyncronous, so we have to wait // until it actually reports that it is no longer playing. for( int i = 0; i < zombieVoices.Num(); i++ ) { zombieVoices[i]->FlushSourceBuffers(); if( !zombieVoices[i]->IsPlaying() ) { freeVoices.Append( zombieVoices[i] ); zombieVoices.RemoveIndexFast( i ); i--; } else { static int playingZombies; playingZombies++; } } /* if( s_showPerfData.GetBool() ) { XAUDIO2_PERFORMANCE_DATA perfData; pXAudio2->GetPerformanceData( &perfData ); idLib::Printf( "Voices: %d/%d CPU: %.2f%% Mem: %dkb\n", perfData.ActiveSourceVoiceCount, perfData.TotalSourceVoiceCount, perfData.AudioCyclesSinceLastQuery / ( float )perfData.TotalCyclesSinceLastQuery, perfData.MemoryUsageInBytes / 1024 ); } */ /* if( vuMeterRMS == NULL ) { // Init probably hasn't been called yet return; } vuMeterRMS->Enable( s_showLevelMeter.GetBool() ); vuMeterPeak->Enable( s_showLevelMeter.GetBool() ); if( !s_showLevelMeter.GetBool() ) { pMasterVoice->DisableEffect( 0 ); return; } else { pMasterVoice->EnableEffect( 0 ); } float peakLevels[ 8 ]; float rmsLevels[ 8 ]; XAUDIO2FX_VOLUMEMETER_LEVELS levels; levels.ChannelCount = outputChannels; levels.pPeakLevels = peakLevels; levels.pRMSLevels = rmsLevels; if( levels.ChannelCount > 8 ) { levels.ChannelCount = 8; } pMasterVoice->GetEffectParameters( 0, &levels, sizeof( levels ) ); int currentTime = Sys_Milliseconds(); for( int i = 0; i < outputChannels; i++ ) { if( vuMeterPeakTimes[i] < currentTime ) { vuMeterPeak->SetValue( i, vuMeterPeak->GetValue( i ) * 0.9f, colorRed ); } } float width = 20.0f; float height = 200.0f; float left = 100.0f; float top = 100.0f; sscanf( s_meterPosition.GetString(), "%f %f %f %f", &left, &top, &width, &height ); vuMeterRMS->SetPosition( left, top, width * levels.ChannelCount, height ); vuMeterPeak->SetPosition( left, top, width * levels.ChannelCount, height ); for( uint32 i = 0; i < levels.ChannelCount; i++ ) { vuMeterRMS->SetValue( i, rmsLevels[ i ], idVec4( 0.5f, 1.0f, 0.0f, 1.00f ) ); if( peakLevels[ i ] >= vuMeterPeak->GetValue( i ) ) { vuMeterPeak->SetValue( i, peakLevels[ i ], colorRed ); vuMeterPeakTimes[i] = currentTime + s_meterTopTime.GetInteger(); } } */ }
/* ======================== InDebugRange Helper function for net_ssTemplateDebug debugging ======================== */ bool InDebugRange( int i ) { return ( i >= net_ssTemplateDebug_start.GetInteger() && i < net_ssTemplateDebug_start.GetInteger() + net_ssTemplateDebug_len.GetInteger() ); }
namespace BFG { class idCmdArgs; idCVar s_showLevelMeter( "s_showLevelMeter", "0", CVAR_BOOL | CVAR_ARCHIVE, "Show VU meter" ); idCVar s_meterTopTime( "s_meterTopTime", "1000", CVAR_INTEGER | CVAR_ARCHIVE, "How long (in milliseconds) peaks are displayed on the VU meter" ); idCVar s_meterPosition( "s_meterPosition", "100 100 20 200", CVAR_ARCHIVE, "VU meter location (x y w h)" ); idCVar s_device( "s_device", "-1", CVAR_INTEGER | CVAR_ARCHIVE, "Which audio device to use (listDevices to list, -1 for default)" ); //idCVar s_showPerfData( "s_showPerfData", "0", CVAR_BOOL, "Show XAudio2 Performance data" ); extern idCVar s_volume_dB; /* ======================== idSoundHardware_OpenAL::idSoundHardware_OpenAL ======================== */ idSoundHardware_OpenAL::idSoundHardware_OpenAL() { openalDevice = NULL; openalContext = NULL; //vuMeterRMS = NULL;PrintDeviceList //vuMeterPeak = NULL; //outputChannels = 0; //channelMask = 0; voices.SetNum( 0 ); zombieVoices.SetNum( 0 ); freeVoices.SetNum( 0 ); OpenALDeviceList.Clear(); lastResetTime = 0; } void idSoundHardware_OpenAL::OpenBestDevice() { const ALCchar *deviceNameList = NULL; idLib::Printf( "idSoundHardware_OpenAL::OpenBestDevice: rebuilding devices list\n" ); //first clean the list OpenALDeviceList.Clear(); //let's build it again if( alcIsExtensionPresent( NULL, "ALC_ENUMERATE_ALL_EXT" ) != AL_FALSE ) { deviceNameList = alcGetString( NULL, ALC_ALL_DEVICES_SPECIFIER ); //all the devices } else { deviceNameList = alcGetString( NULL, ALC_DEVICE_SPECIFIER ); // just one device } if( deviceNameList && *deviceNameList != '\0' ) { do { OpenALDeviceList.Append( deviceNameList ); deviceNameList += strlen( deviceNameList ) + 1; } while( *deviceNameList != '\0' ); } if ( OpenALDeviceList.Num() == 0 ) { idLib::Printf( "idSoundHardware_OpenAL::OpenBestDevice: there are still no devices in the device list!!!\n" ); openalDevice = NULL; return; } //let's proceed to open the correct device int selectedInt = s_device.GetInteger(); if ( ( s_device.GetInteger() > OpenALDeviceList.Num() - 1 ) || ( selectedInt == -1 ) || ( OpenALDeviceList.Num() == 1 ) ) { idLib::Printf( "idSoundHardware_OpenAL::OpenBestDevice: selected default device\n" ); openalDevice = alcOpenDevice( NULL ); //the default one } else { idLib::Printf( "idSoundHardware_OpenAL::OpenBestDevice: selected the %ith device\n", selectedInt ); openalDevice = alcOpenDevice( OpenALDeviceList[ selectedInt ] ); } } void idSoundHardware_OpenAL::PrintDeviceList( const char* list ) { int index = 0; if( !list || *list == '\0' ) { idLib::Printf( " !!! none !!!\n" ); } else { do { idLib::Printf( " %i: %s\n", index, list ); list += strlen( list ) + 1; index++; } while( *list != '\0' ); } } void idSoundHardware_OpenAL::PrintALCInfo( ALCdevice* device ) { ALCint major, minor; if( device ) { const ALCchar* devname = NULL; idLib::Printf( "\n" ); if( alcIsExtensionPresent( device, "ALC_ENUMERATE_ALL_EXT" ) != AL_FALSE ) { devname = alcGetString( device, ALC_ALL_DEVICES_SPECIFIER ); } if( CheckALCErrors( device ) != ALC_NO_ERROR || !devname ) { devname = alcGetString( device, ALC_DEVICE_SPECIFIER ); } idLib::Printf( "** Info for device \"%s\" **\n", devname ); } if( CheckALCErrors( device ) == ALC_NO_ERROR ) { alcGetIntegerv( device, ALC_MAJOR_VERSION, 1, &major ); alcGetIntegerv( device, ALC_MINOR_VERSION, 1, &minor ); idLib::Printf( "ALC version: %d.%d\n", major, minor ); } if( device ) { idLib::Printf( "OpenAL extensions:\n%s\n", alGetString( AL_EXTENSIONS ) ); //idLib::Printf("ALC extensions:"); //printList(alcGetString(device, ALC_EXTENSIONS), ' '); CheckALCErrors( device ); } } void idSoundHardware_OpenAL::PrintALInfo() { idLib::Printf( "OpenAL vendor string: %s\n", alGetString( AL_VENDOR ) ); idLib::Printf( "OpenAL renderer string: %s\n", alGetString( AL_RENDERER ) ); idLib::Printf( "OpenAL version string: %s\n", alGetString( AL_VERSION ) ); idLib::Printf( "OpenAL extensions: %s", alGetString( AL_EXTENSIONS ) ); //PrintList(alGetString(AL_EXTENSIONS), ' '); CheckALErrors(); } //void idSoundHardware_OpenAL::listDevices_f( const idCmdArgs& args ) void listDevices_f( const idCmdArgs& args ) { idLib::Printf( "Available playback devices:\n\n" ); if( alcIsExtensionPresent( NULL, "ALC_ENUMERATE_ALL_EXT" ) != AL_FALSE ) { idSoundHardware_OpenAL::PrintDeviceList( alcGetString( NULL, ALC_ALL_DEVICES_SPECIFIER ) ); } else { idSoundHardware_OpenAL::PrintDeviceList( alcGetString( NULL, ALC_DEVICE_SPECIFIER ) ); } idLib::Printf( "\n" ); //idLib::Printf("Available capture devices:\n"); //printDeviceList(alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER)); if( alcIsExtensionPresent( NULL, "ALC_ENUMERATE_ALL_EXT" ) != AL_FALSE ) { idLib::Printf( "Default playback device: %s\n", alcGetString( NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER ) ); } else { idLib::Printf( "Default playback device: %s\n", alcGetString( NULL, ALC_DEFAULT_DEVICE_SPECIFIER ) ); } if( s_device.GetInteger() == -1) { idLib::Printf( "Selected playback device is default's.\n" ); } else { idLib::Printf( "Selected playback device is device: %i\n", s_device.GetInteger() ); //FIXME this could bring wrong info if s_device points to a fake number } //idLib::Printf("Default capture device: %s\n", alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER)); idSoundHardware_OpenAL::PrintALCInfo( NULL ); idSoundHardware_OpenAL::PrintALCInfo( ( ALCdevice* )soundSystem->GetOpenALDevice() ); } /* ======================== idSoundHardware_OpenAL::Init ======================== */ void idSoundHardware_OpenAL::Init() { cmdSystem->AddCommand( "listDevices", listDevices_f, 0, "Lists the connected sound devices", NULL ); common->Printf( "Setup OpenAL device and context... \n" ); idSoundHardware_OpenAL::OpenBestDevice(); if( openalDevice == NULL ) { common->FatalError( "idSoundHardware_OpenAL::Init: alcOpenDevice() failed\n" ); return; } openalContext = alcCreateContext( openalDevice, NULL ); if( alcMakeContextCurrent( openalContext ) == 0 ) { common->FatalError( "idSoundHardware_OpenAL::Init: alcMakeContextCurrent( %p) failed\n", openalContext ); return; } common->Printf( "Done.\n" ); common->Printf( "OpenAL vendor: %s\n", alGetString( AL_VENDOR ) ); common->Printf( "OpenAL renderer: %s\n", alGetString( AL_RENDERER ) ); common->Printf( "OpenAL version: %s\n", alGetString( AL_VERSION ) ); common->Printf( "OpenAL extensions: %s\n", alGetString( AL_EXTENSIONS ) ); //pMasterVoice->SetVolume( DBtoLinear( s_volume_dB.GetFloat() ) ); //outputChannels = deviceDetails.OutputFormat.Format.nChannels; //channelMask = deviceDetails.OutputFormat.dwChannelMask; //idSoundVoice::InitSurround( outputChannels, channelMask ); // --------------------- // Create VU Meter Effect // --------------------- /* IUnknown* vuMeter = NULL; XAudio2CreateVolumeMeter( &vuMeter, 0 ); XAUDIO2_EFFECT_DESCRIPTOR descriptor; descriptor.InitialState = true; descriptor.OutputChannels = outputChannels; descriptor.pEffect = vuMeter; XAUDIO2_EFFECT_CHAIN chain; chain.EffectCount = 1; chain.pEffectDescriptors = &descriptor; pMasterVoice->SetEffectChain( &chain ); vuMeter->Release(); */ // --------------------- // Create VU Meter Graph // --------------------- /* vuMeterRMS = console->CreateGraph( outputChannels ); vuMeterPeak = console->CreateGraph( outputChannels ); vuMeterRMS->Enable( false ); vuMeterPeak->Enable( false ); memset( vuMeterPeakTimes, 0, sizeof( vuMeterPeakTimes ) ); vuMeterPeak->SetFillMode( idDebugGraph::GRAPH_LINE ); vuMeterPeak->SetBackgroundColor( idVec4( 0.0f, 0.0f, 0.0f, 0.0f ) ); vuMeterRMS->AddGridLine( 0.500f, idVec4( 0.5f, 0.5f, 0.5f, 1.0f ) ); vuMeterRMS->AddGridLine( 0.250f, idVec4( 0.5f, 0.5f, 0.5f, 1.0f ) ); vuMeterRMS->AddGridLine( 0.125f, idVec4( 0.5f, 0.5f, 0.5f, 1.0f ) ); const char* channelNames[] = { "L", "R", "C", "S", "Lb", "Rb", "Lf", "Rf", "Cb", "Ls", "Rs" }; for( int i = 0, ci = 0; ci < sizeof( channelNames ) / sizeof( channelNames[0] ); ci++ ) { if( ( channelMask & BIT( ci ) ) == 0 ) { continue; } vuMeterRMS->SetLabel( i, channelNames[ ci ] ); i++; } */ // OpenAL doesn't really impose a maximum number of sources voices.SetNum( voices.Max() ); freeVoices.SetNum( voices.Max() ); zombieVoices.SetNum( 0 ); for( int i = 0; i < voices.Num(); i++ ) { freeVoices[i] = &voices[i]; } } /* ======================== idSoundHardware_OpenAL::Shutdown ======================== */ void idSoundHardware_OpenAL::Shutdown() { zombieVoices.Clear(); freeVoices.Clear(); for( int i = 0; i < voices.Num(); i++ ) { voices[ i ].DestroyInternal(); } voices.Clear(); alcMakeContextCurrent( NULL ); alcDestroyContext( openalContext ); openalContext = NULL; alcCloseDevice( openalDevice ); openalDevice = NULL; OpenALDeviceList.Clear(); /* if( vuMeterRMS != NULL ) { console->DestroyGraph( vuMeterRMS ); vuMeterRMS = NULL; } if( vuMeterPeak != NULL ) { console->DestroyGraph( vuMeterPeak ); vuMeterPeak = NULL; } */ } /* ======================== idSoundHardware_OpenAL::AllocateVoice ======================== */ idSoundVoice* idSoundHardware_OpenAL::AllocateVoice( const idSoundSample* leadinSample, const idSoundSample* loopingSample ) { if( leadinSample == NULL ) { return NULL; } if( loopingSample != NULL ) { if( ( leadinSample->format.basic.formatTag != loopingSample->format.basic.formatTag ) || ( leadinSample->format.basic.numChannels != loopingSample->format.basic.numChannels ) ) { idLib::Warning( "Leadin/looping format mismatch: %s & %s", leadinSample->GetName(), loopingSample->GetName() ); loopingSample = NULL; } } // Try to find a free voice that matches the format // But fallback to the last free voice if none match the format idSoundVoice* voice = NULL; for( int i = 0; i < freeVoices.Num(); i++ ) { if( freeVoices[i]->IsPlaying() ) { continue; } voice = ( idSoundVoice* )freeVoices[i]; if( voice->CompatibleFormat( ( idSoundSample_OpenAL* )leadinSample ) ) { break; } } if( voice != NULL ) { voice->Create( leadinSample, loopingSample ); freeVoices.Remove( voice ); return voice; } return NULL; } /* ======================== idSoundHardware_OpenAL::FreeVoice ======================== */ void idSoundHardware_OpenAL::FreeVoice( idSoundVoice* voice ) { voice->Stop(); // Stop() is asyncronous, so we won't flush bufferes until the // voice on the zombie channel actually returns !IsPlaying() zombieVoices.Append( voice ); } /* ======================== idSoundHardware_OpenAL::Update ======================== */ void idSoundHardware_OpenAL::Update() { if( openalDevice == NULL ) { int nowTime = Sys_Milliseconds(); if( lastResetTime + 1000 < nowTime ) { lastResetTime = nowTime; Init(); } return; } if( soundSystem->IsMuted() ) { alListenerf( AL_GAIN, 0.0f ); } else { alListenerf( AL_GAIN, DBtoLinear( s_volume_dB.GetFloat() ) ); } // IXAudio2SourceVoice::Stop() has been called for every sound on the // zombie list, but it is documented as asyncronous, so we have to wait // until it actually reports that it is no longer playing. for( int i = 0; i < zombieVoices.Num(); i++ ) { zombieVoices[i]->FlushSourceBuffers(); if( !zombieVoices[i]->IsPlaying() ) { freeVoices.Append( zombieVoices[i] ); zombieVoices.RemoveIndexFast( i ); i--; } else { static int playingZombies; playingZombies++; } } /* if( s_showPerfData.GetBool() ) { XAUDIO2_PERFORMANCE_DATA perfData; pXAudio2->GetPerformanceData( &perfData ); idLib::Printf( "Voices: %d/%d CPU: %.2f%% Mem: %dkb\n", perfData.ActiveSourceVoiceCount, perfData.TotalSourceVoiceCount, perfData.AudioCyclesSinceLastQuery / ( float )perfData.TotalCyclesSinceLastQuery, perfData.MemoryUsageInBytes / 1024 ); } */ /* if( vuMeterRMS == NULL ) { // Init probably hasn't been called yet return; } vuMeterRMS->Enable( s_showLevelMeter.GetBool() ); vuMeterPeak->Enable( s_showLevelMeter.GetBool() ); if( !s_showLevelMeter.GetBool() ) { pMasterVoice->DisableEffect( 0 ); return; } else { pMasterVoice->EnableEffect( 0 ); } float peakLevels[ 8 ]; float rmsLevels[ 8 ]; XAUDIO2FX_VOLUMEMETER_LEVELS levels; levels.ChannelCount = outputChannels; levels.pPeakLevels = peakLevels; levels.pRMSLevels = rmsLevels; if( levels.ChannelCount > 8 ) { levels.ChannelCount = 8; } pMasterVoice->GetEffectParameters( 0, &levels, sizeof( levels ) ); int currentTime = Sys_Milliseconds(); for( int i = 0; i < outputChannels; i++ ) { if( vuMeterPeakTimes[i] < currentTime ) { vuMeterPeak->SetValue( i, vuMeterPeak->GetValue( i ) * 0.9f, colorRed ); } } float width = 20.0f; float height = 200.0f; float left = 100.0f; float top = 100.0f; sscanf( s_meterPosition.GetString(), "%f %f %f %f", &left, &top, &width, &height ); vuMeterRMS->SetPosition( left, top, width * levels.ChannelCount, height ); vuMeterPeak->SetPosition( left, top, width * levels.ChannelCount, height ); for( uint32 i = 0; i < levels.ChannelCount; i++ ) { vuMeterRMS->SetValue( i, rmsLevels[ i ], idVec4( 0.5f, 1.0f, 0.0f, 1.00f ) ); if( peakLevels[ i ] >= vuMeterPeak->GetValue( i ) ) { vuMeterPeak->SetValue( i, peakLevels[ i ], colorRed ); vuMeterPeakTimes[i] = currentTime + s_meterTopTime.GetInteger(); } } */ } } // namespace BFG
/* ======================== idMenuScreen_Shell_SystemOptions::idMenuDataSource_SystemSettings::GetField ======================== */ idSWFScriptVar idMenuScreen_Shell_SystemOptions::idMenuDataSource_SystemSettings::GetField( const int fieldIndex ) const { switch( fieldIndex ) { case SYSTEM_FIELD_FULLSCREEN: { const int fullscreen = r_fullscreen.GetInteger(); const int vidmode = r_vidMode.GetInteger(); if( fullscreen == 0 ) { return "#str_swf_disabled"; } if( fullscreen < 0 || vidmode < 0 || vidmode >= modeList.Num() ) { return "???"; } if( modeList[vidmode].displayHz == 60 ) { return va( "%4i x %4i", modeList[vidmode].width, modeList[vidmode].height ); } else { return va( "%4i x %4i @ %dhz", modeList[vidmode].width, modeList[vidmode].height, modeList[vidmode].displayHz ); } } case SYSTEM_FIELD_FRAMERATE: return va( "%d FPS", com_engineHz.GetInteger() ); case SYSTEM_FIELD_VSYNC: if( r_swapInterval.GetInteger() == 1 ) { return "#str_swf_smart"; } else if( r_swapInterval.GetInteger() == 2 ) { return "#str_swf_enabled"; } else { return "#str_swf_disabled"; } case SYSTEM_FIELD_ANTIALIASING: if( r_multiSamples.GetInteger() == 0 ) { return "#str_swf_disabled"; } return va( "%dx", r_multiSamples.GetInteger() ); case SYSTEM_FIELD_MOTIONBLUR: if( r_motionBlur.GetInteger() == 0 ) { return "#str_swf_disabled"; } return va( "%dx", idMath::IPow( 2, r_motionBlur.GetInteger() ) ); // RB begin case SYSTEM_FIELD_SHADOWMAPPING: if( r_useShadowMapping.GetInteger() == 1 ) { return "#str_swf_enabled"; } else { return "#str_swf_disabled"; } //case SYSTEM_FIELD_LODBIAS: // return LinearAdjust( r_lodBias.GetFloat(), -1.0f, 1.0f, 0.0f, 100.0f ); // RB end case SYSTEM_FIELD_BRIGHTNESS: return LinearAdjust( r_lightScale.GetFloat(), 2.0f, 4.0f, 0.0f, 100.0f ); case SYSTEM_FIELD_VOLUME: { return 100.0f * Square( 1.0f - ( s_volume_dB.GetFloat() / DB_SILENCE ) ); } } return false; }
rvGamePlayback::rvGamePlayback( void ) { idStr newName; const idVec3 trace_mins( -1.0f, -1.0f, -1.0f ); const idVec3 trace_maxs( 1.0f, 1.0f, 1.0f ); const idBounds trace_bounds( trace_mins, trace_maxs ); idTraceModel traceModel( trace_bounds ); mStartTime = gameLocal.time; mOldFlags = 0; mClipModel = new idClipModel( traceModel ); if( !g_currentPlayback.GetInteger() ) { newName = declManager->GetNewName( DECL_PLAYBACK, "playbacks/untitled" ); mPlayback = ( rvDeclPlayback * )declManager->CreateNewDecl( DECL_PLAYBACK, newName, newName + ".playback" ); mPlayback->ReplaceSourceFileText(); mPlayback->Invalidate(); g_currentPlayback.SetInteger( mPlayback->Index() ); } else { mPlayback = ( rvDeclPlayback * )declManager->PlaybackByIndex( g_currentPlayback.GetInteger() ); } declManager->StartPlaybackRecord( mPlayback ); common->Printf( "Starting playback record to %s type %d\n", mPlayback->GetName(), g_recordPlayback.GetInteger() ); }