Sfoglia il codice sorgente

update

tags/day-25
Ledda 2 mesi fa
parent
commit
51c9509a13
5 ha cambiato i file con 137 aggiunte e 23 eliminazioni
  1. +5
    -0
      .clangd
  2. +1
    -1
      misc/build.bat
  3. +1
    -1
      src/handmade.h
  4. +125
    -21
      src/win32_handmade.cpp
  5. +5
    -0
      src/win32_handmade.h

+ 5
- 0
.clangd Vedi File

@@ -0,0 +1,5 @@
CompileFlags:
Add:
- -DHANDMADE_INTERNAL
- -DHANDMADE_SLOW
- -DHANDMADE_WIN32

+ 1
- 1
misc/build.bat Vedi File

@@ -14,7 +14,7 @@ cl ^
-FC %= Full path of source code file in diagnostics =%^
-Zi %= Generate debugger info =%^
-Fe:handmade.exe ..\src\win32_handmade.cpp %= Output filename, input filename =%^
user32.lib Gdi32.lib %= Linked libraries =%^
user32.lib Gdi32.lib winmm.lib %= Linked libraries =%^
/link -subsystem:windows,5.1 %= Linker stuff =%
popd
exit /b


+ 1
- 1
src/handmade.h Vedi File

@@ -26,7 +26,7 @@
*/

#if HANDMADE_SLOW
#define Assert(Expression) if (!(Expression)) {*(int *)0 = 0;}
#define Assert(Expression) if (!(Expression)) {*(volatile int *)0 = 0;}
#else
#define Assert(Expression)
#endif


+ 125
- 21
src/win32_handmade.cpp Vedi File

@@ -3,6 +3,7 @@
#include <Xinput.h>
#include <dsound.h>

// Local imports
#include "win32_handmade.h"
#include "handmade.cpp"

@@ -10,6 +11,7 @@ global ATOM HH_CTRLW;
global bool globalRunning;
global Win32OffscreenBuffer globalBackBuffer;
global LPDIRECTSOUNDBUFFER globalSecondaryBuffer;
global int64 globalPerfCountFrequency;

// XInputGetState
#define X_INPUT_GET_STATE(name) DWORD WINAPI name(DWORD dwUserIndex, XINPUT_STATE *pState)
@@ -91,6 +93,7 @@ internal void resizeDIBSection(Win32OffscreenBuffer *buffer, int width, int heig

buffer->width = width;
buffer->height = height;
buffer->bytesPerPixel = 4;

buffer->info.bmiHeader.biSize = sizeof(buffer->info.bmiHeader);
buffer->info.bmiHeader.biWidth = buffer->width;
@@ -351,10 +354,62 @@ internal void win32ProcessPendingMessages(GameControllerInput *keyboardControlle
}
}

inline LARGE_INTEGER win32GetWallClock() {
LARGE_INTEGER result;
QueryPerformanceCounter(&result);
return result;
}

inline real32 win32GetSecondsElapsed(LARGE_INTEGER start, LARGE_INTEGER end) {
return (real32)(end.QuadPart - start.QuadPart) / (real32)globalPerfCountFrequency;
}

// int monitorRefreshHz = 60;
// int gameUpdateHz = monitorRefreshHz / 2;

#define framesOfAudioLatency 3
#define monitorRefreshHz 60
#define gameUpdateHz (monitorRefreshHz / 2)

internal void win32DebugDrawVertical(Win32OffscreenBuffer *screenBuffer, int x, int top, int bottom, int32 color) {
int pitch = screenBuffer->width*screenBuffer->bytesPerPixel;
uint8 *pixel = (uint8 *)screenBuffer->memory + top * pitch + x*screenBuffer->bytesPerPixel;
for (int y = top; y < bottom; y++) {
*(uint32 *)pixel = color;
pixel += pitch;
}
}

inline void win32DrawSoundBufferMarker(Win32OffscreenBuffer *buffer, Win32SoundOutput *soundOutput, real32 pxPerSoundBufferEntry, int padX, int top, int bottom, DWORD value, uint32 color) {
Assert(value < (DWORD)soundOutput->secondaryBufferSize);
int x = padX + (int)(pxPerSoundBufferEntry * (real32)value);
win32DebugDrawVertical(buffer, x, top, bottom, color);
}

