Windows build ready. Program icon, however, exceeds string length on MSVC.

This commit is contained in:
2026-05-27 00:07:06 -07:00
parent 5f663308d2
commit e72db80fb4
13 changed files with 270 additions and 141 deletions
+16
View File
@@ -3,3 +3,19 @@ handmadehero
handmadehero.dSYM handmadehero.dSYM
libhandmade.so libhandmade.so
libhandmade.so.dSYM 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
+2 -14
View File
@@ -15,12 +15,6 @@ endif
CC = clang CC = clang
UFLAGS = 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 \ FLAGS = -Wall -Wextra \
-Wincompatible-pointer-types \ -Wincompatible-pointer-types \
-Wint-conversion -Wimplicit-int-float-conversion -Wformat \ -Wint-conversion -Wimplicit-int-float-conversion -Wformat \
@@ -43,10 +37,6 @@ else ifeq ($(DETECTED_OS),linux)
INCLUDE = -I./sdl/include/ INCLUDE = -I./sdl/include/
LIBS = ./sdl/lib/x86_64-linux/libSDL2.a -lm -lX11 LIBS = ./sdl/lib/x86_64-linux/libSDL2.a -lm -lX11
FRAMEWORKS = FRAMEWORKS =
else ifeq ($(DETECTED_OS),windows)
INCLUDE =
LIBS =
FRAMEWORKS =
else else
INCLUDE = INCLUDE =
LIBS = LIBS =
@@ -58,12 +48,10 @@ EXE=handmadehero
default: libhandmade $(EXE) default: libhandmade $(EXE)
libhandmade: handmade.c libhandmade: handmade.c
@ $(CC) $(FLAGS) $(UFLAGS) -fPIC -shared $(INCLUDE) $^ $(LIBS) \ @ $(CC) $(FLAGS) $(UFLAGS) -fPIC -shared $(INCLUDE) $^ $(LIBS) $(FRAMEWORKS) -o libhandmade.so
$(FRAMEWORKS) -o libhandmade.so
$(EXE): sdl_handmade.c libhandmade $(EXE): sdl_handmade.c libhandmade
@ $(CC) $(FLAGS) $(UFLAGS) $(INCLUDE) sdl_handmade.c $(LIBS) \ @ $(CC) $(FLAGS) $(UFLAGS) $(INCLUDE) sdl_handmade.c $(LIBS) $(FRAMEWORKS) -o $@ $(ifneq $(filter $(DETECTED_OS), macos linux), /link /FORCE:MULTIPLE)
$(FRAMEWORKS) -o $@
run: run:
@ ./$(EXE) @ ./$(EXE)
+29
View File
@@ -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
+4
View File
@@ -0,0 +1,4 @@
#!/bin/sh
CC = clang
+27 -19
View File
@@ -1,5 +1,7 @@
#ifndef CORE_H_SENTRY #ifndef CORE_H
#define CORE_H_SENTRY #define CORE_H
#include <stdint.h>
/* ---- Switches ------------------------------------------------------- */ /* ---- Switches ------------------------------------------------------- */
@@ -31,10 +33,10 @@
#define ARCHITECTURE_ARM32 0 #define ARCHITECTURE_ARM32 0
#endif #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 #undef ARCHITECTURE_X64
#define ARCHITECTURE_X64 1 #define ARCHITECTURE_X64 1
#elif defined(i386) || defined(__i386) || defined(__i386__) #elif defined(i386) || defined(__i386) || defined(__i386__) || defined(_M_I86)
#undef ARCHITECTURE_X86 #undef ARCHITECTURE_X86
#define ARCHITECTURE_X86 1 #define ARCHITECTURE_X86 1
#elif defined(__aarch64__) #elif defined(__aarch64__)
@@ -111,20 +113,20 @@
#define FALSE 0 #define FALSE 0
#endif #endif
typedef unsigned char U8; typedef uint8_t U8;
typedef unsigned short U16; typedef uint16_t U16;
typedef unsigned int U32; typedef uint32_t U32;
typedef unsigned long long U64; typedef uint64_t U64;
typedef signed char S8; typedef int8_t S8;
typedef short S16; typedef int16_t S16;
typedef int S32; typedef int32_t S32;
typedef long long S64; typedef int64_t S64;
typedef S8 B8; typedef S8 B8;
typedef S16 B16; typedef S16 B16;
typedef S32 B32; typedef S32 B32;
typedef S64 B64; typedef S64 B64;
typedef float F32; typedef float F32;
typedef double F64; typedef double F64;
/* ---- Units ---------------------------------------------------------- */ /* ---- Units ---------------------------------------------------------- */
@@ -143,7 +145,13 @@ typedef double F64;
/* ---- Asserts -------------------------------------------------------- */ /* ---- 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) #define ASSERT_ALWAYS(x) do { if(!(x)) { TRAP(); } } while(0)
#if BUILD_DEBUG #if BUILD_DEBUG
+34 -2
View File
@@ -199,7 +199,7 @@ static loaded_bitmap DEBUGLoadBMP(thread_context *Thread, debug_read_file_result
bit_scan_result GreenShift = FindLeastSignificantSetBit(GreenMask); bit_scan_result GreenShift = FindLeastSignificantSetBit(GreenMask);
bit_scan_result BlueShift = FindLeastSignificantSetBit(BlueMask); bit_scan_result BlueShift = FindLeastSignificantSetBit(BlueMask);
bit_scan_result AlphaShift = FindLeastSignificantSetBit(AlphaMask); bit_scan_result AlphaShift = FindLeastSignificantSetBit(AlphaMask);
ASSERT(RedShift.Found); ASSERT(RedShift.Found);
ASSERT(GreenShift.Found); ASSERT(GreenShift.Found);
ASSERT(BlueShift.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.Offset.X += 0.5f*PlayerWidth;
PlayerRight = RecannonicalizePosition(TileMap, PlayerRight); 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)) { if(!AreOnSameTile(&GameState->PlayerP, &NewPlayerP)) {
U32 NewTileValue = GetTileValueByPos(TileMap, NewPlayerP); U32 NewTileValue = GetTileValueByPos(TileMap, NewPlayerP);
+5 -6
View File
@@ -103,14 +103,10 @@ typedef struct game_memory {
B32 IsInitialized; B32 IsInitialized;
U64 PermanentStorageSize; U64 PermanentStorageSize;
void *PermanentStorage; /* WARNING: This memory is REQUIRED to be zero void *PermanentStorage; /* WARNING: This memory is REQUIRED to be zero initialized!!! (Done by the OS layer.) */
initialized!!! (Done by the OS
layer.) */
U64 TransientStorageSize; U64 TransientStorageSize;
void *TransientStorage; /* WARNING: This memory is REQUIRED to be zero void *TransientStorage; /* WARNING: This memory is REQUIRED to be zero initialized!!! (Done by the OS layer.) */
initialized!!! (Done by the OS
layer.) */
#if BUILD_INTERNAL #if BUILD_INTERNAL
debug_read_file_result (*DEBUGPlatformReadEntireFile)(thread_context *Thread,const char *); debug_read_file_result (*DEBUGPlatformReadEntireFile)(thread_context *Thread,const char *);
@@ -124,6 +120,9 @@ typedef struct game_memory {
F32 SecondsElapsed; F32 SecondsElapsed;
} game_clocks;*/ } game_clocks;*/
#if OS_WINDOWS
__declspec(dllexport)
#endif
void UpdateAndRender(thread_context *Thread, game_memory *Memory, void UpdateAndRender(thread_context *Thread, game_memory *Memory,
game_input *Input, game_offscreen_buffer *Buffer, game_input *Input, game_offscreen_buffer *Buffer,
game_sound_output_buffer *SoundBuffer); game_sound_output_buffer *SoundBuffer);
+3 -1
View File
@@ -48,7 +48,9 @@ static bit_scan_result FindLeastSignificantSetBit(U32 Value)
memset(&Result, 0, sizeof(Result)); memset(&Result, 0, sizeof(Result));
#if COMPILER_MSVC #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 #elif COMPILER_CLANG
Result.Index = __builtin_ffsll(Value); // NOTE: It is a GCC function, but is supported by clang compiler. 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 // https://gcc.gnu.org/onlinedocs/gcc/Bit-Operation-Builtins.html
+6
View File
@@ -65,4 +65,10 @@ F32 Square(F32 A)
return Result; return Result;
} }
F32 InnerProduct(v2 A, v2 B)
{
F32 Result = A.X*B.X + A.Y*B.Y;
return Result;
}
#endif #endif
+2 -1
View File
@@ -1,9 +1,10 @@
/* GIMP RGBA C-Source image dump (program_icon.c) */ /* 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 { static const struct {
unsigned int width; unsigned int width;
unsigned int height; 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]; unsigned char pixel_data[1024 * 1024 * 4 + 1];
} program_icon = { } program_icon = {
1024, 1024, 4, 1024, 1024, 4,
Binary file not shown.
+140 -96
View File
@@ -1,31 +1,47 @@
/* NOTE: This layer only supports MacOS and Linux, for now. */
#include "core.h" #include "core.h"
// Remove SDL's entry point.
#if OS_WINDOWS
#define SDL_MAIN_HANDLED
#endif
#include "handmade.h" #include "handmade.h"
#include "sdl_handmade.h" #include "sdl_handmade.h"
#include <SDL.h> #include <SDL.h>
#include <sys/mman.h> /* mmap */
#include <stdlib.h> /* malloc, calloc */ #include <stdlib.h> /* malloc, calloc */
#include <string.h> /* memset, memcpy */ #include <string.h> /* memset, memcpy */
#include <stdio.h> #include <stdio.h>
#include <sys/stat.h> /* fstat */ #include <sys/stat.h> /* fstat */
#include <fcntl.h> /* open */ #include <fcntl.h> /* open */
#include <unistd.h> /* close, write, read, readlink, unlink */
#include <dlfcn.h> /* dlopen */
#include <sys/stat.h> /* stat */ #include <sys/stat.h> /* stat */
#if OS_MACOS || OS_LINUX
#include <dlfcn.h> /* dlopen */
#include <sys/mman.h> /* mmap */
#include <unistd.h> /* close, write, read, readlink, unlink */
#endif
#if OS_WINDOWS
#include <windows.h> /* VirtualAlloc */
#endif
#if OS_MACOS #if OS_MACOS
#include <mach-o/dyld.h> /* _NSGetExecutablePath */ #include <mach-o/dyld.h> /* _NSGetExecutablePath */
#endif #endif
/* NOTE: This is so it compiles on ARM. */ /* NOTE: This is so it compiles on ARM. */
#if ARCHITECTURE_X64 || ARCHITECTURE_X86 #if ARCHITECTURE_X64 || ARCHITECTURE_X86
#include <x86intrin.h> #if OS_MACOS || OS_LINUX
#include <x86intrin.h> // TODO: What is the equivalent on Windows?
#endif
#endif #endif
#if 0
#include "program_icon.c" #include "program_icon.c"
#endif
#define RESOLUTION_WIDTH 960 #define RESOLUTION_WIDTH 960
#define RESOLUTION_HEIGHT 540 #define RESOLUTION_HEIGHT 540
@@ -61,77 +77,65 @@ static U32 SafeTruncateUInt64(U64 Value)
debug_read_file_result DEBUGPlatformReadEntireFile(thread_context *Thread, const char *Filename) debug_read_file_result DEBUGPlatformReadEntireFile(thread_context *Thread, const char *Filename)
{ {
(void)Thread;
debug_read_file_result Result; debug_read_file_result Result;
memset(&Result, 0, sizeof(Result)); memset(&Result, 0, sizeof(Result));
S32 FileHandle = open(Filename, O_RDONLY); SDL_RWops *FileHandle = SDL_RWFromFile(Filename, "r");
if(FileHandle == -1) { if(FileHandle) {
return Result; S64 FileSize = SDL_RWsize(FileHandle);
} if(FileSize >= 0) {
Result.ContentsSize = SafeTruncateUInt64(FileSize);
} else {
Result.ContentsSize = 0;
SDL_RWclose(FileHandle);
return Result;
}
struct stat FileStatus; Result.Contents = malloc(Result.ContentsSize);
if(fstat(FileHandle, &FileStatus) == -1) { if(!Result.Contents) {
close(FileHandle); Result.ContentsSize = 0;
return Result; SDL_RWclose(FileHandle);
} return Result;
Result.ContentsSize = SafeTruncateUInt64(FileStatus.st_size); }
Result.Contents = malloc(Result.ContentsSize); size_t ObjectsRead = SDL_RWread(FileHandle, (void *)Result.Contents, (size_t)Result.ContentsSize, 1);
if(!Result.Contents) { if(ObjectsRead == 0) {
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) {
free(Result.Contents); free(Result.Contents);
Result.Contents = 0; Result.Contents = 0;
Result.ContentsSize = 0; Result.ContentsSize = 0;
close(FileHandle); SDL_RWclose(FileHandle);
return Result; return Result;
} }
BytesToRead -= BytesRead;
NextByteLocation += BytesRead;
}
close(FileHandle); SDL_RWclose(FileHandle);
}
return Result; return Result;
} }
B32 DEBUGPlatformWriteEntireFile(thread_context *Thread, const char *Filename, U32 MemorySize, void *Memory) 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); SDL_RWops *FileHandle = SDL_RWFromFile(Filename, "w");
if(FileHandle == -1) if(FileHandle) {
return FALSE; size_t ObjectsWritten = SDL_RWwrite(FileHandle, (void *)Memory, (size_t)MemorySize, 1);
if(ObjectsWritten == 0) {
U32 BytesToWrite = MemorySize; SDL_RWclose(FileHandle);
U8 *NextByteLocation = (U8*)Memory;
while(BytesToWrite) {
U32 BytesWritten;
BytesWritten = write(FileHandle, NextByteLocation, BytesToWrite);
if(BytesWritten == (U32)-1) {
close(FileHandle);
return FALSE; return FALSE;
} }
BytesToWrite -= BytesWritten;
NextByteLocation += BytesWritten; SDL_RWclose(FileHandle);
return TRUE;
} }
close(FileHandle); return FALSE;
return TRUE;
} }
void DEBUGPlatformFreeFileMemory(thread_context *Thread, void *Memory) void DEBUGPlatformFreeFileMemory(thread_context *Thread, void *Memory)
{ {
if(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) 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. */ /* TODO: We temporarily introduce the target rectangle to avoid stretching the canvas. */
/* SDL_RenderCopy(Renderer, Buffer.Texture, 0, 0); */ /* SDL_RenderCopy(Renderer, Buffer.Texture, 0, 0); */
sdl_window_size WindowSize = SDLGetWindowSize(Window); sdl_window_size WinSize = SDLGetWindowSize(Window);
if(WindowSize.Width >= Buffer->Width*2 && WindowSize.Height >= Buffer->Height*2) { if(WinSize.Width >= Buffer->Width*2 && WinSize.Height >= Buffer->Height*2) {
SDL_Rect dest_rect = { OffsetX, OffsetY, Buffer->Width*2, 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)); SDL_RenderCopy(Renderer, Buffer->Texture, 0, (const SDL_Rect *)(&dest_rect));
} else { } else {
@@ -230,7 +234,7 @@ static void SDLInitSound(S32 SamplesPerSecond, S32 BufferSize)
AudioSettings.freq = SamplesPerSecond; AudioSettings.freq = SamplesPerSecond;
AudioSettings.format = AUDIO_S16LSB; AudioSettings.format = AUDIO_S16LSB;
AudioSettings.channels = 2; AudioSettings.channels = 2;
AudioSettings.samples = BufferSize; AudioSettings.samples = (U16)BufferSize; // TODO: Unsafe truncate from S32 to U16
SDL_OpenAudio(&AudioSettings, 0); SDL_OpenAudio(&AudioSettings, 0);
@@ -381,10 +385,8 @@ static void SDLProcessMessages(sdl_state *SDLState, game_controller_input *Keybo
} }
if(WasDown) { if(WasDown) {
/* NOTE: If your window manager already uses an Alt+F4 /* NOTE: If your window manager already uses an Alt+F4 keybind to close programs, then we are likely
* keybind to close programs, then we are likely * to see SDL_QUIT event occur before our keybind. */
* to see SDL_QUIT event occur before our
* keybind. */
B32 AltKeyWasDown = (Event.key.keysym.mod & KMOD_ALT); B32 AltKeyWasDown = (Event.key.keysym.mod & KMOD_ALT);
if(KeyCode == SDLK_F4 && AltKeyWasDown) if(KeyCode == SDLK_F4 && AltKeyWasDown)
@@ -463,18 +465,38 @@ static U32 GetLastWriteTime(const char *FileName)
return (U32)file_info.st_mtime; return (U32)file_info.st_mtime;
} }
#if OS_MACOS || OS_LINUX
#define GAME_DLL_NAME "libhandmade.so" #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) static sdl_game_code SDLLoadGameCode(char *DLLPath)
{ {
sdl_game_code Result; sdl_game_code Result;
memset(&Result, 0, sizeof(Result)); memset(&Result, 0, sizeof(Result));
#if OS_MACOS || OS_LINUX
Result.GameCodeDLL = dlopen(DLLPath, RTLD_NOW); Result.GameCodeDLL = dlopen(DLLPath, RTLD_NOW);
#elif OS_WINDOWS
Result.GameCodeDLL = LoadLibraryA(DLLPath);
#else
#error Unknown OS: implement DLL loading...
#endif
if(Result.GameCodeDLL) { if(Result.GameCodeDLL) {
Result.DLLLastWriteTime = GetLastWriteTime(DLLPath); 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) { if(!Result.UpdateAndRender) {
/* TODO: Diagnostic. dlerror() */ /* TODO: Diagnostic. dlerror() */
} }
@@ -493,8 +515,15 @@ static sdl_game_code SDLLoadGameCode(char *DLLPath)
static void SDLUnloadGameCode(sdl_game_code *GameCode) static void SDLUnloadGameCode(sdl_game_code *GameCode)
{ {
if(GameCode->GameCodeDLL) if(GameCode->GameCodeDLL) {
#if OS_MACOS || OS_LINUX
dlclose(GameCode->GameCodeDLL); /* NOTE: Might fail. */ 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->IsValid = FALSE;
GameCode->UpdateAndRender = NULL; GameCode->UpdateAndRender = NULL;
} }
@@ -503,7 +532,7 @@ void GetExecutablePath(char *path, size_t path_size)
{ {
#if OS_MACOS #if OS_MACOS
U32 size; U32 size;
#else #elif OS_LINUX
ssize_t size; ssize_t size;
#endif #endif
@@ -512,18 +541,20 @@ void GetExecutablePath(char *path, size_t path_size)
#if OS_MACOS #if OS_MACOS
size = path_size; size = path_size;
if(_NSGetExecutablePath(path, &size) != 0) { /* NOTE: Not an if(_NSGetExecutablePath(path, &size) != 0) { /* NOTE: Not an absolute path. */
absolute
path. */
/* TODO: Diagnostics. */ /* TODO: Diagnostics. */
} }
#else #elif OS_LINUX
size = readlink("/proc/self/exe", path, path_size - 1); size = readlink("/proc/self/exe", path, path_size - 1);
if(size != -1) { if(size != -1) {
path[size] = '\0'; path[size] = '\0';
} else { } else {
/* TODO: Diagnostics. */ /* TODO: Diagnostics. */
} }
#elif OS_WINDOWS
GetModuleFileName(NULL, path, (DWORD)path_size); // TODO: hm...
#else
#error Unknown OS: Implement getting executable location.
#endif #endif
} }
} }
@@ -533,7 +564,16 @@ static void SDLGetEXEDirPath(char *path, size_t path_size)
GetExecutablePath(path, path_size); GetExecutablePath(path, path_size);
U32 len = str_len(path); U32 len = str_len(path);
U32 i = len; 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--; i--;
} }
path[i+1] = '\0'; path[i+1] = '\0';
@@ -557,6 +597,7 @@ U64 __rdtsc()
* drawing into a bitmap. */ * drawing into a bitmap. */
void SDLSetProgramIcon(SDL_Window *Window) void SDLSetProgramIcon(SDL_Window *Window)
{ {
#if 0
U32 Rmask, Gmask, Bmask, Amask; U32 Rmask, Gmask, Bmask, Amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN #if SDL_BYTEORDER == SDL_BIG_ENDIAN
S32 shift_by = (program_icon.bytes_per_pixel == 3) ? 8 : 0; 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; Amask = (program_icon.bytes_per_pixel == 3) ? 0 : 0xff000000;
#endif #endif
SDL_Surface * icon = SDL_CreateRGBSurfaceFrom( SDL_Surface * icon = SDL_CreateRGBSurfaceFrom((void *)program_icon.pixel_data, program_icon.width, program_icon.height,
(void *)program_icon.pixel_data, program_icon.bytes_per_pixel * 8, program_icon.bytes_per_pixel * program_icon.width, Rmask, Gmask, Bmask, Amask);
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) { if(icon) {
SDL_SetWindowIcon(Window, icon); SDL_SetWindowIcon(Window, icon);
SDL_FreeSurface(icon); SDL_FreeSurface(icon);
} else { } else {
/* TODO: This didn't work . . . SDL_GetError() */ /* TODO: This didn't work . . . SDL_GetError() */
} }
#endif
} }
#include "handmade_intrinsics.h" #include "handmade_intrinsics.h"
@@ -595,7 +632,7 @@ S32 main(S32 argc, char *argv[])
SDLGetEXEDirPath(SDLState.EXEDirPath, sizeof(SDLState.EXEDirPath)); SDLGetEXEDirPath(SDLState.EXEDirPath, sizeof(SDLState.EXEDirPath));
SDLGetDLLPath(SDLState.DLLPath, sizeof(SDLState.DLLPath), 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 . . . */ /* 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); SDL_Renderer *Renderer = SDL_CreateRenderer(Window, -1, SDL_RENDERER_PRESENTVSYNC);
/* NOTE: For future reference, the custom window bar should use /* NOTE: For future reference, the custom window bar should use SDL_SetWindowHitTest to define areas that will be used to drag the window. */
* 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." /* "Wayland needs an event loop and rendering or it won't function."
* https://github.com/libsdl-org/SDL/issues/7699#issuecomment-1545684792 */ * 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; SoundOutput.LatencySampleCount = SoundOutput.SamplesPerSecond / 15;
SDLInitSound(SoundOutput.SamplesPerSecond, SoundOutput.SamplesPerSecond * SoundOutput.BytesPerSample / 60); 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 = calloc(SoundOutput.SamplesPerSecond, SoundOutput.BytesPerSample);
/* SoundOutput.Samples = /* SoundOutput.Samples =
@@ -672,13 +707,18 @@ S32 main(S32 argc, char *argv[])
GameMemory.PermanentStorageSize = MB(64); GameMemory.PermanentStorageSize = MB(64);
GameMemory.TransientStorageSize = GB(1); GameMemory.TransientStorageSize = GB(1);
GameMemory.DEBUGPlatformReadEntireFile = &DEBUGPlatformReadEntireFile; GameMemory.DEBUGPlatformReadEntireFile = &DEBUGPlatformReadEntireFile;
GameMemory.DEBUGPlatformWriteEntireFile = &DEBUGPlatformWriteEntireFile; //GameMemory.DEBUGPlatformWriteEntireFile = &DEBUGPlatformWriteEntireFile;
GameMemory.DEBUGPlatformFreeFileMemory = &DEBUGPlatformFreeFileMemory; GameMemory.DEBUGPlatformFreeFileMemory = &DEBUGPlatformFreeFileMemory;
SDLState.TotalSize = GameMemory.PermanentStorageSize + GameMemory.TransientStorageSize; SDLState.TotalSize = GameMemory.PermanentStorageSize + GameMemory.TransientStorageSize;
/* NOTE: On MacOS and Linux, mmap seems to zero-fill anonymous #if OS_MACOS || OS_LINUX
* memory as a side-effect of security. */ /* 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); 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.PermanentStorage = SDLState.GameMmemoryBlock;
GameMemory.TransientStorage = (U8 *)(GameMemory.PermanentStorage) + GameMemory.PermanentStorageSize; 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_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) { while(GlobalRunning) {
NewInput->dtForFrame = TargetSecondsPerFrame; NewInput->dtForFrame = TargetSecondsPerFrame;
LastCounter = SDLGetWallClock(); LastCounter = SDLGetWallClock();
/* NOTE: rdtsc reports clock cylces, however it is not /* NOTE: rdtsc reports clock cylces, however it is not meant for really precise profiler work as the
* 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. */
* value returned is varied. */
/* Also, __rdtsc is not available on MacOS ARM; I
* have not checked MacOS x64. */
LastCycleCount = __rdtsc(); LastCycleCount = __rdtsc();
U32 NewDLLWriteTime = GetLastWriteTime(SDLState.DLLPath); U32 NewDLLWriteTime = GetLastWriteTime(SDLState.DLLPath);
@@ -842,7 +881,8 @@ S32 main(S32 argc, char *argv[])
if(SecondsElapsedForFrame < TargetSecondsPerFrame) { if(SecondsElapsedForFrame < TargetSecondsPerFrame) {
while(SecondsElapsedForFrame < TargetSecondsPerFrame) { while(SecondsElapsedForFrame < TargetSecondsPerFrame) {
SecondsElapsedForFrame = SDLGetSecondsElapsed(LastCounter, SDLGetWallClock()); SecondsElapsedForFrame = SDLGetSecondsElapsed(LastCounter, SDLGetWallClock());
SDL_Delay((U32)((TargetSecondsPerFrame - SecondsElapsedForFrame) * 1000.0)); if((TargetSecondsPerFrame - SecondsElapsedForFrame) >= 0.0f)
SDL_Delay((U32)((TargetSecondsPerFrame - SecondsElapsedForFrame) * 1000.0));
} }
} else { } else {
/* TODO: Missed frame rate! */ /* TODO: Missed frame rate! */
@@ -859,17 +899,21 @@ S32 main(S32 argc, char *argv[])
LastCounter = EndCounter; LastCounter = EndCounter;
#if 1 #if 1
U64 EndCycleCount = __rdtsc(); if(SDLGetSecondsElapsed(FPSLastCounter, SDLGetWallClock()) > 0.1f) {
U64 CyclesElapsed = EndCycleCount - LastCycleCount; U64 EndCycleCount = __rdtsc();
F64 MCPF = ((F64)CyclesElapsed / (1000.0 * 1000.0)); 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]; static char fps_buffer[128];
snprintf(fps_buffer, sizeof(fps_buffer), "%.02f ms/f, %.02f f/s, %.02f mc/f", MSPerFrame, FPS, MCPF); 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); SDL_SetWindowTitle(Window, (const char *)fps_buffer);
LastCycleCount = EndCycleCount; LastCycleCount = EndCycleCount;
FPSLastCounter = SDLGetWallClock();
}
#endif #endif
SWAP(game_input *, OldInput, NewInput); SWAP(game_input *, OldInput, NewInput);
+2 -2
View File
@@ -34,8 +34,8 @@ typedef struct sdl_sound_output {
void *Samples; void *Samples;
} sdl_sound_output; } sdl_sound_output;
/* NOTE: We choose 1024 only because MacOS's MAXPATHLEN says such a value. /* TODO: We choose 1024 only because MacOS's MAXPATHLEN says such a value.
* For example, linux/limits.h PATH_MAX says 4096. */ * For example, linux/limits.h PATH_MAX says 4096. Windows has MAX_PATH. */
#define SDL_STATE_PATH_SIZE 1024 #define SDL_STATE_PATH_SIZE 1024
typedef struct sdl_state { typedef struct sdl_state {