Day 36. 25:01. Need to draw assets.

This commit is contained in:
igor
2026-04-16 22:18:24 -07:00
parent dea811e073
commit a8a3b57f8a
6 changed files with 269 additions and 362 deletions
+12 -11
View File
@@ -15,18 +15,19 @@ endif
CC = clang CC = clang
UFLAGS = UFLAGS =
# NOTE: We comply with C89 (plain C), however the standard has no 64-bit # NOTE: This project's code bases itself on C89 (plain C) standard, however
# support. But, every compiler at that time supported long long, # allowing a few convenient features of newer standards. Mid-scope
# hence we ignore the incompliance in our code. # variable declarations, comments that begin with '//', long long,
# NOTE: We allow function declrations with specifying void # designated initializers, compound literals, and anonymous structures
# (ex, void test() is allowed). # are allowed as they are convenient. Everything else that has come out
FLAGS = -ansi -pedantic -pedantic-errors -Wno-long-long \ # of modern standards is pretty much destructive and should not be used.
-Wno-overlength-strings -Wincompatible-pointer-types \ FLAGS = -Wall -Wextra \
-Wint-conversion -Wimplicit-int-float-conversion -Wformat \ -Wincompatible-pointer-types \
-Wno-strict-prototypes -Wall -Wextra -fno-caret-diagnostics \ -Wint-conversion -Wimplicit-int-float-conversion -Wformat \
-fno-show-column -Wno-missing-field-initializers \ -Wno-strict-prototypes -Wno-missing-field-initializers \
-Wno-unused-function -Wno-unused-parameter -Wno-unused-variable \ -Wno-unused-function -Wno-unused-parameter -Wno-unused-variable \
-Wno-unused-but-set-variable -Wno-unused-but-set-variable \
-fno-caret-diagnostics -fno-show-column
ifeq ($(DETECTED_OS),macos) ifeq ($(DETECTED_OS),macos)
UFLAGS = -glldb UFLAGS = -glldb
+93 -118
View File
@@ -5,7 +5,7 @@
#include "handmade_intrinsics.h" #include "handmade_intrinsics.h"
#include "handmade_random.h" #include "handmade_random.h"
#include "handmade_tile.h" #include "handmade_tile.h"
#include "handmade_tile.cpp" #include "handmade_tile.c"
#include <string.h> /* memset */ #include <string.h> /* memset */
@@ -44,12 +44,10 @@ static void GameOutputSound(game_state *GameState,
static void ClearBackground(game_offscreen_buffer *Buffer) static void ClearBackground(game_offscreen_buffer *Buffer)
{ {
S32 Width, Height, X; S32 Width = Buffer->Width;
S32 Height = Buffer->Height;
Width = Buffer->Width; for(S32 X = 0; X < Width * Height; X++) {
Height = Buffer->Height;
for(X = 0; X < Width * Height; X++) {
U32 *Pixel = &((U32 *)Buffer->Memory)[X]; U32 *Pixel = &((U32 *)Buffer->Memory)[X];
*Pixel = 0xFFFFFF; *Pixel = 0xFFFFFF;
} }
@@ -68,10 +66,6 @@ static void DrawRectangle(game_offscreen_buffer *Buffer,
S32 Width = Buffer->Width; S32 Width = Buffer->Width;
S32 Height = Buffer->Height; S32 Height = Buffer->Height;
U8 *Row;
S32 Y, X;
U32 Color;
if(MinX < 0) if(MinX < 0)
MinX = 0; MinX = 0;
if(MinY < 0) if(MinY < 0)
@@ -82,15 +76,15 @@ static void DrawRectangle(game_offscreen_buffer *Buffer,
if(MaxY > Height) if(MaxY > Height)
MaxY = Height; MaxY = Height;
Color = (U32)((RoundF32toS32(R * 255.0f) << 16) | U32 Color = (U32)((RoundF32toS32(R * 255.0f) << 16) |
(RoundF32toS32(G * 255.0f) << 8) | (RoundF32toS32(G * 255.0f) << 8) |
(RoundF32toS32(B * 255.0f) << 0)); (RoundF32toS32(B * 255.0f) << 0));
Row = ((U8 *)Buffer->Memory + MinX*Buffer->BytesPerPixel + U8 *Row = ((U8 *)Buffer->Memory + MinX*Buffer->BytesPerPixel +
MinY*Buffer->Pitch); MinY*Buffer->Pitch);
for(Y = MinY; Y < MaxY; Y++) { for(S32 Y = MinY; Y < MaxY; Y++) {
U32 *Pixel = (U32 *)Row; U32 *Pixel = (U32 *)Row;
for(X = MinX; X < MaxX; X++) { for(S32 X = MinX; X < MaxX; X++) {
*(U32 *)Pixel = Color; *(U32 *)Pixel = Color;
Pixel++; Pixel++;
} }
@@ -102,60 +96,36 @@ 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)
{ {
#define TILEMAP_COUNT_X 256
#define TILEMAP_COUNT_Y 256
game_state *GameState;
U32 ControllerIndex;
F32 PlayerR, PlayerG, PlayerB,
PlayerWidth, PlayerHeight,
PlayerLeft, PlayerTop;
F32 ScreenCenterX, ScreenCenterY;
world *World;
tile_map *TileMap;
S32 TileSideInPixels;
F32 MetersToPixels;
ASSERT((&Input->Controllers[0].u.buttons.Terminator - ASSERT((&Input->Controllers[0].u.buttons.Terminator -
&Input->Controllers[0].u.Buttons[0]) == &Input->Controllers[0].u.Buttons[0]) ==
ARRAY_SIZE(Input->Controllers[0].u.Buttons)); ARRAY_SIZE(Input->Controllers[0].u.Buttons));
ASSERT(sizeof(game_state) <= Memory->PermanentStorageSize); ASSERT(sizeof(game_state) <= Memory->PermanentStorageSize);
PlayerHeight = 1.4f; #define TILEMAP_COUNT_X 256
PlayerWidth = 0.75f * PlayerHeight; #define TILEMAP_COUNT_Y 256
game_state *GameState;
F32 PlayerHeight = 1.4f;
F32 PlayerWidth = 0.75f * PlayerHeight;
GameState = (game_state *)Memory->PermanentStorage; GameState = (game_state *)Memory->PermanentStorage;
if(!Memory->IsInitialized) { if(!Memory->IsInitialized) {
U32 TilesPerWidth, TilesPerHeight;
U32 ScreenX, ScreenY;
U32 ScreenIndex;
tile_map *TileMap;
world *World;
U32 AbsTileZ;
B32 DoorTop, DoorBottom, DoorLeft, DoorRight, DoorUp, DoorDown;
U32 RandomNumberIndex;
GameState->PlayerP.AbsTileX = 2; GameState->PlayerP.AbsTileX = 2;
GameState->PlayerP.AbsTileY = 3; GameState->PlayerP.AbsTileY = 3;
GameState->PlayerP.TileRelX = 5.0f; GameState->PlayerP.OffsetX = 5.0f;
GameState->PlayerP.TileRelY = 5.0f; GameState->PlayerP.OffsetY = 5.0f;
InitializeArena(&GameState->WorldArena, InitializeArena(&GameState->WorldArena,
Memory->PermanentStorageSize - sizeof(game_state), Memory->PermanentStorageSize - sizeof(game_state),
(U8 *)Memory->PermanentStorage + sizeof(game_state)); (U8 *)Memory->PermanentStorage + sizeof(game_state));
GameState->World = PUSH_STRUCT(&GameState->WorldArena, world); GameState->World = PUSH_STRUCT(&GameState->WorldArena, world);
World = GameState->World; world *World = GameState->World;
World->TileMap = PUSH_STRUCT(&GameState->WorldArena, tile_map); World->TileMap = PUSH_STRUCT(&GameState->WorldArena, tile_map);
TileMap = World->TileMap; tile_map *TileMap = World->TileMap;
TileMap->ChunkShift = 4; TileMap->ChunkShift = 4;
TileMap->ChunkMask = (1 << TileMap->ChunkShift) - 1; TileMap->ChunkMask = (1 << TileMap->ChunkShift) - 1;
@@ -174,34 +144,37 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
TileMap->TileSideInMeters = 1.4f; TileMap->TileSideInMeters = 1.4f;
RandomNumberIndex = 0; U32 RandomNumberIndex = 0;
TilesPerWidth = 17; U32 TilesPerWidth = 17;
TilesPerHeight = 9; U32 TilesPerHeight = 9;
ScreenX = 0; U32 ScreenX = 0;
ScreenY = 0; U32 ScreenY = 0;
AbsTileZ = 0; U32 AbsTileZ = 0;
DoorTop = FALSE;
DoorBottom = FALSE;
DoorLeft = FALSE;
DoorRight = FALSE;
DoorUp = FALSE;
DoorDown = FALSE;
for(ScreenIndex = 0; ScreenIndex < 100; ScreenIndex++) {
/* TODO: Random number generator. */
U32 TileX, TileY;
U32 RandomChoice;
B32 DoorTop = FALSE;
B32 DoorBottom = FALSE;
B32 DoorLeft = FALSE;
B32 DoorRight = FALSE;
B32 DoorUp = FALSE;
B32 DoorDown = FALSE;
for(U32 ScreenIndex = 0; ScreenIndex < 100; ScreenIndex++) {
ASSERT(RandomNumberIndex < ARRAY_SIZE(RandomNumberTable)); ASSERT(RandomNumberIndex < ARRAY_SIZE(RandomNumberTable));
/* TODO: Random number generator. */
U32 RandomChoice;
if(DoorUp || DoorDown) { if(DoorUp || DoorDown) {
RandomChoice = RandomNumberTable[RandomNumberIndex++] % 2; RandomChoice = RandomNumberTable[RandomNumberIndex++] % 2;
} else { } else {
RandomChoice = RandomNumberTable[RandomNumberIndex++] % 3; RandomChoice = RandomNumberTable[RandomNumberIndex++] % 3;
} }
B32 CreatedZDoor = FALSE;
if(RandomChoice == 2) { if(RandomChoice == 2) {
CreatedZDoor = TRUE;
if(AbsTileZ == 0) { if(AbsTileZ == 0) {
DoorUp = TRUE; DoorUp = TRUE;
} else { } else {
@@ -213,8 +186,8 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
DoorTop = TRUE; DoorTop = TRUE;
} }
for(TileY = 0; TileY < TilesPerHeight; TileY++) { for(U32 TileY = 0; TileY < TilesPerHeight; TileY++) {
for(TileX = 0; TileX < TilesPerWidth; TileX++) { for(U32 TileX = 0; TileX < TilesPerWidth; TileX++) {
U32 AbsTileX = ScreenX * TilesPerWidth + TileX; U32 AbsTileX = ScreenX * TilesPerWidth + TileX;
U32 AbsTileY = ScreenY * TilesPerHeight + TileY; U32 AbsTileY = ScreenY * TilesPerHeight + TileY;
@@ -259,16 +232,12 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
} }
} }
DoorLeft = DoorRight; DoorLeft = DoorRight;
DoorBottom = DoorTop; DoorBottom = DoorTop;
if(DoorUp) { if(CreatedZDoor) {
DoorDown = TRUE; DoorDown = !DoorDown;
DoorUp = FALSE; DoorUp = !DoorUp;
} else if (DoorDown) {
DoorUp = TRUE;
DoorDown = FALSE;
} else { } else {
DoorUp = FALSE; DoorUp = FALSE;
DoorDown = FALSE; DoorDown = FALSE;
@@ -293,13 +262,13 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
Memory->IsInitialized = TRUE; Memory->IsInitialized = TRUE;
} }
World = GameState->World; world *World = GameState->World;
TileMap = World->TileMap; tile_map *TileMap = World->TileMap;
TileSideInPixels = 60; S32 TileSideInPixels = 60;
MetersToPixels = (F32)TileSideInPixels / TileMap->TileSideInMeters; F32 MetersToPixels = (F32)TileSideInPixels / TileMap->TileSideInMeters;
for(ControllerIndex = 0; for(U32 ControllerIndex = 0;
ControllerIndex < ARRAY_SIZE(Input->Controllers); ControllerIndex < ARRAY_SIZE(Input->Controllers);
ControllerIndex++) ControllerIndex++)
{ {
@@ -310,8 +279,6 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
F32 dPlayerX = 0.0f; F32 dPlayerX = 0.0f;
F32 dPlayerY = 0.0f; F32 dPlayerY = 0.0f;
tile_map_position NewPlayerP, PlayerLeft, PlayerRight;
if(Controller->u.buttons.MoveUp.EndedDown) { if(Controller->u.buttons.MoveUp.EndedDown) {
dPlayerY = 1.0f; dPlayerY = 1.0f;
} }
@@ -325,48 +292,58 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
dPlayerX = 1.0f; dPlayerX = 1.0f;
} }
{ F32 PlayerSpeed = 2.0f;
F32 PlayerSpeed = 2.0f;
if(Controller->u.buttons.ActionUp.EndedDown) if(Controller->u.buttons.ActionUp.EndedDown)
PlayerSpeed = 10.0f; PlayerSpeed = 10.0f;
dPlayerX *= PlayerSpeed; dPlayerX *= PlayerSpeed;
dPlayerY *= PlayerSpeed; dPlayerY *= PlayerSpeed;
}
tile_map_position NewPlayerP;
NewPlayerP = GameState->PlayerP; NewPlayerP = GameState->PlayerP;
NewPlayerP.TileRelX += Input->dtForFrame*dPlayerX; NewPlayerP.OffsetX += Input->dtForFrame*dPlayerX;
NewPlayerP.TileRelY += Input->dtForFrame*dPlayerY; NewPlayerP.OffsetY += Input->dtForFrame*dPlayerY;
NewPlayerP = RecannonicalizePosition(TileMap, NewPlayerP); NewPlayerP = RecannonicalizePosition(TileMap, NewPlayerP);
tile_map_position PlayerLeft;
PlayerLeft = NewPlayerP; PlayerLeft = NewPlayerP;
PlayerLeft.TileRelX -= 0.5f*PlayerWidth; PlayerLeft.OffsetX -= 0.5f*PlayerWidth;
PlayerLeft = RecannonicalizePosition(TileMap, PlayerLeft); PlayerLeft = RecannonicalizePosition(TileMap, PlayerLeft);
tile_map_position PlayerRight;
PlayerRight = NewPlayerP; PlayerRight = NewPlayerP;
PlayerRight.TileRelX += 0.5f*PlayerWidth; PlayerRight.OffsetX += 0.5f*PlayerWidth;
PlayerRight = RecannonicalizePosition(TileMap, PlayerRight); PlayerRight = RecannonicalizePosition(TileMap, PlayerRight);
if(IsTileMapPointEmpty(TileMap, NewPlayerP) && if(IsTileMapPointEmpty(TileMap, NewPlayerP) &&
IsTileMapPointEmpty(TileMap, PlayerLeft) && IsTileMapPointEmpty(TileMap, PlayerLeft) &&
IsTileMapPointEmpty(TileMap, PlayerRight)) IsTileMapPointEmpty(TileMap, PlayerRight))
{ {
if(!AreOnSameTile(&GameState->PlayerP, &NewPlayerP)) {
U32 NewTileValue =
GetTileValueByPos(TileMap, NewPlayerP);
if(NewTileValue == 3) {
NewPlayerP.AbsTileZ++;
} else if(NewTileValue == 4) {
NewPlayerP.AbsTileZ--;
}
}
GameState->PlayerP = NewPlayerP; GameState->PlayerP = NewPlayerP;
} }
} }
} }
ScreenCenterX = 0.5f * (F32)Buffer->Width; F32 ScreenCenterX = 0.5f * (F32)Buffer->Width;
ScreenCenterY = 0.5f * (F32)Buffer->Height; F32 ScreenCenterY = 0.5f * (F32)Buffer->Height;
DrawRectangle(Buffer, 0.0f, 0.0f, DrawRectangle(Buffer, 0.0f, 0.0f,
(F32)Buffer->Width, (F32)Buffer->Height, (F32)Buffer->Width, (F32)Buffer->Height,
0.0f, 1.0f, 0.0f); 0.0f, 1.0f, 0.0f);
{ {
S32 RelRow, RelColumn; for(S32 RelRow = -10; RelRow < 10; RelRow++) {
for(RelRow = -10; RelRow < 10; RelRow++) { for(S32 RelColumn = -20; RelColumn < 20; RelColumn++) {
for(RelColumn = -20; RelColumn < 20; RelColumn++) {
U32 Column = GameState->PlayerP.AbsTileX + RelColumn; U32 Column = GameState->PlayerP.AbsTileX + RelColumn;
U32 Row = GameState->PlayerP.AbsTileY + RelRow; U32 Row = GameState->PlayerP.AbsTileY + RelRow;
@@ -376,8 +353,6 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
GameState->PlayerP.AbsTileZ); GameState->PlayerP.AbsTileZ);
if(TileID > 0) { if(TileID > 0) {
F32 CenterX, CenterY, MinX, MinY, MaxX, MaxY;
F32 Gray = 0.5f; F32 Gray = 0.5f;
if(TileID == 2) { if(TileID == 2) {
Gray = 1.0f; Gray = 1.0f;
@@ -394,16 +369,16 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
} }
CenterX = ScreenCenterX - F32 CenterX = ScreenCenterX -
MetersToPixels*GameState->PlayerP.TileRelX + MetersToPixels*GameState->PlayerP.OffsetX +
(F32)RelColumn*(F32)TileSideInPixels; (F32)RelColumn*(F32)TileSideInPixels;
CenterY = ScreenCenterY + F32 CenterY = ScreenCenterY +
MetersToPixels*GameState->PlayerP.TileRelY - MetersToPixels*GameState->PlayerP.OffsetY -
(F32)RelRow*(F32)TileSideInPixels; (F32)RelRow*(F32)TileSideInPixels;
MinX = CenterX - 0.5f*(F32)TileSideInPixels; F32 MinX = CenterX - 0.5f*(F32)TileSideInPixels;
MinY = CenterY - 0.5f*(F32)TileSideInPixels; F32 MinY = CenterY - 0.5f*(F32)TileSideInPixels;
MaxX = CenterX + 0.5f*(F32)TileSideInPixels; F32 MaxX = CenterX + 0.5f*(F32)TileSideInPixels;
MaxY = CenterY + 0.5f*(F32)TileSideInPixels; F32 MaxY = CenterY + 0.5f*(F32)TileSideInPixels;
DrawRectangle(Buffer, DrawRectangle(Buffer,
MinX, MinY, MaxX, MaxY, MinX, MinY, MaxX, MaxY,
Gray, Gray, Gray); Gray, Gray, Gray);
@@ -412,11 +387,11 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
} }
} }
PlayerR = 1.0f; F32 PlayerR = 1.0f;
PlayerG = 0.0f; F32 PlayerG = 0.0f;
PlayerB = 0.0f; F32 PlayerB = 0.0f;
PlayerLeft = ScreenCenterX - 0.5f * MetersToPixels*PlayerWidth; F32 PlayerLeft = ScreenCenterX - 0.5f * MetersToPixels*PlayerWidth;
PlayerTop = ScreenCenterY - MetersToPixels*PlayerHeight; F32 PlayerTop = ScreenCenterY - MetersToPixels*PlayerHeight;
DrawRectangle(Buffer, DrawRectangle(Buffer,
PlayerLeft, PlayerTop, PlayerLeft, PlayerTop,
PlayerLeft + MetersToPixels*PlayerWidth, PlayerLeft + MetersToPixels*PlayerWidth,
+80 -64
View File
@@ -21,29 +21,6 @@ static tile_chunk *GetTileChunk(tile_map *TileMap,
return TileChunk; return TileChunk;
} }
static void CannonicalizeCoord(tile_map *TileMap, U32 *Tile, F32 *TileRel)
{
/* NOTE: The world is assumed to be toroidal topology. If you step off
one end, you come back on the other. */
S32 Offset = RoundF32toS32(*TileRel / TileMap->TileSideInMeters);
*Tile += Offset;
*TileRel -= (F32)Offset * TileMap->TileSideInMeters;
ASSERT(*TileRel >= -0.5f*TileMap->TileSideInMeters);
ASSERT(*TileRel <= 0.5f*TileMap->TileSideInMeters);
}
static tile_map_position RecannonicalizePosition(tile_map *TileMap,
tile_map_position Pos)
{
tile_map_position Result = Pos;
CannonicalizeCoord(TileMap, &Result.AbsTileX, &Result.TileRelX);
CannonicalizeCoord(TileMap, &Result.AbsTileY, &Result.TileRelY);
return Result;
}
static tile_chunk_position GetChunkPositionFor(tile_map *TileMap, static tile_chunk_position GetChunkPositionFor(tile_map *TileMap,
U32 AbsTileX, U32 AbsTileX,
U32 AbsTileY, U32 AbsTileY,
@@ -63,26 +40,14 @@ static tile_chunk_position GetChunkPositionFor(tile_map *TileMap,
static U32 GetTileValueUnchecked(tile_map *TileMap, tile_chunk *TileChunk, static U32 GetTileValueUnchecked(tile_map *TileMap, tile_chunk *TileChunk,
U32 TileX, U32 TileY) U32 TileX, U32 TileY)
{ {
U32 TileChunkValue;
ASSERT(TileChunk); ASSERT(TileChunk);
ASSERT(TileX < TileMap->ChunkDim); ASSERT(TileX < TileMap->ChunkDim);
ASSERT(TileY < TileMap->ChunkDim); ASSERT(TileY < TileMap->ChunkDim);
TileChunkValue = TileChunk->Tiles[TileY * TileMap->ChunkDim + TileX]; U32 TileChunkValue = TileChunk->Tiles[TileY * TileMap->ChunkDim + TileX];
return TileChunkValue; return TileChunkValue;
} }
static void SetTileValueUnchecked(tile_map *TileMap, tile_chunk *TileChunk,
U32 TileX, U32 TileY, U32 TileValue)
{
ASSERT(TileChunk);
ASSERT(TileX < TileMap->ChunkDim);
ASSERT(TileY < TileMap->ChunkDim);
TileChunk->Tiles[TileY * TileMap->ChunkDim + TileX] = TileValue;
}
static U32 GetTileChunkValue(tile_map *TileMap, tile_chunk *TileChunk, static U32 GetTileChunkValue(tile_map *TileMap, tile_chunk *TileChunk,
U32 TestTileX, U32 TestTileY) U32 TestTileX, U32 TestTileY)
{ {
@@ -98,18 +63,6 @@ static U32 GetTileChunkValue(tile_map *TileMap, tile_chunk *TileChunk,
return TileChunkValue; return TileChunkValue;
} }
static void SetTileChunkValue(tile_map *TileMap, tile_chunk *TileChunk,
U32 TestTileX, U32 TestTileY,
U32 TileValue)
{
if(TileChunk && TileChunk->Tiles) {
SetTileValueUnchecked(TileMap,
TileChunk,
TestTileX, TestTileY,
TileValue);
}
}
static U32 GetTileValue(tile_map *TileMap, static U32 GetTileValue(tile_map *TileMap,
U32 AbsTileX, U32 AbsTileY, U32 AbsTileZ) U32 AbsTileX, U32 AbsTileY, U32 AbsTileZ)
{ {
@@ -127,15 +80,43 @@ static U32 GetTileValue(tile_map *TileMap,
return TileChunkValue; return TileChunkValue;
} }
static B32 IsTileMapPointEmpty(tile_map *TileMap, tile_map_position CanPos) static U32 GetTileValueByPos(tile_map *TileMap, tile_map_position Pos)
{ {
B32 Empty;
U32 TileChunkValue = GetTileValue(TileMap, U32 TileChunkValue = GetTileValue(TileMap,
CanPos.AbsTileX, Pos.AbsTileX,
CanPos.AbsTileY, Pos.AbsTileY,
CanPos.AbsTileZ); Pos.AbsTileZ);
Empty = (TileChunkValue == 1); return TileChunkValue;
}
static void SetTileValueUnchecked(tile_map *TileMap, tile_chunk *TileChunk,
U32 TileX, U32 TileY, U32 TileValue)
{
ASSERT(TileChunk);
ASSERT(TileX < TileMap->ChunkDim);
ASSERT(TileY < TileMap->ChunkDim);
TileChunk->Tiles[TileY * TileMap->ChunkDim + TileX] = TileValue;
}
static void SetTileChunkValue(tile_map *TileMap, tile_chunk *TileChunk,
U32 TestTileX, U32 TestTileY,
U32 TileValue)
{
if(TileChunk && TileChunk->Tiles) {
SetTileValueUnchecked(TileMap,
TileChunk,
TestTileX, TestTileY,
TileValue);
}
}
static B32 IsTileMapPointEmpty(tile_map *TileMap, tile_map_position Pos)
{
U32 TileChunkValue = GetTileValueByPos(TileMap, Pos);
B32 Empty = ((TileChunkValue == 1) ||
(TileChunkValue == 3) ||
(TileChunkValue == 4));
return Empty; return Empty;
} }
@@ -144,22 +125,22 @@ static void SetTileValue(memory_arena *Arena,
U32 AbsTileX, U32 AbsTileY, U32 AbsTileZ, U32 AbsTileX, U32 AbsTileY, U32 AbsTileZ,
U32 TileValue) U32 TileValue)
{ {
tile_chunk_position ChunkPos;
tile_chunk *TileChunk;
ChunkPos = GetChunkPositionFor(TileMap, AbsTileX, AbsTileY, AbsTileZ); tile_chunk_position ChunkPos = GetChunkPositionFor(TileMap,
TileChunk = GetTileChunk(TileMap, AbsTileX,
ChunkPos.TileChunkX, AbsTileY,
ChunkPos.TileChunkY, AbsTileZ);
ChunkPos.TileChunkZ); tile_chunk *TileChunk = GetTileChunk(TileMap,
ChunkPos.TileChunkX,
ChunkPos.TileChunkY,
ChunkPos.TileChunkZ);
ASSERT(TileChunk); ASSERT(TileChunk);
if(!TileChunk->Tiles) { if(!TileChunk->Tiles) {
U32 TileCount = TileMap->ChunkDim*TileMap->ChunkDim; U32 TileCount = TileMap->ChunkDim*TileMap->ChunkDim;
U32 TileIndex;
TileChunk->Tiles = PUSH_ARRAY(Arena, TileCount, U32); TileChunk->Tiles = PUSH_ARRAY(Arena, TileCount, U32);
for(TileIndex = 0; TileIndex < TileCount; TileIndex++) { for(U32 TileIndex = 0; TileIndex < TileCount; TileIndex++) {
TileChunk->Tiles[TileIndex] = 1; TileChunk->Tiles[TileIndex] = 1;
} }
@@ -170,3 +151,38 @@ static void SetTileValue(memory_arena *Arena,
ChunkPos.RelTileY, ChunkPos.RelTileY,
TileValue); TileValue);
} }
//
// TODO: Do these belong more in a "positioning" or "geometry" file?
//
static void CannonicalizeCoord(tile_map *TileMap, U32 *Tile, F32 *TileRel)
{
// NOTE: The world is assumed to be toroidal topology. If you step off
// one end, you come back on the other.
S32 Offset = RoundF32toS32(*TileRel / TileMap->TileSideInMeters);
*Tile += Offset;
*TileRel -= (F32)Offset * TileMap->TileSideInMeters;
ASSERT(*TileRel >= -0.5f*TileMap->TileSideInMeters);
ASSERT(*TileRel <= 0.5f*TileMap->TileSideInMeters);
}
static tile_map_position RecannonicalizePosition(tile_map *TileMap,
tile_map_position Pos)
{
tile_map_position Result = Pos;
CannonicalizeCoord(TileMap, &Result.AbsTileX, &Result.OffsetX);
CannonicalizeCoord(TileMap, &Result.AbsTileY, &Result.OffsetY);
return Result;
}
static B32 AreOnSameTile(tile_map_position *A, tile_map_position *B)
{
B32 Result = ((A->AbsTileX == B->AbsTileX) &&
(A->AbsTileY == B->AbsTileY) &&
(A->AbsTileZ == B->AbsTileZ));
return Result;
}
+3 -3
View File
@@ -6,9 +6,9 @@ typedef struct tile_map_position {
U32 AbsTileY; U32 AbsTileY;
U32 AbsTileZ; U32 AbsTileZ;
/* NOTE: Tile-relative X and Y. */ /* NOTE: X and Y relative to tile center. */
F32 TileRelX; F32 OffsetX;
F32 TileRelY; F32 OffsetY;
} tile_map_position; } tile_map_position;
typedef struct tile_chunk_position { typedef struct tile_chunk_position {
+81 -153
View File
@@ -50,10 +50,8 @@ static S32 str_len(char *str)
static U32 SafeTruncateUInt64(U64 Value) static U32 SafeTruncateUInt64(U64 Value)
{ {
U32 Result;
ASSERT(Value <= 0xFFFFFFFF); ASSERT(Value <= 0xFFFFFFFF);
Result = (U32)Value; U32 Result = (U32)Value;
return Result; return Result;
} }
@@ -61,17 +59,14 @@ debug_read_file_result DEBUGPlatformReadEntireFile(thread_context *Thread,
const char *Filename) const char *Filename)
{ {
debug_read_file_result Result; debug_read_file_result Result;
S32 FileHandle;
struct stat FileStatus;
U32 BytesToRead;
U8 *NextByteLocation;
memset(&Result, 0, sizeof(Result)); memset(&Result, 0, sizeof(Result));
FileHandle = open(Filename, O_RDONLY);
S32 FileHandle = open(Filename, O_RDONLY);
if(FileHandle == -1) { if(FileHandle == -1) {
return Result; return Result;
} }
struct stat FileStatus;
if(fstat(FileHandle, &FileStatus) == -1) { if(fstat(FileHandle, &FileStatus) == -1) {
close(FileHandle); close(FileHandle);
return Result; return Result;
@@ -85,12 +80,10 @@ debug_read_file_result DEBUGPlatformReadEntireFile(thread_context *Thread,
return Result; return Result;
} }
BytesToRead = Result.ContentsSize; U32 BytesToRead = Result.ContentsSize;
NextByteLocation = (U8 *)Result.Contents; U8 *NextByteLocation = (U8 *)Result.Contents;
while(BytesToRead) { while(BytesToRead) {
U32 BytesRead; U32 BytesRead = read(FileHandle, NextByteLocation, BytesToRead);
BytesRead = read(FileHandle, NextByteLocation, BytesToRead);
if(BytesRead == (U32)-1) { if(BytesRead == (U32)-1) {
free(Result.Contents); free(Result.Contents);
Result.Contents = 0; Result.Contents = 0;
@@ -111,17 +104,13 @@ B32 DEBUGPlatformWriteEntireFile(thread_context *Thread,
const char *Filename, U32 MemorySize, const char *Filename, U32 MemorySize,
void *Memory) void *Memory)
{ {
S32 FileHandle; S32 FileHandle = open(Filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR |
U32 BytesToWrite; S_IRGRP | S_IROTH);
U8 *NextByteLocation;
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;
BytesToWrite = MemorySize; U32 BytesToWrite = MemorySize;
NextByteLocation = (U8*)Memory; U8 *NextByteLocation = (U8*)Memory;
while(BytesToWrite) { while(BytesToWrite) {
U32 BytesWritten; U32 BytesWritten;
@@ -155,15 +144,13 @@ static sdl_window_dimension SDLGetWindowDimension(SDL_Window *Window)
static void SDLResizeTexture(offscreen_buffer *Buffer, static void SDLResizeTexture(offscreen_buffer *Buffer,
SDL_Renderer *Renderer, int Width, int Height) SDL_Renderer *Renderer, int Width, int Height)
{ {
S32 BytesPerPixel;
if(Buffer->Texture) if(Buffer->Texture)
SDL_DestroyTexture(Buffer->Texture); SDL_DestroyTexture(Buffer->Texture);
if(Buffer->Memory) if(Buffer->Memory)
free(Buffer->Memory); free(Buffer->Memory);
BytesPerPixel = 4; S32 BytesPerPixel = 4;
Buffer->Texture = SDL_CreateTexture(Renderer, SDL_PIXELFORMAT_ARGB8888, Buffer->Texture = SDL_CreateTexture(Renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING, SDL_TEXTUREACCESS_STREAMING,
@@ -179,7 +166,6 @@ static void SDLDisplayBufferInWindow(offscreen_buffer Buffer,
SDL_Window *Window, SDL_Window *Window,
SDL_Renderer *Renderer) SDL_Renderer *Renderer)
{ {
SDL_Rect dest_rect;
S32 OffsetX = 10; S32 OffsetX = 10;
S32 OffsetY = 10; S32 OffsetY = 10;
@@ -193,21 +179,17 @@ static void SDLDisplayBufferInWindow(offscreen_buffer Buffer,
/* TODO: We temporarily introduce the target rectangle to avoid /* TODO: We temporarily introduce the target rectangle to avoid
* stretching the canvas. */ * stretching the canvas. */
/* SDL_RenderCopy(Renderer, Buffer.Texture, 0, 0); */ /* SDL_RenderCopy(Renderer, Buffer.Texture, 0, 0); */
dest_rect.x = OffsetX; SDL_Rect dest_rect = { OffsetX, OffsetY,
dest_rect.y = OffsetY; RESOLUTION_WIDTH, RESOLUTION_HEIGHT };
dest_rect.w = RESOLUTION_WIDTH;
dest_rect.h = RESOLUTION_HEIGHT;
SDL_RenderCopy(Renderer, Buffer.Texture, 0, (const SDL_Rect *)(&dest_rect)); SDL_RenderCopy(Renderer, Buffer.Texture, 0, (const SDL_Rect *)(&dest_rect));
SDL_RenderPresent(Renderer); SDL_RenderPresent(Renderer);
} }
static void SDLInitControllers() static void SDLInitControllers()
{ {
S32 MaxJoysticks, ControllerIndex, JoystickIndex; S32 MaxJoysticks = SDL_NumJoysticks();
S32 ControllerIndex = 0;
MaxJoysticks = SDL_NumJoysticks(); for(S32 JoystickIndex = 0; JoystickIndex < MaxJoysticks; JoystickIndex++) {
ControllerIndex = 0;
for(JoystickIndex = 0; JoystickIndex < MaxJoysticks; JoystickIndex++) {
if(!SDL_IsGameController(JoystickIndex)) if(!SDL_IsGameController(JoystickIndex))
continue; continue;
if(ControllerIndex >= MAX_CONTROLLERS) if(ControllerIndex >= MAX_CONTROLLERS)
@@ -221,9 +203,7 @@ static void SDLInitControllers()
/* /*
static void SDLDeinitControllers() static void SDLDeinitControllers()
{ {
S32 ControllerIndex; for(S32 ControllerIndex = 0;
for(ControllerIndex = 0;
ControllerIndex < MAX_CONTROLLERS; ControllerIndex < MAX_CONTROLLERS;
ControllerIndex++) ControllerIndex++)
{ {
@@ -236,7 +216,6 @@ static void SDLDeinitControllers()
static void SDLInitSound(S32 SamplesPerSecond, S32 BufferSize) static void SDLInitSound(S32 SamplesPerSecond, S32 BufferSize)
{ {
SDL_AudioSpec AudioSettings; SDL_AudioSpec AudioSettings;
memset(&AudioSettings, 0, sizeof(AudioSettings)); memset(&AudioSettings, 0, sizeof(AudioSettings));
AudioSettings.freq = SamplesPerSecond; AudioSettings.freq = SamplesPerSecond;
@@ -283,12 +262,8 @@ static void SDLProcessInputDigitalButton(SDL_GameController *Controller,
static void HandleEvent(SDL_Event *Event) static void HandleEvent(SDL_Event *Event)
{ {
/* TODO: Should this be below scopes? */ SDL_Window *Window = SDL_GetWindowFromID(Event->window.windowID);
SDL_Window *Window; SDL_Renderer *Renderer = SDL_GetRenderer(Window);
SDL_Renderer *Renderer;
Window = SDL_GetWindowFromID(Event->window.windowID);
Renderer = SDL_GetRenderer(Window);
switch(Event->type) { switch(Event->type) {
case SDL_QUIT: { case SDL_QUIT: {
@@ -404,13 +379,11 @@ static void SDLProcessMessages(sdl_state *SDLState,
} }
if(WasDown) { if(WasDown) {
B32 AltKeyWasDown;
/* 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 * to see SDL_QUIT event occur before our
* keybind. */ * keybind. */
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)
GlobalRunning = FALSE; GlobalRunning = FALSE;
#if BUILD_INTERNAL #if BUILD_INTERNAL
@@ -429,9 +402,7 @@ static void SDLProcessMessages(sdl_state *SDLState,
static F32 SDLProcessInputStickValue(F32 Value, S32 DeadZoneThreshold) static F32 SDLProcessInputStickValue(F32 Value, S32 DeadZoneThreshold)
{ {
F32 Result; F32 Result = 0.0f;
Result = 0.0f;
if(Value < -(F32)DeadZoneThreshold) if(Value < -(F32)DeadZoneThreshold)
Result = ((Value + (F32)DeadZoneThreshold) / Result = ((Value + (F32)DeadZoneThreshold) /
(32768.0f - (F32)DeadZoneThreshold)); (32768.0f - (F32)DeadZoneThreshold));
@@ -445,11 +416,9 @@ static F32 SDLProcessInputStickValue(F32 Value, S32 DeadZoneThreshold)
#define DEFAULT_REFRESH_RATE 60 #define DEFAULT_REFRESH_RATE 60
static S32 SDLGetWindowRefreshRate(SDL_Window *Window) static S32 SDLGetWindowRefreshRate(SDL_Window *Window)
{ {
S32 DisplayIndex; S32 DisplayIndex = SDL_GetWindowDisplayIndex(Window);
SDL_DisplayMode Mode; SDL_DisplayMode Mode;
DisplayIndex = SDL_GetWindowDisplayIndex(Window);
if(SDL_GetDesktopDisplayMode(DisplayIndex, &Mode) != 0) if(SDL_GetDesktopDisplayMode(DisplayIndex, &Mode) != 0)
return DEFAULT_REFRESH_RATE; return DEFAULT_REFRESH_RATE;
if(Mode.refresh_rate == 0) if(Mode.refresh_rate == 0)
@@ -482,7 +451,6 @@ typedef struct sdl_game_code {
static U32 GetLastWriteTime(const char *FileName) static U32 GetLastWriteTime(const char *FileName)
{ {
struct stat file_info; struct stat file_info;
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"); */
@@ -561,11 +529,9 @@ void GetExecutablePath(char *path, size_t path_size)
static void SDLGetEXEDirPath(char *path, size_t path_size) static void SDLGetEXEDirPath(char *path, size_t path_size)
{ {
U32 len, i;
GetExecutablePath(path, path_size); GetExecutablePath(path, path_size);
len = str_len(path); U32 len = str_len(path);
i = len; U32 i = len;
while(path[i] != '/' || i == 0) { while(path[i] != '/' || i == 0) {
i--; i--;
} }
@@ -590,8 +556,6 @@ U64 __rdtsc()
* drawing into a bitmap. */ * drawing into a bitmap. */
void SDLSetProgramIcon(SDL_Window *Window) void SDLSetProgramIcon(SDL_Window *Window)
{ {
SDL_Surface *icon;
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;
@@ -606,12 +570,12 @@ 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
icon = SDL_CreateRGBSurfaceFrom( SDL_Surface * icon = SDL_CreateRGBSurfaceFrom(
(void *)program_icon.pixel_data, (void *)program_icon.pixel_data,
program_icon.width, program_icon.height, program_icon.width, program_icon.height,
program_icon.bytes_per_pixel * 8, program_icon.bytes_per_pixel * 8,
program_icon.bytes_per_pixel * program_icon.width, program_icon.bytes_per_pixel * program_icon.width,
Rmask, Gmask, Bmask, Amask); Rmask, Gmask, Bmask, Amask);
if(icon) { if(icon) {
SDL_SetWindowIcon(Window, icon); SDL_SetWindowIcon(Window, icon);
SDL_FreeSurface(icon); SDL_FreeSurface(icon);
@@ -623,8 +587,6 @@ void SDLSetProgramIcon(SDL_Window *Window)
S32 main(S32 argc, char *argv[]) S32 main(S32 argc, char *argv[])
{ {
sdl_state SDLState; sdl_state SDLState;
SDL_Window *Window;
memset(&SDLState, 0, sizeof(SDLState)); memset(&SDLState, 0, sizeof(SDLState));
SDLGetEXEDirPath(SDLState.EXEDirPath, sizeof(SDLState.EXEDirPath)); SDLGetEXEDirPath(SDLState.EXEDirPath, sizeof(SDLState.EXEDirPath));
@@ -642,20 +604,20 @@ S32 main(S32 argc, char *argv[])
/* NOTE: Floating windows are not supported oficially by Wayland /* NOTE: Floating windows are not supported oficially by Wayland
* 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, SDL_Window *Window = SDL_CreateWindow("Handmade Hero",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
RESOLUTION_WIDTH, RESOLUTION_HEIGHT, SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOW_RESIZABLE); RESOLUTION_WIDTH, RESOLUTION_HEIGHT,
SDL_WINDOW_RESIZABLE);
/*SDL_WINDOW_RESIZABLE | /*SDL_WINDOW_RESIZABLE |
SDL_WINDOW_ALWAYS_ON_TOP);*/ SDL_WINDOW_ALWAYS_ON_TOP);*/
if(Window) { if(Window) {
SDL_Renderer *Renderer;
SDL_DisplayMode display_mode; SDL_DisplayMode display_mode;
SDL_GetCurrentDisplayMode(0, &display_mode); SDL_GetCurrentDisplayMode(0, &display_mode);
Renderer = SDL_CreateRenderer(Window, -1, SDL_RENDERER_PRESENTVSYNC); SDL_Renderer *Renderer =
SDL_CreateRenderer(Window, -1, SDL_RENDERER_PRESENTVSYNC);
SDL_SetWindowPosition(Window, (display_mode.w - RESOLUTION_WIDTH), SDL_SetWindowPosition(Window, (display_mode.w - RESOLUTION_WIDTH),
(display_mode.h - RESOLUTION_HEIGHT)); (display_mode.h - RESOLUTION_HEIGHT));
@@ -666,11 +628,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_window_dimension Dimension;
sdl_sound_output SoundOutput;
game_memory GameMemory;
S32 ReplayIndex;
#if BUILD_DEBUG #if BUILD_DEBUG
void *BaseAddress = (void *)TB(2); void *BaseAddress = (void *)TB(2);
#else #else
@@ -686,10 +643,11 @@ S32 main(S32 argc, char *argv[])
GlobalRunning = TRUE; GlobalRunning = TRUE;
Dimension = SDLGetWindowDimension(Window); sdl_window_dimension Dimension = SDLGetWindowDimension(Window);
SDLResizeTexture(&GlobalBackbuffer, Renderer, Dimension.Width, SDLResizeTexture(&GlobalBackbuffer, Renderer, Dimension.Width,
Dimension.Height); Dimension.Height);
sdl_sound_output SoundOutput;
memset(&SoundOutput, 0, sizeof(SoundOutput)); memset(&SoundOutput, 0, sizeof(SoundOutput));
SoundOutput.SamplesPerSecond = 48000; SoundOutput.SamplesPerSecond = 48000;
SoundOutput.BytesPerSample = sizeof(S16) * 2; SoundOutput.BytesPerSample = sizeof(S16) * 2;
@@ -712,6 +670,7 @@ S32 main(S32 argc, char *argv[])
/* NOTE: calloc auto clears to zero */ /* NOTE: calloc auto clears to zero */
/* SDLClearSoundBuffer(&SoundOutput); */ /* SDLClearSoundBuffer(&SoundOutput); */
game_memory GameMemory;
memset(&GameMemory, 0, sizeof(GameMemory)); memset(&GameMemory, 0, sizeof(GameMemory));
GameMemory.PermanentStorageSize = MB(64); GameMemory.PermanentStorageSize = MB(64);
GameMemory.TransientStorageSize = GB(1); GameMemory.TransientStorageSize = GB(1);
@@ -735,65 +694,29 @@ S32 main(S32 argc, char *argv[])
(U8 *)(GameMemory.PermanentStorage) + (U8 *)(GameMemory.PermanentStorage) +
GameMemory.PermanentStorageSize; GameMemory.PermanentStorageSize;
for(ReplayIndex = 0;
ReplayIndex < (S32)ARRAY_SIZE(SDLState.ReplayBuffers);
ReplayIndex++)
{
sdl_replay_buffer *ReplayBuffer =
&SDLState.ReplayBuffers[ReplayIndex];
ReplayBuffer->MemoryBlock = mmap(NULL,
(size_t)SDLState.TotalSize,
PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE,
-1, 0);
if(ReplayBuffer->MemoryBlock) {
} else {
/* TODO: Change this to log message. */
}
}
if(SoundOutput.Samples && if(SoundOutput.Samples &&
GameMemory.PermanentStorage && GameMemory.PermanentStorage &&
GameMemory.TransientStorage) GameMemory.TransientStorage)
{ {
game_input Input[2]; game_input Input[2];
game_input *NewInput, *OldInput;
sdl_game_code Game;
F32 TargetSecondsPerFrame;
S32 MonitorRefreshHz, GameUpdateHz;
U64 LastCounter; U64 LastCounter;
U64 LastCycleCount; U64 LastCycleCount;
MonitorRefreshHz = SDLGetWindowRefreshRate(Window); S32 MonitorRefreshHz = SDLGetWindowRefreshRate(Window);
/*GameUpdateHz = MonitorRefreshHz;*/ /*GameUpdateHz = MonitorRefreshHz;*/
GameUpdateHz = 30; /* NOTE: Temporarily target 30 FPS. */ S32 GameUpdateHz = 30; /* NOTE: Temporarily target 30 FPS. */
TargetSecondsPerFrame = 1.0f / (F32)GameUpdateHz; F32 TargetSecondsPerFrame = 1.0f / (F32)GameUpdateHz;
NewInput = &Input[0]; game_input *NewInput = &Input[0];
OldInput = &Input[1]; game_input *OldInput = &Input[1];
memset(&Input, 0, sizeof(Input)); memset(&Input, 0, sizeof(Input));
GlobalPerfCountFrequency = SDL_GetPerformanceFrequency(); GlobalPerfCountFrequency = SDL_GetPerformanceFrequency();
Game = SDLLoadGameCode(SDLState.DLLPath); sdl_game_code Game = SDLLoadGameCode(SDLState.DLLPath);
while(GlobalRunning) { while(GlobalRunning) {
thread_context Context;
U32 NewDLLWriteTime, ButtonIndex, ControllerIndex,
SDLMouseButtons;
game_controller_input *OldKeyboardController,
*NewKeyboardController;
game_controller_input ZeroController;
S32 TargetQueueBytes, BytesToWrite;
game_sound_output_buffer SoundBuffer;
game_offscreen_buffer Buffer;
U64 WorkCounter, EndCounter;
F32 WorkSecondsElapsed, SecondsElapsedForFrame;
F64 MSPerFrame, FPS;
U64 EndCycleCount, CyclesElapsed;
F64 MCPF;
NewInput->dtForFrame = TargetSecondsPerFrame; NewInput->dtForFrame = TargetSecondsPerFrame;
LastCounter = SDLGetWallClock(); LastCounter = SDLGetWallClock();
@@ -805,14 +728,15 @@ S32 main(S32 argc, char *argv[])
* have not checked MacOS x64. */ * have not checked MacOS x64. */
LastCycleCount = __rdtsc(); LastCycleCount = __rdtsc();
NewDLLWriteTime = GetLastWriteTime(SDLState.DLLPath); U32 NewDLLWriteTime = GetLastWriteTime(SDLState.DLLPath);
if(NewDLLWriteTime > Game.DLLLastWriteTime) { if(NewDLLWriteTime > Game.DLLLastWriteTime) {
SDLUnloadGameCode(&Game); SDLUnloadGameCode(&Game);
Game = SDLLoadGameCode(SDLState.DLLPath); Game = SDLLoadGameCode(SDLState.DLLPath);
} }
SDLMouseButtons = SDL_GetMouseState(&(NewInput->MouseX), U32 SDLMouseButtons =
&(NewInput->MouseY)); SDL_GetMouseState(&(NewInput->MouseX),
&(NewInput->MouseY));
NewInput->MouseZ = 0; /* TODO: Support mouse wheel? */ NewInput->MouseZ = 0; /* TODO: Support mouse wheel? */
SDLProcessKeyboardMessage(&(NewInput->MouseButtons[0]), SDLProcessKeyboardMessage(&(NewInput->MouseButtons[0]),
SDL_BUTTON_LMASK & SDLMouseButtons); SDL_BUTTON_LMASK & SDLMouseButtons);
@@ -828,13 +752,16 @@ S32 main(S32 argc, char *argv[])
SDLProcessKeyboardMessage(&(NewInput->MouseButtons[4]), SDLProcessKeyboardMessage(&(NewInput->MouseButtons[4]),
SDL_BUTTON_X2MASK & SDLMouseButtons); SDL_BUTTON_X2MASK & SDLMouseButtons);
OldKeyboardController = GetController(OldInput, 0); game_controller_input *OldKeyboardController =
NewKeyboardController = GetController(NewInput, 0); GetController(OldInput, 0);
game_controller_input *NewKeyboardController =
GetController(NewInput, 0);
game_controller_input ZeroController;
memset(&ZeroController, 0, sizeof(ZeroController)); memset(&ZeroController, 0, sizeof(ZeroController));
*NewKeyboardController = ZeroController; *NewKeyboardController = ZeroController;
NewKeyboardController->IsConnected = TRUE; NewKeyboardController->IsConnected = TRUE;
for(ButtonIndex = 0; for(U32 ButtonIndex = 0;
ButtonIndex < ARRAY_SIZE( ButtonIndex < ARRAY_SIZE(
NewKeyboardController->u.Buttons); NewKeyboardController->u.Buttons);
ButtonIndex++) ButtonIndex++)
@@ -848,11 +775,12 @@ S32 main(S32 argc, char *argv[])
SDLProcessMessages(&SDLState, NewKeyboardController); SDLProcessMessages(&SDLState, NewKeyboardController);
for(ControllerIndex = 0; for(U32 ControllerIndex = 0;
ControllerIndex < MAX_CONTROLLERS; ControllerIndex < MAX_CONTROLLERS;
ControllerIndex++) ControllerIndex++)
{ {
game_controller_input *OldController, *NewController; game_controller_input *OldController,
*NewController;
OldController = OldController =
GetController(OldInput, ControllerIndex+1); GetController(OldInput, ControllerIndex+1);
@@ -863,18 +791,15 @@ S32 main(S32 argc, char *argv[])
SDL_GameControllerGetAttached( SDL_GameControllerGetAttached(
ControllerHandles[ControllerIndex])) ControllerHandles[ControllerIndex]))
{ {
S16 StickX, StickY;
float Threshold;
NewController->IsAnalog = NewController->IsAnalog =
OldController->IsAnalog; OldController->IsAnalog;
NewController->IsConnected = TRUE; NewController->IsConnected = TRUE;
StickX = S16 StickX =
SDL_GameControllerGetAxis( SDL_GameControllerGetAxis(
ControllerHandles[ControllerIndex], ControllerHandles[ControllerIndex],
SDL_CONTROLLER_AXIS_LEFTX); SDL_CONTROLLER_AXIS_LEFTX);
StickY = S16 StickY =
SDL_GameControllerGetAxis( SDL_GameControllerGetAxis(
ControllerHandles[ControllerIndex], ControllerHandles[ControllerIndex],
SDL_CONTROLLER_AXIS_LEFTY); SDL_CONTROLLER_AXIS_LEFTY);
@@ -925,7 +850,7 @@ S32 main(S32 argc, char *argv[])
NewController->IsAnalog = FALSE; NewController->IsAnalog = FALSE;
} }
Threshold = 0.5f; F32 Threshold = 0.5f;
SDLProcessInputDigitalButton( SDLProcessInputDigitalButton(
ControllerHandles[ ControllerHandles[
(NewController->StickAverageY < (NewController->StickAverageY <
@@ -1002,18 +927,21 @@ S32 main(S32 argc, char *argv[])
} }
} }
TargetQueueBytes = SoundOutput.LatencySampleCount * S32 TargetQueueBytes = SoundOutput.LatencySampleCount *
SoundOutput.BytesPerSample; SoundOutput.BytesPerSample;
BytesToWrite = S32 BytesToWrite =
TargetQueueBytes - SDL_GetQueuedAudioSize(1); TargetQueueBytes - SDL_GetQueuedAudioSize(1);
game_sound_output_buffer SoundBuffer;
SoundBuffer.SamplesPerSecond = SoundBuffer.SamplesPerSecond =
SoundOutput.SamplesPerSecond; SoundOutput.SamplesPerSecond;
SoundBuffer.SampleCount = SoundBuffer.SampleCount =
BytesToWrite / SoundOutput.BytesPerSample; BytesToWrite / SoundOutput.BytesPerSample;
SoundBuffer.Samples = (short *)SoundOutput.Samples; SoundBuffer.Samples = (short *)SoundOutput.Samples;
thread_context Context;
memset(&Context, 0, sizeof(Context)); memset(&Context, 0, sizeof(Context));
game_offscreen_buffer Buffer;
Buffer.Memory = GlobalBackbuffer.Memory; Buffer.Memory = GlobalBackbuffer.Memory;
Buffer.Width = GlobalBackbuffer.Width; Buffer.Width = GlobalBackbuffer.Width;
Buffer.Height = GlobalBackbuffer.Height; Buffer.Height = GlobalBackbuffer.Height;
@@ -1028,11 +956,11 @@ S32 main(S32 argc, char *argv[])
SDLFillSoundBuffer(&SoundOutput, BytesToWrite); SDLFillSoundBuffer(&SoundOutput, BytesToWrite);
WorkCounter = SDLGetWallClock(); U64 WorkCounter = SDLGetWallClock();
WorkSecondsElapsed = SDLGetSecondsElapsed(LastCounter, F32 WorkSecondsElapsed =
WorkCounter); SDLGetSecondsElapsed(LastCounter, WorkCounter);
SecondsElapsedForFrame = WorkSecondsElapsed; F32 SecondsElapsedForFrame = WorkSecondsElapsed;
if(SecondsElapsedForFrame < TargetSecondsPerFrame) { if(SecondsElapsedForFrame < TargetSecondsPerFrame) {
while(SecondsElapsedForFrame < TargetSecondsPerFrame) { while(SecondsElapsedForFrame < TargetSecondsPerFrame) {
SecondsElapsedForFrame = SecondsElapsedForFrame =
@@ -1046,21 +974,21 @@ S32 main(S32 argc, char *argv[])
/* TODO: Logging. */ /* TODO: Logging. */
} }
EndCounter = SDLGetWallClock(); U64 EndCounter = SDLGetWallClock();
SDLDisplayBufferInWindow(GlobalBackbuffer, Window, SDLDisplayBufferInWindow(GlobalBackbuffer, Window,
Renderer); Renderer);
MSPerFrame = 1000.0 * SDLGetSecondsElapsed(LastCounter, F64 MSPerFrame = 1000.0 *
EndCounter); SDLGetSecondsElapsed(LastCounter, EndCounter);
FPS = 0.0; F64 FPS = 0.0;
LastCounter = EndCounter; LastCounter = EndCounter;
#if 0 #if 0
EndCycleCount = __rdtsc(); U64 EndCycleCount = __rdtsc();
CyclesElapsed = EndCycleCount - LastCycleCount; U64 CyclesElapsed = EndCycleCount - LastCycleCount;
MCPF = ((double)CyclesElapsed / (1000.0 * 1000.0)); F64 MCPF = ((double)CyclesElapsed / (1000.0 * 1000.0));
fprintf(stderr, "%.02f ms/f, %.02f/s, %.02f mc/f\n", fprintf(stderr, "%.02f ms/f, %.02f/s, %.02f mc/f\n",
MSPerFrame, FPS, MCPF); MSPerFrame, FPS, MCPF);
LastCycleCount = EndCycleCount; LastCycleCount = EndCycleCount;
-13
View File
@@ -34,22 +34,9 @@ typedef struct sdl_sound_output {
* For example, linux/limits.h PATH_MAX says 4096. */ * For example, linux/limits.h PATH_MAX says 4096. */
#define SDL_STATE_PATH_SIZE 1024 #define SDL_STATE_PATH_SIZE 1024
typedef struct sdl_replay_buffer {
char ReplayFilename[SDL_STATE_PATH_SIZE];
void *MemoryBlock;
} sdl_replay_buffer;
typedef struct sdl_state { typedef struct sdl_state {
U64 TotalSize; U64 TotalSize;
void *GameMmemoryBlock; void *GameMmemoryBlock;
sdl_replay_buffer ReplayBuffers[4];
S32 RecordingHandle;
S32 InputRecordingIndex;
/* NOTE: These functions might be NULL. Check before calling them! */
S32 PlaybackHandle;
S32 InputPlayingIndex;
char EXEDirPath[SDL_STATE_PATH_SIZE]; char EXEDirPath[SDL_STATE_PATH_SIZE];
char DLLPath[SDL_STATE_PATH_SIZE]; char DLLPath[SDL_STATE_PATH_SIZE];