Browse Source

update

tags/day-25
Ledda 2 months ago
parent
commit
19ae9a2031
6 changed files with 137 additions and 59 deletions
  1. +1
    -1
      misc/bdebug.bat
  2. +1
    -1
      misc/brun.bat
  3. +9
    -7
      misc/build.bat
  4. +18
    -20
      src/handmade.cpp
  5. +35
    -17
      src/handmade.h
  6. +73
    -13
      src/win32_handmade.cpp

+ 1
- 1
misc/bdebug.bat View File

@@ -1,2 +1,2 @@
call build || exit /b %errorlevel% call build || exit /b %errorlevel%
devenv .\build\handmade.exe
devenv .\build\handmade_win32.exe

+ 1
- 1
misc/brun.bat View File

@@ -1,2 +1,2 @@
call build || exit /b %errorlevel% call build || exit /b %errorlevel%
.\build\handmade.exe
.\build\handmade_win32.exe

+ 9
- 7
misc/build.bat View File

@@ -1,9 +1,9 @@
@echo off @echo off
if NOT EXIST .\build mkdir .\build if NOT EXIST .\build mkdir .\build
pushd .\build
cl ^

set commonLinkerFlags= -opt:ref user32.lib Gdi32.lib winmm.lib
set commonCompilerFlags=^
-MT %= Make sure the C runtime library is statically linked =%^ -MT %= Make sure the C runtime library is statically linked =%^
-Fmwin32_handmade.map %= Create a map file =%^
-Gm- %= Turns off incremently building =%^ -Gm- %= Turns off incremently building =%^
-nologo %= No one cares you made the compiler Microsoft =%^ -nologo %= No one cares you made the compiler Microsoft =%^
-Oi %= Always use intrinsics =%^ -Oi %= Always use intrinsics =%^
@@ -12,10 +12,12 @@ cl ^
-WX -W4 -wd4201 -wd4100 -wd4189 %= Compiler warnings, -WX warnings as errors, -W4 warning level 4, -wdXXXX disable warning XXXX =%^ -WX -W4 -wd4201 -wd4100 -wd4189 %= Compiler warnings, -WX warnings as errors, -W4 warning level 4, -wdXXXX disable warning XXXX =%^
-DHANDMADE_INTERNAL=1 -DHANDMADE_SLOW=1 -DHANDMADE_WIN32=1 %= Custom #defines =%^ -DHANDMADE_INTERNAL=1 -DHANDMADE_SLOW=1 -DHANDMADE_WIN32=1 %= Custom #defines =%^
-FC %= Full path of source code file in diagnostics =%^ -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 winmm.lib %= Linked libraries =%^
/link -subsystem:windows,5.1 %= Linker stuff =%
-Zi %= Generate debugger info =%

pushd .\build

cl %commonCompilerFlags% -Fe:handmade.dll ..\src\handmade.cpp -Fmhandmade.map /link /DLL /EXPORT:gameGetSoundSamples /EXPORT:gameUpdateAndRender
cl %commonCompilerFlags% -Fe:handmade_win32.exe ..\src\win32_handmade.cpp -Fmwin32_handmade.map /link %commonLinkerFlags%
popd popd
exit /b exit /b




+ 18
- 20
src/handmade.cpp View File

@@ -2,16 +2,6 @@


#define PI32 3.141592653589f #define PI32 3.141592653589f


void debug_printf(wchar_t* format, ...) {
size_t bufsize = wcslen(format)*10;
wchar_t *output = (wchar_t*)malloc(bufsize);
va_list list;
va_start(list, format);
vswprintf(output, bufsize, format, list);
OutputDebugStringW(output);
free(output);
}

internal void outputSineSound(GameSoundOutputBuffer *soundBuffer, GameState *state) { internal void outputSineSound(GameSoundOutputBuffer *soundBuffer, GameState *state) {
int16 toneVolume = 3000; int16 toneVolume = 3000;
int wavePeriod = soundBuffer->samplesPerSecond/state->toneHz; int wavePeriod = soundBuffer->samplesPerSecond/state->toneHz;
@@ -34,23 +24,25 @@ internal void renderWeirdGradient(GameOffscreenBuffer *buffer, int xOffset, int
for (int x = 0; x < buffer->width; x++) { for (int x = 0; x < buffer->width; x++) {
uint8 blue = (uint8)(x + xOffset); uint8 blue = (uint8)(x + xOffset);
uint8 green = (uint8)(y + yOffset); uint8 green = (uint8)(y + yOffset);
*pixel++ = (green << 8) | blue;
*pixel++ = (green << 16) | blue;
} }
row += pitch; row += pitch;
} }
} }


