Day 34 complete.
This commit is contained in:
+121
-165
@@ -5,6 +5,9 @@
|
|||||||
#include "handmade_intrinsics.h"
|
#include "handmade_intrinsics.h"
|
||||||
#include <string.h> /* memset */
|
#include <string.h> /* memset */
|
||||||
|
|
||||||
|
#include "handmade_tile.h"
|
||||||
|
#include "handmade_tile.cpp"
|
||||||
|
|
||||||
static void GameOutputSound(game_state *GameState,
|
static void GameOutputSound(game_state *GameState,
|
||||||
game_sound_output_buffer *SoundBuffer,
|
game_sound_output_buffer *SoundBuffer,
|
||||||
S32 ToneHz)
|
S32 ToneHz)
|
||||||
@@ -94,111 +97,26 @@ static void DrawRectangle(game_offscreen_buffer *Buffer,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static tile_chunk *GetTileChunk(world *World,
|
static void InitializeArena(memory_arena *Arena, U64 Size, U8 *Base)
|
||||||
S32 TileChunkX, S32 TileChunkY)
|
|
||||||
{
|
{
|
||||||
tile_chunk *TileChunk = NULL;
|
Arena->Size = Size;
|
||||||
|
Arena->Base = Base;
|
||||||
if((TileChunkX >= 0) && (TileChunkX < World->TileChunkCountX) &&
|
Arena->Used = 0;
|
||||||
(TileChunkY >= 0) && (TileChunkY < World->TileChunkCountY))
|
|
||||||
{
|
|
||||||
TileChunk = &World->TileChunks[TileChunkY *
|
|
||||||
World->TileChunkCountX +
|
|
||||||
TileChunkX];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return TileChunk;
|
#define PUSH_STRUCT(Arena, type) (type *)PushSize_(Arena, sizeof(type))
|
||||||
}
|
#define PUSH_ARRAY(Arena, Count, type) (type *)PushSize_(Arena, (Count)*sizeof(type))
|
||||||
|
static void *PushSize_(memory_arena *Arena, U64 Size)
|
||||||
static U32 GetTileValueUnchecked(world *World, tile_chunk *TileChunk,
|
|
||||||
U32 TileX, U32 TileY)
|
|
||||||
{
|
{
|
||||||
U32 TileChunkValue;
|
void *Result;
|
||||||
|
|
||||||
ASSERT(TileChunk);
|
ASSERT((Arena->Used + Size) <= Arena->Size);
|
||||||
ASSERT(TileX < World->ChunkDim);
|
|
||||||
ASSERT(TileY < World->ChunkDim);
|
|
||||||
|
|
||||||
TileChunkValue = TileChunk->Tiles[TileY * World->ChunkDim + TileX];
|
|
||||||
return TileChunkValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
static U32 GetTileChunkValue(world *World, tile_chunk *TileChunk,
|
|
||||||
U32 TestTileX, U32 TestTileY)
|
|
||||||
{
|
|
||||||
U32 TileChunkValue = 0;
|
|
||||||
|
|
||||||
if(TileChunk) {
|
|
||||||
TileChunkValue = GetTileValueUnchecked(World,
|
|
||||||
TileChunk,
|
|
||||||
TestTileX, TestTileY);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TileChunkValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void CannonicalizeCoord(world *World, 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 = FloorF32toS32(*TileRel / World->TileSideInMeters);
|
|
||||||
*Tile += Offset;
|
|
||||||
*TileRel -= (F32)Offset * World->TileSideInMeters;
|
|
||||||
|
|
||||||
ASSERT(*TileRel >= 0);
|
|
||||||
ASSERT(*TileRel < World->TileSideInMeters);
|
|
||||||
}
|
|
||||||
|
|
||||||
static cannonical_position RecannonicalizePosition(world *World,
|
|
||||||
cannonical_position Pos)
|
|
||||||
{
|
|
||||||
cannonical_position Result = Pos;
|
|
||||||
|
|
||||||
CannonicalizeCoord(World, &Result.AbsTileX, &Result.TileRelX);
|
|
||||||
CannonicalizeCoord(World, &Result.AbsTileY, &Result.TileRelY);
|
|
||||||
|
|
||||||
|
Result = (void *)(Arena->Base + Arena->Used);
|
||||||
|
Arena->Used += Size;
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static tile_chunk_position GetChunkPositionFor(world *World,
|
|
||||||
U32 AbsTileX, U32 AbsTileY)
|
|
||||||
{
|
|
||||||
tile_chunk_position Result;
|
|
||||||
|
|
||||||
Result.TileChunkX = AbsTileX >> World->ChunkShift;
|
|
||||||
Result.TileChunkY = AbsTileY >> World->ChunkShift;
|
|
||||||
Result.RelTileX = AbsTileX & World->ChunkMask;
|
|
||||||
Result.RelTileY = AbsTileY & World->ChunkMask;
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static U32 GetTileValue(world *World, U32 AbsTileX, U32 AbsTileY)
|
|
||||||
{
|
|
||||||
tile_chunk_position ChunkPos = GetChunkPositionFor(World,
|
|
||||||
AbsTileX,
|
|
||||||
AbsTileY);
|
|
||||||
tile_chunk *TileMap = GetTileChunk(World,
|
|
||||||
ChunkPos.TileChunkX,
|
|
||||||
ChunkPos.TileChunkY);
|
|
||||||
U32 TileChunkValue = GetTileChunkValue(World, TileMap,
|
|
||||||
ChunkPos.RelTileX,
|
|
||||||
ChunkPos.RelTileY);
|
|
||||||
return TileChunkValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
static B32 IsWorldPointEmpty(world *World, cannonical_position CanPos)
|
|
||||||
{
|
|
||||||
B32 Empty;
|
|
||||||
|
|
||||||
U32 TileChunkValue = GetTileValue(World,
|
|
||||||
CanPos.AbsTileX,
|
|
||||||
CanPos.AbsTileY);
|
|
||||||
Empty = (TileChunkValue == 0);
|
|
||||||
|
|
||||||
return Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateAndRender(thread_context *Thread, game_memory *Memory,
|
void UpdateAndRender(thread_context *Thread, game_memory *Memory,
|
||||||
game_input *Input, game_offscreen_buffer *Buffer,
|
game_input *Input, game_offscreen_buffer *Buffer,
|
||||||
game_sound_output_buffer *SoundBuffer)
|
game_sound_output_buffer *SoundBuffer)
|
||||||
@@ -209,73 +127,98 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
|
|||||||
game_state *GameState;
|
game_state *GameState;
|
||||||
U32 ControllerIndex;
|
U32 ControllerIndex;
|
||||||
|
|
||||||
U32 TempTiles[TILEMAP_COUNT_Y][TILEMAP_COUNT_X] = {
|
|
||||||
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
|
||||||
{1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
|
||||||
{1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
|
||||||
{1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
|
||||||
{1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
|
||||||
{1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
|
||||||
{1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
|
||||||
{1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
|
||||||
{1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1},
|
|
||||||
{1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1},
|
|
||||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
|
||||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
|
||||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
|
||||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
|
||||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
|
||||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
|
||||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
|
||||||
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
|
||||||
};
|
|
||||||
|
|
||||||
F32 PlayerR, PlayerG, PlayerB,
|
F32 PlayerR, PlayerG, PlayerB,
|
||||||
PlayerWidth, PlayerHeight,
|
PlayerWidth, PlayerHeight,
|
||||||
PlayerLeft, PlayerTop;
|
PlayerLeft, PlayerTop;
|
||||||
F32 CenterX, CenterY;
|
F32 ScreenCenterX, ScreenCenterY;
|
||||||
|
|
||||||
tile_chunk TileChunk;
|
world *World;
|
||||||
world World;
|
tile_map *TileMap;
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
memset(&World, 0, sizeof(World));
|
|
||||||
/* NOTE: This is set to using 256x256 tile chunks. */
|
|
||||||
World.ChunkShift = 8;
|
|
||||||
World.ChunkMask = 0xFF;
|
|
||||||
World.ChunkDim = 256;
|
|
||||||
|
|
||||||
World.TileChunkCountX = 1;
|
|
||||||
World.TileChunkCountY = 1;
|
|
||||||
|
|
||||||
TileChunk.Tiles = (U32 *)TempTiles;
|
|
||||||
World.TileChunks = &TileChunk;
|
|
||||||
|
|
||||||
World.TileSideInMeters = 1.4f;
|
|
||||||
World.TileSideInPixels = 60;
|
|
||||||
World.MetersToPixels =
|
|
||||||
(F32)World.TileSideInPixels / World.TileSideInMeters;
|
|
||||||
|
|
||||||
PlayerHeight = 1.4f;
|
PlayerHeight = 1.4f;
|
||||||
PlayerWidth = 0.75f * PlayerHeight;
|
PlayerWidth = 0.75f * PlayerHeight;
|
||||||
|
|
||||||
CenterX = 0.5f * (F32)Buffer->Width;
|
|
||||||
CenterY = 0.5f * (F32)Buffer->Height;
|
|
||||||
|
|
||||||
GameState = (game_state *)Memory->PermanentStorage;
|
GameState = (game_state *)Memory->PermanentStorage;
|
||||||
if(!Memory->IsInitialized) {
|
if(!Memory->IsInitialized) {
|
||||||
GameState->PlayerP.AbsTileX = 3;
|
U32 TilesPerWidth, TilesPerHeight;
|
||||||
|
U32 ScreenX, ScreenY;
|
||||||
|
tile_map *TileMap;
|
||||||
|
world *World;
|
||||||
|
|
||||||
|
GameState->PlayerP.AbsTileX = 2;
|
||||||
GameState->PlayerP.AbsTileY = 3;
|
GameState->PlayerP.AbsTileY = 3;
|
||||||
GameState->PlayerP.TileRelX = 5.0f;
|
GameState->PlayerP.TileRelX = 5.0f;
|
||||||
GameState->PlayerP.TileRelY = 5.0f;
|
GameState->PlayerP.TileRelY = 5.0f;
|
||||||
|
|
||||||
|
InitializeArena(&GameState->WorldArena,
|
||||||
|
Memory->PermanentStorageSize - sizeof(game_state),
|
||||||
|
(U8 *)Memory->PermanentStorage + sizeof(game_state));
|
||||||
|
|
||||||
|
GameState->World = PUSH_STRUCT(&GameState->WorldArena, world);
|
||||||
|
World = GameState->World;
|
||||||
|
World->TileMap = PUSH_STRUCT(&GameState->WorldArena, tile_map);
|
||||||
|
|
||||||
|
TileMap = World->TileMap;
|
||||||
|
|
||||||
|
TileMap->ChunkShift = 8;
|
||||||
|
TileMap->ChunkMask = (1 << TileMap->ChunkShift) - 1;
|
||||||
|
TileMap->ChunkDim = 256;
|
||||||
|
|
||||||
|
TileMap->TileChunkCountX = 4;
|
||||||
|
TileMap->TileChunkCountY = 4;
|
||||||
|
|
||||||
|
TileMap->TileChunks =
|
||||||
|
PUSH_ARRAY(&GameState->WorldArena,
|
||||||
|
TileMap->TileChunkCountX*TileMap->TileChunkCountX,
|
||||||
|
tile_chunk);
|
||||||
|
|
||||||
|
{
|
||||||
|
U32 X, Y;
|
||||||
|
for(Y = 0; Y < TileMap->TileChunkCountY; Y++) {
|
||||||
|
for(X = 0; X < TileMap->TileChunkCountX; X++) {
|
||||||
|
TileMap->TileChunks[Y*TileMap->TileChunkCountX + X].Tiles =
|
||||||
|
PUSH_ARRAY(&GameState->WorldArena,
|
||||||
|
TileMap->ChunkDim*TileMap->ChunkDim,
|
||||||
|
U32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TileMap->TileSideInMeters = 1.4f;
|
||||||
|
TileMap->TileSideInPixels = 60;
|
||||||
|
TileMap->MetersToPixels =
|
||||||
|
(F32)TileMap->TileSideInPixels / TileMap->TileSideInMeters;
|
||||||
|
|
||||||
|
TilesPerWidth = 17;
|
||||||
|
TilesPerHeight = 9;
|
||||||
|
for(ScreenY = 0; ScreenY < 32; ScreenY++) {
|
||||||
|
for(ScreenX = 0; ScreenX < 32; ScreenX++) {
|
||||||
|
U32 TileX, TileY;
|
||||||
|
for(TileY = 0; TileY < TilesPerWidth; TileY++) {
|
||||||
|
for(TileX = 0; TileX < TilesPerWidth; TileX++) {
|
||||||
|
U32 AbsTileX = ScreenX * TilesPerWidth + TileX;
|
||||||
|
U32 AbsTileY = ScreenY * TilesPerHeight + TileY;
|
||||||
|
|
||||||
|
SetTileValue(&GameState->WorldArena,
|
||||||
|
World->TileMap,
|
||||||
|
AbsTileX, AbsTileY,
|
||||||
|
(TileX == TileY) && (TileY % 2) ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Memory->IsInitialized = TRUE;
|
Memory->IsInitialized = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
World = GameState->World;
|
||||||
|
TileMap = World->TileMap;
|
||||||
|
|
||||||
for(ControllerIndex = 0;
|
for(ControllerIndex = 0;
|
||||||
ControllerIndex < ARRAY_SIZE(Input->Controllers);
|
ControllerIndex < ARRAY_SIZE(Input->Controllers);
|
||||||
ControllerIndex++)
|
ControllerIndex++)
|
||||||
@@ -287,7 +230,7 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
|
|||||||
F32 dPlayerX = 0.0f;
|
F32 dPlayerX = 0.0f;
|
||||||
F32 dPlayerY = 0.0f;
|
F32 dPlayerY = 0.0f;
|
||||||
|
|
||||||
cannonical_position NewPlayerP, PlayerLeft, PlayerRight;
|
tile_map_position NewPlayerP, PlayerLeft, PlayerRight;
|
||||||
|
|
||||||
if(Controller->u.buttons.MoveUp.EndedDown) {
|
if(Controller->u.buttons.MoveUp.EndedDown) {
|
||||||
dPlayerY = 1.0f;
|
dPlayerY = 1.0f;
|
||||||
@@ -302,31 +245,41 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
|
|||||||
dPlayerX = 1.0f;
|
dPlayerX = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
dPlayerX *= 5.0f;
|
{
|
||||||
dPlayerY *= 5.0f;
|
F32 PlayerSpeed = 2.0f;
|
||||||
|
|
||||||
|
if(Controller->u.buttons.ActionUp.EndedDown)
|
||||||
|
PlayerSpeed = 10.0f;
|
||||||
|
|
||||||
|
dPlayerX *= PlayerSpeed;
|
||||||
|
dPlayerY *= PlayerSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
NewPlayerP = GameState->PlayerP;
|
NewPlayerP = GameState->PlayerP;
|
||||||
NewPlayerP.TileRelX += Input->dtForFrame*dPlayerX;
|
NewPlayerP.TileRelX += Input->dtForFrame*dPlayerX;
|
||||||
NewPlayerP.TileRelY += Input->dtForFrame*dPlayerY;
|
NewPlayerP.TileRelY += Input->dtForFrame*dPlayerY;
|
||||||
NewPlayerP = RecannonicalizePosition(&World, NewPlayerP);
|
NewPlayerP = RecannonicalizePosition(TileMap, NewPlayerP);
|
||||||
|
|
||||||
PlayerLeft = NewPlayerP;
|
PlayerLeft = NewPlayerP;
|
||||||
PlayerLeft.TileRelX -= 0.5f*PlayerWidth;
|
PlayerLeft.TileRelX -= 0.5f*PlayerWidth;
|
||||||
PlayerLeft = RecannonicalizePosition(&World, PlayerLeft);
|
PlayerLeft = RecannonicalizePosition(TileMap, PlayerLeft);
|
||||||
|
|
||||||
PlayerRight = NewPlayerP;
|
PlayerRight = NewPlayerP;
|
||||||
PlayerRight.TileRelX += 0.5f*PlayerWidth;
|
PlayerRight.TileRelX += 0.5f*PlayerWidth;
|
||||||
PlayerRight = RecannonicalizePosition(&World, PlayerRight);
|
PlayerRight = RecannonicalizePosition(TileMap, PlayerRight);
|
||||||
|
|
||||||
if(IsWorldPointEmpty(&World, NewPlayerP) &&
|
if(IsTileMapPointEmpty(TileMap, NewPlayerP) &&
|
||||||
IsWorldPointEmpty(&World, PlayerLeft) &&
|
IsTileMapPointEmpty(TileMap, PlayerLeft) &&
|
||||||
IsWorldPointEmpty(&World, PlayerRight))
|
IsTileMapPointEmpty(TileMap, PlayerRight))
|
||||||
{
|
{
|
||||||
GameState->PlayerP = NewPlayerP;
|
GameState->PlayerP = NewPlayerP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScreenCenterX = 0.5f * (F32)Buffer->Width;
|
||||||
|
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);
|
||||||
@@ -337,7 +290,7 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
|
|||||||
U32 Column = GameState->PlayerP.AbsTileX + RelColumn;
|
U32 Column = GameState->PlayerP.AbsTileX + RelColumn;
|
||||||
U32 Row = GameState->PlayerP.AbsTileY + RelRow;
|
U32 Row = GameState->PlayerP.AbsTileY + RelRow;
|
||||||
|
|
||||||
U32 TileID = GetTileValue(&World, Column, Row);
|
U32 TileID = GetTileValue(TileMap, Column, Row);
|
||||||
F32 Gray = 0.5f;
|
F32 Gray = 0.5f;
|
||||||
|
|
||||||
if(TileID) {
|
if(TileID) {
|
||||||
@@ -351,15 +304,20 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
F32 MinX, MinY, MaxX, MaxY;
|
F32 CenterX, CenterY, MinX, MinY, MaxX, MaxY;
|
||||||
MinX = CenterX +
|
|
||||||
(F32)RelColumn * (F32)World.TileSideInPixels;
|
CenterX = ScreenCenterX -
|
||||||
MinY = CenterY -
|
TileMap->MetersToPixels*GameState->PlayerP.TileRelX +
|
||||||
(F32)RelRow * (F32)World.TileSideInPixels;
|
(F32)RelColumn * (F32)TileMap->TileSideInPixels;
|
||||||
MaxX = MinX + (F32)World.TileSideInPixels;
|
CenterY = ScreenCenterY +
|
||||||
MaxY = MinY - (F32)World.TileSideInPixels;
|
TileMap->MetersToPixels*GameState->PlayerP.TileRelY -
|
||||||
|
(F32)RelRow * (F32)TileMap->TileSideInPixels;
|
||||||
|
MinX = CenterX - 0.5f*(F32)TileMap->TileSideInPixels;
|
||||||
|
MinY = CenterY - 0.5f*(F32)TileMap->TileSideInPixels;
|
||||||
|
MaxX = CenterX + 0.5f*(F32)TileMap->TileSideInPixels;
|
||||||
|
MaxY = CenterY + 0.5f*(F32)TileMap->TileSideInPixels;
|
||||||
DrawRectangle(Buffer,
|
DrawRectangle(Buffer,
|
||||||
MinX, MaxY, MaxX, MinY,
|
MinX, MinY, MaxX, MaxY,
|
||||||
Gray, Gray, Gray);
|
Gray, Gray, Gray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -369,14 +327,12 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
|
|||||||
PlayerR = 1.0f;
|
PlayerR = 1.0f;
|
||||||
PlayerG = 0.0f;
|
PlayerG = 0.0f;
|
||||||
PlayerB = 0.0f;
|
PlayerB = 0.0f;
|
||||||
PlayerLeft = CenterX + World.MetersToPixels*GameState->PlayerP.TileRelX -
|
PlayerLeft = ScreenCenterX - 0.5f* TileMap->MetersToPixels*PlayerWidth;
|
||||||
0.5f*World.MetersToPixels*PlayerWidth;
|
PlayerTop = ScreenCenterY - TileMap->MetersToPixels*PlayerHeight;
|
||||||
PlayerTop = CenterY - World.MetersToPixels*GameState->PlayerP.TileRelY -
|
|
||||||
World.MetersToPixels*PlayerHeight;
|
|
||||||
DrawRectangle(Buffer,
|
DrawRectangle(Buffer,
|
||||||
PlayerLeft, PlayerTop,
|
PlayerLeft, PlayerTop,
|
||||||
PlayerLeft + World.MetersToPixels*PlayerWidth,
|
PlayerLeft + TileMap->MetersToPixels*PlayerWidth,
|
||||||
PlayerTop + World.MetersToPixels*PlayerHeight,
|
PlayerTop + TileMap->MetersToPixels*PlayerHeight,
|
||||||
PlayerR, PlayerG, PlayerB);
|
PlayerR, PlayerG, PlayerB);
|
||||||
|
|
||||||
GameOutputSound(GameState, SoundBuffer, 400);
|
GameOutputSound(GameState, SoundBuffer, 400);
|
||||||
|
|||||||
+10
-33
@@ -2,6 +2,7 @@
|
|||||||
#define HANDMADE_H_SENTRY
|
#define HANDMADE_H_SENTRY
|
||||||
|
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
|
#include "handmade_tile.h"
|
||||||
|
|
||||||
/* --------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------- */
|
||||||
/* NOTE: Servcies that the platform layer provides to the game. */
|
/* NOTE: Servcies that the platform layer provides to the game. */
|
||||||
@@ -136,44 +137,20 @@ void UpdateAndRender(thread_context *Thread, game_memory *Memory,
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct tile_chunk_position {
|
typedef struct memory_arena {
|
||||||
U32 TileChunkX;
|
U64 Size;
|
||||||
U32 TileChunkY;
|
U8 *Base;
|
||||||
|
U64 Used;
|
||||||
U32 RelTileX;
|
} memory_arena;
|
||||||
U32 RelTileY;
|
|
||||||
} tile_chunk_position;
|
|
||||||
|
|
||||||
typedef struct cannonical_position {
|
|
||||||
U32 AbsTileX;
|
|
||||||
U32 AbsTileY;
|
|
||||||
|
|
||||||
/* NOTE: Tile-relative X and Y. */
|
|
||||||
F32 TileRelX;
|
|
||||||
F32 TileRelY;
|
|
||||||
} cannonical_position;
|
|
||||||
|
|
||||||
typedef struct tile_chunk {
|
|
||||||
U32 *Tiles;
|
|
||||||
} tile_chunk;
|
|
||||||
|
|
||||||
typedef struct world {
|
typedef struct world {
|
||||||
U32 ChunkShift;
|
tile_map *TileMap;
|
||||||
U32 ChunkMask;
|
|
||||||
U32 ChunkDim;
|
|
||||||
|
|
||||||
F32 TileSideInMeters;
|
|
||||||
S32 TileSideInPixels;
|
|
||||||
F32 MetersToPixels;
|
|
||||||
|
|
||||||
S32 TileChunkCountX;
|
|
||||||
S32 TileChunkCountY;
|
|
||||||
|
|
||||||
tile_chunk *TileChunks;
|
|
||||||
} world;
|
} world;
|
||||||
|
|
||||||
typedef struct game_state {
|
typedef struct game_state {
|
||||||
cannonical_position PlayerP;
|
memory_arena WorldArena;
|
||||||
|
world *World;
|
||||||
|
tile_map_position PlayerP;
|
||||||
} game_state;
|
} game_state;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
S32 RoundF32toS32(F32 Real32)
|
S32 RoundF32toS32(F32 Real32)
|
||||||
{
|
{
|
||||||
S32 Result = (S32)(Real32 + 0.5f);
|
S32 Result = (S32)roundf(Real32);
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
#include "handmade_tile.h"
|
||||||
|
|
||||||
|
static tile_chunk *GetTileChunk(tile_map *TileMap,
|
||||||
|
U32 TileChunkX, U32 TileChunkY)
|
||||||
|
{
|
||||||
|
tile_chunk *TileChunk = NULL;
|
||||||
|
|
||||||
|
if((TileChunkX >= 0) && (TileChunkX < TileMap->TileChunkCountX) &&
|
||||||
|
(TileChunkY >= 0) && (TileChunkY < TileMap->TileChunkCountY))
|
||||||
|
{
|
||||||
|
TileChunk = &TileMap->TileChunks[TileChunkY *
|
||||||
|
TileMap->TileChunkCountX +
|
||||||
|
TileChunkX];
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
U32 AbsTileX, U32 AbsTileY)
|
||||||
|
{
|
||||||
|
tile_chunk_position Result;
|
||||||
|
|
||||||
|
Result.TileChunkX = AbsTileX >> TileMap->ChunkShift;
|
||||||
|
Result.TileChunkY = AbsTileY >> TileMap->ChunkShift;
|
||||||
|
Result.RelTileX = AbsTileX & TileMap->ChunkMask;
|
||||||
|
Result.RelTileY = AbsTileY & TileMap->ChunkMask;
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static U32 GetTileValueUnchecked(tile_map *TileMap, tile_chunk *TileChunk,
|
||||||
|
U32 TileX, U32 TileY)
|
||||||
|
{
|
||||||
|
U32 TileChunkValue;
|
||||||
|
|
||||||
|
ASSERT(TileChunk);
|
||||||
|
ASSERT(TileX < TileMap->ChunkDim);
|
||||||
|
ASSERT(TileY < TileMap->ChunkDim);
|
||||||
|
|
||||||
|
TileChunkValue = TileChunk->Tiles[TileY * TileMap->ChunkDim + TileX];
|
||||||
|
return TileChunkValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static U32 GetTileChunkValue(tile_map *TileMap, tile_chunk *TileChunk,
|
||||||
|
U32 TestTileX, U32 TestTileY)
|
||||||
|
{
|
||||||
|
U32 TileChunkValue = 0;
|
||||||
|
|
||||||
|
if(TileChunk) {
|
||||||
|
TileChunkValue = GetTileValueUnchecked(TileMap,
|
||||||
|
TileChunk,
|
||||||
|
TestTileX, TestTileY);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
SetTileValueUnchecked(TileMap,
|
||||||
|
TileChunk,
|
||||||
|
TestTileX, TestTileY,
|
||||||
|
TileValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static U32 GetTileValue(tile_map *TileMap, U32 AbsTileX, U32 AbsTileY)
|
||||||
|
{
|
||||||
|
tile_chunk_position ChunkPos = GetChunkPositionFor(TileMap,
|
||||||
|
AbsTileX,
|
||||||
|
AbsTileY);
|
||||||
|
tile_chunk *TileChunk = GetTileChunk(TileMap,
|
||||||
|
ChunkPos.TileChunkX,
|
||||||
|
ChunkPos.TileChunkY);
|
||||||
|
U32 TileChunkValue = GetTileChunkValue(TileMap, TileChunk,
|
||||||
|
ChunkPos.RelTileX,
|
||||||
|
ChunkPos.RelTileY);
|
||||||
|
return TileChunkValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static B32 IsTileMapPointEmpty(tile_map *TileMap, tile_map_position CanPos)
|
||||||
|
{
|
||||||
|
B32 Empty;
|
||||||
|
|
||||||
|
U32 TileChunkValue = GetTileValue(TileMap,
|
||||||
|
CanPos.AbsTileX,
|
||||||
|
CanPos.AbsTileY);
|
||||||
|
Empty = (TileChunkValue == 0);
|
||||||
|
return Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetTileValue(memory_arena *Arena,
|
||||||
|
tile_map *TileMap,
|
||||||
|
U32 AbsTileX, U32 AbsTileY,
|
||||||
|
U32 TileValue)
|
||||||
|
{
|
||||||
|
tile_chunk_position ChunkPos;
|
||||||
|
tile_chunk *TileChunk;
|
||||||
|
|
||||||
|
ChunkPos = GetChunkPositionFor(TileMap, AbsTileX, AbsTileY);
|
||||||
|
TileChunk = GetTileChunk(TileMap,
|
||||||
|
ChunkPos.TileChunkX,
|
||||||
|
ChunkPos.TileChunkY);
|
||||||
|
ASSERT(TileChunk); /* TODO: On-deman tile chunk creation. */
|
||||||
|
|
||||||
|
SetTileChunkValue(TileMap, TileChunk,
|
||||||
|
ChunkPos.RelTileX,
|
||||||
|
ChunkPos.RelTileY,
|
||||||
|
TileValue);
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#ifndef HANDMADE_TILE_H_SENTRY
|
||||||
|
#define HANDMADE_TILE_H_SENTRY
|
||||||
|
|
||||||
|
typedef struct tile_map_position {
|
||||||
|
U32 AbsTileX;
|
||||||
|
U32 AbsTileY;
|
||||||
|
|
||||||
|
/* NOTE: Tile-relative X and Y. */
|
||||||
|
F32 TileRelX;
|
||||||
|
F32 TileRelY;
|
||||||
|
} tile_map_position;
|
||||||
|
|
||||||
|
typedef struct tile_chunk_position {
|
||||||
|
U32 TileChunkX;
|
||||||
|
U32 TileChunkY;
|
||||||
|
|
||||||
|
U32 RelTileX;
|
||||||
|
U32 RelTileY;
|
||||||
|
} tile_chunk_position;
|
||||||
|
|
||||||
|
typedef struct tile_chunk {
|
||||||
|
U32 *Tiles;
|
||||||
|
} tile_chunk;
|
||||||
|
|
||||||
|
typedef struct tile_map {
|
||||||
|
U32 ChunkShift;
|
||||||
|
U32 ChunkMask;
|
||||||
|
U32 ChunkDim;
|
||||||
|
|
||||||
|
F32 TileSideInMeters;
|
||||||
|
S32 TileSideInPixels;
|
||||||
|
F32 MetersToPixels;
|
||||||
|
|
||||||
|
U32 TileChunkCountX;
|
||||||
|
U32 TileChunkCountY;
|
||||||
|
|
||||||
|
tile_chunk *TileChunks;
|
||||||
|
} tile_map;
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user