#include "core.h" #include "handmade.h" #include "sdl_handmade.h" #include "handmade_intrinsics.h" #include /* memset */ 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 tile_map *GetTileMap(world *World, S32 TileMapX, S32 TileMapY) { tile_map *TileMap = NULL; if((TileMapX >= 0) && (TileMapX < World->TileMapCountX) && (TileMapY >= 0) && (TileMapY < World->TileMapCountY)) { TileMap = &World->TileMaps[TileMapY*World->TileMapCountX + TileMapX]; } return TileMap; } static U32 GetTileValueUnchecked(world *World, tile_map *TileMap, S32 TileX, S32 TileY) { U32 TileMapValue; ASSERT(TileMap); ASSERT((TileX >= 0) && (TileX < World->CountX) && (TileY >= 0) && (TileY < World->CountY)); TileMapValue = TileMap->Tiles[TileY*World->CountX + TileX]; return TileMapValue; } static B32 IsTileMapPointEmpty(world *World, tile_map *TileMap, S32 TestTileX, S32 TestTileY) { B32 Empty = FALSE; if(TileMap) { if((TestTileX >= 0) && (TestTileX < World->CountX) && (TestTileY >= 0) && (TestTileY < World->CountY)) { U32 TileMapValue = GetTileValueUnchecked(World, TileMap, TestTileX, TestTileY); Empty = (TileMapValue == 0); } } return Empty; } static cannonical_position GetCannonicalPosition(world *World, raw_position Pos) { cannonical_position Result; F32 X, Y; Result.TileMapX = Pos.TileMapX; Result.TileMapY = Pos.TileMapY; X = Pos.X - World->UpperLeftX; Y = Pos.Y - World->UpperLeftY; Result.TileX = FloorF32toS32(X / World->TileWidth); Result.TileY = FloorF32toS32(Y / World->TileHeight); Result.X = X - Result.TileX*World->TileWidth; Result.Y = Y - Result.TileY*World->TileHeight; ASSERT(Result.X >= 0); ASSERT(Result.Y >= 0); ASSERT(Result.X < World->TileWidth); ASSERT(Result.Y < World->TileHeight); if(Result.TileX < 0) { Result.TileX = World->CountX + Result.TileX; Result.TileMapX--; } if(Result.TileY < 0) { Result.TileY = World->CountY + Result.TileY; Result.TileMapY--; } if(Result.TileX >= World->CountX) { Result.TileX = Result.TileX - World->CountX; Result.TileMapX++; } if(Result.TileY >= World->CountY) { Result.TileY = Result.TileY - World->CountY; Result.TileMapY++; } return Result; } static B32 IsWorldPointEmpty(world *World, raw_position TestPos) { B32 Empty = FALSE; tile_map *TileMap; cannonical_position CanPos = GetCannonicalPosition(World, TestPos); TileMap = GetTileMap(World, CanPos.TileMapX, CanPos.TileMapY); Empty = IsTileMapPointEmpty(World, TileMap, CanPos.TileX, CanPos.TileY); return Empty; } void UpdateAndRender(thread_context *Thread, game_memory *Memory, game_input *Input, game_offscreen_buffer *Buffer, game_sound_output_buffer *SoundBuffer) { #define TILEMAP_COUNT_X 17 #define TILEMAP_COUNT_Y 9 game_state *GameState; U32 ControllerIndex; S32 Row, Column; U32 Tiles00[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, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 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, 1, 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}, {1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1}, {1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1}, {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1}, }; U32 Tiles01[TILEMAP_COUNT_Y][TILEMAP_COUNT_X] = { {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, 0}, {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}, }; U32 Tiles10[TILEMAP_COUNT_Y][TILEMAP_COUNT_X] = { {1, 1, 1, 1, 1, 1, 1, 1, 1, 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}, {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, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1}, }; U32 Tiles11[TILEMAP_COUNT_Y][TILEMAP_COUNT_X] = { {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}, {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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, }; F32 PlayerR, PlayerG, PlayerB, PlayerWidth, PlayerHeight, PlayerLeft, PlayerTop; tile_map TileMaps[2][2]; tile_map *TileMap; world World; 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); TileMaps[0][0].Tiles = (U32 *)Tiles00; TileMaps[0][1].Tiles = (U32 *)Tiles10; TileMaps[1][0].Tiles = (U32 *)Tiles01; TileMaps[1][1].Tiles = (U32 *)Tiles11; memset(&World, 0, sizeof(World)); World.TileMapCountX = 2; World.TileMapCountY = 2; World.CountX = TILEMAP_COUNT_X; World.CountY = TILEMAP_COUNT_Y; World.UpperLeftX = 0.0f; World.UpperLeftY = 0.0f; World.TileWidth = 57.0f; World.TileHeight = 57.0f; World.TileMaps = (tile_map *)TileMaps; PlayerWidth = 0.75f * World.TileWidth; PlayerHeight = World.TileHeight; GameState = (game_state *)Memory->PermanentStorage; if(!Memory->IsInitialized) { GameState->PlayerX = 200.0f; GameState->PlayerY = 200.0f; Memory->IsInitialized = TRUE; } TileMap = GetTileMap(&World, GameState->PlayerTileMapX, GameState->PlayerTileMapY); ASSERT(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; F32 NewPlayerX, NewPlayerY; raw_position PlayerPos, 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; } dPlayerX *= 200.0f; dPlayerY *= 200.0f; NewPlayerX = RoundF32toS32(GameState->PlayerX + Input->dtForFrame*dPlayerX); NewPlayerY = RoundF32toS32(GameState->PlayerY + Input->dtForFrame*dPlayerY); PlayerPos.TileMapX = GameState->PlayerTileMapX; PlayerPos.TileMapY = GameState->PlayerTileMapY; PlayerPos.X = NewPlayerX; PlayerPos.Y = NewPlayerY; PlayerLeft = PlayerPos; PlayerLeft.X -= 0.5f*PlayerWidth; PlayerRight = PlayerPos; PlayerRight.X += 0.5f*PlayerWidth; if(IsWorldPointEmpty(&World, PlayerPos) && IsWorldPointEmpty(&World, PlayerLeft) && IsWorldPointEmpty(&World, PlayerRight)) { cannonical_position CanPos = GetCannonicalPosition(&World, PlayerPos); GameState->PlayerTileMapX = CanPos.TileMapX; GameState->PlayerTileMapY = CanPos.TileMapY; GameState->PlayerX = World.UpperLeftX + World.TileWidth*CanPos.TileX + CanPos.X; GameState->PlayerY = World.UpperLeftY + World.TileHeight*CanPos.TileY + CanPos.Y; } } } DrawRectangle(Buffer, 0.0f, 0.0f, (F32)(Buffer->Width), (F32)(Buffer->Height), 0.0f, 1.0f, 0.0f); for(Row = 0; Row < TILEMAP_COUNT_Y; Row++) { for(Column = 0; Column < TILEMAP_COUNT_X; Column++) { F32 MinX, MinY, MaxX, MaxY; U32 TileID = GetTileValueUnchecked(&World, TileMap, Column, Row); F32 Gray = 0.5f; if(TileID) { Gray = 1.0f; } MinX = World.UpperLeftX + (F32)(Column) * World.TileWidth; MinY = World.UpperLeftY + (F32)(Row) * World.TileHeight; MaxX = MinX + World.TileWidth; MaxY = MinY + World.TileHeight; DrawRectangle(Buffer, MinX, MinY, MaxX, MaxY, Gray, Gray, Gray); } } PlayerR = 1.0f; PlayerG = 0.0f; PlayerB = 0.0f; PlayerLeft = GameState->PlayerX - 0.5f*PlayerWidth; PlayerTop = GameState->PlayerY - PlayerHeight; DrawRectangle(Buffer, PlayerLeft, PlayerTop, PlayerLeft + PlayerWidth, PlayerTop + PlayerHeight, PlayerR, PlayerG, PlayerB); DrawRectangle(Buffer, (F32)(Input->MouseX) - 15.0f, (F32)(Input->MouseY) - 15.0f, (F32)(Input->MouseX) + 5.0f, (F32)(Input->MouseY) + 5.0f, 1.0f, 0.5f, 0.0f); 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; } } */