Files
handmadehero/handmade.c
T
2026-04-15 11:58:51 -07:00

370 lines
11 KiB
C

#include "core.h"
#include "handmade.h"
#include "sdl_handmade.h"
#include "handmade_intrinsics.h"
#include <string.h> /* memset */
#include "handmade_tile.h"
#include "handmade_tile.cpp"
static void GameOutputSound(game_state *GameState,
game_sound_output_buffer *SoundBuffer,
S32 ToneHz)
{
/*
S16 ToneVolume, *SampleOut;
S32 WavePeriod, SampleIndex;
ToneVolume = 0;
WavePeriod = SoundBuffer->SamplesPerSecond / ToneHz;
SampleOut = SoundBuffer->Samples;
for(SampleIndex = 0;
SampleIndex < SoundBuffer->SampleCount;
SampleIndex++)
{
F32 SineValue;
S16 SampleValue;
SineValue = sinf(GameState->tSine);
SampleValue = (S16)(SineValue * ToneVolume);
*SampleOut++ = SampleValue;
*SampleOut++ = SampleValue;
GameState->tSine += 2.0f * (F32)PI * 1.0f / (F32)WavePeriod;
if(GameState->tSine > 2.0f*(F32)PI) {
GameState->tSine -= 2.0f*(F32)PI;
}
}
*/
}
static void ClearBackground(game_offscreen_buffer *Buffer)
{
S32 Width, Height, X;
Width = Buffer->Width;
Height = Buffer->Height;
for(X = 0; X < Width * Height; X++) {
U32 *Pixel = &((U32 *)Buffer->Memory)[X];
*Pixel = 0xFFFFFF;
}
}
static void DrawRectangle(game_offscreen_buffer *Buffer,
F32 RealMinX, F32 RealMinY,
F32 RealMaxX, F32 RealMaxY,
F32 R, F32 G, F32 B)
{
S32 MinX = RoundF32toS32(RealMinX);
S32 MinY = RoundF32toS32(RealMinY);
S32 MaxX = RoundF32toS32(RealMaxX);
S32 MaxY = RoundF32toS32(RealMaxY);
S32 Width = Buffer->Width;
S32 Height = Buffer->Height;
U8 *Row;
S32 Y, X;
U32 Color;
if(MinX < 0)
MinX = 0;
if(MinY < 0)
MinY = 0;
if(MaxX > Width)
MaxX = Width;
if(MaxY > Height)
MaxY = Height;
Color = (U32)((RoundF32toS32(R * 255.0f) << 16) |
(RoundF32toS32(G * 255.0f) << 8) |
(RoundF32toS32(B * 255.0f) << 0));
Row = ((U8 *)Buffer->Memory + MinX*Buffer->BytesPerPixel +
MinY*Buffer->Pitch);
for(Y = MinY; Y < MaxY; Y++) {
U32 *Pixel = (U32 *)Row;
for(X = MinX; X < MaxX; X++) {
*(U32 *)Pixel = Color;
Pixel++;
}
Row += Buffer->Pitch;
}
}
static void InitializeArena(memory_arena *Arena, U64 Size, U8 *Base)
{
Arena->Size = Size;
Arena->Base = Base;
Arena->Used = 0;
}
#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)
{
void *Result;
ASSERT((Arena->Used + Size) <= Arena->Size);
Result = (void *)(Arena->Base + Arena->Used);
Arena->Used += Size;
return Result;
}
void UpdateAndRender(thread_context *Thread, game_memory *Memory,
game_input *Input, game_offscreen_buffer *Buffer,
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;
ASSERT((&Input->Controllers[0].u.buttons.Terminator -
&Input->Controllers[0].u.Buttons[0]) ==
ARRAY_SIZE(Input->Controllers[0].u.Buttons));
ASSERT(sizeof(game_state) <= Memory->PermanentStorageSize);
PlayerHeight = 1.4f;
PlayerWidth = 0.75f * PlayerHeight;
GameState = (game_state *)Memory->PermanentStorage;
if(!Memory->IsInitialized) {
U32 TilesPerWidth, TilesPerHeight;
U32 ScreenX, ScreenY;
tile_map *TileMap;
world *World;
GameState->PlayerP.AbsTileX = 2;
GameState->PlayerP.AbsTileY = 3;
GameState->PlayerP.TileRelX = 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;
}
World = GameState->World;
TileMap = World->TileMap;
for(ControllerIndex = 0;
ControllerIndex < ARRAY_SIZE(Input->Controllers);
ControllerIndex++)
{
game_controller_input *Controller =
GetController(Input, ControllerIndex);
if(Controller->IsAnalog) {
} else {
F32 dPlayerX = 0.0f;
F32 dPlayerY = 0.0f;
tile_map_position NewPlayerP, PlayerLeft, PlayerRight;
if(Controller->u.buttons.MoveUp.EndedDown) {
dPlayerY = 1.0f;
}
if(Controller->u.buttons.MoveDown.EndedDown) {
dPlayerY = -1.0f;
}
if(Controller->u.buttons.MoveLeft.EndedDown) {
dPlayerX = -1.0f;
}
if(Controller->u.buttons.MoveRight.EndedDown) {
dPlayerX = 1.0f;
}
{
F32 PlayerSpeed = 2.0f;
if(Controller->u.buttons.ActionUp.EndedDown)
PlayerSpeed = 10.0f;
dPlayerX *= PlayerSpeed;
dPlayerY *= PlayerSpeed;
}
NewPlayerP = GameState->PlayerP;
NewPlayerP.TileRelX += Input->dtForFrame*dPlayerX;
NewPlayerP.TileRelY += Input->dtForFrame*dPlayerY;
NewPlayerP = RecannonicalizePosition(TileMap, NewPlayerP);
PlayerLeft = NewPlayerP;
PlayerLeft.TileRelX -= 0.5f*PlayerWidth;
PlayerLeft = RecannonicalizePosition(TileMap, PlayerLeft);
PlayerRight = NewPlayerP;
PlayerRight.TileRelX += 0.5f*PlayerWidth;
PlayerRight = RecannonicalizePosition(TileMap, PlayerRight);
if(IsTileMapPointEmpty(TileMap, NewPlayerP) &&
IsTileMapPointEmpty(TileMap, PlayerLeft) &&
IsTileMapPointEmpty(TileMap, PlayerRight))
{
GameState->PlayerP = NewPlayerP;
}
}
}
ScreenCenterX = 0.5f * (F32)Buffer->Width;
ScreenCenterY = 0.5f * (F32)Buffer->Height;
DrawRectangle(Buffer, 0.0f, 0.0f,
(F32)Buffer->Width, (F32)Buffer->Height,
0.0f, 1.0f, 0.0f);
{
S32 RelRow, RelColumn;
for(RelRow = -10; RelRow < 10; RelRow++) {
for(RelColumn = -20; RelColumn < 20; RelColumn++) {
U32 Column = GameState->PlayerP.AbsTileX + RelColumn;
U32 Row = GameState->PlayerP.AbsTileY + RelRow;
U32 TileID = GetTileValue(TileMap, Column, Row);
F32 Gray = 0.5f;
if(TileID) {
Gray = 1.0f;
}
if((Column == GameState->PlayerP.AbsTileX) &&
(Row == GameState->PlayerP.AbsTileY))
{
Gray = 0.0f;
}
{
F32 CenterX, CenterY, MinX, MinY, MaxX, MaxY;
CenterX = ScreenCenterX -
TileMap->MetersToPixels*GameState->PlayerP.TileRelX +
(F32)RelColumn * (F32)TileMap->TileSideInPixels;
CenterY = ScreenCenterY +
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,
MinX, MinY, MaxX, MaxY,
Gray, Gray, Gray);
}
}
}
}
PlayerR = 1.0f;
PlayerG = 0.0f;
PlayerB = 0.0f;
PlayerLeft = ScreenCenterX - 0.5f* TileMap->MetersToPixels*PlayerWidth;
PlayerTop = ScreenCenterY - TileMap->MetersToPixels*PlayerHeight;
DrawRectangle(Buffer,
PlayerLeft, PlayerTop,
PlayerLeft + TileMap->MetersToPixels*PlayerWidth,
PlayerTop + TileMap->MetersToPixels*PlayerHeight,
PlayerR, PlayerG, PlayerB);
GameOutputSound(GameState, SoundBuffer, 400);
}
/*
static void RenderWeirdGradient(game_offscreen_buffer *Buffer, S32 XOffset,
S32 YOffset)
{
S32 Width, Height, Y;
U8 *Row;
Width = Buffer->Width;
Height = Buffer->Height;
Row = (U8 *)Buffer->Memory;
for(Y = 0; Y < Height; Y++) {
U32 *Pixel = (U32 *)Row;
S32 X;
Pixel = (U32 *)Row;
for(X = 0; X < Width; X++) {
U8 Blue, Green;
Blue = (U8)(X + XOffset);
Green = (U8)(Y + YOffset);
*Pixel = (Green << 8) | Blue;
Pixel++;
}
Row += Buffer->Pitch;
}
}
*/