update
This commit is contained in:
@@ -40,7 +40,7 @@ internal void renderWeirdGradient(GameOffscreenBuffer *buffer, int xOffset, int
|
||||
}
|
||||
}
|
||||
|
||||
internal void gameUpdateAndRender(GameMemory *memory, GameOffscreenBuffer *videoBuf, GameInput *input, GameSoundOutputBuffer *soundBuf) {
|
||||
internal void gameUpdateAndRender(GameMemory *memory, GameOffscreenBuffer *videoBuf, GameInput *input) {
|
||||
Assert(sizeof(GameState) <= memory->permanentStorageSize);
|
||||
|
||||
GameState *state = (GameState*)memory->permanentStorage;
|
||||
@@ -61,26 +61,29 @@ internal void gameUpdateAndRender(GameMemory *memory, GameOffscreenBuffer *video
|
||||
GameControllerInput *controllerInput = &input->controllers[controllerIndex];
|
||||
if (controllerInput->isAnalog) {
|
||||
state->toneHz = 440 + (int)(128.0f*controllerInput->stickAvgX);
|
||||
state->greenOffset -= (int)(4.0f*controllerInput->stickAvgX);
|
||||
state->blueOffset += (int)(4.0f*controllerInput->stickAvgY);
|
||||
state->greenOffset -= (int)(20.0f*controllerInput->stickAvgX);
|
||||
state->blueOffset += (int)(20.0f*controllerInput->stickAvgY);
|
||||
} else {
|
||||
if (controllerInput->stickRight.endedDown) {
|
||||
state->toneHz = 440 + 128;
|
||||
state->greenOffset -= 4;
|
||||
state->greenOffset -= 10;
|
||||
} else if (controllerInput->stickLeft.endedDown) {
|
||||
state->toneHz = 440 - 128;
|
||||
state->greenOffset += 4;
|
||||
state->greenOffset += 10;
|
||||
} else {
|
||||
state->toneHz = 440;
|
||||
//state->toneHz = 440;
|
||||
}
|
||||
if (controllerInput->stickUp.endedDown) {
|
||||
state->blueOffset += 4;
|
||||
state->blueOffset += 10;
|
||||
} else if (controllerInput->stickDown.endedDown) {
|
||||
state->blueOffset -= 4;
|
||||
state->blueOffset -= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outputSineSound(soundBuf, state);
|
||||
renderWeirdGradient(videoBuf, state->greenOffset, state->blueOffset);
|
||||
}
|
||||
|
||||
internal void gameGetSoundSamples(GameMemory *memory, GameSoundOutputBuffer *soundBuf) {
|
||||
outputSineSound(soundBuf, (GameState*)memory->permanentStorage);
|
||||
}
|
||||
|
||||
@@ -125,7 +125,8 @@ struct GameState {
|
||||
};
|
||||
|
||||
// === Game to platform services ===
|
||||
void gameUpdateAndRender(GameMemory *memory, GameInput *input, GameOffscreenBuffer *videoBuf, GameSoundOutputBuffer *soundBuf);
|
||||
internal void gameUpdateAndRender(GameMemory *memory, GameInput *input, GameOffscreenBuffer *videoBuf);
|
||||
internal void gameGetSoundSamples(GameMemory *memory, GameSoundOutputBuffer *soundBuf);
|
||||
|
||||
// === Platform to game services ===
|
||||
#if HANDMADE_INTERNAL
|
||||
|
||||
@@ -367,7 +367,6 @@ inline real32 win32GetSecondsElapsed(LARGE_INTEGER start, LARGE_INTEGER end) {
|
||||
// int monitorRefreshHz = 60;
|
||||
// int gameUpdateHz = monitorRefreshHz / 2;
|
||||
|
||||
#define framesOfAudioLatency 3
|
||||
#define monitorRefreshHz 60
|
||||
#define gameUpdateHz (monitorRefreshHz / 2)
|
||||
|
||||
@@ -395,11 +394,16 @@ internal void win32DebugSyncDisplay(Win32OffscreenBuffer *screenBuffer, int mark
|
||||
int renderWidth = screenBuffer->width - 2 *padX;
|
||||
|
||||
real32 pxPerSoundBufferEntry = (real32)renderWidth / (real32)soundOutput->secondaryBufferSize;
|
||||
int pitch = screenBuffer->width*screenBuffer->bytesPerPixel;
|
||||
|
||||
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);
|
||||
real32 alpha = ((real32)(markerIndex + 1) / (real32)markerCount);
|
||||
int x = padX + (int)(pxPerSoundBufferEntry * (real32)thisMarker->writeCursor);
|
||||
uint8 *pixel = (uint8 *)screenBuffer->memory + top * pitch + x*screenBuffer->bytesPerPixel;
|
||||
uint32 newPixel = (uint32)((real32)alpha * 0xFFFFFFFF + (1.0f - alpha) * (*(uint32 *)pixel));
|
||||
win32DrawSoundBufferMarker(screenBuffer, soundOutput, pxPerSoundBufferEntry, padX, top, bottom, thisMarker->playCursor, newPixel);
|
||||
win32DrawSoundBufferMarker(screenBuffer, soundOutput, pxPerSoundBufferEntry, padX, top, bottom, thisMarker->writeCursor, 0x00FF0000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,7 +460,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 = framesOfAudioLatency * (soundOutput.samplesPerSecond / gameUpdateHz);
|
||||
soundOutput.safetyBytes = (soundOutput.samplesPerSecond * soundOutput.bytesPerSample / gameUpdateHz) / 3;
|
||||
|
||||
int16 *samples = (int16*)VirtualAlloc(NULL, soundOutput.secondaryBufferSize, MEM_COMMIT, PAGE_READWRITE);
|
||||
|
||||
@@ -478,11 +482,12 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
|
||||
globalSecondaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
|
||||
|
||||
LARGE_INTEGER lastWorkCounter = win32GetWallClock();
|
||||
LARGE_INTEGER flipWallClock = win32GetWallClock();
|
||||
|
||||
int64 lastCycleCount = __rdtsc();
|
||||
|
||||
bool32 soundIsValid = false;
|
||||
DWORD lastPlayCursor = 0;
|
||||
DWORD audioLatencyBytes = 0;
|
||||
real32 audioLatencySeconds = 0;
|
||||
|
||||
while (globalRunning) {
|
||||
GameControllerInput *oldKeyboardController = &oldInput->controllers[0];
|
||||
@@ -561,33 +566,75 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
|
||||
videoBuffer.memory = globalBackBuffer.memory;
|
||||
videoBuffer.width = globalBackBuffer.width;
|
||||
videoBuffer.height = globalBackBuffer.height;
|
||||
gameUpdateAndRender(&gameMemory, &videoBuffer, newInput);
|
||||
|
||||
// Sound test
|
||||
DWORD byteToLock = 0;
|
||||
DWORD targetCursor = lastPlayCursor;
|
||||
DWORD bytesToWrite = 0;
|
||||
if (soundIsValid) {
|
||||
byteToLock = (soundOutput.runningSampleIndex*soundOutput.bytesPerSample) % soundOutput.secondaryBufferSize;
|
||||
targetCursor = (lastPlayCursor + soundOutput.latencySampleCount*soundOutput.bytesPerSample) % soundOutput.secondaryBufferSize;
|
||||
if (byteToLock == targetCursor) {
|
||||
bytesToWrite = 0;
|
||||
} else if (byteToLock > targetCursor) {
|
||||
DWORD playCursor = 0;
|
||||
DWORD writeCursor = 0;
|
||||
bool soundIsValid = false;
|
||||
|
||||
if (SUCCEEDED(globalSecondaryBuffer->GetCurrentPosition(&playCursor, &writeCursor))) {
|
||||
if (!soundIsValid) {
|
||||
soundOutput.runningSampleIndex = writeCursor / soundOutput.bytesPerSample;
|
||||
soundIsValid = true;
|
||||
}
|
||||
DWORD byteToLock = (soundOutput.runningSampleIndex*soundOutput.bytesPerSample) % soundOutput.secondaryBufferSize;
|
||||
|
||||
// TODO(dledda): episode 20 ~2:00, something's wrong though, gotta sort it out.
|
||||
|
||||
DWORD expectedSoundBytesPerFrame = (soundOutput.samplesPerSecond * soundOutput.bytesPerSample) / gameUpdateHz;
|
||||
DWORD expectedFrameBoundaryByte = playCursor + expectedSoundBytesPerFrame;
|
||||
DWORD safeWriteCursor = writeCursor;
|
||||
if (safeWriteCursor < playCursor) {
|
||||
safeWriteCursor += soundOutput.secondaryBufferSize;
|
||||
}
|
||||
Assert(safeWriteCursor >= playCursor);
|
||||
safeWriteCursor += soundOutput.safetyBytes + 2000;
|
||||
bool audioIsLowLatency = safeWriteCursor >= expectedFrameBoundaryByte;
|
||||
|
||||
DWORD targetCursor = 0;
|
||||
if (audioIsLowLatency) {
|
||||
targetCursor = expectedFrameBoundaryByte + expectedSoundBytesPerFrame;
|
||||
} else {
|
||||
targetCursor = writeCursor + expectedSoundBytesPerFrame + soundOutput.safetyBytes;
|
||||
}
|
||||
targetCursor %= soundOutput.secondaryBufferSize;
|
||||
|
||||
DWORD bytesToWrite = 0;
|
||||
if (byteToLock > targetCursor) {
|
||||
bytesToWrite = soundOutput.secondaryBufferSize - byteToLock + targetCursor;
|
||||
} else {
|
||||
bytesToWrite = targetCursor - byteToLock;
|
||||
}
|
||||
}
|
||||
|
||||
GameSoundOutputBuffer soundBuffer = {};
|
||||
soundBuffer.samplesPerSecond = soundOutput.samplesPerSecond;
|
||||
soundBuffer.sampleCount = bytesToWrite / soundOutput.bytesPerSample;
|
||||
soundBuffer.samples = samples;
|
||||
GameSoundOutputBuffer soundBuffer = {};
|
||||
soundBuffer.samplesPerSecond = soundOutput.samplesPerSecond;
|
||||
soundBuffer.sampleCount = bytesToWrite / soundOutput.bytesPerSample;
|
||||
soundBuffer.samples = samples;
|
||||
gameGetSoundSamples(&gameMemory, &soundBuffer);
|
||||
#if HANDMADE_INTERNAL
|
||||
Assert(debugTimeMarkerIndex < ArrayCount(debugMarkers));
|
||||
|
||||
gameUpdateAndRender(&gameMemory, &videoBuffer, newInput, &soundBuffer);
|
||||
if (soundIsValid) {
|
||||
Win32DebugTimeMarker *marker = &debugMarkers[debugTimeMarkerIndex++];
|
||||
|
||||
DWORD unwrappedWriteCursor = writeCursor;
|
||||
if (unwrappedWriteCursor < targetCursor) {
|
||||
unwrappedWriteCursor += soundOutput.secondaryBufferSize;
|
||||
}
|
||||
audioLatencyBytes = unwrappedWriteCursor - playCursor;
|
||||
audioLatencySeconds = (((real32)audioLatencyBytes / (real32)soundOutput.bytesPerSample) / (real32)soundOutput.samplesPerSecond);
|
||||
|
||||
if (debugTimeMarkerIndex >= ArrayCount(debugMarkers)) {
|
||||
debugTimeMarkerIndex = 0;
|
||||
}
|
||||
|
||||
globalSecondaryBuffer->GetCurrentPosition(&marker->playCursor, &marker->writeCursor);
|
||||
#endif
|
||||
win32FillSoundBuffer(&soundOutput, byteToLock, bytesToWrite, &soundBuffer);
|
||||
} else {
|
||||
soundIsValid = false;
|
||||
}
|
||||
|
||||
|
||||
real32 secondsElapsedForFrame = win32GetSecondsElapsed(lastWorkCounter, win32GetWallClock());
|
||||
if (secondsElapsedForFrame < targetSecondsPerFrame) {
|
||||
if (sleepIsGranular) {
|
||||
@@ -610,32 +657,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
|
||||
#endif
|
||||
|
||||
win32DrawBufferInWindow(&globalBackBuffer, window);
|
||||
|
||||
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
|
||||
flipWallClock = win32GetWallClock();
|
||||
|
||||
#if 0
|
||||
real64 msElapsed = (real32)(1000.0f*secondsElapsedForFrame) / globalPerfCountFrequency;
|
||||
|
||||
@@ -20,7 +20,7 @@ struct Win32SoundOutput {
|
||||
int bytesPerSample;
|
||||
int secondaryBufferSize;
|
||||
real32 tSine;
|
||||
int latencySampleCount;
|
||||
int safetyBytes;
|
||||
};
|
||||
|
||||
struct Win32DebugTimeMarker {
|
||||
|
||||
Reference in New Issue
Block a user