In process of migrating to ANSI C.

This commit is contained in:
2026-03-21 17:08:46 -07:00
parent a9573a440e
commit 8af1c59bb6
6 changed files with 222 additions and 133 deletions
+8 -7
View File
@@ -12,18 +12,19 @@ else
endif endif
endif endif
CC = clang++ CC = clang
UFLAGS = UFLAGS =
FLAGS = -Wall -Wextra -ggdb -fno-caret-diagnostics -fno-show-column -Wno-missing-field-initializers -Wno-unused-function -Wno-unused-parameter -Wno-unused-variable -Wno-unused-but-set-variable FLAGS = -ansi -D_POSIX_C_SOURCE=200809L -pedantic -pedantic-errors -Wall -Wextra -fno-caret-diagnostics -fno-show-column -Wno-missing-field-initializers -Wno-unused-function -Wno-unused-parameter -Wno-unused-variable -Wno-unused-but-set-variable
#-std=c99 -pedantic # -pedantic-errors
ifeq ($(DETECTED_OS),macos) ifeq ($(DETECTED_OS),macos)
UFLAGS = -gldb
INCLUDE = -I./sdl/include/ INCLUDE = -I./sdl/include/
LIBS = ./sdl/lib/arm-macos/libSDL2.a -lm LIBS = ./sdl/lib/arm-macos/libSDL2.a -lm
FRAMEWORKS = -framework Cocoa -framework IOKit -framework CoreAudio -framework AudioToolbox -framework ForceFeedback -framework Carbon -framework GameController -framework Metal -framework QuartzCore -framework CoreHaptics FRAMEWORKS = -framework Cocoa -framework IOKit -framework CoreAudio -framework AudioToolbox -framework ForceFeedback -framework Carbon -framework GameController -framework Metal -framework QuartzCore -framework CoreHaptics
else ifeq ($(DETECTED_OS),linux) else ifeq ($(DETECTED_OS),linux)
UFLAGS = -ggdb
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 =
@@ -41,11 +42,11 @@ EXE=handmadehero
default: libhandmade $(EXE) default: libhandmade $(EXE)
libhandmade: handmade.cpp 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.cpp libhandmade $(EXE): sdl_handmade.c libhandmade
@ $(CC) $(FLAGS) $(UFLAGS) $(INCLUDE) sdl_handmade.cpp $(LIBS) $(FRAMEWORKS) -o $@ @ $(CC) $(FLAGS) $(UFLAGS) $(INCLUDE) sdl_handmade.c $(LIBS) $(FRAMEWORKS) -o $@
run: run:
./$(EXE) ./$(EXE)
+8
View File
@@ -3,6 +3,14 @@
/* ---- Types ---------------------------------------------------------- */ /* ---- Types ---------------------------------------------------------- */
#ifndef BUILD_DEBUG
#define BUILD_DEBUG 1
#endif
#ifndef BUILD_INTERNAL
#define BUILD_INTERNAL 1
#endif
#ifndef TRUE #ifndef TRUE
#define TRUE 1 #define TRUE 1
#endif #endif
+22 -14
View File
@@ -1,3 +1,4 @@
#include "core.h"
#include "handmade.h" #include "handmade.h"
#include "sdl_handmade.h" #include "sdl_handmade.h"
@@ -9,9 +10,11 @@ static void GameOutputSound(game_state *GameState, game_sound_output_buffer *Sou
S32 WavePeriod = SoundBuffer->SamplesPerSecond / ToneHz; S32 WavePeriod = SoundBuffer->SamplesPerSecond / ToneHz;
S16 *SampleOut = SoundBuffer->Samples; S16 *SampleOut = SoundBuffer->Samples;
for(S32 SampleIndex = 0; SampleIndex < SoundBuffer->SampleCount; SampleIndex++) {
S32 SampleIndex;
for(SampleIndex = 0; SampleIndex < SoundBuffer->SampleCount; SampleIndex++) {
F32 SineValue = sinf(GameState->tSine); F32 SineValue = sinf(GameState->tSine);
S16 SampleValue = S16(SineValue * ToneVolume); S16 SampleValue = (S16)(SineValue * ToneVolume);
*SampleOut++ = SampleValue; *SampleOut++ = SampleValue;
*SampleOut++ = SampleValue; *SampleOut++ = SampleValue;
@@ -28,9 +31,11 @@ static void RenderWeirdGradient(game_offscreen_buffer *Buffer, S32 XOffset, S32
S32 Height = Buffer->Height; S32 Height = Buffer->Height;
U8 *Row = (U8 *)Buffer->Memory; U8 *Row = (U8 *)Buffer->Memory;
for(S32 Y = 0; Y < Height; Y++) { S32 Y;
for(Y = 0; Y < Height; Y++) {
U32 *Pixel = (U32 *)Row; U32 *Pixel = (U32 *)Row;
for(S32 X = 0; X < Width; X++) { S32 X;
for(X = 0; X < Width; X++) {
U8 Blue = (U8)(X + XOffset); U8 Blue = (U8)(X + XOffset);
U8 Green = (U8)(Y + YOffset); U8 Green = (U8)(Y + YOffset);
@@ -48,24 +53,27 @@ void UpdateAndRender(game_memory *Memory, game_input *Input, game_offscreen_buff
game_state *GameState = (game_state *)Memory->PermanentStorage; game_state *GameState = (game_state *)Memory->PermanentStorage;
if(!Memory->IsInitialized) { if(!Memory->IsInitialized) {
#if BUILD_INTERNAL
char FileName[] = "/home/igor/Developer/handmade/sdl_handmade.cpp"; char FileName[] = "/home/igor/Developer/handmade/sdl_handmade.cpp";
debug_read_file_result BitmapMemory = Memory->DEBUGPlatformReadEntireFile(FileName); debug_read_file_result BitmapMemory = Memory->DEBUGPlatformReadEntireFile(FileName);
if(BitmapMemory.Contents) { if(BitmapMemory.Contents) {
Memory->DEBUGPlatformWriteEntireFile("test.out", BitmapMemory.ContentsSize, BitmapMemory.Contents); Memory->DEBUGPlatformWriteEntireFile("test.out", BitmapMemory.ContentsSize, BitmapMemory.Contents);
Memory->DEBUGPlatformFreeFileMemory(BitmapMemory.Contents); Memory->DEBUGPlatformFreeFileMemory(BitmapMemory.Contents);
} }
#endif
GameState->ToneHz = 256; GameState->ToneHz = 256;
GameState->tSine = 0.0f; GameState->tSine = 0.0f;
// TODO: Maybe more appropriate to do in the platform layer? /* TODO: Maybe more appropriate to do in the platform layer? */
Memory->IsInitialized = true; Memory->IsInitialized = TRUE;
} }
// GameState.ToneHz; /* GameState.ToneHz; */
// GameState.GreenOffset; /* GameState.GreenOffset; */
// GameState.BlueOffset; /* GameState.BlueOffset; */
for(U32 ControllerIndex = 0; ControllerIndex < ARRAY_SIZE(Input->Controllers); ControllerIndex++) { U32 ControllerIndex;
for(ControllerIndex = 0; ControllerIndex < ARRAY_SIZE(Input->Controllers); ControllerIndex++) {
game_controller_input *Controller = GetController(Input, ControllerIndex); game_controller_input *Controller = GetController(Input, ControllerIndex);
if(Controller->IsAnalog) { if(Controller->IsAnalog) {
GameState->GreenOffset += (int)(4.0f*(Controller->StickAverageY)); GameState->GreenOffset += (int)(4.0f*(Controller->StickAverageY));
@@ -73,16 +81,16 @@ void UpdateAndRender(game_memory *Memory, game_input *Input, game_offscreen_buff
GameState->ToneHz = 256 + (S32)(128.0f*(Controller->StickAverageY)); GameState->ToneHz = 256 + (S32)(128.0f*(Controller->StickAverageY));
} else { } else {
if(Controller->MoveUp.EndedDown) { if(Controller->MoveUp.EndedDown) {
GameState->GreenOffset -= 1; GameState->GreenOffset -= 5;
} }
if(Controller->MoveDown.EndedDown) { if(Controller->MoveDown.EndedDown) {
GameState->GreenOffset += 2; GameState->GreenOffset += 5;
} }
if(Controller->MoveLeft.EndedDown) { if(Controller->MoveLeft.EndedDown) {
GameState->BlueOffset -= 1; GameState->BlueOffset -= 5;
} }
if(Controller->MoveRight.EndedDown) { if(Controller->MoveRight.EndedDown) {
GameState->BlueOffset += 1; GameState->BlueOffset += 5;
} }
} }
} }
+25 -26
View File
@@ -1,16 +1,13 @@
#ifndef HANDMADE_H #ifndef HANDMADE_H_SENTRY
#define HANDMADE_H #define HANDMADE_H_SENTRY
#include "sdl_handmade.h"
#include "core.h" #include "core.h"
/////////////////////////////////////////////////////////////////////////////// /* --------------------------------------------------------------------- */
// NOTE: Servcies that the platform layer provides to the game. // /* NOTE: Servcies that the platform layer provides to the game. */
/////////////////////////////////////////////////////////////////////////////// /* --------------------------------------------------------------------- */
#if BUILD_INTERNAL #if BUILD_INTERNAL
// NOTE: WARNING: Not for the shipping game.
typedef struct debug_read_file_result { typedef struct debug_read_file_result {
U32 ContentsSize; U32 ContentsSize;
void *Contents; void *Contents;
@@ -21,12 +18,12 @@ B32 DEBUGPlatformWriteEntireFile(const char *Filename, U32 MemorySize, void *Mem
void DEBUGPlatformFreeFileMemory(void *Memory); void DEBUGPlatformFreeFileMemory(void *Memory);
#endif #endif
/////////////////////////////////////////////////////////////////////////////// /* --------------------------------------------------------------------- */
// NOTE: Servcies that the game provides to the platform layer. // /* NOTE: Servcies that the game provides to the platform layer. */
/////////////////////////////////////////////////////////////////////////////// /* --------------------------------------------------------------------- */
typedef struct game_offscreen_buffer { typedef struct game_offscreen_buffer {
// Pixels are always 32-bit and have the bytes in BGRX (little-endian). /* Pixels are always 32-bit and have the bytes in BGRX (little-endian). */
void *Memory; void *Memory;
S32 Width; S32 Width;
S32 Height; S32 Height;
@@ -70,7 +67,7 @@ typedef struct game_controller_input {
game_button_state Start; game_button_state Start;
game_button_state Back; game_button_state Back;
// NOTE: All buttons must be added above this line. /* NOTE: All buttons must be added above this line. */
game_button_state Terminator; game_button_state Terminator;
}; };
@@ -78,11 +75,11 @@ typedef struct game_controller_input {
} game_controller_input; } game_controller_input;
typedef struct game_input { typedef struct game_input {
// TODO: Insert clock value here . . . /* TODO: Insert clock value here . . . */
game_controller_input Controllers[5]; game_controller_input Controllers[5];
} game_input; } game_input;
inline game_controller_input *GetController(game_input *Input, S32 ControllerIndex) game_controller_input *GetController(game_input *Input, S32 ControllerIndex)
{ {
Assert((U32)ControllerIndex < ARRAY_SIZE(Input->Controllers)); Assert((U32)ControllerIndex < ARRAY_SIZE(Input->Controllers));
game_controller_input *Result = &(Input->Controllers[ControllerIndex]); game_controller_input *Result = &(Input->Controllers[ControllerIndex]);
@@ -93,26 +90,28 @@ typedef struct game_memory {
B32 IsInitialized; B32 IsInitialized;
U64 PermanentStorageSize; 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; 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)(const char *); debug_read_file_result (*DEBUGPlatformReadEntireFile)(const char *);
B32 (*DEBUGPlatformWriteEntireFile)(const char *, U32, void *); B32 (*DEBUGPlatformWriteEntireFile)(const char *, U32, void *);
void (*DEBUGPlatformFreeFileMemory)(void *); void (*DEBUGPlatformFreeFileMemory)(void *);
#endif
} game_memory; } game_memory;
// typedef struct game_clocks { /*typedef struct game_clocks {
// U64 Ticks; U64 Ticks;
// F32 SecondsElapsed; F32 SecondsElapsed;
// } game_clocks; } game_clocks;*/
extern "C" void UpdateAndRender(game_memory *Memory, game_input *Input, game_offscreen_buffer *Buffer, game_sound_output_buffer *SoundBuffer); void UpdateAndRender(game_memory *Memory, game_input *Input, game_offscreen_buffer *Buffer, game_sound_output_buffer *SoundBuffer);
// /**/
// /**/
// /**/
typedef struct game_state { typedef struct game_state {
S32 ToneHz; S32 ToneHz;
@@ -122,4 +121,4 @@ typedef struct game_state {
F32 tSine; F32 tSine;
} game_state; } game_state;
#endif // HANDMADE_H #endif
+143 -75
View File
@@ -1,29 +1,31 @@
/* NOTE: This layer only supports MacOS and Linux, for now. */
#include "core.h" #include "core.h"
#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 <sys/mman.h> /* mmap */
#include <stdlib.h> // malloc, calloc #include <stdlib.h> /* malloc, calloc */
#include <string.h> // memset #include <string.h> /* memset */
#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, read, readlink #include <unistd.h> /* close, write, read, readlink */
#include <dlfcn.h> // dlopen #include <dlfcn.h> /* dlopen */
#include <sys/stat.h> // stat #include <sys/stat.h> /* stat */
#if __APPLE__ && __MACH__ #if __APPLE__ && __MACH__
#include <mach-o/dyld.h> #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 __x86_64__ || __i386__ #if __x86_64__ || __i386__
#include <x86intrin.h> #include <x86intrin.h>
#endif #endif
static bool GlobalRunning; static B32 GlobalRunning;
static U64 GlobalPerfCountFrequency; static U64 GlobalPerfCountFrequency;
@@ -86,7 +88,7 @@ B32 DEBUGPlatformWriteEntireFile(const char *Filename, U32 MemorySize, void *Mem
{ {
S32 FileHandle = open(Filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); S32 FileHandle = open(Filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if(FileHandle == -1) if(FileHandle == -1)
return false; return FALSE;
U32 BytesToWrite = MemorySize; U32 BytesToWrite = MemorySize;
U8 *NextByteLocation = (U8*)Memory; U8 *NextByteLocation = (U8*)Memory;
@@ -94,7 +96,7 @@ B32 DEBUGPlatformWriteEntireFile(const char *Filename, U32 MemorySize, void *Mem
U32 BytesWritten = write(FileHandle, NextByteLocation, BytesToWrite); U32 BytesWritten = write(FileHandle, NextByteLocation, BytesToWrite);
if(BytesWritten == (U32)-1) { if(BytesWritten == (U32)-1) {
close(FileHandle); close(FileHandle);
return false; return FALSE;
} }
BytesToWrite -= BytesWritten; BytesToWrite -= BytesWritten;
NextByteLocation += BytesWritten; NextByteLocation += BytesWritten;
@@ -102,7 +104,7 @@ B32 DEBUGPlatformWriteEntireFile(const char *Filename, U32 MemorySize, void *Mem
close(FileHandle); close(FileHandle);
return true; return TRUE;
} }
void DEBUGPlatformFreeFileMemory(void *Memory) void DEBUGPlatformFreeFileMemory(void *Memory)
@@ -140,7 +142,7 @@ static void SDLResizeTexture(offscreen_buffer *Buffer, SDL_Renderer *Renderer, i
static void SDLDisplayBufferInWindow(offscreen_buffer Buffer, SDL_Window *Window, SDL_Renderer *Renderer) static void SDLDisplayBufferInWindow(offscreen_buffer Buffer, SDL_Window *Window, SDL_Renderer *Renderer)
{ {
if(SDL_UpdateTexture(Buffer.Texture, 0, Buffer.Memory, Buffer.Pitch)) { if(SDL_UpdateTexture(Buffer.Texture, 0, Buffer.Memory, Buffer.Pitch)) {
// TODO: Do something about this error! /* TODO: Do something about this error! */
} }
SDL_RenderCopy(Renderer, Buffer.Texture, 0, 0); SDL_RenderCopy(Renderer, Buffer.Texture, 0, 0);
@@ -198,7 +200,7 @@ static void SDLClearSoundBuffer(sdl_sound_output *SoundOutput)
memset(SoundOutput->Samples, 0, SoundOutput->SecondaryBufferSize); memset(SoundOutput->Samples, 0, SoundOutput->SecondaryBufferSize);
} }
static void SDLProcessKeyboardMessage(game_button_state *NewState, bool IsDown) static void SDLProcessKeyboardMessage(game_button_state *NewState, B32 IsDown)
{ {
Assert(NewState->EndedDown != IsDown); Assert(NewState->EndedDown != IsDown);
NewState->EndedDown = IsDown; NewState->EndedDown = IsDown;
@@ -216,7 +218,7 @@ static void HandleEvent(SDL_Event *Event)
{ {
switch(Event->type) { switch(Event->type) {
case SDL_QUIT: { case SDL_QUIT: {
GlobalRunning = false; GlobalRunning = FALSE;
} break; } break;
case SDL_WINDOWEVENT: { case SDL_WINDOWEVENT: {
@@ -236,7 +238,49 @@ static void HandleEvent(SDL_Event *Event)
} }
} }
static void SDLProcessMessages(game_controller_input *KeyboardController) static void SDLBeginRecordingInput(sdl_state *SDLState, S32 InputRecordingIndex)
{
SDLState->InputRecordingIndex = InputRecordingIndex;
const char *FileName = "foo.hmi";
SDLState->RecordingHandle = open(FileName, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
write(SDLState->RecordingHandle, SDLState->GameMmemoryBlock, (size_t)(SDLState->TotalSize));
}
static void SDLEndRecordingInput(sdl_state *SDLState)
{
close(SDLState->RecordingHandle);
SDLState->InputRecordingIndex = 0;
}
static void SDLBeginInputPlayback(sdl_state *SDLState, S32 InputPlayingIndex)
{
SDLState->InputPlayingIndex = InputPlayingIndex;
const char *FileName = "foo.hmi";
SDLState->PlaybackHandle = open(FileName, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
}
static void SDLEndInputPlayback(sdl_state *SDLState)
{
close(SDLState->PlaybackHandle);
SDLState->InputPlayingIndex = 0;
}
static void SDLRecordInput(sdl_state *SDLState, game_input *NewInput)
{
write(SDLState->RecordingHandle, NewInput, sizeof(*NewInput));
}
static void SDLPlaybackInput(sdl_state *SDLState, game_input *NewInput)
{
ssize_t size = read(SDLState->PlaybackHandle, NewInput, sizeof(*NewInput));
if(size == EOF || size == -1) {
S32 PlayingIndex = SDLState->InputPlayingIndex;
SDLEndInputPlayback(SDLState);
SDLBeginInputPlayback(SDLState, PlayingIndex);
}
}
static void SDLProcessMessages(sdl_state *SDLState, game_controller_input *KeyboardController)
{ {
SDL_Event Event; SDL_Event Event;
while(SDL_PollEvent(&Event)) { while(SDL_PollEvent(&Event)) {
@@ -244,12 +288,12 @@ static void SDLProcessMessages(game_controller_input *KeyboardController)
case SDL_KEYDOWN: case SDL_KEYDOWN:
case SDL_KEYUP: { case SDL_KEYUP: {
SDL_Keycode KeyCode = Event.key.keysym.sym; SDL_Keycode KeyCode = Event.key.keysym.sym;
bool IsDown = (Event.key.state == SDL_PRESSED); B32 IsDown = (Event.key.state == SDL_PRESSED);
bool WasDown = false; B32 WasDown = FALSE;
if(Event.key.state == SDL_RELEASED) { if(Event.key.state == SDL_RELEASED) {
WasDown = true; WasDown = TRUE;
} else if(Event.key.repeat != 0) { } else if(Event.key.repeat != 0) {
WasDown = true; WasDown = TRUE;
} }
if(Event.key.repeat == 0) { if(Event.key.repeat == 0) {
@@ -280,12 +324,27 @@ static void SDLProcessMessages(game_controller_input *KeyboardController)
} }
} }
// 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. if(WasDown) {
bool AltKeyWasDown = (Event.key.keysym.mod & KMOD_ALT); #if BUILD_INTERNAL
if(KeyCode == SDLK_l) {
if(SDLState->InputRecordingIndex == 0) {
SDLBeginRecordingInput(SDLState, 1);
} else {
SDLEndRecordingInput(SDLState);
SDLBeginInputPlayback(SDLState, 1);
}
}
#endif
/* 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) if(KeyCode == SDLK_F4 && AltKeyWasDown)
GlobalRunning = false; GlobalRunning = FALSE;
#if BUILD_INTERNAL
if(KeyCode == SDLK_ESCAPE) if(KeyCode == SDLK_ESCAPE)
GlobalRunning = false; GlobalRunning = FALSE;
#endif
}
} break; } break;
default: { default: {
@@ -342,7 +401,7 @@ static U32 GetLastWriteTime(const char *FileName)
struct stat file_info = {0}; struct stat file_info = {0};
if(stat(FileName, &file_info) != 0) { if(stat(FileName, &file_info) != 0) {
// TODO: Diagnostic. perror("stat failed"); /* TODO: Diagnostic. perror("stat failed"); */
} }
return (U32)file_info.st_mtime; return (U32)file_info.st_mtime;
@@ -360,12 +419,12 @@ static sdl_game_code SDLLoadGameCode(char *DLLPath)
Result.UpdateAndRender = (void(*)(game_memory *, game_input *, game_offscreen_buffer *, game_sound_output_buffer *))dlsym(Result.GameCodeDLL, "UpdateAndRender"); Result.UpdateAndRender = (void(*)(game_memory *, game_input *, game_offscreen_buffer *, game_sound_output_buffer *))dlsym(Result.GameCodeDLL, "UpdateAndRender");
if(!Result.UpdateAndRender) { if(!Result.UpdateAndRender) {
// TODO: Diagnostic. dlerror() /* TODO: Diagnostic. dlerror() */
} }
Result.IsValid = Result.UpdateAndRender ? TRUE : FALSE; Result.IsValid = Result.UpdateAndRender ? TRUE : FALSE;
} else { } else {
// TODO: Diagnostic. dlerror() /* TODO: Diagnostic. dlerror() */
} }
if(!Result.IsValid) { if(!Result.IsValid) {
@@ -378,26 +437,27 @@ 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)
dlclose(GameCode->GameCodeDLL); // NOTE: Might fail. dlclose(GameCode->GameCodeDLL); /* NOTE: Might fail. */
GameCode->IsValid = FALSE; GameCode->IsValid = FALSE;
GameCode->UpdateAndRender = NULL; GameCode->UpdateAndRender = NULL;
} }
char *GetExecutablePath() char *GetExecutablePath()
{ {
static char path[1024] = ""; // NOTE: We choose 1024 only because MacOS's MAXPATHLEN says such a value. static char path[1024] = ""; /* NOTE: We choose 1024 only because MacOS's MAXPATHLEN says such a value. For example, linux/limits.h PATH_MAX says 4096. */
ssize_t size = (ssize_t)sizeof(path); // WARNING: size_t is usually an unsigned integer, whilst ssize_t is signed. We don't care because the path is not long. size_t path_size = sizeof(path);
#if __APPLE__ && __MACH__ #if __APPLE__ && __MACH__
if(_NSGetExecutablePath(path, &size) != 0) { // NOTE: Not an absolute path. U32 size = path_size;
// TODO: Diagnostics. if(_NSGetExecutablePath(path, &size) != 0) { /* NOTE: Not an absolute path. */
/* TODO: Diagnostics. */
} }
#else #else
size = readlink("/proc/self/exe", path, size - 1); ssize_t 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. */
} }
#endif #endif
@@ -426,13 +486,14 @@ S32 main(S32 argc, char *argv[])
SDL_Window *Window = SDL_CreateWindow("Handmade Hero", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 700, 500, SDL_WINDOW_RESIZABLE); SDL_Window *Window = SDL_CreateWindow("Handmade Hero", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 700, 500, SDL_WINDOW_RESIZABLE);
if(Window) { if(Window) {
//SDL_Renderer *Renderer = SDL_CreateRenderer(Window, -1, 0); /*SDL_Renderer *Renderer = SDL_CreateRenderer(Window, -1, 0); */
SDL_Renderer *Renderer = SDL_CreateRenderer(Window, -1, SDL_RENDERER_PRESENTVSYNC); SDL_Renderer *Renderer = SDL_CreateRenderer(Window, -1, SDL_RENDERER_PRESENTVSYNC);
// "Wayland needs an event loop and rendering or it won't function." https://github.com/libsdl-org/SDL/issues/7699#issuecomment-1545684792 /* "Wayland needs an event loop and rendering or it won't function." https://github.com/libsdl-org/SDL/issues/7699#issuecomment-1545684792 */
// NOTE: This means that we need to readraw to even resize the window, otherwise the window frame will appear outdated to its actual size. /* NOTE: This means that we need to readraw to even resize the window, otherwise the window frame will appear outdated to its actual size. */
// SDL_RenderPresent(Renderer) is enough to display the window. /* SDL_RenderPresent(Renderer) is enough to display the window. */
if(Renderer) { if(Renderer) {
GlobalRunning = true; sdl_state SDLState = {0};
GlobalRunning = TRUE;
sdl_window_dimension Dimension = SDLGetWindowDimension(Window); sdl_window_dimension Dimension = SDLGetWindowDimension(Window);
SDLResizeTexture(&GlobalBackbuffer, Renderer, Dimension.Width, Dimension.Height); SDLResizeTexture(&GlobalBackbuffer, Renderer, Dimension.Width, Dimension.Height);
@@ -448,8 +509,8 @@ S32 main(S32 argc, char *argv[])
SDL_PauseAudio(0); SDL_PauseAudio(0);
SoundOutput.Samples = calloc(SoundOutput.SamplesPerSecond, SoundOutput.BytesPerSample); SoundOutput.Samples = calloc(SoundOutput.SamplesPerSecond, SoundOutput.BytesPerSample);
// SoundOutput.Samples = malloc(SoundOutput.SecondaryBufferSize); /* SoundOutput.Samples = malloc(SoundOutput.SecondaryBufferSize); */
// SDLClearSoundBuffer(&SoundOutput); // NOTE: calloc auto clears to zero /* SDLClearSoundBuffer(&SoundOutput); */ /* NOTE: calloc auto clears to zero */
#if BUILD_DEBUG #if BUILD_DEBUG
void *BaseAddress = (void *)TB(2); void *BaseAddress = (void *)TB(2);
@@ -458,19 +519,17 @@ S32 main(S32 argc, char *argv[])
#endif #endif
game_memory GameMemory = {0}; game_memory GameMemory = {0};
GameMemory.PermanentStorageSize = MB(64); GameMemory.PermanentStorageSize = MB(64);
GameMemory.TransientStorageSize = GB(4); GameMemory.TransientStorageSize = GB(4);
U64 TotalStorageSize = GameMemory.PermanentStorageSize + GameMemory.TransientStorageSize;
// NOTE: On MacOS and Linux, mmap seems to zero-fill anonymous memory as a side-effect of security.
GameMemory.PermanentStorage = mmap(BaseAddress, TotalStorageSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
GameMemory.TransientStorage = (U8 *)(GameMemory.PermanentStorage) + GameMemory.PermanentStorageSize;
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.GameMmemoryBlock = mmap(BaseAddress, SDLState.TotalSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); /* NOTE: On MacOS and Linux, mmap seems to zero-fill anonymous memory as a side-effect of security. */
GameMemory.PermanentStorage = SDLState.GameMmemoryBlock;
GameMemory.TransientStorage = (U8 *)(GameMemory.PermanentStorage) + GameMemory.PermanentStorageSize;
if(SoundOutput.Samples && GameMemory.PermanentStorage && GameMemory.TransientStorage) { if(SoundOutput.Samples && GameMemory.PermanentStorage && GameMemory.TransientStorage) {
game_input Input[2]; game_input Input[2];
game_input *NewInput = &Input[0]; game_input *NewInput = &Input[0];
@@ -490,11 +549,11 @@ S32 main(S32 argc, char *argv[])
LastCounter = SDLGetWallClock(); LastCounter = SDLGetWallClock();
#if __x86_64__ || __i386__ #if __x86_64__ || __i386__
LastCycleCount = __rdtsc(); // NOTE: rdtsc reports clock cylces, however it is not meant for really precise profiler work as the value returned is varied. LastCycleCount = __rdtsc(); /* NOTE: rdtsc reports clock cylces, however it is not meant for really precise profiler work as the value returned is varied. */
#endif // Also, __rdtsc is not available on MacOS ARM; I have not checked MacOS x64. #endif /* Also, __rdtsc is not available on MacOS ARM; I have not checked MacOS x64. */
S32 MonitorRefreshHz = SDLGetWindowRefreshRate(Window); S32 MonitorRefreshHz = SDLGetWindowRefreshRate(Window);
S32 GameUpdateHz = MonitorRefreshHz / 2; S32 GameUpdateHz = MonitorRefreshHz;
F32 TargetSecondsPerFrame = 1.0f / (F32)GameUpdateHz; F32 TargetSecondsPerFrame = 1.0f / (F32)GameUpdateHz;
U32 NewDLLWriteTime = GetLastWriteTime(game_dll_path); U32 NewDLLWriteTime = GetLastWriteTime(game_dll_path);
@@ -507,50 +566,50 @@ S32 main(S32 argc, char *argv[])
game_controller_input *NewKeyboardController = GetController(NewInput, 0); game_controller_input *NewKeyboardController = GetController(NewInput, 0);
game_controller_input ZeroController = {0}; game_controller_input ZeroController = {0};
*NewKeyboardController = ZeroController; *NewKeyboardController = ZeroController;
NewKeyboardController->IsConnected = true; NewKeyboardController->IsConnected = TRUE;
for(unsigned int ButtonIndex = 0; ButtonIndex < ARRAY_SIZE(NewKeyboardController->Buttons); ButtonIndex++) { for(unsigned int ButtonIndex = 0; ButtonIndex < ARRAY_SIZE(NewKeyboardController->Buttons); ButtonIndex++) {
NewKeyboardController->Buttons[ButtonIndex].EndedDown = OldKeyboardController->Buttons[ButtonIndex].EndedDown; NewKeyboardController->Buttons[ButtonIndex].EndedDown = OldKeyboardController->Buttons[ButtonIndex].EndedDown;
} }
SDLProcessMessages(NewKeyboardController); SDLProcessMessages(&SDLState, NewKeyboardController);
for(unsigned int ControllerIndex = 0; ControllerIndex < MAX_CONTROLLERS; ControllerIndex++) { for(unsigned int ControllerIndex = 0; ControllerIndex < MAX_CONTROLLERS; ControllerIndex++) {
game_controller_input *OldController = GetController(OldInput, ControllerIndex+1); game_controller_input *OldController = GetController(OldInput, ControllerIndex+1);
game_controller_input *NewController = GetController(NewInput, ControllerIndex+1); game_controller_input *NewController = GetController(NewInput, ControllerIndex+1);
if(ControllerHandles[ControllerIndex] != 0 && SDL_GameControllerGetAttached(ControllerHandles[ControllerIndex])) { if(ControllerHandles[ControllerIndex] != 0 && SDL_GameControllerGetAttached(ControllerHandles[ControllerIndex])) {
NewController->IsConnected = true; NewController->IsConnected = TRUE;
S16 StickX = SDL_GameControllerGetAxis(ControllerHandles[ControllerIndex], SDL_CONTROLLER_AXIS_LEFTX); S16 StickX = SDL_GameControllerGetAxis(ControllerHandles[ControllerIndex], SDL_CONTROLLER_AXIS_LEFTX);
S16 StickY = SDL_GameControllerGetAxis(ControllerHandles[ControllerIndex], SDL_CONTROLLER_AXIS_LEFTY); S16 StickY = SDL_GameControllerGetAxis(ControllerHandles[ControllerIndex], SDL_CONTROLLER_AXIS_LEFTY);
NewController->IsAnalog = true; NewController->IsAnalog = TRUE;
NewController->StickAverageX = SDLProcessInputStickValue((F32)StickX, CONTROLLER_LEFT_THUMB_DEADZONE); NewController->StickAverageX = SDLProcessInputStickValue((F32)StickX, CONTROLLER_LEFT_THUMB_DEADZONE);
NewController->StickAverageY = SDLProcessInputStickValue((F32)StickY, CONTROLLER_LEFT_THUMB_DEADZONE); NewController->StickAverageY = SDLProcessInputStickValue((F32)StickY, CONTROLLER_LEFT_THUMB_DEADZONE);
if((NewController->StickAverageX != 0.0f) || (NewController->StickAverageY != 0.0f)) { if((NewController->StickAverageX != 0.0f) || (NewController->StickAverageY != 0.0f)) {
NewController->IsAnalog = true; NewController->IsAnalog = TRUE;
} }
if(SDL_GameControllerGetButton(ControllerHandles[ControllerIndex], SDL_CONTROLLER_BUTTON_DPAD_UP)) { if(SDL_GameControllerGetButton(ControllerHandles[ControllerIndex], SDL_CONTROLLER_BUTTON_DPAD_UP)) {
NewController->StickAverageY = -1.0f; NewController->StickAverageY = -1.0f;
NewController->IsAnalog = false; NewController->IsAnalog = FALSE;
} }
if(SDL_GameControllerGetButton(ControllerHandles[ControllerIndex], SDL_CONTROLLER_BUTTON_DPAD_DOWN)) { if(SDL_GameControllerGetButton(ControllerHandles[ControllerIndex], SDL_CONTROLLER_BUTTON_DPAD_DOWN)) {
NewController->StickAverageY = 1.0f; NewController->StickAverageY = 1.0f;
NewController->IsAnalog = false; NewController->IsAnalog = FALSE;
} }
if(SDL_GameControllerGetButton(ControllerHandles[ControllerIndex], SDL_CONTROLLER_BUTTON_DPAD_LEFT)) { if(SDL_GameControllerGetButton(ControllerHandles[ControllerIndex], SDL_CONTROLLER_BUTTON_DPAD_LEFT)) {
NewController->StickAverageX = -1.0f; NewController->StickAverageX = -1.0f;
NewController->IsAnalog = false; NewController->IsAnalog = FALSE;
} }
if(SDL_GameControllerGetButton(ControllerHandles[ControllerIndex], SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) { if(SDL_GameControllerGetButton(ControllerHandles[ControllerIndex], SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) {
NewController->StickAverageX = 1.0f; NewController->StickAverageX = 1.0f;
NewController->IsAnalog = false; NewController->IsAnalog = FALSE;
} }
float Threshold = 0.5f; float Threshold = 0.5f;
@@ -569,8 +628,8 @@ S32 main(S32 argc, char *argv[])
SDLProcessInputDigitalButton(ControllerHandles[ControllerIndex], &OldController->Start, SDL_CONTROLLER_BUTTON_START, &NewController->Start); SDLProcessInputDigitalButton(ControllerHandles[ControllerIndex], &OldController->Start, SDL_CONTROLLER_BUTTON_START, &NewController->Start);
SDLProcessInputDigitalButton(ControllerHandles[ControllerIndex], &OldController->Back, SDL_CONTROLLER_BUTTON_BACK, &NewController->Back); SDLProcessInputDigitalButton(ControllerHandles[ControllerIndex], &OldController->Back, SDL_CONTROLLER_BUTTON_BACK, &NewController->Back);
} else { } else {
// NOTE: This controller is not plugged in. /* NOTE: This controller is not plugged in. */
NewController->IsConnected = false; NewController->IsConnected = FALSE;
} }
} }
@@ -586,8 +645,17 @@ S32 main(S32 argc, char *argv[])
Buffer.Width = GlobalBackbuffer.Width; Buffer.Width = GlobalBackbuffer.Width;
Buffer.Height = GlobalBackbuffer.Height; Buffer.Height = GlobalBackbuffer.Height;
Buffer.Pitch = GlobalBackbuffer.Pitch; Buffer.Pitch = GlobalBackbuffer.Pitch;
if(SDLState.InputRecordingIndex) {
SDLRecordInput(&SDLState, NewInput);
}
if(SDLState.InputPlayingIndex) {
SDLPlaybackInput(&SDLState, NewInput);
}
if(Game.UpdateAndRender) if(Game.UpdateAndRender)
Game.UpdateAndRender(&GameMemory, NewInput, &Buffer, &SoundBuffer); Game.UpdateAndRender(&GameMemory, NewInput, &Buffer, &SoundBuffer);
SDLFillSoundBuffer(&SoundOutput, BytesToWrite); SDLFillSoundBuffer(&SoundOutput, BytesToWrite);
U64 WorkCounter = SDLGetWallClock(); U64 WorkCounter = SDLGetWallClock();
@@ -600,8 +668,8 @@ S32 main(S32 argc, char *argv[])
SDL_Delay((unsigned int)((TargetSecondsPerFrame - SecondsElapsedForFrame) * 1000.0)); SDL_Delay((unsigned int)((TargetSecondsPerFrame - SecondsElapsedForFrame) * 1000.0));
} }
} else { } else {
// TODO: Missed frame rate! /* TODO: Missed frame rate! */
// TODO: Logging. /* TODO: Logging. */
} }
U64 EndCounter = SDLGetWallClock(); U64 EndCounter = SDLGetWallClock();
@@ -626,21 +694,21 @@ S32 main(S32 argc, char *argv[])
SWAP(game_input *, NewInput, OldInput); SWAP(game_input *, NewInput, OldInput);
} }
} else { } else {
// TODO: Failed to allocate Samples and Sound memory . . . /* TODO: Failed to allocate Samples and Sound memory . . . */
} }
} else { } else {
// TODO: This didn't work . . . /* TODO: This didn't work . . . */
} }
} else { } else {
// TODO: This didn't work . . . /* TODO: This didn't work . . . */
} }
// NOTE: Let the OS clean things up. /* NOTE: Let the OS clean things up. */
// SDLDeinitControllers(); // NOTE: This, however, might need to be closed? Is there maybe some clean up state that close communicates to the controller? /* SDLDeinitControllers(); // NOTE: This, however, might need to be closed? Is there maybe some clean up state that close communicates to the controller? */
// SDL_CloseAudio(); /* SDL_CloseAudio(); */
// SDL_DestroyRenderer(Renderer); /* SDL_DestroyRenderer(Renderer); */
// SDL_DestroyWindow(Window); /* SDL_DestroyWindow(Window); */
// SDL_Quit(); /* SDL_Quit(); */
return 0; return 0;
} }
+14 -9
View File
@@ -1,16 +1,10 @@
#ifndef SDL_HANDMADE_H #ifndef SDL_HANDMADE_H
#define SDL_HANDMADE_H #define SDL_HANDMADE_H
#include "core.h"
#include <SDL.h> #include <SDL.h>
#if !defined(BUILD_DEBUG) #include "core.h"
# define BUILD_DEBUG 1 #include "handmade.h"
#endif
#if !defined(BUILD_INTERNAL) // NOTE: Added in by igor.
# define BUILD_INTERNAL 1
#endif
typedef struct sdl_window_dimension { typedef struct sdl_window_dimension {
S32 Width; S32 Width;
@@ -18,7 +12,7 @@ typedef struct sdl_window_dimension {
} sdl_window_dimension; } sdl_window_dimension;
typedef struct offscreen_buffer { typedef struct offscreen_buffer {
// Pixels are always 32-bit and have the bytes in BGRX (little-endian). /* Pixels are always 32-bit and have the bytes in BGRX (little-endian). */
SDL_Texture *Texture; SDL_Texture *Texture;
void *Memory; void *Memory;
S32 Width; S32 Width;
@@ -35,4 +29,15 @@ typedef struct sdl_sound_output {
void *Samples; void *Samples;
} sdl_sound_output; } sdl_sound_output;
typedef struct sdl_state {
U64 TotalSize;
void *GameMmemoryBlock;
S32 RecordingHandle;
S32 InputRecordingIndex;
S32 PlaybackHandle;
S32 InputPlayingIndex;
} sdl_state;
#endif #endif