diff --git a/.gitignore b/.gitignore index 70b4f45..71207d9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,19 @@ handmadehero handmadehero.dSYM libhandmade.so libhandmade.so.dSYM + +handmade.dll +handmade.exp +handmade.ilk +handmade.lib +handmade.obj +handmade.pdb +handmade.rdi +handmadehero.exe +handmadehero.exp +handmadehero.ilk +handmadehero.lib +handmadehero.pdb +handmadehero.rdi +sdl_handmade.obj +vc140.pdb diff --git a/Makefile b/Makefile index db13fdf..e85d1e8 100644 --- a/Makefile +++ b/Makefile @@ -15,12 +15,6 @@ endif CC = clang UFLAGS = -# NOTE: This project's code bases itself on C89 (plain C) standard, however -# allowing a few convenient features of newer standards. Mid-scope -# variable declarations, comments that begin with '//', long long, -# designated initializers, compound literals, and anonymous structures -# are allowed as they are convenient. Everything else that has come out -# of modern standards is pretty much destructive and should not be used. FLAGS = -Wall -Wextra \ -Wincompatible-pointer-types \ -Wint-conversion -Wimplicit-int-float-conversion -Wformat \ @@ -43,10 +37,6 @@ else ifeq ($(DETECTED_OS),linux) INCLUDE = -I./sdl/include/ LIBS = ./sdl/lib/x86_64-linux/libSDL2.a -lm -lX11 FRAMEWORKS = -else ifeq ($(DETECTED_OS),windows) - INCLUDE = - LIBS = - FRAMEWORKS = else INCLUDE = LIBS = @@ -58,12 +48,10 @@ EXE=handmadehero default: libhandmade $(EXE) libhandmade: handmade.c - @ $(CC) $(FLAGS) $(UFLAGS) -fPIC -shared $(INCLUDE) $^ $(LIBS) \ - $(FRAMEWORKS) -o libhandmade.so + @ $(CC) $(FLAGS) $(UFLAGS) -fPIC -shared $(INCLUDE) $^ $(LIBS) $(FRAMEWORKS) -o libhandmade.so $(EXE): sdl_handmade.c libhandmade - @ $(CC) $(FLAGS) $(UFLAGS) $(INCLUDE) sdl_handmade.c $(LIBS) \ - $(FRAMEWORKS) -o $@ + @ $(CC) $(FLAGS) $(UFLAGS) $(INCLUDE) sdl_handmade.c $(LIBS) $(FRAMEWORKS) -o $@ $(ifneq $(filter $(DETECTED_OS), macos linux), /link /FORCE:MULTIPLE) run: @ ./$(EXE) diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..facb058 --- /dev/null +++ b/build.bat @@ -0,0 +1,29 @@ +@ECHO OFF + +IF "%1"=="compile" ( + GOTO compile +) ELSE IF "%1"=="run" ( + GOTO run +) ELSE IF "%1"=="clean" ( + GOTO clean +) ELSE ( + ECHO Unknown command... + ECHO.Usage: build.bat [compile^|run^|clean] +) + +EXIT /B 1 + +:compile +cl /wd4201 /wd4204 /wd4189 /wd4100 /MT /LD /Zi /Od /W4 /I sdl/include handmade.c sdl/lib/x86_64-win/SDL2.lib user32.lib gdi32.lib winmm.lib setupapi.lib oleaut32.lib version.lib Imm32.lib shell32.lib Ole32.lib Advapi32.lib /link /DEBUG /OUT:handmade.dll + +cl /wd4201 /wd4204 /wd4189 /wd4100 /MT /Zi /Od /W4 /I sdl/include sdl_handmade.c sdl/lib/x86_64-win/SDL2.lib user32.lib gdi32.lib winmm.lib setupapi.lib oleaut32.lib version.lib Imm32.lib shell32.lib Ole32.lib Advapi32.lib /link /DEBUG /OUT:handmadehero.exe +EXIT /B 0 + +:run +handmadehero.exe +EXIT /B 0 + +:clean +del handmadehero.exe handmadehero.rdi handmadehero.lib handmadehero.exp +del handmade.lib handmade.dll handmade.exp handmade.rdi handmade.ilk handmade.pdb handmade.obj vc140.pdb +EXIT /B 0 \ No newline at end of file diff --git a/build_linux.sh b/build_linux.sh new file mode 100644 index 0000000..2a864a9 --- /dev/null +++ b/build_linux.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +CC = clang + diff --git a/core.h b/core.h index edf6e2f..abe49f8 100644 --- a/core.h +++ b/core.h @@ -1,5 +1,7 @@ -#ifndef CORE_H_SENTRY -#define CORE_H_SENTRY +#ifndef CORE_H +#define CORE_H + +#include /* ---- Switches ------------------------------------------------------- */ @@ -31,10 +33,10 @@ #define ARCHITECTURE_ARM32 0 #endif -#if defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) || defined(__amd64) +#if defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) || defined(__amd64) || defined(_M_AMD64) #undef ARCHITECTURE_X64 #define ARCHITECTURE_X64 1 -#elif defined(i386) || defined(__i386) || defined(__i386__) +#elif defined(i386) || defined(__i386) || defined(__i386__) || defined(_M_I86) #undef ARCHITECTURE_X86 #define ARCHITECTURE_X86 1 #elif defined(__aarch64__) @@ -111,20 +113,20 @@ #define FALSE 0 #endif -typedef unsigned char U8; -typedef unsigned short U16; -typedef unsigned int U32; -typedef unsigned long long U64; -typedef signed char S8; -typedef short S16; -typedef int S32; -typedef long long S64; -typedef S8 B8; -typedef S16 B16; -typedef S32 B32; -typedef S64 B64; -typedef float F32; -typedef double F64; +typedef uint8_t U8; +typedef uint16_t U16; +typedef uint32_t U32; +typedef uint64_t U64; +typedef int8_t S8; +typedef int16_t S16; +typedef int32_t S32; +typedef int64_t S64; +typedef S8 B8; +typedef S16 B16; +typedef S32 B32; +typedef S64 B64; +typedef float F32; +typedef double F64; /* ---- Units ---------------------------------------------------------- */ @@ -143,7 +145,13 @@ typedef double F64; /* ---- Asserts -------------------------------------------------------- */ -#define TRAP() __builtin_trap() // TODO: GCC and CLANG thing; not supported on MSVC. +#if COMPILER_CLANG || COMPILER_GCC +#define TRAP() __builtin_trap() +#elif COMPILER_MSVC +#define TRAP() __debugbreak() +#else +#error Unknow debug break for the compiler . . . +#endif #define ASSERT_ALWAYS(x) do { if(!(x)) { TRAP(); } } while(0) #if BUILD_DEBUG diff --git a/handmade.c b/handmade.c index 74db243..976fa1a 100644 --- a/handmade.c +++ b/handmade.c @@ -199,7 +199,7 @@ static loaded_bitmap DEBUGLoadBMP(thread_context *Thread, debug_read_file_result bit_scan_result GreenShift = FindLeastSignificantSetBit(GreenMask); bit_scan_result BlueShift = FindLeastSignificantSetBit(BlueMask); bit_scan_result AlphaShift = FindLeastSignificantSetBit(AlphaMask); - + ASSERT(RedShift.Found); ASSERT(GreenShift.Found); ASSERT(BlueShift.Found); @@ -457,7 +457,39 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory, game_input *In PlayerRight.Offset.X += 0.5f*PlayerWidth; PlayerRight = RecannonicalizePosition(TileMap, PlayerRight); - if(IsTileMapPointEmpty(TileMap, NewPlayerP) && IsTileMapPointEmpty(TileMap, PlayerLeft) && IsTileMapPointEmpty(TileMap, PlayerRight)) { + B32 Collided = FALSE; + tile_map_position ColP; + memset(&ColP, 0, sizeof(ColP)); + if(!IsTileMapPointEmpty(TileMap, NewPlayerP)) { + ColP = NewPlayerP; + Collided = TRUE; + } + if(!IsTileMapPointEmpty(TileMap, PlayerLeft)) { + ColP = PlayerLeft; + Collided = TRUE; + } + if(!IsTileMapPointEmpty(TileMap, PlayerRight)) { + ColP = PlayerRight; + Collided = TRUE; + } + + if(Collided) { + v2 r = { 0, 0 }; + if(ColP.AbsTileX < GameState->PlayerP.AbsTileX) { + r = (v2){ 1, 0 }; + } + if(ColP.AbsTileX > GameState->PlayerP.AbsTileX) { + r = (v2){ -1, 0 }; + } + if(ColP.AbsTileY < GameState->PlayerP.AbsTileY) { + r = (v2){ 0, 1 }; + } + if(ColP.AbsTileY > GameState->PlayerP.AbsTileY) { + r = (v2){ 0, -1 }; + } + + GameState->dPlayerP = V2Subtract(GameState->dPlayerP, V2Multiply(1*InnerProduct(GameState->dPlayerP, r), r)); + } else { if(!AreOnSameTile(&GameState->PlayerP, &NewPlayerP)) { U32 NewTileValue = GetTileValueByPos(TileMap, NewPlayerP); diff --git a/handmade.h b/handmade.h index 08dc75f..8259f45 100644 --- a/handmade.h +++ b/handmade.h @@ -103,14 +103,10 @@ typedef struct game_memory { B32 IsInitialized; U64 PermanentStorageSize; - void *PermanentStorage; /* WARNING: This memory is REQUIRED to be zero - initialized!!! (Done by the OS - layer.) */ + void *PermanentStorage; /* WARNING: This memory is REQUIRED to be zero initialized!!! (Done by the OS layer.) */ U64 TransientStorageSize; - void *TransientStorage; /* WARNING: This memory is REQUIRED to be zero - initialized!!! (Done by the OS - layer.) */ + void *TransientStorage; /* WARNING: This memory is REQUIRED to be zero initialized!!! (Done by the OS layer.) */ #if BUILD_INTERNAL debug_read_file_result (*DEBUGPlatformReadEntireFile)(thread_context *Thread,const char *); @@ -124,6 +120,9 @@ typedef struct game_memory { F32 SecondsElapsed; } game_clocks;*/ +#if OS_WINDOWS +__declspec(dllexport) +#endif void UpdateAndRender(thread_context *Thread, game_memory *Memory, game_input *Input, game_offscreen_buffer *Buffer, game_sound_output_buffer *SoundBuffer); diff --git a/handmade_intrinsics.h b/handmade_intrinsics.h index 095a0d5..9c2f548 100644 --- a/handmade_intrinsics.h +++ b/handmade_intrinsics.h @@ -48,7 +48,9 @@ static bit_scan_result FindLeastSignificantSetBit(U32 Value) memset(&Result, 0, sizeof(Result)); #if COMPILER_MSVC - Result.Found = _BitScanForward(&Result.Index, Value); // TODO: I have not tested this. + unsigned long Index; + Result.Found = _BitScanForward(&Index, Value); + Result.Index = (U32)Index; #elif COMPILER_CLANG Result.Index = __builtin_ffsll(Value); // NOTE: It is a GCC function, but is supported by clang compiler. // https://gcc.gnu.org/onlinedocs/gcc/Bit-Operation-Builtins.html diff --git a/handmade_math.h b/handmade_math.h index 94ce4a5..849c6b3 100644 --- a/handmade_math.h +++ b/handmade_math.h @@ -65,4 +65,10 @@ F32 Square(F32 A) return Result; } +F32 InnerProduct(v2 A, v2 B) +{ + F32 Result = A.X*B.X + A.Y*B.Y; + return Result; +} + #endif diff --git a/program_icon.c b/program_icon.c index 01fb233..dab3cd5 100644 --- a/program_icon.c +++ b/program_icon.c @@ -1,9 +1,10 @@ /* GIMP RGBA C-Source image dump (program_icon.c) */ +// TODO: There is no way to disable a string limit via compiler flag in MSVC. static const struct { unsigned int width; unsigned int height; - unsigned int bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */ + unsigned int bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */ unsigned char pixel_data[1024 * 1024 * 4 + 1]; } program_icon = { 1024, 1024, 4, diff --git a/sdl/lib/x86_64-win/SDL2.lib b/sdl/lib/x86_64-win/SDL2.lib new file mode 100644 index 0000000..2c7dd22 Binary files /dev/null and b/sdl/lib/x86_64-win/SDL2.lib differ diff --git a/sdl_handmade.c b/sdl_handmade.c index a396c38..a2f7e8f 100644 --- a/sdl_handmade.c +++ b/sdl_handmade.c @@ -1,31 +1,47 @@ -/* NOTE: This layer only supports MacOS and Linux, for now. */ - #include "core.h" +// Remove SDL's entry point. +#if OS_WINDOWS +#define SDL_MAIN_HANDLED +#endif + #include "handmade.h" #include "sdl_handmade.h" #include -#include /* mmap */ + #include /* malloc, calloc */ #include /* memset, memcpy */ #include #include /* fstat */ #include /* open */ -#include /* close, write, read, readlink, unlink */ -#include /* dlopen */ #include /* stat */ + +#if OS_MACOS || OS_LINUX +#include /* dlopen */ +#include /* mmap */ +#include /* close, write, read, readlink, unlink */ +#endif + +#if OS_WINDOWS +#include /* VirtualAlloc */ +#endif + #if OS_MACOS #include /* _NSGetExecutablePath */ #endif /* NOTE: This is so it compiles on ARM. */ #if ARCHITECTURE_X64 || ARCHITECTURE_X86 -#include +#if OS_MACOS || OS_LINUX +#include // TODO: What is the equivalent on Windows? +#endif #endif +#if 0 #include "program_icon.c" +#endif #define RESOLUTION_WIDTH 960 #define RESOLUTION_HEIGHT 540 @@ -61,77 +77,65 @@ static U32 SafeTruncateUInt64(U64 Value) debug_read_file_result DEBUGPlatformReadEntireFile(thread_context *Thread, const char *Filename) { + (void)Thread; + debug_read_file_result Result; memset(&Result, 0, sizeof(Result)); - S32 FileHandle = open(Filename, O_RDONLY); - if(FileHandle == -1) { - return Result; - } + SDL_RWops *FileHandle = SDL_RWFromFile(Filename, "r"); + if(FileHandle) { + S64 FileSize = SDL_RWsize(FileHandle); + if(FileSize >= 0) { + Result.ContentsSize = SafeTruncateUInt64(FileSize); + } else { + Result.ContentsSize = 0; + SDL_RWclose(FileHandle); + return Result; + } - struct stat FileStatus; - if(fstat(FileHandle, &FileStatus) == -1) { - close(FileHandle); - return Result; - } - Result.ContentsSize = SafeTruncateUInt64(FileStatus.st_size); + Result.Contents = malloc(Result.ContentsSize); + if(!Result.Contents) { + Result.ContentsSize = 0; + SDL_RWclose(FileHandle); + return Result; + } - Result.Contents = malloc(Result.ContentsSize); - if(!Result.Contents) { - Result.ContentsSize = 0; - close(FileHandle); - return Result; - } - - U32 BytesToRead = Result.ContentsSize; - U8 *NextByteLocation = (U8 *)Result.Contents; - while(BytesToRead) { - U32 BytesRead = read(FileHandle, NextByteLocation, BytesToRead); - if(BytesRead == (U32)-1) { + size_t ObjectsRead = SDL_RWread(FileHandle, (void *)Result.Contents, (size_t)Result.ContentsSize, 1); + if(ObjectsRead == 0) { free(Result.Contents); Result.Contents = 0; Result.ContentsSize = 0; - close(FileHandle); + SDL_RWclose(FileHandle); return Result; } - BytesToRead -= BytesRead; - NextByteLocation += BytesRead; - } - close(FileHandle); + SDL_RWclose(FileHandle); + } return Result; } B32 DEBUGPlatformWriteEntireFile(thread_context *Thread, const char *Filename, U32 MemorySize, void *Memory) { - S32 FileHandle = open(Filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - if(FileHandle == -1) - return FALSE; - - U32 BytesToWrite = MemorySize; - U8 *NextByteLocation = (U8*)Memory; - while(BytesToWrite) { - U32 BytesWritten; - - BytesWritten = write(FileHandle, NextByteLocation, BytesToWrite); - if(BytesWritten == (U32)-1) { - close(FileHandle); + SDL_RWops *FileHandle = SDL_RWFromFile(Filename, "w"); + if(FileHandle) { + size_t ObjectsWritten = SDL_RWwrite(FileHandle, (void *)Memory, (size_t)MemorySize, 1); + if(ObjectsWritten == 0) { + SDL_RWclose(FileHandle); return FALSE; } - BytesToWrite -= BytesWritten; - NextByteLocation += BytesWritten; + + SDL_RWclose(FileHandle); + return TRUE; } - close(FileHandle); - - return TRUE; + return FALSE; } void DEBUGPlatformFreeFileMemory(thread_context *Thread, void *Memory) { if(Memory) - free(Memory); + free(Memory); // TODO: Should we accept debug_read_file_result instead of just memory. } static sdl_window_size SDLGetWindowSize(SDL_Window *Window) @@ -187,8 +191,8 @@ static void SDLDisplayBufferInWindow(offscreen_buffer *Buffer, SDL_Window *Windo /* TODO: We temporarily introduce the target rectangle to avoid stretching the canvas. */ /* SDL_RenderCopy(Renderer, Buffer.Texture, 0, 0); */ - sdl_window_size WindowSize = SDLGetWindowSize(Window); - if(WindowSize.Width >= Buffer->Width*2 && WindowSize.Height >= Buffer->Height*2) { + sdl_window_size WinSize = SDLGetWindowSize(Window); + if(WinSize.Width >= Buffer->Width*2 && WinSize.Height >= Buffer->Height*2) { SDL_Rect dest_rect = { OffsetX, OffsetY, Buffer->Width*2, Buffer->Height*2 }; SDL_RenderCopy(Renderer, Buffer->Texture, 0, (const SDL_Rect *)(&dest_rect)); } else { @@ -230,7 +234,7 @@ static void SDLInitSound(S32 SamplesPerSecond, S32 BufferSize) AudioSettings.freq = SamplesPerSecond; AudioSettings.format = AUDIO_S16LSB; AudioSettings.channels = 2; - AudioSettings.samples = BufferSize; + AudioSettings.samples = (U16)BufferSize; // TODO: Unsafe truncate from S32 to U16 SDL_OpenAudio(&AudioSettings, 0); @@ -381,10 +385,8 @@ static void SDLProcessMessages(sdl_state *SDLState, game_controller_input *Keybo } if(WasDown) { - /* NOTE: If your window manager already uses an Alt+F4 - * keybind to close programs, then we are likely - * to see SDL_QUIT event occur before our - * keybind. */ + /* NOTE: If your window manager already uses an Alt+F4 keybind to close programs, then we are likely + * to see SDL_QUIT event occur before our keybind. */ B32 AltKeyWasDown = (Event.key.keysym.mod & KMOD_ALT); if(KeyCode == SDLK_F4 && AltKeyWasDown) @@ -463,18 +465,38 @@ static U32 GetLastWriteTime(const char *FileName) return (U32)file_info.st_mtime; } +#if OS_MACOS || OS_LINUX #define GAME_DLL_NAME "libhandmade.so" +#elif OS_WINDOWS +#define GAME_DLL_NAME "handmade.dll" +#else +#error Unknown OS: please specify GAME_DLL_NAME +#endif static sdl_game_code SDLLoadGameCode(char *DLLPath) { sdl_game_code Result; memset(&Result, 0, sizeof(Result)); +#if OS_MACOS || OS_LINUX Result.GameCodeDLL = dlopen(DLLPath, RTLD_NOW); +#elif OS_WINDOWS + Result.GameCodeDLL = LoadLibraryA(DLLPath); +#else +#error Unknown OS: implement DLL loading... +#endif + if(Result.GameCodeDLL) { Result.DLLLastWriteTime = GetLastWriteTime(DLLPath); - Result.UpdateAndRender = (void(*)(thread_context *, game_memory *, game_input *, game_offscreen_buffer *, game_sound_output_buffer *)) dlsym(Result.GameCodeDLL, "UpdateAndRender"); +#if OS_MACOS || OS_LINUX + Result.UpdateAndRender = (void(*)(thread_context *, game_memory *, game_input *, game_offscreen_buffer *, game_sound_output_buffer *))dlsym(Result.GameCodeDLL, "UpdateAndRender"); +#elif OS_WINDOWS + Result.UpdateAndRender = (void(*)(thread_context *, game_memory *, game_input *, game_offscreen_buffer *, game_sound_output_buffer *))GetProcAddress(Result.GameCodeDLL, "UpdateAndRender"); +#else +#error Unknown OS: implement DLL loading... +#endif + if(!Result.UpdateAndRender) { /* TODO: Diagnostic. dlerror() */ } @@ -493,8 +515,15 @@ static sdl_game_code SDLLoadGameCode(char *DLLPath) static void SDLUnloadGameCode(sdl_game_code *GameCode) { - if(GameCode->GameCodeDLL) + if(GameCode->GameCodeDLL) { +#if OS_MACOS || OS_LINUX dlclose(GameCode->GameCodeDLL); /* NOTE: Might fail. */ +#elif OS_WINDOWS + FreeLibrary(GameCode->GameCodeDLL); +#else +#error Unknown OS: implement closing of DLL +#endif + } GameCode->IsValid = FALSE; GameCode->UpdateAndRender = NULL; } @@ -503,7 +532,7 @@ void GetExecutablePath(char *path, size_t path_size) { #if OS_MACOS U32 size; -#else +#elif OS_LINUX ssize_t size; #endif @@ -512,18 +541,20 @@ void GetExecutablePath(char *path, size_t path_size) #if OS_MACOS size = path_size; - if(_NSGetExecutablePath(path, &size) != 0) { /* NOTE: Not an - absolute - path. */ + if(_NSGetExecutablePath(path, &size) != 0) { /* NOTE: Not an absolute path. */ /* TODO: Diagnostics. */ } -#else +#elif OS_LINUX size = readlink("/proc/self/exe", path, path_size - 1); if(size != -1) { path[size] = '\0'; } else { /* TODO: Diagnostics. */ } +#elif OS_WINDOWS + GetModuleFileName(NULL, path, (DWORD)path_size); // TODO: hm... +#else +#error Unknown OS: Implement getting executable location. #endif } } @@ -533,7 +564,16 @@ static void SDLGetEXEDirPath(char *path, size_t path_size) GetExecutablePath(path, path_size); U32 len = str_len(path); U32 i = len; - while(path[i] != '/' || i == 0) { + +#if OS_MACOS || OS_LINUX + char delimeter = '/'; +#elif OS_WINDOWS + char delimeter = '\\'; +#else +#error Unknown OS: specify whether your OS uses forward or backward slashes for paths +#endif + + while(path[i] != delimeter || i == 0) { i--; } path[i+1] = '\0'; @@ -557,6 +597,7 @@ U64 __rdtsc() * drawing into a bitmap. */ void SDLSetProgramIcon(SDL_Window *Window) { +#if 0 U32 Rmask, Gmask, Bmask, Amask; #if SDL_BYTEORDER == SDL_BIG_ENDIAN S32 shift_by = (program_icon.bytes_per_pixel == 3) ? 8 : 0; @@ -571,19 +612,15 @@ void SDLSetProgramIcon(SDL_Window *Window) Amask = (program_icon.bytes_per_pixel == 3) ? 0 : 0xff000000; #endif - SDL_Surface * icon = SDL_CreateRGBSurfaceFrom( - (void *)program_icon.pixel_data, - program_icon.width, program_icon.height, - program_icon.bytes_per_pixel * 8, - program_icon.bytes_per_pixel * program_icon.width, - Rmask, Gmask, Bmask, Amask); + SDL_Surface * icon = SDL_CreateRGBSurfaceFrom((void *)program_icon.pixel_data, program_icon.width, program_icon.height, + program_icon.bytes_per_pixel * 8, program_icon.bytes_per_pixel * program_icon.width, Rmask, Gmask, Bmask, Amask); if(icon) { SDL_SetWindowIcon(Window, icon); SDL_FreeSurface(icon); } else { /* TODO: This didn't work . . . SDL_GetError() */ } - +#endif } #include "handmade_intrinsics.h" @@ -595,7 +632,7 @@ S32 main(S32 argc, char *argv[]) SDLGetEXEDirPath(SDLState.EXEDirPath, sizeof(SDLState.EXEDirPath)); SDLGetDLLPath(SDLState.DLLPath, sizeof(SDLState.DLLPath), SDLState.EXEDirPath); - if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER | SDL_INIT_AUDIO)) { + if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMECONTROLLER)) { /* TODO: This didn't work . . . */ } @@ -616,9 +653,7 @@ S32 main(S32 argc, char *argv[]) SDL_Renderer *Renderer = SDL_CreateRenderer(Window, -1, SDL_RENDERER_PRESENTVSYNC); - /* NOTE: For future reference, the custom window bar should use - * SDL_SetWindowHitTest to define areas that will be used to - * drag the window. */ + /* NOTE: For future reference, the custom window bar should use SDL_SetWindowHitTest to define areas that will be used to drag the window. */ /* "Wayland needs an event loop and rendering or it won't function." * https://github.com/libsdl-org/SDL/issues/7699#issuecomment-1545684792 */ @@ -653,7 +688,7 @@ S32 main(S32 argc, char *argv[]) SoundOutput.LatencySampleCount = SoundOutput.SamplesPerSecond / 15; SDLInitSound(SoundOutput.SamplesPerSecond, SoundOutput.SamplesPerSecond * SoundOutput.BytesPerSample / 60); - SDL_PauseAudio(0); + SDL_PauseAudio(0); // TODO: This should be paused until we have some actual sound to play. SoundOutput.Samples = calloc(SoundOutput.SamplesPerSecond, SoundOutput.BytesPerSample); /* SoundOutput.Samples = @@ -672,13 +707,18 @@ S32 main(S32 argc, char *argv[]) GameMemory.PermanentStorageSize = MB(64); GameMemory.TransientStorageSize = GB(1); GameMemory.DEBUGPlatformReadEntireFile = &DEBUGPlatformReadEntireFile; - GameMemory.DEBUGPlatformWriteEntireFile = &DEBUGPlatformWriteEntireFile; + //GameMemory.DEBUGPlatformWriteEntireFile = &DEBUGPlatformWriteEntireFile; GameMemory.DEBUGPlatformFreeFileMemory = &DEBUGPlatformFreeFileMemory; SDLState.TotalSize = GameMemory.PermanentStorageSize + GameMemory.TransientStorageSize; - /* NOTE: On MacOS and Linux, mmap seems to zero-fill anonymous - * memory as a side-effect of security. */ +#if OS_MACOS || OS_LINUX + /* NOTE: On MacOS and Linux, mmap seems to zero-fill anonymous memory as a side-effect of security. */ SDLState.GameMmemoryBlock = mmap(BaseAddress, (size_t)SDLState.TotalSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); +#elif OS_WINDOWS + SDLState.GameMmemoryBlock = VirtualAlloc(BaseAddress, SDLState.TotalSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); +#else +#error Unknown OS: please, allocate memory for arena +#endif GameMemory.PermanentStorage = SDLState.GameMmemoryBlock; GameMemory.TransientStorage = (U8 *)(GameMemory.PermanentStorage) + GameMemory.PermanentStorageSize; @@ -701,18 +741,17 @@ S32 main(S32 argc, char *argv[]) sdl_game_code Game = SDLLoadGameCode(SDLState.DLLPath); - SDL_ShowWindow(Window); // NOTE: Everything is ready; display the window. + SDL_ShowWindow(Window); // Everything is ready; display the window. + + U64 FPSLastCounter = SDLGetWallClock(); while(GlobalRunning) { NewInput->dtForFrame = TargetSecondsPerFrame; LastCounter = SDLGetWallClock(); - /* NOTE: rdtsc reports clock cylces, however it is not - * meant for really precise profiler work as the - * value returned is varied. */ - /* Also, __rdtsc is not available on MacOS ARM; I - * have not checked MacOS x64. */ + /* NOTE: rdtsc reports clock cylces, however it is not meant for really precise profiler work as the + * value returned is varied. Also, __rdtsc is not available on MacOS ARM; I have not checked MacOS x64. */ LastCycleCount = __rdtsc(); U32 NewDLLWriteTime = GetLastWriteTime(SDLState.DLLPath); @@ -842,7 +881,8 @@ S32 main(S32 argc, char *argv[]) if(SecondsElapsedForFrame < TargetSecondsPerFrame) { while(SecondsElapsedForFrame < TargetSecondsPerFrame) { SecondsElapsedForFrame = SDLGetSecondsElapsed(LastCounter, SDLGetWallClock()); - SDL_Delay((U32)((TargetSecondsPerFrame - SecondsElapsedForFrame) * 1000.0)); + if((TargetSecondsPerFrame - SecondsElapsedForFrame) >= 0.0f) + SDL_Delay((U32)((TargetSecondsPerFrame - SecondsElapsedForFrame) * 1000.0)); } } else { /* TODO: Missed frame rate! */ @@ -859,17 +899,21 @@ S32 main(S32 argc, char *argv[]) LastCounter = EndCounter; #if 1 - U64 EndCycleCount = __rdtsc(); - U64 CyclesElapsed = EndCycleCount - LastCycleCount; - F64 MCPF = ((F64)CyclesElapsed / (1000.0 * 1000.0)); + if(SDLGetSecondsElapsed(FPSLastCounter, SDLGetWallClock()) > 0.1f) { + U64 EndCycleCount = __rdtsc(); + U64 CyclesElapsed = EndCycleCount - LastCycleCount; + F64 MCPF = ((F64)CyclesElapsed / (1000.0 * 1000.0)); - //fprintf(stderr, "%.02f ms/f, %.02f f/s, %.02f mc/f\n", MSPerFrame, FPS, MCPF); + //fprintf(stderr, "%.02f ms/f, %.02f f/s, %.02f mc/f\n", MSPerFrame, FPS, MCPF); - static char fps_buffer[128]; - snprintf(fps_buffer, sizeof(fps_buffer), "%.02f ms/f, %.02f f/s, %.02f mc/f", MSPerFrame, FPS, MCPF); - SDL_SetWindowTitle(Window, (const char *)fps_buffer); + static char fps_buffer[128]; + snprintf(fps_buffer, sizeof(fps_buffer), "%.02f ms/f, %.02f f/s, %.02f mc/f", MSPerFrame, FPS, MCPF); + SDL_SetWindowTitle(Window, (const char *)fps_buffer); - LastCycleCount = EndCycleCount; + LastCycleCount = EndCycleCount; + + FPSLastCounter = SDLGetWallClock(); + } #endif SWAP(game_input *, OldInput, NewInput); diff --git a/sdl_handmade.h b/sdl_handmade.h index cfef6db..483454b 100644 --- a/sdl_handmade.h +++ b/sdl_handmade.h @@ -34,8 +34,8 @@ typedef struct sdl_sound_output { void *Samples; } sdl_sound_output; -/* NOTE: We choose 1024 only because MacOS's MAXPATHLEN says such a value. - * For example, linux/limits.h PATH_MAX says 4096. */ +/* TODO: We choose 1024 only because MacOS's MAXPATHLEN says such a value. + * For example, linux/limits.h PATH_MAX says 4096. Windows has MAX_PATH. */ #define SDL_STATE_PATH_SIZE 1024 typedef struct sdl_state {