void EldritchGame::SetColorGradingTexture( const SimpleString& TextureFilename )
{
    XTRACE_FUNCTION;

    m_ColorGradingTexture = TextureFilename;

    if( m_PostQuad )
    {
        EldritchFramework* const pFramework = EldritchFramework::GetInstance();
        ASSERT( pFramework );

        TextureManager* const pTextureManager = pFramework->GetRenderer()->GetTextureManager();
        ASSERT( pTextureManager );

        m_PostQuad->SetTexture( 1, pTextureManager->GetTexture( TextureFilename.CStr() ) );
    }
}
void MusicManager::QueueNextSequence()
{
	FreeSequence( m_NextSequence );

	STATICHASH( NextSequence );
	STATICHASH( NumTransitions );
	STATICHASH( File );
	MAKEHASHFROM( DefinitionName, m_CurrentSequence.m_DefinitionName );

	SimpleString NextSequence = ConfigManager::GetString( sNextSequence, "", sDefinitionName );

	// Try all the mood transitions; if none match, it'll just fall back to NextSequence
	int NumTransitions = ConfigManager::GetInt( sNumTransitions, 0, sDefinitionName );
	for( int i = 0; i < NumTransitions; ++i )
	{
		SimpleString TransitionMood = ConfigManager::GetSequenceString( "TransitionMood%d", i, "", sDefinitionName );
		SimpleString TransitionSequence = ConfigManager::GetSequenceString( "TransitionSeq%d", i, "", sDefinitionName );
		if( TransitionMood == m_Mood )
		{
			NextSequence = TransitionSequence;
			break;
		}
	}

	if( NextSequence != "" )
	{
		SimpleString NextFilename = ConfigManager::GetString( sFile, "", NextSequence );
		if( NextFilename != "" )
		{
			SSoundInit SoundInit;
			SoundInit.m_Filename = NextFilename.CStr();
			SoundInit.m_IsStream = true;
			SoundInit.m_IsLooping = false;
			SoundInit.m_Is3D = false;
			SoundInit.m_Category = "Music";
			SoundInit.m_Priority = ESP_High;

			m_NextSequence.m_Sound = m_AudioSystem->GetSoundManager()->GetSound( SoundInit, NextSequence );
			m_NextSequence.m_Instance = m_NextSequence.m_Sound->CreateSoundInstance();
			m_AudioSystem->AddSoundInstance( m_NextSequence.m_Instance );
			m_NextSequence.m_Instance->Tick();	// Tick to apply all properties in advance
			m_NextSequence.m_DefinitionName = NextSequence;
		}
	}
}
/*virtual*/ void Framework3D::Initialize()
{
	XTRACE_FUNCTION;

	m_IsInitializing = true;

#if BUILD_SDL
	const int Error = SDL_Init( SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE );
	ASSERT( 0 == Error );
	Unused( Error );
	if( 0 != Error )
	{
		PRINTF( "SDL_Init: %s\n", SDL_GetError() );
	}

	SDL_DisableScreenSaver();
#endif

	STATICHASH( Framework );

#if BUILD_WINDOWS
#if BUILD_FINAL
	STATICHASH( ShowConsole );
	const bool ShowConsole = ConfigManager::GetBool( sShowConsole, false, sFramework );
	if( ShowConsole )
#endif
	{
		Console::GetInstance()->SetPos( 0, 0 );
	}
#endif

	STATICHASH( UseRandomSeed );
	const bool UseRandomSeed = ConfigManager::GetBool( sUseRandomSeed, false, sFramework );

	STATICHASH( RandomSeed );
	const int RandomSeed = ConfigManager::GetInt( sRandomSeed, 0, sFramework );

	if( UseRandomSeed )
	{
		Math::SeedGenerator( RandomSeed );
	}
	else
	{
		Math::SeedGenerator();
	}

	STATICHASH( UseFixedFrameTime );
	m_UseFixedFrameTime	= ConfigManager::GetBool( sUseFixedFrameTime, true, sFramework );

	STATICHASH( FixedFrameTime );
	m_FixedFrameTime = ConfigManager::GetFloat( sFixedFrameTime, 1.0f / 60.0f, sFramework );

	STATICHASH( FramesLimit );
	const int FramesLimit = ConfigManager::GetInt( sFramesLimit, 5, sFramework );
	m_FrameTimeLimit = m_FixedFrameTime * static_cast<float>( FramesLimit );

	STATICHASH( DoVideoCapture );
	m_DoVideoCapture = ConfigManager::GetBool( sDoVideoCapture, false, sFramework );

	STATICHASH( VideoCaptureFixedFrameTime );
	m_VideoCaptureFixedFrameTime = ConfigManager::GetFloat( sVideoCaptureFixedFrameTime, 1.0f / 30.0f, sFramework );

	uint DisplayWidth = 0;
	uint DisplayHeight = 0;
	SimpleString WindowTitle;

	// Loads display parameters from config, so GetInitialDisplaySize can use that.
	m_Display = new Display;

	// Make sure that we use a supported resolution regardless of what the config file said.
	const SDisplayMode BestDisplayMode = m_Display->GetBestDisplayMode( m_Display->m_Width, m_Display->m_Height );
	m_Display->SetResolution( BestDisplayMode.Width, BestDisplayMode.Height );

	uint WindowIcon = 0;
	GetInitialWindowIcon( WindowIcon );
	GetInitialDisplaySize( DisplayWidth, DisplayHeight );
	GetInitialWindowTitle( WindowTitle );

	CreateSplashWindow( WindowIcon, WindowTitle.CStr() );

	m_Window = new Window;

#if BUILD_WINDOWS_NO_SDL
	DWORD WindowStyle = 0;
	if( m_Display->m_Fullscreen ||
		(	m_Display->m_ScreenWidth == m_Display->m_Width &&
			m_Display->m_ScreenHeight == m_Display->m_Height ) )
	{
		WindowStyle = WS_POPUP;
	}
	else
	{
		WindowStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
	}

	m_Window->Init( WindowTitle.CStr(), "Class1", WindowStyle, 0, DisplayWidth, DisplayHeight, m_hInstance, WindowProc, WindowIcon, m_Display->m_ScreenWidth, m_Display->m_ScreenHeight );
#elif BUILD_SDL
	uint WindowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN;
	if( m_Display->m_Fullscreen ||
		(	m_Display->m_ScreenWidth == m_Display->m_Width &&
			m_Display->m_ScreenHeight == m_Display->m_Height ) )
	{
		WindowFlags |= SDL_WINDOW_BORDERLESS;
	}
	// TODO SDL: Unify interface?
	m_Window->Init( WindowTitle.CStr(), WindowFlags, DisplayWidth, DisplayHeight );

	STATICHASH( IconImage );
	const char* const	pIconImage	= ConfigManager::GetString( sIconImage, NULL, sFramework );
	ASSERT( pIconImage );
	const Surface		IconSurface	= Surface( PackStream( pIconImage ), Surface::ESFT_BMP );
	SDL_SetWindowIcon( m_Window->GetSDLWindow(), IconSurface.GetSDLSurface() );
#endif

	m_Window->SetFullscreen( m_Display->m_Fullscreen );
	if( m_Display->m_Fullscreen )
	{
		m_Window->SetPosition( 0, 0 );
	}

	m_Clock = new Clock;

	XTRACE_BEGIN( InitializeDevices );
		m_Keyboard	= new Keyboard;
#if BUILD_WINDOWS_NO_SDL
		m_Mouse		= new Mouse( m_hInstance, m_Window->GetHWnd() );
#elif BUILD_SDL
		m_Mouse		= new Mouse( m_Window );
#endif
	XTRACE_END;

	InitializeUIInputMap();

	XTRACE_BEGIN( InitializeAudioSystem );
		InitializeAudioSystem();
	XTRACE_END;

	XTRACE_BEGIN( InitializeRenderer );
#if BUILD_WINDOWS_NO_SDL
		STATICHASH( OpenGL );
		const bool OpenGL = ConfigManager::GetBool( sOpenGL );
		if( OpenGL )
#endif
		{
			PRINTF( "Using OpenGL renderer.\n" );
			m_Renderer = CreateGL2Renderer( m_Window );
		}
#if BUILD_WINDOWS_NO_SDL
		else
		{
			PRINTF( "Using Direct3D renderer.\n" );
			m_Renderer = CreateD3D9Renderer( m_Window->GetHWnd(), m_Display->m_Fullscreen );
		}
#endif

		IRenderer::SRestoreDeviceCallback Callback;
		Callback.m_Callback = &Framework3D::RendererRestoreDeviceCallback;
		Callback.m_Void = this;
		m_Renderer->SetRestoreDeviceCallback( Callback );

		InitializeRender();
		m_Renderer->Initialize();
		m_Renderer->SetDisplay( m_Display );
		m_Renderer->SetClock( m_Clock );
	XTRACE_END;

	if( ShowWindowASAP() )
	{
		SafeDelete( m_SplashWindow );
#if BUILD_WINDOWS_NO_SDL
		m_Window->Show( m_CmdShow );
#elif BUILD_SDL
		m_Window->Show();
#endif

		// Reattach GL context if needed.
		m_Renderer->Refresh();
	}

	if( UseClassicTargetManager() )
	{
		m_TargetManager = new TargetManager( m_Renderer, DisplayWidth, DisplayHeight );
	}

	XTRACE_BEGIN( InitializeUI );
		SimpleString UIManagerDefinitionName;
		GetUIManagerDefinitionName( UIManagerDefinitionName );

		m_UIManager = new UIManagerFramework( this );
		m_UIManager->InitializeFromDefinition( UIManagerDefinitionName );
		m_UIManager->GetUIStack()->SetFadeOverlay( m_UIManager->GetScreen( "Fade" ) );
		UIScreen::UpdateMouseButtonsSwapped();
	XTRACE_END;

	m_IsInitializing = false;
}
Beispiel #4
0
void Patcher_GetNextPatchFile()
{
	ASSERT( g_FilesInManifest.Size() );

	// Iterate to find the next valid patch file
	for( ; g_NextPatchFileIndex < g_FilesInManifest.Size(); ++g_NextPatchFileIndex )
	{
		SManifestFile& PatchFile = g_FilesInManifest[ g_NextPatchFileIndex ];
		SimpleString PatchFilename = PatchFile.m_Filename;
		if( FileUtil::Exists( PatchFilename.CStr() ) )
		{
			FileStream ExtantFile( PatchFilename.CStr(), FileStream::EFM_Read );

			int ExtantSize = ExtantFile.Size();
			uint32 ExtantChecksum = Checksum::Adler32( ExtantFile );
			SimpleString ExtantLengthString = SimpleString::PrintF( "%d", ExtantSize );
			SimpleString ExtantChecksumString = SimpleString::PrintF( "0x%08X", ExtantChecksum );

			if( ExtantLengthString == PatchFile.m_Length && ExtantChecksumString == PatchFile.m_Checksum )
			{
				AddStatus( SimpleString::PrintF( "%s is up to date.", PatchFilename.CStr() ), g_StatusColor );
			}
			else
			{
				// This file isn't up to date. Patch it!
				break;
			}
		}
		else
		{
			// This file isn't on disk. Get it!
			break;
		}
	}

	if( g_NextPatchFileIndex < g_FilesInManifest.Size() )
	{
		SimpleString PatchFile = g_FilesInManifest[ g_NextPatchFileIndex ].m_Filename;

		AddStatus( SimpleString::PrintF( "Getting %s...", PatchFile.CStr() ), g_StatusColor );

		STATICHASH( ContentSyncer );
		STATICHASH( PatcherHost );
		STATICHASH( PatcherContentPath );

		g_Patcher_GettingVersionNumber = false;
		g_Patcher_GettingManifestFile = false;
		g_Patcher_GettingNextPatchFile = true;

		g_Patcher_WaitingToConnect = true;
		g_Patcher_WaitingToReceive = false;

		HTTPSocket::SSocketInit SocketInit;

		SocketInit.m_CloseConnection = true;
		SocketInit.m_HostName = ConfigManager::GetString( sPatcherHost, "", sContentSyncer );
		SocketInit.m_Path = SimpleString::PrintF( "%s%s", ConfigManager::GetString( sPatcherContentPath, "", sContentSyncer ), PatchFile.CStr() );
		SocketInit.m_Async = true;
		g_HTTPSocket->Connect( SocketInit );
	}
	else
	{
		// Nothing left to patch! Handle the wrap up.
		FinishPatching();
	}
}
SimpleString EldritchGame::DecorateWorldFileName( const SimpleString& LevelName ) const
{
    XTRACE_FUNCTION;
    const SimpleString SaveLoadPath			= EldritchFramework::GetInstance()->GetSaveLoadPath();
    const SimpleString DecoratedFileName	= SimpleString::PrintF( "%s%s.eldritchworldsave", SaveLoadPath.CStr(), LevelName.CStr() );
    return DecoratedFileName;
}
void UIWidgetImage::InitializeFromDefinition( const SimpleString& DefinitionName )
{
	UIWidget::InitializeFromDefinition( DefinitionName );

	MAKEHASH( DefinitionName );
	MAKEHASH( m_Archetype );

	STATICHASH( DisplayWidth );
	const float DisplayWidth	= ConfigManager::GetFloat( sDisplayWidth );
	const float ParentWidth		= m_OriginParent ? m_OriginParent->GetWidth() : DisplayWidth;
	const float ParentX			= m_OriginParent ? Ceiling( m_OriginParent->GetX() ) : 0.0f;

	STATICHASH( DisplayHeight );
	const float DisplayHeight	= ConfigManager::GetFloat( sDisplayHeight );
	const float ParentHeight	= m_OriginParent ? m_OriginParent->GetHeight() : DisplayHeight;
	const float ParentY			= m_OriginParent ? Ceiling( m_OriginParent->GetY() ) : 0.0f;

	STATICHASH( PixelX );
	STATICHASH( ScreenX );
	float X = Pick(
		ConfigManager::GetArchetypeFloat( sPixelX, sm_Archetype, 0.0f, sDefinitionName ),
		ParentWidth * ConfigManager::GetArchetypeFloat( sScreenX, sm_Archetype, 0.0f, sDefinitionName ) );

	STATICHASH( PixelY );
	STATICHASH( ScreenY );
	float Y = Pick(
		ConfigManager::GetArchetypeFloat( sPixelY, sm_Archetype, 0.0f, sDefinitionName ),
		ParentHeight * ConfigManager::GetArchetypeFloat( sScreenY, sm_Archetype, 0.0f, sDefinitionName ) );
	
	STATICHASH( PixelWidth );
	STATICHASH( ScreenWidth );
	float Width = Pick(
		ConfigManager::GetArchetypeFloat( sPixelWidth, sm_Archetype, 0.0f, sDefinitionName ),
		ParentWidth * ConfigManager::GetArchetypeFloat( sScreenWidth, sm_Archetype, 0.0f, sDefinitionName ) );

	STATICHASH( PixelHeight );
	STATICHASH( ScreenHeight );
	float Height = Pick(
		ConfigManager::GetArchetypeFloat( sPixelHeight, sm_Archetype, 0.0f, sDefinitionName ),
		ParentHeight * ConfigManager::GetArchetypeFloat( sScreenHeight, sm_Archetype, 0.0f, sDefinitionName ) );

	// Adjust for desired aspect ratio if one dimension is not given
	// (This is used to size images using ScreenWidth or ScreenHeight
	// properly regardless of screen aspect ratio.
	STATICHASH( AspectRatio );
	const float AspectRatio = ConfigManager::GetArchetypeFloat( sAspectRatio, sm_Archetype, 1.0f, sDefinitionName );
	if( Width == 0.0f )
	{
		Width = Height * AspectRatio;
	}
	else if( Height == 0.0f )
	{
		Height = Width / AspectRatio;
	}

	// Offset relative to resolved image dimensions if specified
	STATICHASH( ImageX );
	X = Pick( X, ConfigManager::GetArchetypeFloat( sImageX, sm_Archetype, 0.0f, sDefinitionName ) * Width );

	STATICHASH( ImageY );
	Y = Pick( Y, ConfigManager::GetArchetypeFloat( sImageY, sm_Archetype, 0.0f, sDefinitionName ) * Height );

	AdjustDimensionsToParent( X, Y, Width, Height, ParentX, ParentY, ParentWidth, ParentHeight );
	GetPositionFromOrigin( X, Y, Width, Height );

	STATICHASH( ClampToPixelGrid );
	if( ConfigManager::GetArchetypeBool( sClampToPixelGrid, sm_Archetype, true, sDefinitionName ) )
	{
		m_TopLeft.x = Round( m_TopLeft.x );
		m_TopLeft.y = Round( m_TopLeft.y );
	}

	// Offset to properly align on pixel grid.
	const float PixelGridOffset = GetPixelGridOffset();
	m_TopLeft.x -= PixelGridOffset;
	m_TopLeft.y -= PixelGridOffset;

	// If LoadImage is false, we're expecting to dynamically set the texture in code somewhere
	STATICHASH( LoadImage );
	if( ConfigManager::GetArchetypeBool( sLoadImage, sm_Archetype, true, sDefinitionName ) )
	{
		STATICHASH( Image );
		SetTexture( ConfigManager::GetArchetypeString( sImage, sm_Archetype, DEFAULT_TEXTURE, sDefinitionName ) );
	}

	m_Dimensions = Vector2( Width, Height );

	STATICHASH( Calibration );
	m_Calibration = ConfigManager::GetArchetypeBool( sCalibration, sm_Archetype, false, sDefinitionName );

	STATICHASH( MaterialOverride );
	const SimpleString DefaultMaterial( "Material_HUD" );
	m_Material = ConfigManager::GetArchetypeString( sMaterialOverride, sm_Archetype, DefaultMaterial.CStr(), sDefinitionName );

	UpdateRender();
}
Beispiel #7
0
/*virtual*/ void EldritchFramework::Initialize() {
  XTRACE_FUNCTION;

  XTRACE_BEGIN(PreFramework3D);
  ReverseHash::Initialize();

  PackStream::StaticAddPackageFile("eldritch-base.cpk");
  FrameworkUtil::MinimalLoadConfigFiles("Config/default.ccf");

  InitializePackages();

  InitializeDLC();

  // Load prefs over anything in the defaults.
  LoadPrefsConfig();

  LOADPRINTLEVELS;

  STATICHASH(Version);
  STATICHASH(ContentSyncer);
  SimpleString LocalVersion =
      ConfigManager::GetString(sVersion, "", sContentSyncer);
  PRINTF("Version: %s\n", LocalVersion.CStr());

  XTRACE_BEGIN(InitializeFactories);
  PRINTF("Initializing factories...\n");

  PRINTF("Initializing SDP factories.\n");
  SDPFactory::InitializeBaseFactories();
#define ADDSDPFACTORY(type) \
  SDPFactory::RegisterSDPFactory(#type, SDP##type::Factory);
#include "eldritchsdps.h"
#undef ADDSDPFACTORY

  PRINTF("Initializing UI factories.\n");
  UIFactory::InitializeBaseFactories();
#define ADDUISCREENFACTORY(type) \
  UIFactory::RegisterUIScreenFactory(#type, UIScreen##type::Factory);
#include "eldritchuiscreens.h"
#undef ADDUISCREENFACTORY

  PRINTF("Initializing anim event factories.\n");
#define ADDANIMEVENTFACTORY(type) \
  AnimEventFactory::GetInstance()->Register(#type, AnimEvent##type::Factory);
#include "eldritchanimevents.h"
#undef ADDANIMEVENTFACTORY

  PRINTF("Initializing PE factories.\n");
  WBParamEvaluatorFactory::InitializeBaseFactories();
#define ADDWBPEFACTORY(type) \
  WBParamEvaluatorFactory::RegisterFactory(#type, WBPE##type::Factory);
#include "rodinwbpes.h"
#include "eldritchwbpes.h"
#undef ADDWBPEFACTORY

  PRINTF("Initializing action factories.\n");
  WBActionFactory::InitializeBaseFactories();
#define ADDWBACTIONFACTORY(type) \
  WBActionFactory::RegisterFactory(#type, WBAction##type::Factory);
#include "uiwbactions.h"
#include "rodinwbactions.h"
#include "eldritchwbactions.h"
#undef ADDWBPEFACTORY

  PRINTF("Initializing BT factories.\n");
  RodinBTNodeFactory::InitializeBaseFactories();
#define ADDRODINBTNODEFACTORY(type) \
  RodinBTNodeFactory::RegisterFactory(#type, RodinBTNode##type::Factory);
#include "eldritchrodinbtnodes.h"
#undef ADDRODINBTNODEFACTORY

  // Initialize core and Eldritch Workbench component factories.
  PRINTF("Initializing component factories.\n");
  WBComponent::InitializeBaseFactories();
#define ADDWBCOMPONENT(type) \
  WBComponent::RegisterWBCompFactory(#type, WBComp##type::Factory);
#include "rodinwbcomponents.h"
#include "eldritchwbcomponents.h"
#undef ADDWBCOMPONENT
  XTRACE_END;

  PRINTF("Factories initialized.\n");

  // Create input system before framework so it will exist for UI. But don't
  // attach devices yet, as they don't exist.
  PRINTF("Initializing input system.\n");
  m_InputSystem = new InputSystem;
  m_InputSystem->Initialize("EldritchInput");
  XTRACE_END;

  Framework3D::Initialize();

  STATICHASH(DisplayWidth);
  STATICHASH(DisplayHeight);
  m_DisplayWidth = ConfigManager::GetInt(sDisplayWidth);
  m_DisplayHeight = ConfigManager::GetInt(sDisplayHeight);

#if BUILD_WINDOWS
  m_CheckForUpdates = new CheckForUpdates(m_UIManager);
#endif

  m_Controller = new XInputController;

  m_TargetManager = new EldritchTargetManager(m_Renderer);
  m_TargetManager->CreateTargets(m_Display->m_Width, m_Display->m_Height);

  m_Audio3DListener = new EldritchSound3DListener;
  m_Audio3DListener->Initialize();

  ASSERT(m_AudioSystem);
  m_AudioSystem->Set3DListener(m_Audio3DListener);

  STATICHASH(FOV);
  const float FOV = ConfigManager::GetFloat(sFOV, 90.0f);

  STATICHASH(ForegroundFOV);
  const float FGFOV = ConfigManager::GetFloat(sForegroundFOV, 60.0f);

  STATICHASH(NearClip);
  const float NearClip = ConfigManager::GetFloat(sNearClip, 0.1f);

  STATICHASH(FarClip);
  const float FarClip = ConfigManager::GetFloat(sFarClip, 0.1f);

  const float fDisplayWidth = static_cast<float>(m_DisplayWidth);
  const float fDisplayHeight = static_cast<float>(m_DisplayHeight);
  const float AspectRatio = fDisplayWidth / fDisplayHeight;

  m_MainView =
      new View(Vector(), Angles(), FOV, AspectRatio, NearClip, FarClip);
  m_FGView =
      new View(Vector(), Angles(), FGFOV, AspectRatio, NearClip, FarClip);
  CreateHUDView();
  CreateMirrorView();
  CreateMinimapView();

  CreateBuckets();

  m_InputSystem->SetKeyboard(m_Keyboard);
  m_InputSystem->SetMouse(m_Mouse);
  m_InputSystem->SetController(m_Controller);
  m_InputSystem->SetClock(m_Clock);

  WBActionStack::Initialize();

  PRINTF("Initializing Eldritch.\n");

  InitializeWorld(HashedString(), false);

  m_Game = new EldritchGame;
  m_Game->RefreshRTDependentSystems();
  m_Game->Initialize();

  // Initialize config stuff
  {
    STATICHASH(InvertY);
    const bool InvertY = ConfigManager::GetBool(sInvertY);

    STATIC_HASHED_STRING(TurnY);
    m_InputSystem->SetMouseInvert(sTurnY, InvertY);
    m_InputSystem->SetControllerInvert(sTurnY, InvertY);

    STATICHASH(ControllerPower);
    const float ControllerPower = ConfigManager::GetFloat(sControllerPower);

    STATIC_HASHED_STRING(MoveX);
    m_InputSystem->SetControllerPower(sMoveX, ControllerPower);
    STATIC_HASHED_STRING(MoveY);
    m_InputSystem->SetControllerPower(sMoveY, ControllerPower);
    STATIC_HASHED_STRING(TurnX);
    m_InputSystem->SetControllerPower(sTurnX, ControllerPower);
    m_InputSystem->SetControllerPower(sTurnY, ControllerPower);
  }

  // Initialize UI sliders. This could be neater.
  // This also pushes the initial values to their respective systems, which is
  // pret-ty terrible design.
  {
    WBEventManager* pEventManager = WBWorld::GetInstance()->GetEventManager();

    {
      STATICHASH(MouseSpeed);
      const float MouseSpeed = ConfigManager::GetFloat(sMouseSpeed, 1.0f);

      STATIC_HASHED_STRING(ControlsOptionsScreen);
      STATIC_HASHED_STRING(MouseSpeedSlider);
      WB_MAKE_EVENT(SetUISliderValue, NULL);
      WB_SET_AUTO(SetUISliderValue, Hash, Screen, sControlsOptionsScreen);
      WB_SET_AUTO(SetUISliderValue, Hash, Widget, sMouseSpeedSlider);
      WB_SET_AUTO(SetUISliderValue, Float, SliderValue,
                  GetSliderValueFromMouseSpeed(MouseSpeed));
      WB_DISPATCH_EVENT(pEventManager, SetUISliderValue, NULL);
    }

    {
      STATICHASH(ControllerSpeed);
      const float ControllerSpeed =
          ConfigManager::GetFloat(sControllerSpeed, 1.0f);

      STATIC_HASHED_STRING(ControlsOptionsScreen);
      STATIC_HASHED_STRING(ControllerSpeedSlider);
      WB_MAKE_EVENT(SetUISliderValue, NULL);
      WB_SET_AUTO(SetUISliderValue, Hash, Screen, sControlsOptionsScreen);
      WB_SET_AUTO(SetUISliderValue, Hash, Widget, sControllerSpeedSlider);
      WB_SET_AUTO(SetUISliderValue, Float, SliderValue,
                  GetSliderValueFromControllerSpeed(ControllerSpeed));
      WB_DISPATCH_EVENT(pEventManager, SetUISliderValue, NULL);
    }

    {
      STATICHASH(Brightness);
      const float Brightness = ConfigManager::GetFloat(sBrightness, 1.0f);

      STATIC_HASHED_STRING(BrightnessScreen);
      STATIC_HASHED_STRING(BrightnessSlider);
      WB_MAKE_EVENT(SetUISliderValue, NULL);
      WB_SET_AUTO(SetUISliderValue, Hash, Screen, sBrightnessScreen);
      WB_SET_AUTO(SetUISliderValue, Hash, Widget, sBrightnessSlider);
      WB_SET_AUTO(SetUISliderValue, Float, SliderValue,
                  GetSliderValueFromBrightness(Brightness));
      WB_DISPATCH_EVENT(pEventManager, SetUISliderValue, NULL);
    }

    {
      STATIC_HASHED_STRING(DisplayOptionsScreen);
      STATIC_HASHED_STRING(FOVSlider);
      WB_MAKE_EVENT(SetUISliderValue, NULL);
      WB_SET_AUTO(SetUISliderValue, Hash, Screen, sDisplayOptionsScreen);
      WB_SET_AUTO(SetUISliderValue, Hash, Widget, sFOVSlider);
      WB_SET_AUTO(SetUISliderValue, Float, SliderValue,
                  GetSliderValueFromFOV(FOV));
      WB_DISPATCH_EVENT(pEventManager, SetUISliderValue, NULL);
    }

    {
      STATICHASH(MasterVolume);
      const float MasterVolume = ConfigManager::GetFloat(sMasterVolume);

      STATIC_HASHED_STRING(AudioOptionsScreen);
      STATIC_HASHED_STRING(VolumeSlider);
      WB_MAKE_EVENT(SetUISliderValue, NULL);
      WB_SET_AUTO(SetUISliderValue, Hash, Screen, sAudioOptionsScreen);
      WB_SET_AUTO(SetUISliderValue, Hash, Widget, sVolumeSlider);
      WB_SET_AUTO(SetUISliderValue, Float, SliderValue, MasterVolume);
      WB_DISPATCH_EVENT(pEventManager, SetUISliderValue, NULL);
    }

    {
      STATICHASH(MusicVolume);
      const float MusicVolume = ConfigManager::GetFloat(sMusicVolume);

      STATIC_HASHED_STRING(AudioOptionsScreen);
      STATIC_HASHED_STRING(MusicVolumeSlider);
      WB_MAKE_EVENT(SetUISliderValue, NULL);
      WB_SET_AUTO(SetUISliderValue, Hash, Screen, sAudioOptionsScreen);
      WB_SET_AUTO(SetUISliderValue, Hash, Widget, sMusicVolumeSlider);
      WB_SET_AUTO(SetUISliderValue, Float, SliderValue, MusicVolume);
      WB_DISPATCH_EVENT(pEventManager, SetUISliderValue, NULL);
    }
  }

  // Initialize UI callbacks
  {
    UIScreenEldSetRes* pSetRes =
        m_UIManager->GetScreen<UIScreenEldSetRes>("SetResScreen");
    pSetRes->SetUICallback(SUICallback(EldritchFramework::OnSetRes, nullptr));

    UIScreenFade* pFade = m_UIManager->GetScreen<UIScreenFade>("Fade");
    pFade->SetFadeCallback(
        SUICallback(EldritchFramework::OnFadeFinished, nullptr));
  }

  WB_MAKE_EVENT(ResetToInitialScreens, NULL);
  WB_DISPATCH_EVENT(WBWorld::GetInstance()->GetEventManager(),
                    ResetToInitialScreens, NULL);

  {
    // HACK: Too content aware
    STATIC_HASHED_STRING(MKGLogoScreen);
    WB_MAKE_EVENT(PushUIScreen, NULL);
    WB_SET_AUTO(PushUIScreen, Hash, Screen, sMKGLogoScreen);
    WB_DISPATCH_EVENT(WBWorld::GetInstance()->GetEventManager(), PushUIScreen,
                      NULL);
  }

  // Tick world once to pump the event queue. Fixes title screen bugs.
  m_World->Tick(0.0f);

  // All done, show the window finally.
  SafeDelete(m_SplashWindow);
#if BUILD_WINDOWS_NO_SDL
  m_Window->Show(m_CmdShow);
#elif BUILD_SDL
  m_Window->Show();
#endif

  // Reattach GL context if needed.
  m_Renderer->Refresh();

  PRINTF("Eldritch initialization complete.\n");
}
void UIScreenEldSetRes::InitializeFromDefinition(
    const SimpleString& DefinitionName) {
  FlushWidgets();
  m_ResMap.Clear();

  UIScreen::InitializeFromDefinition(DefinitionName);

  Display* const pDisplay = m_UIManager->GetDisplay();
  Array<SDisplayMode> DisplayModes;
  m_UIManager->GetRenderer()->EnumerateDisplayModes(DisplayModes);
  DisplayModes.InsertionSort();
  ASSERT(DisplayModes.Size());

  MAKEHASH(DefinitionName);

  // Dynamically create definitions for each text button

  STATICHASH(Rules);
  SimpleString UsingRules =
      ConfigManager::GetString(sRules, "", sDefinitionName);

  MAKEHASH(UsingRules);

  STATICHASH(Archetype);
  const char* const ArchetypeName =
      ConfigManager::GetString(sArchetype, "", sUsingRules);

  STATICHASH(Parent);
  const char* const Parent = ConfigManager::GetString(sParent, "", sUsingRules);

  STATICHASH(PixelYBase);
  const float YBase = ConfigManager::GetFloat(sPixelYBase, 0.0f, sUsingRules);

  STATICHASH(PixelYStep);
  const float YStep = ConfigManager::GetFloat(sPixelYStep, 0.0f, sUsingRules);

  STATICHASH(Column0PixelX);
  const float Column0X =
      ConfigManager::GetFloat(sColumn0PixelX, 0.0f, sUsingRules);

  STATICHASH(Column1PixelX);
  const float Column1X =
      ConfigManager::GetFloat(sColumn1PixelX, 0.0f, sUsingRules);

#if DEBUG_SETRES
  PRINTF("UIScreenEldSetRes info:\n");
  PRINTF("  ScreenWidth:  %d\n", pDisplay->m_ScreenWidth);
  PRINTF("  ScreenHeight: %d\n", pDisplay->m_ScreenHeight);
#endif

  FOR_EACH_ARRAY_REVERSE(DisplayIter, DisplayModes, SDisplayMode) {
    const SDisplayMode& DisplayMode = DisplayIter.GetValue();
    if (!pDisplay->m_Fullscreen &&
        (DisplayMode.Width > pDisplay->m_ScreenWidth ||
         DisplayMode.Height > pDisplay->m_ScreenHeight)) {
#if DEBUG_SETRES
      PRINTF("  Skipping mode %dx%d:\n", DisplayMode.Width, DisplayMode.Height);
#endif
      DisplayModes.FastRemove(DisplayIter);
    }
  }

  const int NumDisplayModes = static_cast<int>(DisplayModes.Size());
  const int LeftColumnSize = (NumDisplayModes + 1) / 2;
  const int RightColumnSize =
      (NumDisplayModes + 1) - LeftColumnSize;  // Add one for the Back button

  for (int DisplayModeIndex = 0; DisplayModeIndex < NumDisplayModes;
       ++DisplayModeIndex) {
    const SDisplayMode& DisplayMode = DisplayModes[DisplayModeIndex];

    float ScreenX = 0.0f;
    float ScreenY = 0.0f;

    int FocusShiftUp = 0;
    int FocusShiftDown = 0;
    int FocusShiftLeft = 0;
    int FocusShiftRight = 0;

    if (DisplayModeIndex < LeftColumnSize) {
      // Display mode is in left column
      ScreenY = YBase + DisplayModeIndex * YStep;
      ScreenX = Column0X;
      FocusShiftLeft = -RightColumnSize;
      FocusShiftRight = LeftColumnSize;
    } else {
      // Display mode is in right column
      ScreenY = YBase + (DisplayModeIndex - LeftColumnSize) * YStep;
      ScreenX = Column1X;
      FocusShiftLeft = -LeftColumnSize;
      FocusShiftRight = RightColumnSize;
    }

    if (DisplayModeIndex == 0) {
      // Display mode is on top left
      FocusShiftUp = -(RightColumnSize + 1);
    } else if (DisplayModeIndex == (LeftColumnSize - 1)) {
      // Display mode is on bottom left
      FocusShiftDown = (RightColumnSize + 1);

      // If columns are the same size (*including* the back button),
      // this widget doesn't have a pair in the right column.
      if (LeftColumnSize == RightColumnSize) {
        // Setting focus override to 0 uses the screen's shift values, so loop
        // instead.
        FocusShiftLeft = -(NumDisplayModes + 1);
        FocusShiftRight = (NumDisplayModes + 1);
      }
    } else if (DisplayModeIndex == LeftColumnSize) {
      // Display mode is on top right left
      FocusShiftUp = -(LeftColumnSize + 1);
    }
    // Back button shift down is handled below this loop.

    const SimpleString NewDefinitionName =
        SimpleString::PrintF("_Res%d", DisplayModeIndex);
    // HACKHACK: Insert the UTF-8 codes for the U+00D7 (multiplication sign)
    const SimpleString ResolutionString = SimpleString::PrintF(
        "%d \xc3\x97 %d", DisplayMode.Width, DisplayMode.Height);

    MAKEHASH(NewDefinitionName);

    STATICHASH(UIWidgetType);
    ConfigManager::SetString(sUIWidgetType, "Text", sNewDefinitionName);

    ConfigManager::SetString(sArchetype, ArchetypeName, sNewDefinitionName);

    ConfigManager::SetString(sParent, Parent, sNewDefinitionName);

    STATICHASH(String);
    ConfigManager::SetString(sString, ResolutionString.CStr(),
                             sNewDefinitionName);

    STATICHASH(PixelX);
    ConfigManager::SetFloat(sPixelX, ScreenX, sNewDefinitionName);

    STATICHASH(PixelY);
    ConfigManager::SetFloat(sPixelY, ScreenY, sNewDefinitionName);

    STATICHASH(FocusShiftUp);
    ConfigManager::SetInt(sFocusShiftUp, FocusShiftUp, sNewDefinitionName);

    STATICHASH(FocusShiftDown);
    ConfigManager::SetInt(sFocusShiftDown, FocusShiftDown, sNewDefinitionName);

    STATICHASH(FocusShiftLeft);
    ConfigManager::SetInt(sFocusShiftLeft, FocusShiftLeft, sNewDefinitionName);

    STATICHASH(FocusShiftRight);
    ConfigManager::SetInt(sFocusShiftRight, FocusShiftRight,
                          sNewDefinitionName);

    UIWidget* const pResWidget =
        UIFactory::CreateWidget(NewDefinitionName, this);
    ASSERT(pResWidget);

    pResWidget->m_Callback = m_Callback;

    AddWidget(pResWidget);

    m_ResMap[NewDefinitionName] = DisplayMode;
  }

  STATIC_HASHED_STRING(SetResBackButton);
  UIWidget* const pBackButtonWidget = GetWidget(sSetResBackButton);
  ASSERT(pBackButtonWidget);
  pBackButtonWidget->m_FocusShiftLeft = -(NumDisplayModes + 1);
  pBackButtonWidget->m_FocusShiftRight = (NumDisplayModes + 1);
  pBackButtonWidget->m_FocusShiftDown = (LeftColumnSize + 1);

  UpdateRender();

  // Initialize focus to the first element (so that we're never unfocused,
  // because that doesn't make sense for controllers).
  if (m_FocusWidgets.Size() > 0) {
    m_FocusedWidget = m_FocusWidgets[0];
    // NOTE: Intentionally not calling SetFocus here, so effects don't happen;
    // we
    // just need an initial focus for controllers, it's not really *getting*
    // focus
  }
}
/*static*/ HashedString ConfigManager::GetInheritedSequenceHash( const SimpleString& FormatName, int Index, const HashedString& Default /*= HashedString::NullString*/, const STRING_TYPE& Context /*= EmptyContext*/ )
{
	return GetInheritedHash( SimpleString::PrintF( FormatName.CStr(), Index ), Default, Context );
}
/*static*/ float ConfigManager::GetInheritedSequenceFloat( const SimpleString& FormatName, int Index, float Default /*= 0.0f*/, const STRING_TYPE& Context /*= EmptyContext*/ )
{
	return GetInheritedFloat( SimpleString::PrintF( FormatName.CStr(), Index ), Default, Context );
}
/*static*/ bool ConfigManager::GetInheritedSequenceBool( const SimpleString& FormatName, int Index, bool Default /*= false*/, const STRING_TYPE& Context /*= EmptyContext*/ )
{
	return GetInheritedBool( SimpleString::PrintF( FormatName.CStr(), Index ), Default, Context );
}
/*static*/ int ConfigManager::GetArchetypeSequenceInt( const SimpleString& FormatName, int Index, const STRING_TYPE& Archetype, int Default /*= 0*/, const STRING_TYPE& Context /*= EmptyContext*/ )
{
	return GetArchetypeInt( SimpleString::PrintF( FormatName.CStr(), Index ), Archetype, Default, Context );
}
/*static*/ void ConfigManager::LoadTiny( const SimpleString& TinyString )
{
	ConfigParser::ParseTiny( MemoryStream( const_cast< char* >( TinyString.CStr() ), TinyString.Length() + 1 ) );
}
void ConfigParser::Parse( const IDataStream& Stream )
{
	Array< SToken >	Tokens;
	SToken			Token;
	Token.m_TokenType						= SToken::ET_Name;
	char			StrMark					= 0;	// Stores the character (either ' or ") that opened a string
	SToken			MacroToken;
	List<int>		ArrayCounters;
	Array<char>		CounterCharArray;
	int				LineCount				= 1;

	for(;;)
	{
		char c = Stream.ReadInt8();

		// Skip the UTF-8 byte order mark if present.
		if( UTF8_BOM_0 == static_cast<byte>( c ) )
		{
			CHECK( UTF8_BOM_1 == static_cast<byte>( Stream.ReadInt8() ) );
			CHECK( UTF8_BOM_2 == static_cast<byte>( Stream.ReadInt8() ) );
			c = Stream.ReadInt8();
		}

		if( Stream.EOS() )
		{
			if( Token.m_TokenString.Empty() )
			{
				Token.m_TokenType = SToken::ET_None;
				Tokens.PushBack( Token );
				DEBUGCATPRINTF( "Core", 2, "%s\n", SToken::m_TokenNames[ Token.m_TokenType ] );
			}
			else
			{
				Token.m_TokenString.PushBack( '\0' );
				Tokens.PushBack( Token );
				DEBUGCATPRINTF( "Core", 2, "%s: %s\n", SToken::m_TokenNames[ Token.m_TokenType ], Token.m_TokenString.GetData() );
				Token.m_TokenString.Clear();
			}

			break;
		}

		if( c == '&' )
		{
			if( Token.m_TokenType == SToken::ET_Name )
			{
				// Increment the current counter and add it to the current name.
				ASSERT( ArrayCounters.Size() > 0 );
				List<int>::Iterator CounterIter = ArrayCounters.Back();
				( *CounterIter )++;
				SimpleString CounterString = SimpleString::PrintF( "%d", *CounterIter );
				CounterCharArray.Clear();
				CounterString.FillArray( CounterCharArray );
				Token.m_TokenString.Append( CounterCharArray );
			}
			else if( Token.m_TokenType == SToken::ET_None )
			{
				// Add a new counter
				// Push a counter token that will be replaced with the count int later.
				ArrayCounters.PushBack( -1 );
				Token.m_TokenType = SToken::ET_Counter;
			}
			else if( Token.m_TokenType == SToken::ET_String )
			{
				Token.m_TokenString.PushBack( c );
			}
			else
			{
				WARNDESC( "Unexpected character '&' in token." );
			}
		}
		else if( c == '^' )
		{
			if( Token.m_TokenType == SToken::ET_Name )
			{
				// Add the current counter to the current name.
				ASSERT( ArrayCounters.Size() > 0 );
				List<int>::Iterator CounterIter = ArrayCounters.Back();
				ASSERT( ( *CounterIter ) >= 0 );
				SimpleString CounterString = SimpleString::PrintF( "%d", *CounterIter );
				CounterCharArray.Clear();
				CounterString.FillArray( CounterCharArray );
				Token.m_TokenString.Append( CounterCharArray );
			}
			else if( Token.m_TokenType == SToken::ET_String )
			{
				Token.m_TokenString.PushBack( c );
			}
			else
			{
				WARNDESC( "Unexpected character '^' in token." );
			}
		}
		else if( c == ' ' || c == '\t' )
		{
			switch( Token.m_TokenType )
			{
			case SToken::ET_None:
			case SToken::ET_Equals:
				// Ignore whitespace
				break;
			case SToken::ET_Name:
			case SToken::ET_Context:
			case SToken::ET_Macro:
				if( Token.m_TokenString.Empty() )
				{
					// If the name is empty, ignore whitespace (before the name)
				}
				else
				{
					// Close current token, push it, and expect an equals

					// If we're closing a macro, save it as such
					if( Token.m_TokenType == SToken::ET_Macro )
					{
						MacroToken = Token;
					}

					Token.m_TokenString.PushBack( '\0' );
					Tokens.PushBack( Token );
					DEBUGCATPRINTF( "Core", 2, "%s: %s\n", SToken::m_TokenNames[ Token.m_TokenType ], Token.m_TokenString.GetData() );
					Token.m_TokenString.Clear();

					if( Token.m_TokenType == SToken::ET_Name )
					{
						Token.m_TokenType = SToken::ET_Equals;
					}
					else if( Token.m_TokenType == SToken::ET_Context || Token.m_TokenType == SToken::ET_Macro )
					{
						Token.m_TokenType = SToken::ET_Name;
					}
				}
				break;
			case SToken::ET_Bool:
			case SToken::ET_Int:
			case SToken::ET_Float:
				// Close current token, push it, and expect nothing
				Token.m_TokenString.PushBack( '\0' );
				Tokens.PushBack( Token );
				DEBUGCATPRINTF( "Core", 2, "%s: %s\n", SToken::m_TokenNames[ Token.m_TokenType ], Token.m_TokenString.GetData() );
				Token.m_TokenString.Clear();

				Token.m_TokenType = SToken::ET_None;
				break;
			case SToken::ET_String:
				Token.m_TokenString.PushBack( c );
				break;
			default:
				WARNDESC( "Unexpected token" );
				break;
			}
		}
		else if( c == '=' )
		{
			switch( Token.m_TokenType )
			{
			case SToken::ET_Name:
				// Close current token, push it and an equals
				Token.m_TokenString.PushBack( '\0' );
				Tokens.PushBack( Token );
				DEBUGCATPRINTF( "Core", 2, "%s: %s\n", SToken::m_TokenNames[ Token.m_TokenType ], Token.m_TokenString.GetData() );
				Token.m_TokenString.Clear();

				Token.m_TokenType = SToken::ET_Equals;
				DEBUGCATPRINTF( "Core", 2, "%s\n", SToken::m_TokenNames[ Token.m_TokenType ] );
				Tokens.PushBack( Token );

				Token.m_TokenType = SToken::ET_None;
				break;
			case SToken::ET_Equals:
				// Already expecting =, just push it
				Tokens.PushBack( Token );
				DEBUGCATPRINTF( "Core", 2, "%s\n", SToken::m_TokenNames[ Token.m_TokenType ] );

				Token.m_TokenType = SToken::ET_None;
				break;
			case SToken::ET_String:
				Token.m_TokenString.PushBack( c );
				break;
			default:
				WARNDESC( "Unexpected token" );
				break;
			}
		}
		else if( c == '#' )
		{
			// # starts a comment

			// Allow # inside a string
			if( Token.m_TokenType == SToken::ET_String )
			{
				Token.m_TokenString.PushBack( c );
			}
			else
			{
				c = Stream.ReadInt8();
				
				if( c == '!' )	// #! and !# indicate the start and end of block comments
				{
					while( !Stream.EOS() )
					{
						if( Stream.ReadInt8() == '!' && Stream.ReadInt8() == '#' )
						{
							break;
						}
					}
				}
				else
				{
					// Read to end of line
					while( c != '\n' && c!= '\v' && !Stream.EOS() )	// Vertical tab stupidity again
					{
						c = Stream.ReadInt8();
					}

					// Change the context because we're on a new line
					Token.m_TokenType = SToken::ET_Name;

					++LineCount;
				}
			}
		}
		else if( c == '\\' && Token.m_TokenType == SToken::ET_String )
		{
			// Escape sequence, intended to insert linebreaks (and maybe other things in the future)
			// Config string escape sequences are not the same as C++ escape sequences. They can be
			// \\, \n, \?, \", or \xx (where x are hex digits, to specify any character by hex).

			char next = Stream.ReadInt8();
			if( next == 'n' )
			{
				Token.m_TokenString.PushBack( '\n' );
			}
			else if( next == '\"' )
			{
				Token.m_TokenString.PushBack( '\"' );
			}
			else if( next == '\\' )
			{
				Token.m_TokenString.PushBack( '\\' );
			}
			else if( next == 'x' )
			{
				char Hex = 0;
				for( uint HexIndex = 0; HexIndex < 2; ++HexIndex )
				{
					next = Stream.ReadInt8();
					ASSERT( IsHex( next ) );
					Hex = ( Hex << 4 ) | GetHex( next );
				}
				Token.m_TokenString.PushBack( Hex );
			}
			else if( next == 'u' )
			{
				// First, extract a unicode code point (e.g. \u00d7 for U+00D7)
				// NOTE: This only support the first Unicode plane, and is strict about
				// using four characters, so \ud7 is not a valid substitute for \u00d7.
				unicode_t CodePoint = 0;
				for( uint UnicodeIndex = 0; UnicodeIndex < 4; ++UnicodeIndex )
				{
					next = Stream.ReadInt8();
					ASSERT( IsHex( next ) );
					CodePoint = ( CodePoint << 4 ) | GetHex( next );
				}

				// Then convert the two-byte code point to UTF-8.
				Array<unicode_t> CodePointArray;
				CodePointArray.PushBack( CodePoint );
				const SimpleString UTF8String = SimpleString::SetUTF8( CodePointArray );

				for( uint CharIndex = 0; CharIndex < UTF8String.Length(); ++CharIndex )
				{
					const char NextChar = UTF8String.GetChar( CharIndex );
					Token.m_TokenString.PushBack( NextChar );
				}
			}
			else
			{
				PRINTF( "Unrecognized escape sequence \\%c at line %d\n", next, LineCount );
				WARNDESC( "Unrecognized escape sequence" );
			}
		}
		else if( c == 0x0d )
		{
			// DOS linebreak is 0D 0A, so ignore and expect \n to follow
		}
		else if( c == '\0' )
		{
			// Don't know how these are getting in either, but ignore them
		}
		else if( c == '\n' || c == '\v' )
		{
			if( Token.m_TokenType == SToken::ET_Macro )
			{
				MacroToken = Token;
			}

			// Dunno how vertical tabs are getting in, but treat them as linebreaks
			if( Token.m_TokenString.Empty() )
			{
				if( Token.m_TokenType != SToken::ET_Counter )
				{
					Token.m_TokenType = SToken::ET_None;
				}
				Tokens.PushBack( Token );
				DEBUGCATPRINTF( "Core", 2, "%s\n", SToken::m_TokenNames[ Token.m_TokenType ] );

				Token.m_TokenType = SToken::ET_Name;
			}
			else
			{
				Token.m_TokenString.PushBack( '\0' );
				Tokens.PushBack( Token );
				DEBUGCATPRINTF( "Core", 2, "%s: %s\n", SToken::m_TokenNames[ Token.m_TokenType ], Token.m_TokenString.GetData() );
				Token.m_TokenString.Clear();

				Token.m_TokenType = SToken::ET_Name;
			}

			++LineCount;
		}
		else if( c == '[' )
		{
			if( Token.m_TokenType == SToken::ET_String )
			{
				Token.m_TokenString.PushBack( c );
			}
			else
			{
				// We should only ever open a context when we're expecting a name
				ASSERT( Token.m_TokenType == SToken::ET_Name );
				Token.m_TokenType = SToken::ET_Context;

				// Opening a new context, clear the macro token.
				MacroToken = SToken();
			}
		}
		else if( c == ']' )
		{
			// If we've already closed the context, ignore; else, push token
			if( Token.m_TokenType == SToken::ET_String )
			{
				Token.m_TokenString.PushBack( c );
			}
			else
			{
				ASSERT( Token.m_TokenType == SToken::ET_Context );
				Token.m_TokenString.PushBack( '\0' );
				Tokens.PushBack( Token );
				DEBUGCATPRINTF( "Core", 2, "%s: %s\n", SToken::m_TokenNames[ Token.m_TokenType ], Token.m_TokenString.GetData() );
				Token.m_TokenString.Clear();
			}
		}
		else if( c == '@' )
		{
			if( Token.m_TokenType == SToken::ET_String )
			{
				Token.m_TokenString.PushBack( c );
			}
			else
			{
				// We should only ever declare or insert a macro when we're expecting a name
				ASSERT( Token.m_TokenType == SToken::ET_Name );
				c = Stream.ReadInt8();
				if( c == '@' )
				{
					// @@... means we're inserting the current macro into a name

					// Make sure there is a current macro. If this fails, a macro probably
					// wasn't opened in the current context.
					ASSERT( MacroToken.m_TokenString.Size() > 0 );

					const uint MacroLength = MacroToken.m_TokenString.Size();
					for( uint MacroIndex = 0; MacroIndex < MacroLength; ++MacroIndex )
					{
						Token.m_TokenString.PushBack( MacroToken.m_TokenString[ MacroIndex ] );
					}
				}
				else
				{
					// @... means we're declaring a new macro
					Token.m_TokenType = SToken::ET_Macro;
					if( c == ' ' || c == '\t' )
					{
						// Ignore whitespace at the front of macro
					}
					else
					{
						Token.m_TokenString.PushBack( c );
					}
				}
			}
		}
		else
		{
			bool ClosedString = false;
			InnerParse( c, StrMark, Token.m_TokenString, LineCount, Token.m_TokenType, &ClosedString );
			if( ClosedString )
			{
				Tokens.PushBack( Token );
				DEBUGCATPRINTF( "Core", 2, "%s: %s\n", SToken::m_TokenNames[ Token.m_TokenType ], Token.m_TokenString.GetData() );
				Token.m_TokenString.Clear();
				Token.m_TokenType = SToken::ET_None;
			}
		}
	}

	SimpleString Context = "";

	// Tokens are made, now create config vars
	for( uint i = 0; i < Tokens.Size(); ++i )
	{
		SToken& NameToken = Tokens[i];
		SimpleString Name = "";
		const char* ValueString = NULL;
		if( NameToken.m_TokenType == SToken::ET_Name )
		{
			Name = NameToken.m_TokenString.GetData();
			ASSERT( Tokens[ i + 1 ].m_TokenType == SToken::ET_Equals );

			SToken& ValueToken = Tokens[ i + 2 ];
			ValueString = ValueToken.m_TokenString.GetData();

			if( Context != "" )
			{
				CATPRINTF( "Core", 2, "%s:", Context.CStr() );
			}
			CATPRINTF( "Core", 2, "%s: %s: %s\n", Name.CStr(), SToken::m_TokenNames[ ValueToken.m_TokenType ], ValueString );

			switch( ValueToken.m_TokenType )
			{
			case SToken::ET_Bool:
				{
					// Just use the first character to determine truth
					bool Value = false;
					char first = ValueString[0];
					if( first == 't' || first == 'T' )
					{
						Value = true;
					}
					ConfigManager::SetBool( Name, Value, Context );
				}
				break;
			case SToken::ET_Int:
				{
					int Value = atoi( ValueString );
					ConfigManager::SetInt( Name, Value, Context );
				}
				break;
			case SToken::ET_Counter:
				{
					List<int>::Iterator NextCounterIter = ArrayCounters.Front();
					( *NextCounterIter )++;	// Add one to the last value we incremented, and that's the total for this array
					ConfigManager::SetInt( Name, *NextCounterIter, Context );
					ArrayCounters.PopFront();
				}
				break;
			case SToken::ET_Float:
				{
					float Value = (float)atof( ValueString );
					ConfigManager::SetFloat( Name, Value, Context );
				}
				break;
			case SToken::ET_String:
				{
					// Make a permanent copy of the string
					uint Length = (uint)strlen( ValueString );
					char* pString = new char[ Length + 1];
					memcpy_s( pString, Length + 1, ValueString, Length );
					pString[ Length ] = '\0';
					StringManager::AddString( StringManager::ESL_Permanent, pString );

					ConfigManager::SetString( Name, pString, Context );
				}

				break;
			default:
				WARNDESC( "Unexpected token" );
				break;
			}

			i += 2;
		}
		else if( NameToken.m_TokenType == SToken::ET_Context )
		{
			Context = NameToken.m_TokenString.GetData();
			//CATPRINTF( "Core", 2, "Pushed context %s\n", Context.CStr() );
		}
		else
		{
			DEBUGCATPRINTF( "Core", 2, "Skipped unexpected token %s (expected ET_Name)\n", SToken::m_TokenNames[ NameToken.m_TokenType ] );
		}
	}

	// Clean up
	for( uint i = 0; i < Tokens.Size(); ++i )
	{
		Tokens[i].m_TokenString.Clear();
	}
	Tokens.Clear();
}
Beispiel #15
0
void WBCompState::Report() const {
  Super::Report();

  const SimpleString State = ReverseHash::ReversedHash(m_State);
  PRINTF(WBPROPERTY_REPORT_PREFIX "Current State: %s\n", State.CStr());
}
void UIWidgetFrame::InitializeFromDefinition( const SimpleString& DefinitionName )
{
	UIWidget::InitializeFromDefinition( DefinitionName );

	MAKEHASH( DefinitionName );
	MAKEHASH( m_Archetype );

	STATICHASH( DisplayWidth );
	const float DisplayWidth	= ConfigManager::GetFloat( sDisplayWidth );
	const float ParentWidth		= m_OriginParent ? m_OriginParent->GetWidth() : DisplayWidth;
	const float ParentX			= m_OriginParent ? Ceiling( m_OriginParent->GetX() ) : 0.0f;

	STATICHASH( DisplayHeight );
	const float DisplayHeight	= ConfigManager::GetFloat( sDisplayHeight );
	const float ParentHeight	= m_OriginParent ? m_OriginParent->GetHeight() : DisplayHeight;
	const float ParentY			= m_OriginParent ? Ceiling( m_OriginParent->GetY() ) : 0.0f;

	// "Screen" values are now relative to parent, which may or may not be screen dimensions.

	STATICHASH( PixelX );
	STATICHASH( ScreenX );
	float X = Pick(
		ConfigManager::GetArchetypeFloat( sPixelX, sm_Archetype, 0.0f, sDefinitionName ),
		ParentWidth * ConfigManager::GetArchetypeFloat( sScreenX, sm_Archetype, 0.0f, sDefinitionName ) );

	STATICHASH( PixelY );
	STATICHASH( ScreenY );
	float Y = Pick(
		ConfigManager::GetArchetypeFloat( sPixelY, sm_Archetype, 0.0f, sDefinitionName ),
		ParentHeight * ConfigManager::GetArchetypeFloat( sScreenY, sm_Archetype, 0.0f, sDefinitionName ) );
	
	STATICHASH( PixelWidth );
	STATICHASH( ScreenWidth );
	float Width = Pick(
		ConfigManager::GetArchetypeFloat( sPixelWidth, sm_Archetype, 0.0f, sDefinitionName ),
		ParentWidth * ConfigManager::GetArchetypeFloat( sScreenWidth, sm_Archetype, 0.0f, sDefinitionName ) );
	
	STATICHASH( PixelHeight );
	STATICHASH( ScreenHeight );
	float Height = Pick(
		ConfigManager::GetArchetypeFloat( sPixelHeight, sm_Archetype, 0.0f, sDefinitionName ),
		ParentHeight * ConfigManager::GetArchetypeFloat( sScreenHeight, sm_Archetype, 0.0f, sDefinitionName ) );

	STATICHASH( PixelBorder );
	m_Border = ConfigManager::GetArchetypeFloat( sPixelBorder, sm_Archetype, 0.0f, sDefinitionName );

	// Adjust for desired aspect ratio if one dimension is not given
	// (This is used to size images using ScreenWidth or ScreenHeight
	// properly regardless of screen aspect ratio.
	STATICHASH( AspectRatio );
	const float AspectRatio = ConfigManager::GetArchetypeFloat( sAspectRatio, sm_Archetype, 1.0f, sDefinitionName );
	if( Width == 0.0f )
	{
		Width = Height * AspectRatio;
	}
	else if( Height == 0.0f )
	{
		Height = Width / AspectRatio;
	}

	AdjustDimensionsToParent( X, Y, Width, Height, ParentX, ParentY, ParentWidth, ParentHeight );
	GetPositionFromOrigin( X, Y, Width, Height );

	ASSERT( Width > m_Border * 2.0f );
	ASSERT( Height > m_Border * 2.0f );

	STATICHASH( ClampToPixelGrid );
	if( ConfigManager::GetArchetypeBool( sClampToPixelGrid, sm_Archetype, true, sDefinitionName ) )
	{
		m_TopLeft.x = Round( m_TopLeft.x );
		m_TopLeft.y = Round( m_TopLeft.y );
	}

	// Offset to properly align on pixel grid.
	const float PixelGridOffset = GetPixelGridOffset();
	m_TopLeft.x -= PixelGridOffset;
	m_TopLeft.y -= PixelGridOffset;

	STATICHASH( Image );
	const char* const Filename = ConfigManager::GetArchetypeString( sImage, sm_Archetype, DEFAULT_TEXTURE, sDefinitionName );
	m_Texture = m_UIManager->GetRenderer()->GetTextureManager()->GetTexture( Filename, TextureManager::ETL_Permanent );

	m_Dimensions = Vector2( Width, Height );

	STATICHASH( MaterialOverride );
	const SimpleString DefaultMaterial( "Material_HUD" );
	m_Material = ConfigManager::GetArchetypeString( sMaterialOverride, sm_Archetype, DefaultMaterial.CStr(), sDefinitionName );

	UpdateRender();
}