internal void win32DebugSyncDisplay(Win32OffscreenBuffer *screenBuffer, int markerCount, Win32DebugTimeMarker *markers, Win32SoundOutput *soundOutput, real32 targetSecondsPerFrame) {
int padX = 16;
int padY = 16;

int top = padY;
int bottom = screenBuffer->height - padY;
int renderWidth = screenBuffer->width - 2 *padX;

real32 pxPerSoundBufferEntry = (real32)renderWidth / (real32)soundOutput->secondaryBufferSize;

for (int markerIndex = 0; markerIndex < markerCount; markerIndex++) {
Win32DebugTimeMarker *thisMarker = &markers[markerIndex];
win32DrawSoundBufferMarker(screenBuffer, soundOutput, pxPerSoundBufferEntry, padX, top, bottom, thisMarker->playCursor, 0xFFFFFFFF);
win32DrawSoundBufferMarker(screenBuffer, soundOutput, pxPerSoundBufferEntry, padX, top, bottom, thisMarker->writeCursor, 0xFFFF0000);
}
}

int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLine, int commandShow) {
LARGE_INTEGER performanceFrequencyResult;
QueryPerformanceFrequency(&performanceFrequencyResult);
int64 performanceFrequency = performanceFrequencyResult.QuadPart;
globalPerfCountFrequency = performanceFrequencyResult.QuadPart;

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

WNDCLASSA windowClass = {};
windowClass.style = CS_VREDRAW | CS_HREDRAW;
@@ -364,6 +419,8 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin

resizeDIBSection(&globalBackBuffer, 1280, 720);

real32 targetSecondsPerFrame = 1.0f / (real32)gameUpdateHz;

if (RegisterClass(&windowClass)) {
HWND window = CreateWindowExA(
NULL,
@@ -388,6 +445,9 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
GameInput *oldInput = &input[0];
GameInput *newInput = &input[1];

int debugTimeMarkerIndex = 0;
Win32DebugTimeMarker debugMarkers[gameUpdateHz / 2] = {};

win32LoadXInput();

// sound test
@@ -396,7 +456,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
soundOutput.runningSampleIndex = 0;
soundOutput.bytesPerSample = sizeof(int16)*2;
soundOutput.secondaryBufferSize = soundOutput.samplesPerSecond*soundOutput.bytesPerSample;
soundOutput.latencySampleCount = (int)(soundOutput.samplesPerSecond / 15.0f);
soundOutput.latencySampleCount = framesOfAudioLatency * (soundOutput.samplesPerSecond / gameUpdateHz);

int16 *samples = (int16*)VirtualAlloc(NULL, soundOutput.secondaryBufferSize, MEM_COMMIT, PAGE_READWRITE);

@@ -417,9 +477,13 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
win32ClearBuffer(&soundOutput);
globalSecondaryBuffer->Play(0, 0, DSBPLAY_LOOPING);

LARGE_INTEGER lastCounter;
QueryPerformanceCounter(&lastCounter);
LARGE_INTEGER lastWorkCounter = win32GetWallClock();
int64 lastCycleCount = __rdtsc();

bool32 soundIsValid = false;
DWORD lastPlayCursor = 0;

while (globalRunning) {
GameControllerInput *oldKeyboardController = &oldInput->controllers[0];
GameControllerInput *newKeyboardController = &newInput->controllers[0];
@@ -499,15 +563,12 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
videoBuffer.height = globalBackBuffer.height;

// Sound test
DWORD playCursor = 0;
DWORD writeCursor = 0;
DWORD byteToLock = 0;
DWORD targetCursor = 0;
DWORD targetCursor = lastPlayCursor;
DWORD bytesToWrite = 0;
bool soundIsValid = true;
if (SUCCEEDED(globalSecondaryBuffer->GetCurrentPosition(&playCursor, &writeCursor))) {
if (soundIsValid) {
byteToLock = (soundOutput.runningSampleIndex*soundOutput.bytesPerSample) % soundOutput.secondaryBufferSize;
targetCursor = (playCursor + soundOutput.latencySampleCount*soundOutput.bytesPerSample) % soundOutput.secondaryBufferSize;
targetCursor = (lastPlayCursor + soundOutput.latencySampleCount*soundOutput.bytesPerSample) % soundOutput.secondaryBufferSize;
if (byteToLock == targetCursor) {
bytesToWrite = 0;
} else if (byteToLock > targetCursor) {
@@ -515,7 +576,6 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
} else {
bytesToWrite = targetCursor - byteToLock;
}
soundIsValid = true;
}

GameSoundOutputBuffer soundBuffer = {};
@@ -524,23 +584,66 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
soundBuffer.samples = samples;

gameUpdateAndRender(&gameMemory, &videoBuffer, newInput, &soundBuffer);

if (soundIsValid) {
win32FillSoundBuffer(&soundOutput, byteToLock, bytesToWrite, &soundBuffer);
}

real32 secondsElapsedForFrame = win32GetSecondsElapsed(lastWorkCounter, win32GetWallClock());
if (secondsElapsedForFrame < targetSecondsPerFrame) {
if (sleepIsGranular) {
DWORD sleepMs = (DWORD)(1000.0f * (targetSecondsPerFrame - secondsElapsedForFrame));
if (sleepMs > 0) {
Sleep(sleepMs);
}
}
while (secondsElapsedForFrame < targetSecondsPerFrame) {
secondsElapsedForFrame = win32GetSecondsElapsed(lastWorkCounter, win32GetWallClock());
}
} else {
// logging, MISSED FRAME!
}

lastWorkCounter = win32GetWallClock();

#if HANDMADE_INTERNAL
win32DebugSyncDisplay(&globalBackBuffer, ArrayCount(debugMarkers), debugMarkers, &soundOutput, targetSecondsPerFrame);
#endif

win32DrawBufferInWindow(&globalBackBuffer, window);

LARGE_INTEGER endCounter;
QueryPerformanceCounter(&endCounter);
DWORD playCursor = 0;
DWORD writeCursor = 0;
if (SUCCEEDED(globalSecondaryBuffer->GetCurrentPosition(&playCursor, &writeCursor))) {
lastPlayCursor = playCursor;
if (!soundIsValid) {
soundOutput.runningSampleIndex = writeCursor / soundOutput.bytesPerSample;
soundIsValid = true;
}
} else {
soundIsValid = false;
}

#if HANDMADE_INTERNAL
{
Assert(debugTimeMarkerIndex < ArrayCount(debugMarkers));

Win32DebugTimeMarker *marker = &debugMarkers[debugTimeMarkerIndex++];

if (debugTimeMarkerIndex >= ArrayCount(debugMarkers)) {
debugTimeMarkerIndex = 0;
}
globalSecondaryBuffer->GetCurrentPosition(&marker->playCursor, &marker->writeCursor);
}
#endif

#if 0
real64 msElapsed = (real32)(1000.0f*secondsElapsedForFrame) / globalPerfCountFrequency;
real64 fps = (real32)(1000.0f*globalPerfCountFrequency/(real32)secondsElapsedForFrame)/1000.0f;
int64 endCycleCount = __rdtsc();
int64 cyclesElapsed = endCycleCount - lastCycleCount;
lastCycleCount = endCycleCount;

int64 counterElapsed = endCounter.QuadPart - lastCounter.QuadPart;
real32 msElapsed = (real32)(1000.0f*counterElapsed) / performanceFrequency;
real32 fps = (real32)(1000.0f*performanceFrequency/(real32)counterElapsed)/1000.0f;

lastCounter = endCounter;
#endif

GameInput *temp = newInput;
newInput = oldInput;
@@ -552,6 +655,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
} else {
// failed
}
return(0);

return 0;
}


+ 5
- 0
src/win32_handmade.h Vedi File

@@ -22,3 +22,8 @@ struct Win32SoundOutput {
real32 tSine;
int latencySampleCount;
};

struct Win32DebugTimeMarker {
DWORD playCursor;
DWORD writeCursor;
};

Caricamento…
Annulla
Salva