update
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
call build || exit /b %errorlevel%
|
||||
devenv .\build\handmade.exe
|
||||
devenv .\build\handmade_win32.exe
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
call build || exit /b %errorlevel%
|
||||
.\build\handmade.exe
|
||||
.\build\handmade_win32.exe
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
@echo off
|
||||
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 =%^
|
||||
-Fmwin32_handmade.map %= Create a map file =%^
|
||||
-Gm- %= Turns off incremently building =%^
|
||||
-nologo %= No one cares you made the compiler Microsoft =%^
|
||||
-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 =%^
|
||||
-DHANDMADE_INTERNAL=1 -DHANDMADE_SLOW=1 -DHANDMADE_WIN32=1 %= Custom #defines =%^
|
||||
-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
|
||||
exit /b
|
||||
|
||||
|
||||
@@ -2,16 +2,6 @@
|
||||
|
||||
#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) {
|
||||
int16 toneVolume = 3000;
|
||||
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++) {
|
||||
uint8 blue = (uint8)(x + xOffset);
|
||||
uint8 green = (uint8)(y + yOffset);
|
||||
*pixel++ = (green << 8) | blue;
|
||||
*pixel++ = (green << 16) | blue;
|
||||
}
|
||||
row += pitch;
|
||||
}
|
||||
}
|
||||
|
||||
internal void gameUpdateAndRender(GameMemory *memory, GameOffscreenBuffer *videoBuf, GameInput *input) {
|
||||
extern "C" GAME_UPDATE_AND_RENDER(gameUpdateAndRender) {
|
||||
Assert(sizeof(GameState) <= memory->permanentStorageSize);
|
||||
|
||||
GameState *state = (GameState*)memory->permanentStorage;
|
||||
|
||||
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->tSine = 0;
|
||||
@@ -70,8 +62,6 @@ internal void gameUpdateAndRender(GameMemory *memory, GameOffscreenBuffer *video
|
||||
} else if (controllerInput->stickLeft.endedDown) {
|
||||
state->toneHz = 440 - 128;
|
||||
state->greenOffset += 10;
|
||||
} else {
|
||||
//state->toneHz = 440;
|
||||
}
|
||||
if (controllerInput->stickUp.endedDown) {
|
||||
state->blueOffset += 10;
|
||||
@@ -84,6 +74,14 @@ internal void gameUpdateAndRender(GameMemory *memory, GameOffscreenBuffer *video
|
||||
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);
|
||||
}
|
||||
|
||||
#if HANDMADE_WIN32
|
||||
#include "windows.h"
|
||||
|
||||
BOOL DllMain() {
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -64,6 +64,28 @@ inline uint32 safeTruncateUInt64(uint64 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
|
||||
struct GameSoundOutputBuffer {
|
||||
int samplesPerSecond;
|
||||
@@ -111,10 +133,17 @@ struct GameInput {
|
||||
|
||||
struct GameMemory {
|
||||
bool32 isInitialised;
|
||||
|
||||
uint64 permanentStorageSize;
|
||||
void *permanentStorage; // required to be initialised to zero at startup
|
||||
|
||||
uint64 transientStorageSize;
|
||||
void *transientStorage; // required to be initialised to zero at startup
|
||||
|
||||
DebugPlatformReadEntireFileFn *debugReadEntireFile;
|
||||
DebugPlatformFreeFileMemoryFn *debugFreeFileMemory;
|
||||
DebugPlatformWriteEntireFileFn *debugWriteEntireFile;
|
||||
DebugPrintfFn *debug_printf;
|
||||
};
|
||||
|
||||
struct GameState {
|
||||
@@ -125,22 +154,11 @@ struct GameState {
|
||||
};
|
||||
|
||||
// === 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) {}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#include <dsound.h>
|
||||
|
||||
// Local imports
|
||||
#include "handmade.h"
|
||||
#include "win32_handmade.h"
|
||||
#include "handmade.cpp"
|
||||
|
||||
global ATOM HH_CTRLW;
|
||||
global bool globalRunning;
|
||||
@@ -31,13 +31,23 @@ typedef HRESULT WINAPI DirectSoundCreateFn(LPCGUID pcGuidDevice, LPDIRECTSOUND *
|
||||
|
||||
#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) {
|
||||
VirtualFree(fileMemory, NULL, MEM_RELEASE);
|
||||
}
|
||||
}
|
||||
|
||||
DebugReadFileResult DEBUG_platformReadEntireFile(char *filename) {
|
||||
DEBUG_PLATFORM_READ_ENTIRE_FILE(debugReadEntireFile) {
|
||||
DebugReadFileResult result = {};
|
||||
HANDLE fileHandle = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
|
||||
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)) {
|
||||
result.contentsSize = fileSize32;
|
||||
} else {
|
||||
DEBUG_platformFreeFileMemory(result.contents);
|
||||
debugFreeFileMemory(result.contents);
|
||||
result.contents = NULL;
|
||||
// logging
|
||||
}
|
||||
@@ -68,7 +78,7 @@ DebugReadFileResult DEBUG_platformReadEntireFile(char *filename) {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool32 DEBUG_platformWriteEntireFile(char *filename, uint32 memorySize, void *memory) {
|
||||
DEBUG_PLATFORM_WRITE_ENTIRE_FILE(debugWriteEntireFile) {
|
||||
bool32 result = false;
|
||||
HANDLE fileHandle = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, NULL, NULL);
|
||||
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() {
|
||||
HMODULE xInputLib = LoadLibrary("xinput1_4.dll");
|
||||
if (!xInputLib) {
|
||||
@@ -472,6 +518,10 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
|
||||
GameMemory gameMemory = {};
|
||||
gameMemory.permanentStorageSize = Megabytes(64);
|
||||
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;
|
||||
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 flipWallClock = win32GetWallClock();
|
||||
|
||||
int64 lastCycleCount = __rdtsc();
|
||||
|
||||
DWORD audioLatencyBytes = 0;
|
||||
real32 audioLatencySeconds = 0;
|
||||
bool soundIsValid = false;
|
||||
|
||||
Win32GameCode game = win32LoadGameCode();
|
||||
uint32 loadCounter = 0;
|
||||
|
||||
int64 lastCycleCount = __rdtsc();
|
||||
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 *newKeyboardController = &newInput->controllers[0];
|
||||
GameControllerInput zeroController = {};
|
||||
@@ -566,11 +627,10 @@ 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);
|
||||
game.updateAndRender(&gameMemory, &videoBuffer, newInput);
|
||||
|
||||
DWORD playCursor = 0;
|
||||
DWORD writeCursor = 0;
|
||||
bool soundIsValid = false;
|
||||
|
||||
if (SUCCEEDED(globalSecondaryBuffer->GetCurrentPosition(&playCursor, &writeCursor))) {
|
||||
if (!soundIsValid) {
|
||||
@@ -579,17 +639,17 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
|
||||
}
|
||||
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;
|
||||
safeWriteCursor += soundOutput.safetyBytes;
|
||||
|
||||
bool audioIsLowLatency = safeWriteCursor < expectedFrameBoundaryByte;
|
||||
|
||||
DWORD targetCursor = 0;
|
||||
if (audioIsLowLatency) {
|
||||
@@ -610,7 +670,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
|
||||
soundBuffer.samplesPerSecond = soundOutput.samplesPerSecond;
|
||||
soundBuffer.sampleCount = bytesToWrite / soundOutput.bytesPerSample;
|
||||
soundBuffer.samples = samples;
|
||||
gameGetSoundSamples(&gameMemory, &soundBuffer);
|
||||
game.getSoundSamples(&gameMemory, &soundBuffer);
|
||||
#if HANDMADE_INTERNAL
|
||||
Assert(debugTimeMarkerIndex < ArrayCount(debugMarkers));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user