Day 24 done.
This commit is contained in:
+82
-32
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
#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 */
|
#include <unistd.h> /* close, write, read, readlink, unlink */
|
||||||
#include <dlfcn.h> /* dlopen */
|
#include <dlfcn.h> /* dlopen */
|
||||||
#include <sys/stat.h> /* stat */
|
#include <sys/stat.h> /* stat */
|
||||||
#if __APPLE__ && __MACH__
|
#if __APPLE__ && __MACH__
|
||||||
@@ -35,6 +35,14 @@ SDL_GameController *ControllerHandles[MAX_CONTROLLERS];
|
|||||||
|
|
||||||
static offscreen_buffer GlobalBackbuffer;
|
static offscreen_buffer GlobalBackbuffer;
|
||||||
|
|
||||||
|
static S32 str_len(char *str)
|
||||||
|
{
|
||||||
|
S32 count = 0;
|
||||||
|
while(*str++)
|
||||||
|
count++;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
static U32 SafeTruncateUInt64(U64 Value)
|
static U32 SafeTruncateUInt64(U64 Value)
|
||||||
{
|
{
|
||||||
U32 Result;
|
U32 Result;
|
||||||
@@ -165,11 +173,20 @@ static void SDLDisplayBufferInWindow(offscreen_buffer Buffer,
|
|||||||
SDL_Window *Window,
|
SDL_Window *Window,
|
||||||
SDL_Renderer *Renderer)
|
SDL_Renderer *Renderer)
|
||||||
{
|
{
|
||||||
|
SDL_Rect dest_rect;
|
||||||
|
|
||||||
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);
|
/* TODO: We temporarily introduce the target rectangle to avoid
|
||||||
|
* stretching the canvas. */
|
||||||
|
/* SDL_RenderCopy(Renderer, Buffer.Texture, 0, 0); */
|
||||||
|
dest_rect.x = 0;
|
||||||
|
dest_rect.y = 0;
|
||||||
|
dest_rect.w = 500;
|
||||||
|
dest_rect.h = 500;
|
||||||
|
SDL_RenderCopy(Renderer, Buffer.Texture, 0, (const SDL_Rect *)(&dest_rect));
|
||||||
SDL_RenderPresent(Renderer);
|
SDL_RenderPresent(Renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,13 +285,18 @@ static void HandleEvent(SDL_Event *Event)
|
|||||||
|
|
||||||
case SDL_WINDOWEVENT: {
|
case SDL_WINDOWEVENT: {
|
||||||
switch(Event->window.event) {
|
switch(Event->window.event) {
|
||||||
|
/* TODO: We temporarily disable for ease of writing the
|
||||||
|
* rendering code. */
|
||||||
|
#if 0
|
||||||
case SDL_WINDOWEVENT_SIZE_CHANGED: {
|
case SDL_WINDOWEVENT_SIZE_CHANGED: {
|
||||||
sdl_window_dimension Dimension;
|
sdl_window_dimension Dimension;
|
||||||
|
|
||||||
Dimension = SDLGetWindowDimension(Window);
|
Dimension = SDLGetWindowDimension(Window);
|
||||||
|
/* TODO: For now we fix the width and height. */
|
||||||
SDLResizeTexture(&GlobalBackbuffer, Renderer,
|
SDLResizeTexture(&GlobalBackbuffer, Renderer,
|
||||||
Dimension.Width, Dimension.Height);
|
Dimension.Width, Dimension.Height);
|
||||||
} break;
|
} break;
|
||||||
|
#endif
|
||||||
|
|
||||||
case SDL_WINDOWEVENT_EXPOSED: {
|
case SDL_WINDOWEVENT_EXPOSED: {
|
||||||
} break;
|
} break;
|
||||||
@@ -295,15 +317,32 @@ static void HandleEvent(SDL_Event *Event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SDLGetInputFileLocation(sdl_state *SDLState, char *path,
|
||||||
|
size_t path_size, S32 SlotIndex)
|
||||||
|
{
|
||||||
|
const char *file_name = "loop.hmi";
|
||||||
|
|
||||||
|
Assert(SlotIndex == 1);
|
||||||
|
|
||||||
|
snprintf(path, path_size, "%s%s", SDLState->EXEDirPath, file_name);
|
||||||
|
}
|
||||||
|
|
||||||
static void SDLBeginRecordingInput(sdl_state *SDLState,
|
static void SDLBeginRecordingInput(sdl_state *SDLState,
|
||||||
S32 InputRecordingIndex)
|
S32 InputRecordingIndex)
|
||||||
{
|
{
|
||||||
char *FileName;
|
char FileName[SDL_STATE_PATH_SIZE];
|
||||||
|
|
||||||
|
SDLGetInputFileLocation(SDLState, FileName, sizeof(FileName),
|
||||||
|
InputRecordingIndex);
|
||||||
|
|
||||||
SDLState->InputRecordingIndex = InputRecordingIndex;
|
SDLState->InputRecordingIndex = InputRecordingIndex;
|
||||||
FileName = "foo.hmi";
|
|
||||||
|
if(unlink(FileName) != 0) {
|
||||||
|
/* TODO: Diagnostics . . . */
|
||||||
|
}
|
||||||
|
|
||||||
SDLState->RecordingHandle =
|
SDLState->RecordingHandle =
|
||||||
open((const char *)FileName, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR |
|
open(FileName, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR |
|
||||||
S_IRGRP | S_IROTH);
|
S_IRGRP | S_IROTH);
|
||||||
write(SDLState->RecordingHandle, SDLState->GameMmemoryBlock,
|
write(SDLState->RecordingHandle, SDLState->GameMmemoryBlock,
|
||||||
(size_t)(SDLState->TotalSize));
|
(size_t)(SDLState->TotalSize));
|
||||||
@@ -318,13 +357,15 @@ static void SDLEndRecordingInput(sdl_state *SDLState)
|
|||||||
static void SDLBeginInputPlayback(sdl_state *SDLState,
|
static void SDLBeginInputPlayback(sdl_state *SDLState,
|
||||||
S32 InputPlayingIndex)
|
S32 InputPlayingIndex)
|
||||||
{
|
{
|
||||||
|
char FileName[SDL_STATE_PATH_SIZE];
|
||||||
ssize_t size;
|
ssize_t size;
|
||||||
char *FileName;
|
|
||||||
|
SDLGetInputFileLocation(SDLState, FileName, sizeof(FileName),
|
||||||
|
InputPlayingIndex);
|
||||||
|
|
||||||
SDLState->InputPlayingIndex = InputPlayingIndex;
|
SDLState->InputPlayingIndex = InputPlayingIndex;
|
||||||
FileName = "foo.hmi";
|
|
||||||
SDLState->PlaybackHandle =
|
SDLState->PlaybackHandle =
|
||||||
open((const char *)FileName, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR |
|
open(FileName, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR |
|
||||||
S_IRGRP | S_IROTH);
|
S_IRGRP | S_IROTH);
|
||||||
size = read(SDLState->PlaybackHandle, SDLState->GameMmemoryBlock,
|
size = read(SDLState->PlaybackHandle, SDLState->GameMmemoryBlock,
|
||||||
(size_t)(SDLState->TotalSize));
|
(size_t)(SDLState->TotalSize));
|
||||||
@@ -352,6 +393,7 @@ static void SDLPlaybackInput(sdl_state *SDLState, game_input *NewInput)
|
|||||||
PlayingIndex = SDLState->InputPlayingIndex;
|
PlayingIndex = SDLState->InputPlayingIndex;
|
||||||
SDLEndInputPlayback(SDLState);
|
SDLEndInputPlayback(SDLState);
|
||||||
SDLBeginInputPlayback(SDLState, PlayingIndex);
|
SDLBeginInputPlayback(SDLState, PlayingIndex);
|
||||||
|
size = read(SDLState->PlaybackHandle, NewInput, sizeof(*NewInput));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,6 +564,7 @@ static U32 GetLastWriteTime(const char *FileName)
|
|||||||
memset(&file_info, 0, sizeof(file_info));
|
memset(&file_info, 0, sizeof(file_info));
|
||||||
if(stat(FileName, &file_info) != 0) {
|
if(stat(FileName, &file_info) != 0) {
|
||||||
/* TODO: Diagnostic. perror("stat failed"); */
|
/* TODO: Diagnostic. perror("stat failed"); */
|
||||||
|
perror("stat failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
return (U32)file_info.st_mtime;
|
return (U32)file_info.st_mtime;
|
||||||
@@ -566,24 +609,21 @@ static void SDLUnloadGameCode(sdl_game_code *GameCode)
|
|||||||
GameCode->UpdateAndRender = NULL;
|
GameCode->UpdateAndRender = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *GetExecutablePath()
|
void GetExecutablePath(char *path, size_t path_size)
|
||||||
{
|
{
|
||||||
static char path[1024];
|
|
||||||
size_t path_size;
|
|
||||||
#if __APPLE__ && __MACH__
|
#if __APPLE__ && __MACH__
|
||||||
U32 size;
|
U32 size;
|
||||||
#else
|
#else
|
||||||
ssize_t size;
|
ssize_t size;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* NOTE: We choose 1024 only because MacOS's MAXPATHLEN says such a
|
if(path_size > 0) {
|
||||||
* value. For example, linux/limits.h PATH_MAX says 4096. */
|
|
||||||
path[0] = '\0';
|
path[0] = '\0';
|
||||||
path_size = sizeof(path);
|
|
||||||
|
|
||||||
#if __APPLE__ && __MACH__
|
#if __APPLE__ && __MACH__
|
||||||
size = path_size;
|
size = path_size;
|
||||||
if(_NSGetExecutablePath(path, &size) != 0) { /* NOTE: Not an absolute
|
if(_NSGetExecutablePath(path, &size) != 0) { /* NOTE: Not an
|
||||||
|
absolute
|
||||||
path. */
|
path. */
|
||||||
/* TODO: Diagnostics. */
|
/* TODO: Diagnostics. */
|
||||||
}
|
}
|
||||||
@@ -595,27 +635,37 @@ char *GetExecutablePath()
|
|||||||
/* TODO: Diagnostics. */
|
/* TODO: Diagnostics. */
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
return path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
S32 main(S32 argc, char *argv[])
|
static void SDLGetEXEDirPath(char *path, size_t path_size)
|
||||||
{
|
{
|
||||||
char *path;
|
|
||||||
U32 len, i;
|
U32 len, i;
|
||||||
char game_dll_path[1024];
|
|
||||||
SDL_Window *Window;
|
|
||||||
|
|
||||||
path = GetExecutablePath();
|
GetExecutablePath(path, path_size);
|
||||||
len = strlen(path);
|
len = str_len(path);
|
||||||
i = len;
|
i = len;
|
||||||
while(path[i] != '/' || i == 0) {
|
while(path[i] != '/' || i == 0) {
|
||||||
i--;
|
i--;
|
||||||
}
|
}
|
||||||
path[i+1] = '\0';
|
path[i+1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(game_dll_path, sizeof(game_dll_path), "%s%s", path,
|
static void SDLGetDLLPath(char *path, size_t path_size, char *exe_path)
|
||||||
GAME_DLL_NAME);
|
{
|
||||||
|
snprintf(path, path_size, "%s%s", exe_path, GAME_DLL_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
S32 main(S32 argc, char *argv[])
|
||||||
|
{
|
||||||
|
sdl_state SDLState;
|
||||||
|
SDL_Window *Window;
|
||||||
|
|
||||||
|
memset(&SDLState, 0, sizeof(SDLState));
|
||||||
|
|
||||||
|
SDLGetEXEDirPath(SDLState.EXEDirPath, sizeof(SDLState.EXEDirPath));
|
||||||
|
SDLGetDLLPath(SDLState.DLLPath, sizeof(SDLState.DLLPath),
|
||||||
|
SDLState.EXEDirPath);
|
||||||
|
|
||||||
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER |
|
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER |
|
||||||
SDL_INIT_AUDIO))
|
SDL_INIT_AUDIO))
|
||||||
@@ -629,7 +679,7 @@ S32 main(S32 argc, char *argv[])
|
|||||||
* protocol. However, SDL_WINDOW_ALWAYS_ON_TOP does work on KDE
|
* protocol. However, SDL_WINDOW_ALWAYS_ON_TOP does work on KDE
|
||||||
* under Wayland. I have not tested GNOME. */
|
* under Wayland. I have not tested GNOME. */
|
||||||
Window = SDL_CreateWindow("Handmade Hero", SDL_WINDOWPOS_UNDEFINED,
|
Window = SDL_CreateWindow("Handmade Hero", SDL_WINDOWPOS_UNDEFINED,
|
||||||
SDL_WINDOWPOS_UNDEFINED, 700, 500,
|
SDL_WINDOWPOS_UNDEFINED, 500, 500,
|
||||||
SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALWAYS_ON_TOP);
|
SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALWAYS_ON_TOP);
|
||||||
|
|
||||||
if(Window) {
|
if(Window) {
|
||||||
@@ -643,7 +693,6 @@ S32 main(S32 argc, char *argv[])
|
|||||||
* its actual size. */
|
* 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) {
|
||||||
sdl_state SDLState;
|
|
||||||
sdl_window_dimension Dimension;
|
sdl_window_dimension Dimension;
|
||||||
sdl_sound_output SoundOutput;
|
sdl_sound_output SoundOutput;
|
||||||
game_memory GameMemory;
|
game_memory GameMemory;
|
||||||
@@ -654,7 +703,6 @@ S32 main(S32 argc, char *argv[])
|
|||||||
void *BaseAddress = (void *)(0);
|
void *BaseAddress = (void *)(0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
memset(&SDLState, 0, sizeof(SDLState));
|
|
||||||
GlobalRunning = TRUE;
|
GlobalRunning = TRUE;
|
||||||
|
|
||||||
Dimension = SDLGetWindowDimension(Window);
|
Dimension = SDLGetWindowDimension(Window);
|
||||||
@@ -685,7 +733,7 @@ S32 main(S32 argc, char *argv[])
|
|||||||
|
|
||||||
memset(&GameMemory, 0, sizeof(GameMemory));
|
memset(&GameMemory, 0, sizeof(GameMemory));
|
||||||
GameMemory.PermanentStorageSize = MB(64);
|
GameMemory.PermanentStorageSize = MB(64);
|
||||||
GameMemory.TransientStorageSize = GB(4);
|
GameMemory.TransientStorageSize = GB(1);
|
||||||
GameMemory.DEBUGPlatformReadEntireFile =
|
GameMemory.DEBUGPlatformReadEntireFile =
|
||||||
&DEBUGPlatformReadEntireFile;
|
&DEBUGPlatformReadEntireFile;
|
||||||
GameMemory.DEBUGPlatformWriteEntireFile =
|
GameMemory.DEBUGPlatformWriteEntireFile =
|
||||||
@@ -724,7 +772,7 @@ S32 main(S32 argc, char *argv[])
|
|||||||
|
|
||||||
GlobalPerfCountFrequency = SDL_GetPerformanceFrequency();
|
GlobalPerfCountFrequency = SDL_GetPerformanceFrequency();
|
||||||
|
|
||||||
Game = SDLLoadGameCode(game_dll_path);
|
Game = SDLLoadGameCode(SDLState.DLLPath);
|
||||||
|
|
||||||
while(GlobalRunning) {
|
while(GlobalRunning) {
|
||||||
S32 MonitorRefreshHz, GameUpdateHz;
|
S32 MonitorRefreshHz, GameUpdateHz;
|
||||||
@@ -759,10 +807,10 @@ S32 main(S32 argc, char *argv[])
|
|||||||
GameUpdateHz = MonitorRefreshHz;
|
GameUpdateHz = MonitorRefreshHz;
|
||||||
TargetSecondsPerFrame = 1.0f / (F32)GameUpdateHz;
|
TargetSecondsPerFrame = 1.0f / (F32)GameUpdateHz;
|
||||||
|
|
||||||
NewDLLWriteTime = GetLastWriteTime(game_dll_path);
|
NewDLLWriteTime = GetLastWriteTime(SDLState.DLLPath);
|
||||||
if(NewDLLWriteTime > Game.DLLLastWriteTime) {
|
if(NewDLLWriteTime > Game.DLLLastWriteTime) {
|
||||||
SDLUnloadGameCode(&Game);
|
SDLUnloadGameCode(&Game);
|
||||||
Game = SDLLoadGameCode(game_dll_path);
|
Game = SDLLoadGameCode(SDLState.DLLPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
OldKeyboardController = GetController(OldInput, 0);
|
OldKeyboardController = GetController(OldInput, 0);
|
||||||
@@ -803,6 +851,8 @@ S32 main(S32 argc, char *argv[])
|
|||||||
S16 StickX, StickY;
|
S16 StickX, StickY;
|
||||||
float Threshold;
|
float Threshold;
|
||||||
|
|
||||||
|
NewController->IsAnalog =
|
||||||
|
OldController->IsAnalog;
|
||||||
NewController->IsConnected = TRUE;
|
NewController->IsConnected = TRUE;
|
||||||
|
|
||||||
StickX =
|
StickX =
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ 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.
|
||||||
|
* For example, linux/limits.h PATH_MAX says 4096. */
|
||||||
|
#define SDL_STATE_PATH_SIZE 1024
|
||||||
typedef struct sdl_state {
|
typedef struct sdl_state {
|
||||||
U64 TotalSize;
|
U64 TotalSize;
|
||||||
void *GameMmemoryBlock;
|
void *GameMmemoryBlock;
|
||||||
@@ -37,8 +40,12 @@ typedef struct sdl_state {
|
|||||||
S32 RecordingHandle;
|
S32 RecordingHandle;
|
||||||
S32 InputRecordingIndex;
|
S32 InputRecordingIndex;
|
||||||
|
|
||||||
|
// NOTE: These functions might be NULL. Check before calling them!
|
||||||
S32 PlaybackHandle;
|
S32 PlaybackHandle;
|
||||||
S32 InputPlayingIndex;
|
S32 InputPlayingIndex;
|
||||||
|
|
||||||
|
char EXEDirPath[SDL_STATE_PATH_SIZE];
|
||||||
|
char DLLPath[SDL_STATE_PATH_SIZE];
|
||||||
} sdl_state;
|
} sdl_state;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user