internal void gameUpdateAndRender(GameMemory *memory, GameOffscreenBuffer *videoBuf, GameInput *input) {
extern "C" GAME_UPDATE_AND_RENDER(gameUpdateAndRender) {
Assert(sizeof(GameState) <= memory->permanentStorageSize); Assert(sizeof(GameState) <= memory->permanentStorageSize);


GameState *state = (GameState*)memory->permanentStorage; GameState *state = (GameState*)memory->permanentStorage;


if (!memory->isInitialised) { if (!memory->isInitialised) {
//DebugReadFileResult bmpMem = DEBUG_platformReadEntireFile(__FILE__);
//if (bmpMem.contents) {
// DEBUG_platformWriteEntireFile("c:/source/repos/handmade/src/test.cpp", bmpMem.contentsSize, bmpMem.contents);
// DEBUG_platformFreeFileMemory(bmpMem.contents);
//}
DebugReadFileResult bmpMem = memory->debugReadEntireFile(__FILE__);
if (bmpMem.contents) {
if (false) {
memory->debugWriteEntireFile("c:/source/repos/handmade/src/test.cpp", bmpMem.contentsSize, bmpMem.contents);
}
memory->debugFreeFileMemory(bmpMem.contents);
}


state->toneHz = 440; state->toneHz = 440;
state->tSine = 0; state->tSine = 0;
@@ -70,8 +62,6 @@ internal void gameUpdateAndRender(GameMemory *memory, GameOffscreenBuffer *video
} else if (controllerInput->stickLeft.endedDown) { } else if (controllerInput->stickLeft.endedDown) {
state->toneHz = 440 - 128; state->toneHz = 440 - 128;
state->greenOffset += 10; state->greenOffset += 10;
} else {
//state->toneHz = 440;
} }
if (controllerInput->stickUp.endedDown) { if (controllerInput->stickUp.endedDown) {
state->blueOffset += 10; state->blueOffset += 10;
@@ -84,6 +74,14 @@ internal void gameUpdateAndRender(GameMemory *memory, GameOffscreenBuffer *video
renderWeirdGradient(videoBuf, state->greenOffset, state->blueOffset); renderWeirdGradient(videoBuf, state->greenOffset, state->blueOffset);
} }


internal void gameGetSoundSamples(GameMemory *memory, GameSoundOutputBuffer *soundBuf) {
extern "C" GAME_GET_SOUND_SAMPLES(gameGetSoundSamples) {
outputSineSound(soundBuf, (GameState*)memory->permanentStorage); outputSineSound(soundBuf, (GameState*)memory->permanentStorage);
} }

#if HANDMADE_WIN32
#include "windows.h"

BOOL DllMain() {
return TRUE;
}
#endif

+ 35
- 17
src/handmade.h View File

@@ -64,6 +64,28 @@ inline uint32 safeTruncateUInt64(uint64 val) {
return (uint32)val; return (uint32)val;
} }


// === Platform to game services ===
#if HANDMADE_INTERNAL

struct DebugReadFileResult {
uint32 contentsSize;
void *contents;
};

#define DEBUG_PLATFORM_READ_ENTIRE_FILE(name) DebugReadFileResult name(char *filename)
typedef DEBUG_PLATFORM_READ_ENTIRE_FILE(DebugPlatformReadEntireFileFn);

#define DEBUG_PLATFORM_FREE_FILE_MEMORY(name) void name(void *fileMemory)
typedef DEBUG_PLATFORM_FREE_FILE_MEMORY(DebugPlatformFreeFileMemoryFn);

#define DEBUG_PLATFORM_WRITE_ENTIRE_FILE(name) bool32 name(char *filename, uint32 memorySize, void *memory)
typedef DEBUG_PLATFORM_WRITE_ENTIRE_FILE(DebugPlatformWriteEntireFileFn);

#define DEBUG_PLATFORM_PRINTF(name) void name(wchar_t* format, ...)
typedef DEBUG_PLATFORM_PRINTF(DebugPrintfFn);

#endif

// Game to platform layer services // Game to platform layer services
struct GameSoundOutputBuffer { struct GameSoundOutputBuffer {
int samplesPerSecond; int samplesPerSecond;
@@ -111,10 +133,17 @@ struct GameInput {


struct GameMemory { struct GameMemory {
bool32 isInitialised; bool32 isInitialised;

uint64 permanentStorageSize; uint64 permanentStorageSize;
void *permanentStorage; // required to be initialised to zero at startup void *permanentStorage; // required to be initialised to zero at startup

uint64 transientStorageSize; uint64 transientStorageSize;
void *transientStorage; // required to be initialised to zero at startup void *transientStorage; // required to be initialised to zero at startup

DebugPlatformReadEntireFileFn *debugReadEntireFile;
DebugPlatformFreeFileMemoryFn *debugFreeFileMemory;
DebugPlatformWriteEntireFileFn *debugWriteEntireFile;
DebugPrintfFn *debug_printf;
}; };


struct GameState { struct GameState {
@@ -125,22 +154,11 @@ struct GameState {
}; };


// === Game to platform services === // === Game to platform services ===
internal void gameUpdateAndRender(GameMemory *memory, GameInput *input, GameOffscreenBuffer *videoBuf);
internal void gameGetSoundSamples(GameMemory *memory, GameSoundOutputBuffer *soundBuf);

// === Platform to game services ===
#if HANDMADE_INTERNAL

struct DebugReadFileResult {
uint32 contentsSize;
void *contents;
};

DebugReadFileResult DEBUG_platformReadEntireFile(char *filename);
void DEBUG_platformFreeFileMemory(void *memory);
bool32 DEBUG_platformWriteEntireFile(char *filename, uint32 memorySize, void *memory);
void debug_printf(wchar_t* format, ...);

#endif


#define GAME_UPDATE_AND_RENDER(name) void name(GameMemory *memory, GameOffscreenBuffer *videoBuf, GameInput *input)
typedef GAME_UPDATE_AND_RENDER(GameUpdateAndRenderFn);
GAME_UPDATE_AND_RENDER(gameUpdateAndRenderStub) {}


#define GAME_GET_SOUND_SAMPLES(name) void name(GameMemory *memory, GameSoundOutputBuffer *soundBuf)
typedef GAME_GET_SOUND_SAMPLES(GameGetSoundSamplesFn);
GAME_GET_SOUND_SAMPLES(gameGetSoundSamplesStub) {}

+ 73
- 13
src/win32_handmade.cpp View File

@@ -4,8 +4,8 @@
#include <dsound.h> #include <dsound.h>


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


global ATOM HH_CTRLW; global ATOM HH_CTRLW;
global bool globalRunning; global bool globalRunning;
@@ -31,13 +31,23 @@ typedef HRESULT WINAPI DirectSoundCreateFn(LPCGUID pcGuidDevice, LPDIRECTSOUND *


#define stackAlloc(size, type) (type*)_alloca(size*sizeof(type)) #define stackAlloc(size, type) (type*)_alloca(size*sizeof(type))


void DEBUG_platformFreeFileMemory(void *fileMemory) {
DEBUG_PLATFORM_PRINTF(debug_printf) {
size_t bufsize = wcslen(format)*10;
wchar_t *output = (wchar_t*)malloc(bufsize);
va_list list;
va_start(list, format);
vswprintf(output, bufsize, format, list);
OutputDebugStringW(output);
free(output);
}

DEBUG_PLATFORM_FREE_FILE_MEMORY(debugFreeFileMemory) {
if (fileMemory) { if (fileMemory) {
VirtualFree(fileMemory, NULL, MEM_RELEASE); VirtualFree(fileMemory, NULL, MEM_RELEASE);
} }
} }


DebugReadFileResult DEBUG_platformReadEntireFile(char *filename) {
DEBUG_PLATFORM_READ_ENTIRE_FILE(debugReadEntireFile) {
DebugReadFileResult result = {}; DebugReadFileResult result = {};
HANDLE fileHandle = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); HANDLE fileHandle = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
if (fileHandle != INVALID_HANDLE_VALUE) { if (fileHandle != INVALID_HANDLE_VALUE) {
@@ -50,7 +60,7 @@ DebugReadFileResult DEBUG_platformReadEntireFile(char *filename) {
if (ReadFile(fileHandle, result.contents, (DWORD)fileSize.QuadPart, &bytesRead, NULL) && (fileSize32 == (uint32)bytesRead)) { if (ReadFile(fileHandle, result.contents, (DWORD)fileSize.QuadPart, &bytesRead, NULL) && (fileSize32 == (uint32)bytesRead)) {
result.contentsSize = fileSize32; result.contentsSize = fileSize32;
} else { } else {
DEBUG_platformFreeFileMemory(result.contents);
debugFreeFileMemory(result.contents);
result.contents = NULL; result.contents = NULL;
// logging // logging
} }
@@ -68,7 +78,7 @@ DebugReadFileResult DEBUG_platformReadEntireFile(char *filename) {
return result; return result;
} }


bool32 DEBUG_platformWriteEntireFile(char *filename, uint32 memorySize, void *memory) {
DEBUG_PLATFORM_WRITE_ENTIRE_FILE(debugWriteEntireFile) {
bool32 result = false; bool32 result = false;
HANDLE fileHandle = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, NULL, NULL); HANDLE fileHandle = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, NULL, NULL);
if (fileHandle != INVALID_HANDLE_VALUE) { if (fileHandle != INVALID_HANDLE_VALUE) {
@@ -128,6 +138,42 @@ internal void win32DrawBufferInWindow(Win32OffscreenBuffer *buffer, HWND window)
); );
} }


struct Win32GameCode {
HMODULE gameCodeLib;
GameUpdateAndRenderFn *updateAndRender;
GameGetSoundSamplesFn *getSoundSamples;
bool isValid;
};

internal Win32GameCode win32LoadGameCode() {
Win32GameCode result = {};

CopyFile("handmade.dll", "handmade_temp.dll", FALSE);
HMODULE gameCodeLib = LoadLibrary("handmade_temp.dll");
result.gameCodeLib = gameCodeLib;

if (gameCodeLib) {
result.updateAndRender = (GameUpdateAndRenderFn *)GetProcAddress(result.gameCodeLib, "gameUpdateAndRender");
result.getSoundSamples = (GameGetSoundSamplesFn *)GetProcAddress(result.gameCodeLib, "gameGetSoundSamples");
result.isValid = (result.updateAndRender && result.getSoundSamples);
}
if (!result.isValid) {
result.getSoundSamples = gameGetSoundSamplesStub;
result.updateAndRender = gameUpdateAndRenderStub;
}

return result;
}

internal void win32UnloadGameCode(Win32GameCode *gameCode) {
if (gameCode->gameCodeLib) {
FreeLibrary(gameCode->gameCodeLib);
}
gameCode->isValid = false;
gameCode->getSoundSamples = gameGetSoundSamplesStub;
gameCode->updateAndRender = gameUpdateAndRenderStub;
}

internal void win32LoadXInput() { internal void win32LoadXInput() {
HMODULE xInputLib = LoadLibrary("xinput1_4.dll"); HMODULE xInputLib = LoadLibrary("xinput1_4.dll");
if (!xInputLib) { if (!xInputLib) {
@@ -472,6 +518,10 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
GameMemory gameMemory = {}; GameMemory gameMemory = {};
gameMemory.permanentStorageSize = Megabytes(64); gameMemory.permanentStorageSize = Megabytes(64);
gameMemory.transientStorageSize = Gigabytes((uint64)4); gameMemory.transientStorageSize = Gigabytes((uint64)4);
gameMemory.debugFreeFileMemory = debugFreeFileMemory;
gameMemory.debugWriteEntireFile = debugWriteEntireFile;
gameMemory.debugReadEntireFile = debugReadEntireFile;
gameMemory.debug_printf = debug_printf;


uint64 totalSize = gameMemory.permanentStorageSize + gameMemory.transientStorageSize; uint64 totalSize = gameMemory.permanentStorageSize + gameMemory.transientStorageSize;
gameMemory.permanentStorage = VirtualAlloc(baseAddress, totalSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); gameMemory.permanentStorage = VirtualAlloc(baseAddress, totalSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
@@ -484,12 +534,23 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
LARGE_INTEGER lastWorkCounter = win32GetWallClock(); LARGE_INTEGER lastWorkCounter = win32GetWallClock();
LARGE_INTEGER flipWallClock = win32GetWallClock(); LARGE_INTEGER flipWallClock = win32GetWallClock();


int64 lastCycleCount = __rdtsc();


DWORD audioLatencyBytes = 0; DWORD audioLatencyBytes = 0;
real32 audioLatencySeconds = 0; real32 audioLatencySeconds = 0;
bool soundIsValid = false;

Win32GameCode game = win32LoadGameCode();
uint32 loadCounter = 0;


int64 lastCycleCount = __rdtsc();
while (globalRunning) { while (globalRunning) {
if (loadCounter++ > 60) {
win32UnloadGameCode(&game);
game = win32LoadGameCode();
loadCounter = 0;
// TODO(dledda): handmade hero episode 22 (from the beginning)
}

GameControllerInput *oldKeyboardController = &oldInput->controllers[0]; GameControllerInput *oldKeyboardController = &oldInput->controllers[0];
GameControllerInput *newKeyboardController = &newInput->controllers[0]; GameControllerInput *newKeyboardController = &newInput->controllers[0];
GameControllerInput zeroController = {}; GameControllerInput zeroController = {};
@@ -566,11 +627,10 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
videoBuffer.memory = globalBackBuffer.memory; videoBuffer.memory = globalBackBuffer.memory;
videoBuffer.width = globalBackBuffer.width; videoBuffer.width = globalBackBuffer.width;
videoBuffer.height = globalBackBuffer.height; videoBuffer.height = globalBackBuffer.height;
gameUpdateAndRender(&gameMemory, &videoBuffer, newInput);
game.updateAndRender(&gameMemory, &videoBuffer, newInput);


DWORD playCursor = 0; DWORD playCursor = 0;
DWORD writeCursor = 0; DWORD writeCursor = 0;
bool soundIsValid = false;


if (SUCCEEDED(globalSecondaryBuffer->GetCurrentPosition(&playCursor, &writeCursor))) { if (SUCCEEDED(globalSecondaryBuffer->GetCurrentPosition(&playCursor, &writeCursor))) {
if (!soundIsValid) { if (!soundIsValid) {
@@ -579,17 +639,17 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
} }
DWORD byteToLock = (soundOutput.runningSampleIndex*soundOutput.bytesPerSample) % soundOutput.secondaryBufferSize; 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 expectedSoundBytesPerFrame = (soundOutput.samplesPerSecond * soundOutput.bytesPerSample) / gameUpdateHz;
DWORD expectedFrameBoundaryByte = playCursor + expectedSoundBytesPerFrame; DWORD expectedFrameBoundaryByte = playCursor + expectedSoundBytesPerFrame;

DWORD safeWriteCursor = writeCursor; DWORD safeWriteCursor = writeCursor;
if (safeWriteCursor < playCursor) { if (safeWriteCursor < playCursor) {
safeWriteCursor += soundOutput.secondaryBufferSize; safeWriteCursor += soundOutput.secondaryBufferSize;
} }
Assert(safeWriteCursor >= playCursor); Assert(safeWriteCursor >= playCursor);
safeWriteCursor += soundOutput.safetyBytes + 2000;
bool audioIsLowLatency = safeWriteCursor >= expectedFrameBoundaryByte;
safeWriteCursor += soundOutput.safetyBytes;

bool audioIsLowLatency = safeWriteCursor < expectedFrameBoundaryByte;


DWORD targetCursor = 0; DWORD targetCursor = 0;
if (audioIsLowLatency) { if (audioIsLowLatency) {
@@ -610,7 +670,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
soundBuffer.samplesPerSecond = soundOutput.samplesPerSecond; soundBuffer.samplesPerSecond = soundOutput.samplesPerSecond;
soundBuffer.sampleCount = bytesToWrite / soundOutput.bytesPerSample; soundBuffer.sampleCount = bytesToWrite / soundOutput.bytesPerSample;
soundBuffer.samples = samples; soundBuffer.samples = samples;
gameGetSoundSamples(&gameMemory, &soundBuffer);
game.getSoundSamples(&gameMemory, &soundBuffer);
#if HANDMADE_INTERNAL #if HANDMADE_INTERNAL
Assert(debugTimeMarkerIndex < ArrayCount(debugMarkers)); Assert(debugTimeMarkerIndex < ArrayCount(debugMarkers));




Loading…
Cancel
Save