int CALLBACK WinMain(HINSTANCE Instance, HINSTANCE PrevInstance, LPSTR CommandLine, int ShowCode) {
	win32_state Win32State = {};

	LARGE_INTEGER PerfCounterFrequencyResult;
	QueryPerformanceFrequency(&PerfCounterFrequencyResult);
	GlobalPerfCounterFrequency = PerfCounterFrequencyResult.QuadPart;

	Win32GetEXEFileName(&Win32State);
	char SourceGameCodeDLLFullPath[WIN32_STATE_FILE_NAME_COUNT];
	Win32BuildEXEPathFileName(&Win32State, "handmade.dll", sizeof(SourceGameCodeDLLFullPath), SourceGameCodeDLLFullPath);
	char TempGameCodeDLLFullPath[WIN32_STATE_FILE_NAME_COUNT];
	Win32BuildEXEPathFileName(&Win32State, "handmade_temp.dll", sizeof(TempGameCodeDLLFullPath), TempGameCodeDLLFullPath);
	char GameCodeLockFullPath[WIN32_STATE_FILE_NAME_COUNT];
	Win32BuildEXEPathFileName(&Win32State, "lock.tmp", sizeof(GameCodeLockFullPath), GameCodeLockFullPath);

	// NOTE: setting windows scheduler granularity for our sleep() call
	UINT DesiredSchedulerMS = 1;
	bool32 SleepIsGranular = (timeBeginPeriod(DesiredSchedulerMS) == TIMERR_NOERROR);

	Win32LoadXInput();
	Win32ResizeDIBSection(&GlobalBackbuffer, 960, 540);

#if HANDMADE_INTERNAL
	DEBUGGlobalShowCursor = true;
#endif

	WNDCLASSEXA WindowClass = {};
	WindowClass.style = CS_VREDRAW | CS_HREDRAW;
	WindowClass.cbSize = sizeof(WNDCLASSEXA);
	WindowClass.lpfnWndProc = Win32MainWindowCallback;
	WindowClass.hInstance = Instance;
	WindowClass.hCursor = LoadCursor(0, IDC_ARROW);
	// WindowClass.hIcon;
	WindowClass.lpszClassName = "HandmadeHeroWindowClass";

	if (RegisterClassExA(&WindowClass)) {
		// WS_EX_TOPMOST|WS_EX_LAYERED
		HWND Window = CreateWindowExA(0, WindowClass.lpszClassName, "Handmade Hero", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 996, 600, 0, 0, Instance, 0);

		if (Window) {
			// TODO: reliably query this from windows
			int MonitorRefreshHz = 60;
			HDC RefreshDC = GetDC(Window);
			int Win32RefreshRate = GetDeviceCaps(RefreshDC, VREFRESH);
			ReleaseDC(Window, RefreshDC);
			if (Win32RefreshRate > 1) {
				MonitorRefreshHz = Win32RefreshRate;

				if (MonitorRefreshHz == 59) {
					MonitorRefreshHz = 60;
				}
			}
			real32 GameUpdateHz = MonitorRefreshHz / 2.0f;
			real32 TargetSecondsPerFrame = 1.0f / GameUpdateHz;

			// NOTE: sound test
			win32_sound_output SoundOutput = {};
			SoundOutput.SamplesPerSecond = 48000;
			SoundOutput.BytesPerSample = sizeof(int16) * 2;
			SoundOutput.SecondaryBufferSize = SoundOutput.SamplesPerSecond * SoundOutput.BytesPerSample;
			// TODO: compute this variance and see what the lowest reasonable value is
			SoundOutput.SafetyBytes = (int)((real32)SoundOutput.SamplesPerSecond * (real32)SoundOutput.BytesPerSample / GameUpdateHz / 3.0f);

			Win32InitDSound(Window, SoundOutput.SamplesPerSecond, SoundOutput.SecondaryBufferSize);
			Win32ClearSoundBuffer(&SoundOutput);
			GlobalSecondaryBuffer->Play(0, 0, DSBPLAY_LOOPING);

			GlobalRunning = true;

			// TODO: pool with bitmap virtualalloc
			int16 *Samples = (int16 *)VirtualAlloc(0, SoundOutput.SecondaryBufferSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

#if HANDMADE_INTERNAL
			LPVOID BaseAddress = (LPVOID)Terabytes(2);
#else
			LPVOID BaseAddress = 0;
#endif

			game_memory GameMemory = {};
			GameMemory.PermanentStorageSize = Megabytes(64);
			GameMemory.TransientStorageSize = Gigabytes(1);
			GameMemory.DEBUGPlatformFreeFileMemory = DEBUGPlatformFreeFileMemory;
			GameMemory.DEBUGPlatformReadEntireFile = DEBUGPlatformReadEntireFile;
			GameMemory.DEBUGPlatformWriteEntireFile = DEBUGPlatformWriteEntireFile;

			// TODO: handle various memory footprints using system metrics
			// TODO: use MEM_LARGE_PAGES
			Win32State.TotalSize = GameMemory.PermanentStorageSize + GameMemory.TransientStorageSize;
			Win32State.GameMemoryBlock = VirtualAlloc(BaseAddress, (size_t)Win32State.TotalSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
			GameMemory.PermanentStorage = Win32State.GameMemoryBlock;
			GameMemory.TransientStorage = (uint8 *)GameMemory.PermanentStorage + GameMemory.PermanentStorageSize;

			for (int ReplayIndex = 1; ReplayIndex < ArrayCount(Win32State.ReplayBuffers); ++ReplayIndex) {
				// TODO: recording system still takes too long on record start
				win32_replay_buffer *ReplayBuffer = &Win32State.ReplayBuffers[ReplayIndex];

				Win32GetInputFileLocation(&Win32State, false, ReplayIndex, sizeof(ReplayBuffer->FileName), ReplayBuffer->FileName);
				ReplayBuffer->FileHandle = CreateFileA(ReplayBuffer->FileName, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);

				LARGE_INTEGER MaxSize;
				MaxSize.QuadPart = Win32State.TotalSize;
				ReplayBuffer->MemoryMap = CreateFileMapping(ReplayBuffer->FileHandle, 0, PAGE_READWRITE, MaxSize.HighPart, MaxSize.LowPart, 0);
				ReplayBuffer->MemoryBlock = MapViewOfFile(ReplayBuffer->MemoryMap, FILE_MAP_ALL_ACCESS, 0, 0, (size_t)Win32State.TotalSize);

				if (!ReplayBuffer->MemoryBlock) {
					// TODO: diagnostic
				}
			}

			if (Samples && GameMemory.PermanentStorage && GameMemory.TransientStorage) {
				game_input Input[2] = {};
				game_input *NewInput = &Input[0];
				game_input *OldInput = &Input[1];

				LARGE_INTEGER LastCounter = Win32GetWallClock();
				LARGE_INTEGER FlipWallClock = Win32GetWallClock();

				int DebugTimeMarkerIndex = 0;
				win32_debug_time_marker DebugTimeMarkers[30] = { 0 };

				// TODO: handle startup specially
				bool32 SoundIsValid = false;
				DWORD AudioLatencyBytes = 0;
				real32 AudioLatencySeconds = 0;

				win32_game_code Game = Win32LoadGameCode(SourceGameCodeDLLFullPath, TempGameCodeDLLFullPath, GameCodeLockFullPath);

				uint64 LastCycleCount = __rdtsc();

				while (GlobalRunning) {
					NewInput->FrameTimeDelta = TargetSecondsPerFrame;

					FILETIME NewDLLWriteTime = Win32GetLastWriteTime(SourceGameCodeDLLFullPath);
					if (CompareFileTime(&NewDLLWriteTime, &Game.DLLLastWriteTime) != 0) {
						Win32UnloadGameCode(&Game);
						Game = Win32LoadGameCode(SourceGameCodeDLLFullPath, TempGameCodeDLLFullPath, GameCodeLockFullPath);
					}

					// TODO: zeroing macro
					// TODO: we cant zero everything as the up/down state will be wrong
					game_controller_input *OldKeyboardController = GetController(OldInput, 0);
					game_controller_input *NewKeyboardController = GetController(NewInput, 0);
					*NewKeyboardController = {};
					NewKeyboardController->IsConnected = true;

					for (int ButtonIndex = 0; ButtonIndex < ArrayCount(NewKeyboardController->Buttons); ++ButtonIndex) {
						NewKeyboardController->Buttons[ButtonIndex].EndedDown = OldKeyboardController->Buttons[ButtonIndex].EndedDown;
					}

					Win32ProcessPendingMessages(&Win32State, NewKeyboardController);

					if (!GlobalPause) {
						POINT MousePoint;
						GetCursorPos(&MousePoint);
						ScreenToClient(Window, &MousePoint);
						NewInput->MouseX = MousePoint.x;
						NewInput->MouseY = MousePoint.y;
						NewInput->MouseZ = 0; // TODO: support mousewheel?
						Win32ProcessKeyboardMessage(&NewInput->MouseButtons[0], GetKeyState(VK_LBUTTON) & (1 << 15));
						Win32ProcessKeyboardMessage(&NewInput->MouseButtons[1], GetKeyState(VK_MBUTTON) & (1 << 15));
						Win32ProcessKeyboardMessage(&NewInput->MouseButtons[2], GetKeyState(VK_RBUTTON) & (1 << 15));
						Win32ProcessKeyboardMessage(&NewInput->MouseButtons[3], GetKeyState(VK_XBUTTON1) & (1 << 15));
						Win32ProcessKeyboardMessage(&NewInput->MouseButtons[4], GetKeyState(VK_XBUTTON2) & (1 << 15));

						// TODO: should we poll this more frequently
						// TODO: dont poll disconnected controllers to prevent xinput frame rate impact
						DWORD MaxControllerCount = XUSER_MAX_COUNT;
						if (MaxControllerCount > (ArrayCount(NewInput->Controllers) - 1)) {
							MaxControllerCount = (ArrayCount(NewInput->Controllers) - 1);
						}

						for (DWORD ControllerIndex = 0; ControllerIndex < MaxControllerCount; ++ControllerIndex) {
							DWORD OurControllerIndex = ControllerIndex + 1;
							game_controller_input *OldController = GetController(OldInput, OurControllerIndex);
							game_controller_input *NewController = GetController(NewInput, OurControllerIndex);

							XINPUT_STATE ControllerState;

							if (XInputGetState(ControllerIndex, &ControllerState) == ERROR_SUCCESS) {
								NewController->IsConnected = true;
								NewController->IsAnalog = OldController->IsAnalog;
								// TODO: See if ControllerState.dwPacketNumber increments too rapidly
								XINPUT_GAMEPAD *Pad = &ControllerState.Gamepad;

								// TODO: currently handling a square deadzone, check if it is circular
								NewController->StickAverageX = Win32ProcessXInputStickValue(Pad->sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
								NewController->StickAverageY = Win32ProcessXInputStickValue(Pad->sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);

								if ((NewController->StickAverageX != 0.0f) || (NewController->StickAverageY != 0.0f)) {
									NewController->IsAnalog = true;
								}

								if (Pad->wButtons & XINPUT_GAMEPAD_DPAD_UP) {
									NewController->StickAverageY = 1.0f;
									NewController->IsAnalog = false;
								}

								if (Pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN) {
									NewController->StickAverageY = -1.0f;
									NewController->IsAnalog = false;
								}

								if (Pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT) {
									NewController->StickAverageX = -1.0f;
									NewController->IsAnalog = false;
								}

								if (Pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) {
									NewController->StickAverageX = 1.0f;
									NewController->IsAnalog = false;
								}

								real32 Threshold = 0.5f;
								Win32ProcessXInputDigitalButton((NewController->StickAverageX < -Threshold) ? 1 : 0, &OldController->MoveLeft, 1, &NewController->MoveLeft);
								Win32ProcessXInputDigitalButton((NewController->StickAverageX > Threshold) ? 1 : 0, &OldController->MoveRight, 1, &NewController->MoveRight);
								Win32ProcessXInputDigitalButton((NewController->StickAverageY < -Threshold) ? 1 : 0, &OldController->MoveDown, 1, &NewController->MoveDown);
								Win32ProcessXInputDigitalButton((NewController->StickAverageY > Threshold) ? 1 : 0, &OldController->MoveUp, 1, &NewController->MoveUp);

								Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->ActionDown, XINPUT_GAMEPAD_A, &NewController->ActionDown);
								Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->ActionRight, XINPUT_GAMEPAD_B, &NewController->ActionRight);
								Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->ActionLeft, XINPUT_GAMEPAD_X, &NewController->ActionLeft);
								Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->ActionUp, XINPUT_GAMEPAD_Y, &NewController->ActionUp);
								Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->LeftShoulder, XINPUT_GAMEPAD_LEFT_SHOULDER, &NewController->LeftShoulder);
								Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->RightShoulder, XINPUT_GAMEPAD_RIGHT_SHOULDER, &NewController->RightShoulder);

								Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->Start, XINPUT_GAMEPAD_START, &NewController->Start);
								Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->Back, XINPUT_GAMEPAD_BACK, &NewController->Back);
							}
							else {
								// NOTE: the controller is not available
								NewController->IsConnected = false;
							}
						}

						thread_context Thread = {};

						game_offscreen_buffer Buffer = {};
						Buffer.Memory = GlobalBackbuffer.Memory;
						Buffer.Width = GlobalBackbuffer.Width;
						Buffer.Height = GlobalBackbuffer.Height;
						Buffer.Pitch = GlobalBackbuffer.Pitch;
						Buffer.BytesPerPixel = GlobalBackbuffer.BytesPerPixel;

						if (Win32State.InputRecordingIndex) {
							Win32RecordInput(&Win32State, NewInput);
						}

						if (Win32State.InputPlaybackIndex) {
							Win32PlaybackInput(&Win32State, NewInput);
						}

						if (Game.UpdateAndRender) {
							Game.UpdateAndRender(&Thread, &GameMemory, NewInput, &Buffer);
						}

						LARGE_INTEGER AudioWallClock = Win32GetWallClock();
						real32 FromBeginToAudioSeconds = Win32GetSecondsElapsed(FlipWallClock, AudioWallClock);

						DWORD PlayCursor;
						DWORD WriteCursor;

						if (GlobalSecondaryBuffer->GetCurrentPosition(&PlayCursor, &WriteCursor) == DS_OK) {
							/* NOTE: Sound output explanation

							We define a safety value that is the number of samples we think our game update loop can vary by.
							When we wake up to write audio we look at the play cursor position and forecast where we think it will be on the next frame boundary.
							If the write cursor is before that by at least our safety value, the target fill position is the frame boundary plus one frame. This gives us perfect audio sync if the audio latency is low enough.
							If the write cursor is after that safety value then we assume we can't sync the audio so we write one frames worth of audio plus the safety values worth of samples.

							*/

							if (!SoundIsValid) {
								SoundOutput.RunningSampleIndex = WriteCursor / SoundOutput.BytesPerSample;
								SoundIsValid = true;
							}

							DWORD ByteToLock = (SoundOutput.RunningSampleIndex * SoundOutput.BytesPerSample) % SoundOutput.SecondaryBufferSize;
							DWORD ExpectedSoundBytesPerFrame = (int)((real32)(SoundOutput.SamplesPerSecond * SoundOutput.BytesPerSample) / GameUpdateHz);
							real32 SecondsLeftUntilFlip = TargetSecondsPerFrame - FromBeginToAudioSeconds;
							DWORD ExpectedBytesUntilFlip = (DWORD)((SecondsLeftUntilFlip / TargetSecondsPerFrame) * (real32)ExpectedSoundBytesPerFrame);
							DWORD ExpectedFrameBoundaryByte = PlayCursor + ExpectedBytesUntilFlip;
							DWORD SafeWriteCursor = WriteCursor;

							if (SafeWriteCursor < PlayCursor) {
								SafeWriteCursor += SoundOutput.SecondaryBufferSize;
							}

							Assert(SafeWriteCursor >= PlayCursor);
							SafeWriteCursor += SoundOutput.SafetyBytes;
							bool32 AudioCardIsLowLatency = (SafeWriteCursor < ExpectedFrameBoundaryByte);
							DWORD TargetCursor = 0;

							if (AudioCardIsLowLatency) {
								TargetCursor = ExpectedFrameBoundaryByte + ExpectedSoundBytesPerFrame;
							}
							else {
								TargetCursor = WriteCursor + ExpectedSoundBytesPerFrame + SoundOutput.SafetyBytes;
							}

							TargetCursor = TargetCursor % SoundOutput.SecondaryBufferSize;
							DWORD BytesToWrite = 0;

							if (ByteToLock > TargetCursor) {
								BytesToWrite = SoundOutput.SecondaryBufferSize - ByteToLock;
								BytesToWrite += TargetCursor;
							}
							else {
								BytesToWrite = TargetCursor - ByteToLock;
							}

							game_sound_output_buffer SoundBuffer = {};
							SoundBuffer.SamplesPerSecond = SoundOutput.SamplesPerSecond;
							SoundBuffer.SampleCount = BytesToWrite / SoundOutput.BytesPerSample;
							SoundBuffer.Samples = Samples;
							if (Game.GetSoundSamples) {
								Game.GetSoundSamples(&Thread, &GameMemory, &SoundBuffer);
							}

#if HANDMADE_INTERNAL
							win32_debug_time_marker *Marker = &DebugTimeMarkers[DebugTimeMarkerIndex];
							Marker->OutputPlayCursor = PlayCursor;
							Marker->OutputWriteCursor = WriteCursor;
							Marker->OutputLocation = ByteToLock;
							Marker->OutputByteCount = BytesToWrite;
							Marker->ExpectedFlipPlayCursor = ExpectedFrameBoundaryByte;
							DWORD UnwrappedWriteCursor = WriteCursor;

							if (UnwrappedWriteCursor < PlayCursor) {
								UnwrappedWriteCursor += SoundOutput.SecondaryBufferSize;
							}

							AudioLatencyBytes = UnwrappedWriteCursor - PlayCursor;
							AudioLatencySeconds = ((real32)AudioLatencyBytes / (real32)SoundOutput.BytesPerSample) / (real32)SoundOutput.SamplesPerSecond;

#if 0
							char DebugSoundBuffer[256];
							sprintf_s(DebugSoundBuffer, "BTL:%u TC:%u BTW:%u - PC:%u WC:%u DELTA:%u (%fs)\n", ByteToLock, TargetCursor, BytesToWrite, PlayCursor, WriteCursor, AudioLatencyBytes, AudioLatencySeconds);
							OutputDebugStringA(DebugSoundBuffer);
#endif
#endif
							Win32FillSoundBuffer(&SoundOutput, ByteToLock, BytesToWrite, &SoundBuffer);
						}
						else {
							SoundIsValid = false;
						}

						LARGE_INTEGER WorkCounter = Win32GetWallClock();
						real32 WorkSecondsElapsed = Win32GetSecondsElapsed(LastCounter, WorkCounter);
						// TODO: not tested yet!
						real32 SecondsElapsedForFrame = WorkSecondsElapsed;

						if (SecondsElapsedForFrame < TargetSecondsPerFrame) {
							if (SleepIsGranular) {
								DWORD SleepMS = (DWORD)(1000.0f * (TargetSecondsPerFrame - SecondsElapsedForFrame));
								if (SleepMS > 0) {
									Sleep(SleepMS);
								}
							}

							real32 TestSecondsElapsedForFrame = Win32GetSecondsElapsed(LastCounter, Win32GetWallClock());

							if (TestSecondsElapsedForFrame < TargetSecondsPerFrame) {
								// TODO: log missed sleep here
							}

							while (SecondsElapsedForFrame < TargetSecondsPerFrame) {
								SecondsElapsedForFrame = Win32GetSecondsElapsed(LastCounter, Win32GetWallClock());
							}
						}
						else {
							// TODO: missed frame rate
							// TODO: logging
						}

						LARGE_INTEGER EndCounter = Win32GetWallClock();
						real32 MSPerFrame = 1000.0f * Win32GetSecondsElapsed(LastCounter, EndCounter);
						LastCounter = EndCounter;

						win32_window_dimension Dimension = Win32GetWindowDimension(Window);
						HDC BufferDC = GetDC(Window);
						Win32DisplayBufferInWindow(&GlobalBackbuffer, BufferDC, Dimension.Width, Dimension.Height);
						ReleaseDC(Window, BufferDC);

						FlipWallClock = Win32GetWallClock();

#if HANDMADE_INTERNAL
						DWORD DebugPlayCursor;
						DWORD DebugWriteCursor;
						if (GlobalSecondaryBuffer->GetCurrentPosition(&DebugPlayCursor, &DebugWriteCursor) == DS_OK) {
							Assert(DebugTimeMarkerIndex < ArrayCount(DebugTimeMarkers));
							win32_debug_time_marker *Marker = &DebugTimeMarkers[DebugTimeMarkerIndex];
							Marker->FlipPlayCursor = DebugPlayCursor;
							Marker->FlipWriteCursor = DebugWriteCursor;
						}
#endif

						game_input *Temp = NewInput;
						NewInput = OldInput;
						OldInput = Temp;
						// TODO: should these be cleared?

#if 0
						uint64 EndCycleCount = __rdtsc();
						uint64 CyclesElapsed = EndCycleCount - LastCycleCount;
						LastCycleCount = EndCycleCount;

						// real32 FPS = (real32)GlobalPerfCounterFrequency / (real32)CounterElapsed;
						real32 FPS = 0.0f;
						real32 MCPF = (real32)CyclesElapsed / (1000.0f * 1000.0f);

						char DebugPerformanceBuffer[256];
						sprintf_s(DebugPerformanceBuffer, "%0.02fmspf, %0.02ffps, %0.02fmcpf\n", MSPerFrame, FPS, MCPF);
						OutputDebugStringA(DebugPerformanceBuffer);
#endif

#if HANDMADE_INTERNAL
						++DebugTimeMarkerIndex;
						if (DebugTimeMarkerIndex == ArrayCount(DebugTimeMarkers)) {
							DebugTimeMarkerIndex = 0;
						}
#endif
					}
				}
			}
			else {
				// TODO: logging
			}
		}
		else {
			// TODO: logging
		}
	}
	else {
		// TODO: logging
	}

	return(0);
}
示例#2
0
int CALLBACK WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int ) {
	LARGE_INTEGER performanceFrequencyResult;
	QueryPerformanceFrequency( &performanceFrequencyResult );
	performanceFrequency = performanceFrequencyResult.QuadPart;

	win32State_t *state = &win32State;
	Win32GetExeFileName( state );
	char gameDllFullPath[ 256 ];
	Win32BuildExePathFileName( state, "tiny.dll", sizeof( gameDllFullPath ), gameDllFullPath );
	char tempGameDllFullPath[ 256 ];
	Win32BuildExePathFileName( state, "tiny_temp.dll", sizeof( tempGameDllFullPath ), tempGameDllFullPath );

	UINT desiredSchedulerMs = 1;
	b32 sleepIsGranular = ( timeBeginPeriod( desiredSchedulerMs ) == TIMERR_NOERROR );

	WNDCLASSA wndClass = { 0 };
	wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wndClass.lpfnWndProc = WindowProc;
	wndClass.hInstance = hInstance;
	wndClass.lpszClassName = "tinyrenderer";

	if ( !RegisterClassA( &wndClass ) ) {
		printf( "Failed RegisterClass()\n" );
		return 1;
	}

	HWND hWnd = CreateWindow(
		wndClass.lpszClassName, "Tiny Renderer",
		WS_OVERLAPPEDWINDOW | WS_VISIBLE,
		CW_USEDEFAULT, CW_USEDEFAULT,
		WINDOW_WIDTH, WINDOW_HEIGHT,
		0, 0, 0, 0 );
	if ( !hWnd ) {
		printf( "Failed CreateWindowA()\n" );
		return 1;
	}

	Win32_ResizeDibSection( &backBuffer, RENDER_WIDTH, RENDER_HEIGHT );

	int monitorRefreshHz = 60;
	HDC refreshDC = GetDC( hWnd );
	int win32RefreshRate = GetDeviceCaps( refreshDC, VREFRESH );
	if ( win32RefreshRate > 1 ) {
		monitorRefreshHz = win32RefreshRate;
	}
	float gameUpdateHz = ( monitorRefreshHz / 2.0f );
	float targetMsPerFrame = 1000.0f * ( 1.0f / ( float ) gameUpdateHz );

	LARGE_INTEGER lastCounter = Win32GetWallClock( );
	LARGE_INTEGER flipWallClock = Win32GetWallClock( );

	win32GameCode_t game = Win32LoadGameCode( gameDllFullPath, tempGameDllFullPath );

	//uint64_t lastCycleCount = __rdtsc();
	running = true;
	while ( running ) {
		FILETIME dllWriteTime = Win32GetLastWriteTime( gameDllFullPath );
		if ( CompareFileTime( &dllWriteTime, &game.lastWriteTime ) != 0 ) {
			Win32UnloadGameCode( &game );
			game = Win32LoadGameCode( gameDllFullPath, tempGameDllFullPath );
		}

		MSG msg = { 0 };
		while ( PeekMessageA( &msg, hWnd, 0, 0, PM_REMOVE ) ) {
			TranslateMessage( &msg );
			DispatchMessageA( &msg );
		}
		if ( running ) {

			gameBackBuffer_t gameBuffer = {};
			gameBuffer.memory = backBuffer.memory;
			gameBuffer.width = backBuffer.width;
			gameBuffer.height = backBuffer.height;
			gameBuffer.pitch = backBuffer.pitch;

			// Render the things
			if ( game.updateAndRender ) {
				game.updateAndRender( &gameBuffer );
			}

			LARGE_INTEGER workCounter = Win32GetWallClock( );
			float workMsElapsed = Win32GetMsElapsed( lastCounter, workCounter );
			float msElapsedForFrame = workMsElapsed;
			if ( msElapsedForFrame < targetMsPerFrame ) {
				if ( sleepIsGranular ) {
					DWORD sleepMs = ( DWORD ) ( targetMsPerFrame - msElapsedForFrame );
					if ( sleepMs > 0 ) {
						Sleep( sleepMs );
					}
				}

				while ( msElapsedForFrame < targetMsPerFrame ) {
					msElapsedForFrame = Win32GetMsElapsed( lastCounter, Win32GetWallClock( ) );
				}
			}

			LARGE_INTEGER endCounter = Win32GetWallClock( );
			float msPerFrame = Win32GetMsElapsed( lastCounter, endCounter );
			lastCounter = endCounter;

			char title[ 256 ];
			sprintf_s( title, "%.2fms/f", msPerFrame );
			SetWindowTextA( hWnd, title );

			// Put the things on the screen
			HDC dc = GetDC( hWnd );
			RECT rect;
			GetClientRect( hWnd, &rect );
			int width = rect.right - rect.left;
			int height = rect.bottom - rect.top;
			Win32_AspectBlt( dc, &backBuffer, width, height );
			ReleaseDC( hWnd, dc );

			flipWallClock = Win32GetWallClock( );
		}
	}

	return 0;
}
示例#3
0
int CALLBACK
old(
    HINSTANCE Instance,
    HINSTANCE PrevInstance,
    LPSTR CommandLine,
    int ShowCode)
{
#if 1
    Win32EnableConsole();
#endif

    sf::ContextSettings settings;
    settings.depthBits = 32; //24
    settings.stencilBits = 0; //0
    settings.antialiasingLevel = 0; //0
    settings.majorVersion = 3;
    settings.minorVersion = 2;

    // Display the list of all the video modes available for fullscreen
    std::vector<sf::VideoMode> modes = sf::VideoMode::getFullscreenModes();
    for (std::size_t i = 0; i < modes.size(); ++i)
    {
        sf::VideoMode mode = modes[i];    
        std::cout << "Mode #" << i << ": "
        << mode.width << "x" << mode.height << " - "
        << mode.bitsPerPixel << " bpp" << std::endl;
    }
    
    uint8 defaultStyle = (sf::Style::Titlebar | sf::Style::Close);
    auto mode = modes[17];
    sf::RenderWindow renderWindow(sf::VideoMode(mode.width, mode.height, mode.bitsPerPixel), "OpenGL", defaultStyle , settings);
    
    renderWindow.setVerticalSyncEnabled(true);
    renderWindow.setFramerateLimit(60);
    renderWindow.resetGLStates();

    settings = renderWindow.getSettings();

    cout << "depth bits:" << settings.depthBits << endl;
    cout << "stencil bits:" << settings.stencilBits << endl;
    cout << "antialiasing level:" << settings.antialiasingLevel << endl;
    cout << "version:" << settings.majorVersion << "." << settings.minorVersion << endl;

    renderWindow.setActive(true);

    sfg::SFGUI sfgui;
    sfg::Desktop sfguiDesktop;

    CreateGui(sfguiDesktop);

    sf::Font retro_font;
    retro_font.loadFromFile( "../data/fonts/Retro Computer_DEMO.ttf" );
    auto fent = std::make_shared<sf::Font>();// = sf::Font>(retro_font);
    fent->loadFromFile( "../data/fonts/Retro Computer_DEMO.ttf" );
    
    //my_font.setGlobalBounds(text.getGlobalBounds.left, text.getGlobalBounds().top);
    sfguiDesktop.GetEngine().GetResourceManager().AddFont( "retro_font", fent );
    //desktop.SetProperty( "*", "FontName",  "custom_font" );

    sfguiDesktop.SetProperties(
        "* {"
        "   FontName: retro_font;"
        "   FontSize: 18;"
        "}"
        );

    sf::Text text;
    text.setFont(retro_font);
    text.setPosition(sf::Vector2f(2, 2));
    text.setCharacterSize(18);
    text.setColor(sf::Color::White);

    KeyboardManager keyboardManager;

    //Game game(renderWindow, retro_font, &keyboardManager);
    char *GameDLLFullPath = "J:/build/terrific.dll";
    char *TempDLLName = "J:/build/tmp.dll";
    char *LockFileName = "J:/build/lock.tmp";

    auto GameCodeDLL = Win32LoadGameCode(GameDLLFullPath, TempDLLName, LockFileName);
    Game *game = GameCodeDLL.CreateGame(renderWindow, retro_font, &keyboardManager);
    uint32 LoadCounter = 0;

    uint32 m_fps_counter = 0;
    float delta = 0;
    sf::Clock m_fps_clock;
    m_fps_clock.restart();

    sf::Clock clock;
    sf::Clock frame_time_clock;

    sf::Int64 frame_times[5000];
    std::size_t frame_times_index = 0;

    std::fill( std::begin( frame_times ), std::end( frame_times ), 0 );
    int X(0), Y(0);
    while (globalRunning)
    {
        sf::Event event;
        while (renderWindow.pollEvent(event))
        {
            if ((event.type == sf::Event::Closed))
            {
                globalRunning = false;
                break;
            }
            else if ((event.type == sf::Event::MouseMoved))
            {
                X = event.mouseMove.x;
                Y = event.mouseMove.y;
            } 
            else if ((event.type == sf::Event::KeyPressed) |
               (event.type == sf::Event::KeyReleased))
            {
                keyboardManager.ProcessEvent(event);
            }
            sfguiDesktop.HandleEvent(event);
        }

        FILETIME NewDLLWriteTime = Win32GetLastWriteTime(GameDLLFullPath);
        auto t = CompareFileTime(&NewDLLWriteTime, &GameCodeDLL.LastWriteTime);
        if(t != 0 && LoadCounter > 0)
        {
            //char buffer[256];
            //sprintf(buffer, "J:/build/tmp%d.dll", LoadCounter);
	  GameCodeDLL->DestroyGame(GameMemory);
            Win32UnloadGameCode(&GameCodeDLL);
            {
                sf::Clock clockT;
                while (clockT.getElapsedTime().asSeconds() < 0.5f)
                {
                    system("cls");
                    cout << "Unloading Game Code  . . . " << endl;
                }
                cout << "Game Code loaded!" << endl;
                clockT.restart();
            }
            GameCodeDLL = Win32LoadGameCode(GameDLLFullPath, TempDLLName, LockFileName);
            if(GameCodeDLL.IsValid) {
                game = GameCodeDLL.CreateGame(renderWindow, retro_font, &keyboardManager);
            }
            LoadCounter++;
        } 
        else 
        {
            LoadCounter++;
        }

        auto microseconds = clock.getElapsedTime().asMicroseconds();
        //delta = static_cast<float>( microseconds ) / 1000000.f;
        // Only update every 5ms
        delta = static_cast<float>(frame_time_clock.getElapsedTime().asSeconds());
        if( microseconds > 5000 ) {
            game->update(delta);
            sfguiDesktop.Update(delta);
            keyboardManager.Update();
            clock.restart();

            renderWindow.setActive( true );
        }
        renderWindow.clear();

        delta = static_cast<float>(frame_time_clock.getElapsedTime().asSeconds());
        game->draw(delta);
        sfgui.Display(renderWindow);
        renderWindow.draw(text);
        renderWindow.display();

        auto frame_time = frame_time_clock.getElapsedTime().asMicroseconds();
        frame_time_clock.restart();

        frame_times[ frame_times_index ] = frame_time;
        frame_times_index = ( frame_times_index + 1 ) % 5000;

        if( m_fps_clock.getElapsedTime().asMicroseconds() >= 1000000 ) {
            m_fps_clock.restart();

            sf::Int64 total_time = 0;

            for( std::size_t index = 0; index < 5000; ++index ) {
                total_time += frame_times[index];
            }

            std::stringstream sstr;
            sstr << "SFGUI test -- FPS: " << m_fps_counter << " -- Frame Time (microsecs): min: "
            << *std::min_element( frame_times, frame_times + 5000 ) << " max: "
            << *std::max_element( frame_times, frame_times + 5000 ) << " avg: "
            << static_cast<float>( total_time ) / 5000.f;

            renderWindow.setTitle( sstr.str() );
            

            m_fps_counter = 0;
        }

        ++m_fps_counter;
    }
    renderWindow.close();

    Win32UnloadGameCode(&GameCodeDLL);
    {
        sf::Clock clockT;
        while (clockT.getElapsedTime().asSeconds() < 0.5f)
        {
            cout << "Unloading Game Code  . . . " << endl;
        }
        clockT.restart();
    }
    DeleteFile(TempDLLName);

    return 0;
}
// WINDOWS MAIN FUNCTION
// hInst = current instance of the program
// hPrevInst = previous instance which is not used anymore.
// cmdLine = holds command line arguments to be passed in to the program
// cmdShow = holds an integer to specify if we want to show this window.
int CALLBACK WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdLine, int cmdShow)
{
    WNDCLASS wc = {0};
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.hInstance = hInst;
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
    wc.lpszClassName = wndClassName;
    wc.hCursor = 0; //TODO: Add cursors and icons to this program.
    wc.hIcon = 0;
    wc.lpfnWndProc = (WNDPROC)wndProc;

    RegisterClass(&wc);

    HWND window = CreateWindow(wndClassName, wndTitle,
                               WS_OVERLAPPEDWINDOW,
                               CW_USEDEFAULT, CW_USEDEFAULT,
                               wndWidth, wndHeight,
                               0, 0, hInst, 0);
    
    if(window)
    {
        ShowWindow(window, SW_SHOW);
        UpdateWindow(window);

        // NOTE: Initializing SDL
        if(SDL_Init(SDL_INIT_VIDEO) != 0 )
        {
            DestroyWindow(window);
            return -2;
        }

        IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG);
        
        sdlWindow = SDL_CreateWindowFrom((void*)window);

        char error[MAX_PATH];
        stringCopy(error, SDL_GetError());
        OutputDebugStringA(error);

        if(!sdlWindow)
        {
            SDL_Quit();
            DestroyWindow(window);
            return -3;
        }
        
        renderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

        if(!renderer)
        {
            SDL_DestroyWindow(sdlWindow);
            SDL_Quit();
            DestroyWindow(window);
            return -4;
        }

        i32 RefreshRate = 0;
        HDC dc = GetDC(window);
        i32 winRefreshRate = GetDeviceCaps(dc, VREFRESH);

        if( winRefreshRate > 1 )
        {
            RefreshRate = winRefreshRate / 2;
        }
        else
        {
            RefreshRate = 30;
        }

        r32 targetSecsPerFrame = 1.0f / RefreshRate;

        GameMemory memory = {};
        memory.permanentSize = Megabytes(64);
        memory.transientSize = Megabytes(64);
        memory.totalSize = memory.permanentSize + memory.transientSize;
        
        gameMemoryBlock = VirtualAlloc( 0, memory.totalSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

        if(!gameMemoryBlock)
        {
            SDL_DestroyRenderer(renderer);
            SDL_DestroyWindow(sdlWindow);
            SDL_Quit();
            DestroyWindow(window);
            return -5;
        }

        memory.permanentBlock = gameMemoryBlock;
        memory.transientBlock = (i8*)gameMemoryBlock + memory.permanentSize;
        memory.readEntireFile = ReadEntireFile;
        memory.freeFile = FreeFile;
        memory.writeEntireFile = WriteEntireFile;

        Win32Dims windowDims = GetWindowDimensions(window);
        
        Render render = {};
        render.renderer = renderer;
        render.screenW = windowDims.width;
        render.screenH = windowDims.height;
        
        GameController input = {0};
        input.dt = targetSecsPerFrame;
        
        Win32State state = {0};
        state.memoryBlock = gameMemoryBlock;
        state.memorySize = memory.totalSize;

        GameCodeDLL gameCode =  Win32LoadGameCode("Game.dll", "Game_temp.dll", "lock.tmp");
        
        isRunning = true;

        r32 sleepIsGranular = (timeBeginPeriod(1) == TIMERR_NOERROR);
        
        LARGE_INTEGER lastCounter = Win32GetClock();

        i64 lastCycles = __rdtsc();
        
        LARGE_INTEGER performanceFreqPerSecRes;
        QueryPerformanceFrequency(&performanceFreqPerSecRes);
        globalPerformanceCountFreq = performanceFreqPerSecRes.QuadPart;
        
        // NOTE: PROGRAM LOOP!!
        while(isRunning)
        {
            // NOTE: compare File times for us to be able to reload the new game code
            FILETIME currentFileTime = Win32GetLastWriteTime("Game.dll");
            if(CompareFileTime(&currentFileTime, &gameCode.lastWriteTime) != 0)
            {
                Win32UnloadGameCode(&gameCode);
                gameCode = Win32LoadGameCode("Game.dll", "Game_temp.dll", "lock.tmp");
            }
            
            MSG msg = {0};
            while(PeekMessage(&msg, window, 0, 0, PM_REMOVE))
            {
                switch(msg.message)
                {
                    case WM_CLOSE:
                    {
                        isRunning = false;
                    }break;

                    case WM_KEYUP:
                    case WM_KEYDOWN:
                    case WM_SYSKEYUP:
                    case WM_SYSKEYDOWN:
                    {
                        u32 vkCode = (u32)msg.wParam;   // This contains the keycode for the key that the user pressed.
                        bool isDown = ((msg.lParam & (1 << 31)) == 0);  // Check to see if the key is down now.
                        bool wasDown = ((msg.lParam & (1 << 30)) != 0); // Check to see if the key was down previously.

                        if(isDown != wasDown)
                        {
                            if(vkCode == 'W')
                            {
                                input.moveUp.isDown = isDown;
                            }
                            else if(vkCode == 'S')
                            {
                                input.moveDown.isDown = isDown;
                            }
                            else if(vkCode == 'A')
                            {
                                input.moveLeft.isDown = isDown;
                            }
                            else if(vkCode == 'D')
                            {
                                input.moveRight.isDown = isDown;
                            }
                            if(vkCode == VK_UP)
                            {
                                input.actionUp.isDown = isDown;
                            }
                            else if(vkCode == VK_DOWN)
                            {
                                input.actionDown.isDown = isDown;
                            }
                            else if(vkCode == VK_LEFT)
                            {
                                input.actionLeft.isDown = isDown;
                            }
                            else if(vkCode == VK_RIGHT)
                            {
                                input.actionRight.isDown = isDown;
                            }
                            else if(vkCode == VK_ESCAPE)
                            {
                                input.back.isDown = isDown;
                            }
                            else if(vkCode == 'O')
                            {
                                if(isDown)
                                {
                                    if(state.recordingIndex == 0)
                                    {
                                        BeginRecording(&state, 1);
                                    }
                                    else
                                    {
                                        EndRecording(&state);
                                        BeginPlayback(&state, 1);
                                    }
                                }
                            }
                            else if(vkCode == 'P')
                            {
                                if(isDown)
                                {
                                    if(state.playbackIndex > 0)
                                    {
                                        EndPlayback(&state);
                                        ZeroMemory(&input, sizeof(input));
                                    }
                                }
                            }
                        }

                        if(isDown)
                        {
                            bool AltKeyWasDown = ((msg.lParam & (1 << 29)) != 0);
                            if(vkCode == VK_RETURN && AltKeyWasDown)
                            {
                                if(msg.hwnd)
                                {
                                    isFullscreen = !isFullscreen;
                                    Win32FullscreenToggle(msg.hwnd);
                                }
                            }
                        }

                    }break;

                    default:
                    {
                        TranslateMessage(&msg);
                        DispatchMessage(&msg);
                    }
                }
            }

            if(input.back.isDown)
            {
                isRunning = false;
                PostQuitMessage(0);
            }

            if(state.recordingIndex > 0)
            {
                RecordingInput(&state, &input);
            }
            else if(state.playbackIndex > 0)
            {
                PlaybackInput(&state, &input);
            }

            Win32Dims windowDims = GetWindowDimensions(window);
            Win32UpdateWindow(windowDims, (i32*)&render.screenW, (i32*)&render.screenH);
            
            if(gameCode.UpdateRender)
            {
                gameCode.UpdateRender(&memory, &input, &render);
            }

            LARGE_INTEGER workCounter = Win32GetClock();
            r32 workSecsElapsed = Win32GetSecondsElapsed(lastCounter, workCounter);

            r32 secondsElapsed = workSecsElapsed;
            if(secondsElapsed < targetSecsPerFrame)
            {
                if(sleepIsGranular)
                {
                    DWORD sleepMS = (DWORD)(1000.0f * (targetSecsPerFrame - secondsElapsed));
                    if(sleepMS > 0)
                    {
                        Sleep(sleepMS);
                    }
                }

                r32 testSecsElapsed = Win32GetSecondsElapsed(lastCounter, Win32GetClock());
                if(testSecsElapsed < targetSecsPerFrame)
                {
                    //TODO: LOG MISSED SLEEP HERE!!
                }

                while(secondsElapsed < targetSecsPerFrame)
                {
                    secondsElapsed = Win32GetSecondsElapsed(lastCounter, Win32GetClock());
                }
            }
            else
            {
                //TODO: MISSED FRAME RATE!!
            }
            
            LARGE_INTEGER endCounter = Win32GetClock();

            i64 endCycles = __rdtsc();
            
            r64 elapsedCounts = (r64)(endCounter.QuadPart - lastCounter.QuadPart);
            r64 elapsedCycles = (r64)(endCycles - lastCycles);

            r32 MSperFrame = ((1000.0f * Win32GetSecondsElapsed(lastCounter, endCounter)));
            r32 FPS = (r32)(globalPerformanceCountFreq / elapsedCounts);
            r32 MegaCyclesPerFrame = (r32)(elapsedCycles / (1000.0f * 1000.0f));
            
            char buffer[256];
            sprintf_s(buffer, "%.02fms, %.02ffps, %.02fmcpf\n", MSperFrame, FPS, MegaCyclesPerFrame);            
            OutputDebugStringA(buffer);
            
            lastCounter = endCounter;
            lastCycles = endCycles;
            
        } // NOTE: END OF WHILE LOOP

        //IMPORTANT: Unload this when we exit the program.
        Win32UnloadGameCode(&gameCode);        
    }
    else
    {
        // TODO: Handle Error Loggin here!!
        return -1;
    }

    if(gameMemoryBlock)
    {
        VirtualFree(gameMemoryBlock, 0, MEM_RELEASE);
    }
    
    //Close
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(sdlWindow);
    IMG_Quit();
    SDL_Quit();
    DestroyWindow(window);

    return 0;
}
示例#5
0
int CALLBACK
WinMain(
    HINSTANCE Instance,
    HINSTANCE PrevInstance,
    LPSTR CommandLine,
    int ShowCode)
{
#if 1
    Win32EnableConsole();


    
#endif

#if TERRIFIC_INTERNAL
    LPVOID BaseAddress = 0;//(LPVOID)Terabytes(2);
#else
    LPVOID BaseAddress = 0;
#endif

    win32_state State = {};

    game_memory GameMemory = {};
    GameMemory.PermanentStorageSize = Megabytes(512);
    GameMemory.TransientStorageSize = Megabytes(512);

    State.TotalSize = GameMemory.PermanentStorageSize + GameMemory.TransientStorageSize;

    State.GameMemoryBlock = VirtualAlloc(BaseAddress, State.TotalSize,
       MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
    DWORD Error = GetLastError();
    GameMemory.PermanentStorage = State.GameMemoryBlock;

    GameMemory.TransientStorage = ((uint8 *)GameMemory.PermanentStorage +
     GameMemory.PermanentStorageSize);


    char *GameDLLFullPath = "J:/build/terrific.dll";
    char *TempDLLName = "J:/build/tmp.dll";
    char *LockFileName = "J:/build/lock.tmp";

    auto GameCodeDLL = Win32LoadGameCode(GameDLLFullPath, TempDLLName, LockFileName);
    //Game *game = GameCodeDLL.CreateGame();

    uint32 m_fps_counter = 0;
    ex::TimeDelta delta = 0;
    sf::Clock m_fps_clock;
    m_fps_clock.restart();

    sf::Clock clock;
    sf::Clock frame_time_clock;

    sf::Int64 frame_times[5000];
    std::size_t frame_times_index = 0;

    std::fill( std::begin( frame_times ), std::end( frame_times ), 0 );

    uint32 loadCounter = 0;
    bool32 running = true;
    if (GameMemory.PermanentStorage && GameMemory.TransientStorage)
    {
        game_state *GameState = (game_state *) GameMemory.PermanentStorage;

        while(running)
        {

            FILETIME NewDLLWriteTime = Win32GetLastWriteTime(GameDLLFullPath);
            auto t = CompareFileTime(&NewDLLWriteTime, &GameCodeDLL.LastWriteTime);
            if(t != 0)
            {
              GameCodeDLL.DestroyGame(&GameMemory);
	      Win32DEBUGDelay(0.1f, "Exiting Game");
                Win32UnloadGameCode(&GameCodeDLL);
                Win32DEBUGDelay(0.2f, "Unloading Game Code");
                if(!DeleteFile(TempDLLName))
                {
                    return 666;
                }
                //Win32DEBUGDelay(0.1f, "Deleting tmp.dll");
                GameCodeDLL = Win32LoadGameCode(GameDLLFullPath, TempDLLName, LockFileName);
                if(GameCodeDLL.IsValid) {
                    //game = GameCodeDLL.CreateGame();
                    GameMemory.IsInitialized = false;

                    GameState = (game_state *) GameMemory.PermanentStorage;
                    GameState->RenderWindow.close();
                    while(GameState->RenderWindow.isOpen())
                    {

                    }
                    //VirtualFree(State.GameMemoryBlock, State.TotalSize, MEM_RELEASE );
                    VirtualFree(State.GameMemoryBlock, 0, MEM_RELEASE);
                    Error = GetLastError();
                    State = {};
                    GameMemory = {};
                    GameState = NULL;
                    GameMemory.PermanentStorageSize = Megabytes(256);
                    GameMemory.TransientStorageSize = Megabytes(256);

                    State.TotalSize = GameMemory.PermanentStorageSize + GameMemory.TransientStorageSize;

                    State.GameMemoryBlock = VirtualAlloc(BaseAddress, State.TotalSize,
                       MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
                    Error = GetLastError();
                    GameMemory.PermanentStorage = State.GameMemoryBlock;

                    GameMemory.TransientStorage = ((uint8 *)GameMemory.PermanentStorage +
                     GameMemory.PermanentStorageSize);
                }
            }
            //running = !game->IsExiting();
            GameState = (game_state *) GameMemory.PermanentStorage;
            if(GameCodeDLL.IsValid && GameMemory.PermanentStorage && GameMemory.TransientStorage)
            {
                //delta = static_cast<float>( microseconds ) / 1000000.f;
                //delta = frame_time_clock.getElapsedTime().asSeconds();
                delta = 0.16f;
                //game->Run2(delta, &GameMemory);
                if(!GameCodeDLL.RunGame(delta, &GameMemory))
                {

                    GameState->RenderWindow.close();
                     GameCodeDLL.DestroyGame(&GameMemory);
		     Win32DEBUGDelay(0.1f, "Exiting Game");
		    VirtualFree(State.GameMemoryBlock, State.TotalSize, MEM_RELEASE );
		    
                    Win32DEBUGDelay(0.25f, "Closing Window");
                    Win32UnloadGameCode(&GameCodeDLL);
                    Win32DEBUGDelay(0.25f, "Unloading Game Code");
                    return(DeleteFile(TempDLLName));
                }
            } 
            else
            {
                running = false;
            }

            auto frame_time = frame_time_clock.getElapsedTime().asMicroseconds();
            frame_time_clock.restart();

            frame_times[ frame_times_index ] = frame_time;
            frame_times_index = ( frame_times_index + 1 ) % 5000;

            if( m_fps_clock.getElapsedTime().asMicroseconds() >= 1000000 ) {
                m_fps_clock.restart();

                sf::Int64 total_time = 0;

                for( std::size_t index = 0; index < 5000; ++index ) {
                    total_time += frame_times[index];
                }

                std::stringstream sstr;
                sstr << "SFGUI test -- FPS: " << m_fps_counter << " -- Frame Time (seconds): min: "
                << static_cast<float>(*std::min_element( frame_times, frame_times + 5000 ) / 1000000.f) << " max: "
                << static_cast<float>(*std::max_element( frame_times, frame_times + 5000 ) / 1000000.f) << " avg: "
                << static_cast<float>((( total_time ) / 5000.f) / 1000000.f);
                if(running)
                {
		  //game->SetTitle(sstr.str());
                }
                //renderWindow.setTitle( sstr.str() );
                GameState->DEBUGString = sstr.str();
                

                m_fps_counter = 0;
            }
            ++m_fps_counter;
        }
    }
    GameCodeDLL.DestroyGame(&GameMemory);
    Win32DEBUGDelay(0.1f, "Exiting Game");
    Win32UnloadGameCode(&GameCodeDLL);
    Win32DEBUGDelay(1.5f, "Unloading Game Code");
    return(DeleteFile(TempDLLName));
    //return 0;
}