#include "core.h" #include "handmade.h" #include "handmade_math.h" #include "sdl_handmade.h" #include "handmade_intrinsics.h" #include "handmade_random.h" #include "handmade_tile.h" #include "handmade_tile.c" #include #include /* memset */ static void GameOutputSound(struct game_state *GameState, struct game_sound_output_buffer *SoundBuffer, int ToneHz) { /* short ToneVolume, *SampleOut; int WavePeriod, SampleIndex; ToneVolume = 0; WavePeriod = SoundBuffer->SamplesPerSecond / ToneHz; SampleOut = SoundBuffer->Samples; for(SampleIndex = 0; SampleIndex < SoundBuffer->SampleCount; SampleIndex++) { float SineValue; short SampleValue; SineValue = sinf(GameState->tSine); SampleValue = (short)(SineValue * ToneVolume); *SampleOut++ = SampleValue; *SampleOut++ = SampleValue; GameState->tSine += 2.0f * (float)PI * 1.0f / (float)WavePeriod; if(GameState->tSine > 2.0f*(float)PI) { GameState->tSine -= 2.0f*(float)PI; } } */ } static void ClearBackground(struct game_offscreen_buffer *Buffer) { int Width = Buffer->Width; int Height = Buffer->Height; int X; for(X = 0; X < Width * Height; X++) { unsigned int *Pixel = &((unsigned int *)Buffer->Memory)[X]; *Pixel = 0xFFFFFF; } } static void DrawRectangle(struct game_offscreen_buffer *Buffer, struct v2 vMin, struct v2 vMax, float R, float G, float B) { int Y, X; int Width, Height; int MinX, MinY, MaxX, MaxY; unsigned int Color; unsigned char *Row; unsigned int *Pixel; MinX = RoundFloatToInt(vMin.X); MinY = RoundFloatToInt(vMin.Y); MaxX = RoundFloatToInt(vMax.X); MaxY = RoundFloatToInt(vMax.Y); Width = Buffer->Width; Height = Buffer->Height; if(MinX < 0) MinX = 0; if(MinY < 0) MinY = 0; if(MaxX > Width) MaxX = Width; if(MaxY > Height) MaxY = Height; /*unsigned int Color = (unsigned int)((RoundFloatToInt(R * 255.0f) << 16) | (RoundFloatToInt(G * 255.0f) << 8) | (RoundFloatToInt(B * 255.0f) << 0));*/ Color = (unsigned int)((RoundFloatToInt(255.0f) << 24) | (RoundFloatToInt(R * 255.0f) << 16) | (RoundFloatToInt(G * 255.0f) << 8) | (RoundFloatToInt(B * 255.0f) << 0)); Row = ((unsigned char *)Buffer->Memory + MinX*Buffer->BytesPerPixel + MinY*Buffer->Pitch); for(Y = MinY; Y < MaxY; Y++) { Pixel = (unsigned int *)Row; for(X = MinX; X < MaxX; X++) { *(unsigned int *)Pixel = Color; Pixel++; } Row += Buffer->Pitch; } } static void DrawBitmap(struct game_offscreen_buffer *Buffer, struct loaded_bitmap *Bitmap, float RelX, float RelY, int AlignX, int AlignY) { int MinX, MinY, MaxX, MaxY; int Width, Height; int SourceOffsetX, SourceOffsetY; unsigned int *SourceRow; unsigned char *DestRow; int Y, X; RelX -= (float)AlignX; RelY -= (float)AlignY; MinX = RoundFloatToInt(RelX); MinY = RoundFloatToInt(RelY); MaxX = RoundFloatToInt(RelX + (float)Bitmap->Width); MaxY = RoundFloatToInt(RelY + (float)Bitmap->Height); Width = Buffer->Width; Height = Buffer->Height; SourceOffsetX = 0; if(MinX < 0) { SourceOffsetX = -MinX; MinX = 0; } SourceOffsetY = 0; if(MinY < 0) { SourceOffsetY = -MinY; MinY = 0; } if(MaxX > Width) MaxX = Width; if(MaxY > Height) MaxY = Height; SourceRow = Bitmap->Pixels + Bitmap->Width*(Bitmap->Height - 1); SourceRow += -Bitmap->Width*SourceOffsetY + SourceOffsetX; DestRow = ((unsigned char *)Buffer->Memory + MinX*Buffer->BytesPerPixel + MinY*Buffer->Pitch); for(Y = MinY; Y < MaxY; Y++) { unsigned int *Dest = (unsigned int *)DestRow; unsigned int *Source = SourceRow; for(X = MinX; X < MaxX; X++) { float SA = (float)((*Source >> 24) & 0xFF); float SR = (float)((*Source >> 16) & 0xFF); float SG = (float)((*Source >> 8) & 0xFF); float SB = (float)((*Source >> 0) & 0xFF); float DR = (float)((*Dest >> 16) & 0xFF); float DG = (float)((*Dest >> 8) & 0xFF); float DB = (float)((*Dest >> 0) & 0xFF); float A = SA / 255.0f; /* TODO: This should be replaced by premultiplied alpha. */ float R = (1.0f-A)*DR + A*SR; float G = (1.0f-A)*DG + A*SG; float B = (1.0f-A)*DB + A*SB; *Dest = (((unsigned int)RoundFloatToInt(SA) << 24) | ((unsigned int)RoundFloatToInt(R) << 16) | ((unsigned int)RoundFloatToInt(G) << 8) | ((unsigned int)RoundFloatToInt(B) << 0)); Dest++; Source++; } DestRow += Buffer->Pitch; SourceRow -= Bitmap->Width; } } #pragma pack(push, 1) struct bitmap_header { unsigned short FileType; unsigned int FileSize; unsigned short Reserved1; unsigned short Reserved2; unsigned int BitmapOffset; unsigned int Size; int Width; int Height; unsigned short Planes; unsigned short BitsPerPixel; unsigned int Compression; unsigned int SizeOfBitmap; int HorzResolution; int VertResolution; unsigned int ColorsUsed; unsigned int ColorsImportant; unsigned int RedMask; unsigned int GreenMask; unsigned int BlueMask; }; #pragma pack(pop) static struct loaded_bitmap DEBUGLoadBMP(struct thread_context *Thread, struct debug_read_file_result (*DEBUGPlatformReadEntireFile)(struct thread_context *Thread, const char *), char *FileName) { struct loaded_bitmap Result; struct debug_read_file_result ReadResult; memset(&Result, 0, sizeof(Result)); ReadResult = DEBUGPlatformReadEntireFile(Thread, FileName); if(ReadResult.ContentsSize > 0) { struct bitmap_header *Header; unsigned int *Pixels; unsigned int RedMask, GreenMask, BlueMask, AlphaMask; struct bit_scan_result RedShift, GreenShift, BlueShift, AlphaShift; unsigned int *SourceDest; int X, Y; Header = (struct bitmap_header *)ReadResult.Contents; Pixels = (unsigned int *)((unsigned char *)ReadResult.Contents + Header->BitmapOffset); Result.Pixels = Pixels; Result.Width = Header->Width; Result.Height = Header->Height; ASSERT(Header->Compression == 3); /* NOTE: The byte order in memory is determined by the Header. */ RedMask = Header->RedMask; GreenMask = Header->GreenMask; BlueMask = Header->BlueMask; AlphaMask = ~(RedMask | GreenMask | BlueMask); RedShift = FindLeastSignificantSetBit(RedMask); GreenShift = FindLeastSignificantSetBit(GreenMask); BlueShift = FindLeastSignificantSetBit(BlueMask); AlphaShift = FindLeastSignificantSetBit(AlphaMask); ASSERT(RedShift.Found); ASSERT(GreenShift.Found); ASSERT(BlueShift.Found); ASSERT(AlphaShift.Found); SourceDest = Pixels; for(Y = 0; Y < Header->Height; Y++) { for(X = 0; X < Header->Width; X++) { unsigned int C = *SourceDest; *SourceDest = ((((C >> AlphaShift.Index) & 0xFF) << 24) | (((C >> RedShift.Index ) & 0xFF) << 16) | (((C >> GreenShift.Index) & 0xFF) << 8) | (((C >> BlueShift.Index ) & 0xFF) << 0)); SourceDest++; } } } return Result; } static struct entity *GetEntity(struct game_state *GameState, unsigned int Index) { struct entity *Entity = NULL; if((Index > 0) && (Index < ARRAY_SIZE(GameState->Entities))) { Entity = &GameState->Entities[Index]; } return Entity; } static void InitializePlayer(struct entity *Entity) { Entity->Exists = 1; Entity->P.AbsTileX = 2; Entity->P.AbsTileY = 3; Entity->P.Offset.X = 5.0f; Entity->P.Offset.Y = 5.0f; Entity->Height = 1.4f; Entity->Width = 0.75f * Entity->Height; } static unsigned int AddEntity(struct game_state *GameState) { unsigned int EntityIndex = ++GameState->EntityCount; struct entity *Entity; ASSERT(GameState->EntityCount < ARRAY_SIZE(GameState->Entities)); Entity = &GameState->Entities[EntityIndex]; memset(Entity, 0, sizeof(struct entity)); return EntityIndex; } static void MovePlayer(struct game_state *GameState, struct entity *Entity, float dt, struct v2 ddPlayer) { struct tile_map *TileMap; float PlayerSpeed; struct tile_map_position OldPlayerP, NewPlayerP; struct v2 PlayerDelta; TileMap = GameState->World->TileMap; if((ddPlayer.X != 0.0f) && (ddPlayer.Y != 0.0f)) ddPlayer = V2Multiply(0.7071067811865475244f, ddPlayer); PlayerSpeed = 10.0f; ddPlayer = V2Multiply(PlayerSpeed, ddPlayer); ddPlayer = V2Add(ddPlayer, V2Unary(V2Multiply(1.5f, Entity->dP))); OldPlayerP = Entity->P; NewPlayerP = OldPlayerP; PlayerDelta = V2Add(V2Multiply(0.5f, V2Multiply(Square(dt), ddPlayer)), V2Multiply(dt, Entity->dP)); NewPlayerP.Offset = V2Add(PlayerDelta, NewPlayerP.Offset); Entity->dP = V2Add(V2Multiply(dt, ddPlayer), Entity->dP); NewPlayerP = RecannonicalizePosition(TileMap, NewPlayerP); { #if 1 struct tile_map_position PlayerLeft, PlayerRight; int Collided; struct tile_map_position ColP; PlayerLeft = NewPlayerP; PlayerLeft.Offset.X -= 0.5f*Entity->Width; PlayerLeft = RecannonicalizePosition(TileMap, PlayerLeft); PlayerRight = NewPlayerP; PlayerRight.Offset.X += 0.5f*Entity->Width; PlayerRight = RecannonicalizePosition(TileMap, PlayerRight); Collided = 0; memset(&ColP, 0, sizeof(ColP)); if(!IsTileMapPointEmpty(TileMap, NewPlayerP)) { ColP = NewPlayerP; Collided = 1; } if(!IsTileMapPointEmpty(TileMap, PlayerLeft)) { ColP = PlayerLeft; Collided = 1; } if(!IsTileMapPointEmpty(TileMap, PlayerRight)) { ColP = PlayerRight; Collided = 1; } if(Collided) { struct v2 r = { 0, 0 }; if(ColP.AbsTileX < Entity->P.AbsTileX) { r.X = 1; r.Y = 0; } if(ColP.AbsTileX > Entity->P.AbsTileX) { r.X = -1; r.Y = 0; } if(ColP.AbsTileY < Entity->P.AbsTileY) { r.X = 0; r.Y = 1; } if(ColP.AbsTileY > Entity->P.AbsTileY) { r.X = 0; r.Y = -1; } Entity->dP = V2Subtract(Entity->dP, V2Multiply(1*InnerProduct(Entity->dP, r), r)); } else { Entity->P = NewPlayerP; } #else unsigned int MinTileX = 0; unsigned int MinTileY = 0; unsigned int OnePastMaxTileX = 0; unsigned int OnePastMaxTileY = 0; unsigned int AbsTileZ = GameState->PlayerP.AbsTileZ; tile_map_position BestPlayerP = GameState->PlayerP; F32 BestDistance = LengthSq(PlayerDelta); for(unsigned int AbsTileY = MinTileY; AbsTileY != OnePastMaxTileY; AbsTileY++) { for(unsigned int AbsTileX = MinTileX; AbsTileX != OnePastMaxTileX; AbsTileX++) { tile_map_position TestTileP = CenteredTilePoint(AbsTileX, AbsTileY, AbsTileZ); unsigned int TileValue = GetTileValueByPos(TileMap, TestTileP); if(IsTileValueEmpty(TileValue)) { v2 MinCorner = V2Multiply(-0.5f, (v2){ TileMap->TileSideInMeters, TileMap->TileSideInMeters }); v2 MaxCorner = V2Multiply(-0.5f, (v2){ TileMap->TileSideInMeters, TileMap->TileSideInMeters }); tile_map_difference RelNewPlayerP = SubtractInF32(TileMap, &TestTileP, &NewPlayerP); v2 TestP = ClosestPointInRectangle(MinCorner, MaxCorner, RelNewPlayerP); if(...) { } } } } #endif } if(!AreOnSameTile(&OldPlayerP, &Entity->P)) { unsigned int NewTileValue = GetTileValueByPos(TileMap, Entity->P); if(NewTileValue == 3) { Entity->P.AbsTileZ++; } else if(NewTileValue == 4) { Entity->P.AbsTileZ--; } } if(AbsoluteValue(ddPlayer.X) > AbsoluteValue(ddPlayer.Y)) { if(ddPlayer.X > 0) { Entity->FacingDirection = 0; } else { Entity->FacingDirection = 2; } } else if(AbsoluteValue(ddPlayer.X) < AbsoluteValue(ddPlayer.Y)) { if(ddPlayer.Y > 0) { Entity->FacingDirection = 1; } else { Entity->FacingDirection = 3; } } } void UpdateAndRender(struct thread_context *Thread, struct game_memory *Memory, struct game_input *Input, struct game_offscreen_buffer *Buffer, struct game_sound_output_buffer *SoundBuffer) { struct game_state *GameState; struct world *World; struct tile_map *TileMap; int TileSideInPixels; float MetersToPixels; unsigned int ControllerIndex; struct entity *CameraFollowingEntity; float ScreenCenterX, ScreenCenterY; int RelRow, RelColumn; struct entity *Entity; unsigned int EntityIndex; ASSERT((&Input->Controllers[0].u.s.Terminator - &Input->Controllers[0].u.Buttons[0]) == ARRAY_SIZE(Input->Controllers[0].u.Buttons)); ASSERT(sizeof(struct game_state) <= Memory->PermanentStorageSize); GameState = (struct game_state *)Memory->PermanentStorage; if(!Memory->IsInitialized) { struct hero_bitmaps *Bitmap; struct world *World; struct tile_map *TileMap; unsigned int RandomNumberIndex; unsigned int TilesPerWidth, TilesPerHeight; unsigned int ScreenX, ScreenY; unsigned int AbsTileZ; int DoorTop, DoorBottom, DoorLeft, DoorRight, DoorUp, DoorDown; unsigned int ScreenIndex; /* NOTE: Reserve entity slot 0 for null entity */ AddEntity(GameState); GameState->rect_pos.X = 0.0f; GameState->rect_pos.Y = 0.0f; GameState->ProgramIcon.Width = 256; GameState->ProgramIcon.Height = 256; GameState->ProgramIcon.BytesPerPixel = 4; GameState->ProgramIcon.Pitch = GameState->ProgramIcon.BytesPerPixel * GameState->ProgramIcon.Width; GameState->ProgramIcon.Memory = malloc(GameState->ProgramIcon.BytesPerPixel * GameState->ProgramIcon.Width * GameState->ProgramIcon.Height); memset(GameState->ProgramIcon.Memory, 0, GameState->ProgramIcon.BytesPerPixel * GameState->ProgramIcon.Width * GameState->ProgramIcon.Height); #if 0 GameState->ProgramIconBMP = DEBUGLoadBMP(Thread, Memory->DEBUGPlatformReadEntireFile, "data/program_icon.bmp"); DrawBitmap(&GameState->ProgramIcon, &GameState->ProgramIconBMP, 0.0f, 0.0f, 0, 0); Memory->SetProgramIcon(&GameState->ProgramIcon); #endif GameState->Backdrop = DEBUGLoadBMP(Thread, Memory->DEBUGPlatformReadEntireFile, "data/test_background.bmp"); Bitmap = &GameState->HeroBitmaps[0]; Bitmap->AlignX = 72; Bitmap->AlignY = 182; Bitmap->Head = DEBUGLoadBMP(Thread, Memory->DEBUGPlatformReadEntireFile, "data/test_hero_right_head.bmp"); Bitmap->Cape = DEBUGLoadBMP(Thread, Memory->DEBUGPlatformReadEntireFile, "data/test_hero_right_cape.bmp"); Bitmap->Torso = DEBUGLoadBMP(Thread, Memory->DEBUGPlatformReadEntireFile, "data/test_hero_right_torso.bmp"); Bitmap++; Bitmap->AlignX = 72; Bitmap->AlignY = 182; Bitmap->Head = DEBUGLoadBMP(Thread, Memory->DEBUGPlatformReadEntireFile, "data/test_hero_back_head.bmp"); Bitmap->Cape = DEBUGLoadBMP(Thread, Memory->DEBUGPlatformReadEntireFile, "data/test_hero_back_cape.bmp"); Bitmap->Torso = DEBUGLoadBMP(Thread, Memory->DEBUGPlatformReadEntireFile, "data/test_hero_back_torso.bmp"); Bitmap++; Bitmap->AlignX = 72; Bitmap->AlignY = 182; Bitmap->Head = DEBUGLoadBMP(Thread, Memory->DEBUGPlatformReadEntireFile, "data/test_hero_left_head.bmp"); Bitmap->Cape = DEBUGLoadBMP(Thread, Memory->DEBUGPlatformReadEntireFile, "data/test_hero_left_cape.bmp"); Bitmap->Torso = DEBUGLoadBMP(Thread, Memory->DEBUGPlatformReadEntireFile, "data/test_hero_left_torso.bmp"); Bitmap++; Bitmap->AlignX = 72; Bitmap->AlignY = 182; Bitmap->Head = DEBUGLoadBMP(Thread, Memory->DEBUGPlatformReadEntireFile, "data/test_hero_front_head.bmp"); Bitmap->Cape = DEBUGLoadBMP(Thread, Memory->DEBUGPlatformReadEntireFile, "data/test_hero_front_cape.bmp"); Bitmap->Torso = DEBUGLoadBMP(Thread, Memory->DEBUGPlatformReadEntireFile, "data/test_hero_front_torso.bmp"); GameState->CameraP.AbsTileX = 17 / 2; GameState->CameraP.AbsTileY = 9 / 2; InitializeArena(&GameState->WorldArena, Memory->PermanentStorageSize - sizeof(struct game_state), (unsigned char *)Memory->PermanentStorage + sizeof(struct game_state)); GameState->World = PUSH_STRUCT(&GameState->WorldArena, struct world); World = GameState->World; World->TileMap = PUSH_STRUCT(&GameState->WorldArena, struct tile_map); TileMap = World->TileMap; TileMap->ChunkShift = 4; TileMap->ChunkMask = (1 << TileMap->ChunkShift) - 1; TileMap->ChunkDim = (1 << TileMap->ChunkShift); TileMap->TileChunkCountX = 128; TileMap->TileChunkCountY = 128; TileMap->TileChunkCountZ = 2; TileMap->TileChunks = PUSH_ARRAY(&GameState->WorldArena, TileMap->TileChunkCountX * TileMap->TileChunkCountY * TileMap->TileChunkCountZ, struct tile_chunk); TileMap->TileSideInMeters = 1.4f; RandomNumberIndex = 0; TilesPerWidth = 17; TilesPerHeight = 9; ScreenX = 0; ScreenY = 0; AbsTileZ = 0; DoorTop = 0; DoorBottom = 0; DoorLeft = 0; DoorRight = 0; DoorUp = 0; DoorDown = 0; for(ScreenIndex = 0; ScreenIndex < 100; ScreenIndex++) { /* TODO: Random number generator. */ unsigned int RandomChoice; int CreatedZDoor; unsigned int TileY, TileX; ASSERT(RandomNumberIndex < ARRAY_SIZE(RandomNumberTable)); if(DoorUp || DoorDown) { RandomChoice = RandomNumberTable[RandomNumberIndex++] % 2; } else { RandomChoice = RandomNumberTable[RandomNumberIndex++] % 3; } CreatedZDoor = 0; if(RandomChoice == 2) { CreatedZDoor = 1; if(AbsTileZ == 0) { DoorUp = 1; } else { DoorDown = 1; } } else if(RandomChoice == 1) { DoorRight = 1; } else { DoorTop = 1; } for(TileY = 0; TileY < TilesPerHeight; TileY++) { for(TileX = 0; TileX < TilesPerWidth; TileX++) { unsigned int AbsTileX = ScreenX * TilesPerWidth + TileX; unsigned int AbsTileY = ScreenY * TilesPerHeight + TileY; unsigned int TileValue = 1; if(TileX == 0 && (!DoorLeft || (TileY != (TilesPerHeight/2)))) { TileValue = 2; } if(TileX == (TilesPerWidth - 1) && (!DoorRight || (TileY != (TilesPerHeight/2)))) { TileValue = 2; } if(TileY == 0 && (!DoorBottom || (TileX != (TilesPerWidth/2)))) { TileValue = 2; } if(TileY == (TilesPerHeight - 1) && (!DoorTop || (TileX != (TilesPerWidth/2)))) { TileValue = 2; } if((TileX == 10) && (TileY == 6)) { if(DoorUp) { TileValue = 3; } if(DoorDown) { TileValue = 4; } } SetTileValue(&GameState->WorldArena, World->TileMap, AbsTileX, AbsTileY, AbsTileZ, TileValue); } } DoorLeft = DoorRight; DoorBottom = DoorTop; if(CreatedZDoor) { DoorDown = !DoorDown; DoorUp = !DoorUp; } else { DoorUp = 0; DoorDown = 0; } DoorTop = 0; DoorRight = 0; if(RandomChoice == 2) { if(AbsTileZ == 0) { AbsTileZ = 1; } else { AbsTileZ = 0; } } else if(RandomChoice == 1) { ScreenX++; } else { ScreenY++; } } Memory->IsInitialized = 1; } World = GameState->World; TileMap = World->TileMap; TileSideInPixels = 60; MetersToPixels = (float)TileSideInPixels / TileMap->TileSideInMeters; for(ControllerIndex = 0; ControllerIndex < ARRAY_SIZE(Input->Controllers); ControllerIndex++) { struct game_controller_input *Controller; struct entity *ControllingEntity; Controller = GetController(Input, ControllerIndex); ControllingEntity = GetEntity(GameState, GameState->PlayerIndexForController[ControllerIndex]); if(ControllingEntity) { struct v2 ddPlayer; /* accerlation */ memset(&ddPlayer, 0, sizeof(ddPlayer)); if(Controller->IsAnalog) { ddPlayer.X = Controller->StickAverageX; ddPlayer.Y = -Controller->StickAverageY; } else { if(Controller->u.s.MoveUp.EndedDown) { GameState->rect_pos.Y -= 1.0f; ddPlayer.Y = 1.0f; } if(Controller->u.s.MoveDown.EndedDown) { GameState->rect_pos.Y += 1.0f; ddPlayer.Y = -1.0f; } if(Controller->u.s.MoveLeft.EndedDown) { GameState->rect_pos.X -= 1.0f; ddPlayer.X = -1.0f; } if(Controller->u.s.MoveRight.EndedDown) { GameState->rect_pos.X += 1.0f; ddPlayer.X = 1.0f; } } MovePlayer(GameState, ControllingEntity, Input->dtForFrame, ddPlayer); } else { if(Controller->u.s.Start.EndedDown) { unsigned int EntityIndex = AddEntity(GameState); ControllingEntity = GetEntity(GameState, EntityIndex); InitializePlayer(ControllingEntity); GameState->PlayerIndexForController[ControllerIndex] = EntityIndex; } } } CameraFollowingEntity = GetEntity(GameState, GameState->CameraFollowingEntityIndex); if(CameraFollowingEntity) { struct tile_map_difference Diff; GameState->CameraP.AbsTileZ = CameraFollowingEntity->P.AbsTileZ; Diff = SubtractInFloat(TileMap, &CameraFollowingEntity->P, &GameState->CameraP); if(Diff.dXY.X > (9.0f*TileMap->TileSideInMeters)) { GameState->CameraP.AbsTileX += 17; } if(Diff.dXY.X < -(9.0f*TileMap->TileSideInMeters)) { GameState->CameraP.AbsTileX -= 17; } if(Diff.dXY.Y > (5.0f*TileMap->TileSideInMeters)) { GameState->CameraP.AbsTileY += 9; } if(Diff.dXY.Y < -(5.0f*TileMap->TileSideInMeters)) { GameState->CameraP.AbsTileY -= 9; } } /*DrawRectangle(Buffer, 0.0f, 0.0f, (F32)Buffer->Width, (F32)Buffer->Height, 0.0f, 1.0f, 0.0f);*/ DrawBitmap(Buffer, &GameState->Backdrop, 0.0f, 0.0f, 0, 0); ScreenCenterX = 0.5f * (float)Buffer->Width; ScreenCenterY = 0.5f * (float)Buffer->Height; for(RelRow = -10; RelRow < 10; RelRow++) { for(RelColumn = -20; RelColumn < 20; RelColumn++) { unsigned int Column = GameState->CameraP.AbsTileX + RelColumn; unsigned int Row = GameState->CameraP.AbsTileY + RelRow; unsigned int TileID = GetTileValue(TileMap, Column, Row, GameState->CameraP.AbsTileZ); if(TileID > 1) { struct v2 TileSide, Center; struct v2 Min, Max; float Gray = 0.5f; if(TileID == 2) { Gray = 1.0f; } if(TileID > 2) { Gray = 0.25f; } if(Column == GameState->CameraP.AbsTileX && Row == GameState->CameraP.AbsTileY) { Gray = 0.0f; } TileSide.X = 0.5f*(float)TileSideInPixels; TileSide.Y = 0.5f*(float)TileSideInPixels; Center.X = ScreenCenterX - MetersToPixels*GameState->CameraP.Offset.X + (float)RelColumn*(float)TileSideInPixels; Center.Y = ScreenCenterY + MetersToPixels * GameState->CameraP.Offset.Y - (float)RelRow*(float)TileSideInPixels; Min = V2Subtract(Center, TileSide); Max = V2Add(Center, TileSide); DrawRectangle(Buffer, Min, Max, Gray, Gray, Gray); } } } Entity = GameState->Entities; for(EntityIndex = 0; EntityIndex < GameState->EntityCount; EntityIndex++, Entity++) { if(Entity->Exists) { struct tile_map_difference Diff; float PlayerR, PlayerG, PlayerB; float PlayerGroundPointX, PlayerGroundPointY; struct v2 PlayerLeftTop, PlayerWidthHeight; struct hero_bitmaps *Bitmap; Diff = SubtractInFloat(TileMap, &Entity->P, &GameState->CameraP); PlayerR = 1.0f; PlayerG = 0.0f; PlayerB = 0.0f; PlayerGroundPointX = ScreenCenterX + MetersToPixels*Diff.dXY.X; PlayerGroundPointY = ScreenCenterY - MetersToPixels*Diff.dXY.Y; PlayerLeftTop.X = PlayerGroundPointX - 0.5f * MetersToPixels*Entity->Width; PlayerLeftTop.Y = PlayerGroundPointY - MetersToPixels*Entity->Height; PlayerWidthHeight.X = Entity->Width; PlayerWidthHeight.X = Entity->Height; DrawRectangle(Buffer, PlayerLeftTop, V2Add(PlayerLeftTop, V2Multiply(MetersToPixels, PlayerWidthHeight)), PlayerR, PlayerG, PlayerB); Bitmap = &GameState->HeroBitmaps[Entity->FacingDirection]; DrawBitmap(Buffer, &Bitmap->Torso, PlayerGroundPointX, PlayerGroundPointY, Bitmap->AlignX, Bitmap->AlignY); DrawBitmap(Buffer, &Bitmap->Cape, PlayerGroundPointX, PlayerGroundPointY, Bitmap->AlignX, Bitmap->AlignY); DrawBitmap(Buffer, &Bitmap->Head, PlayerGroundPointX, PlayerGroundPointY, Bitmap->AlignX, Bitmap->AlignY); /* TODO: Remove this. */ /*DrawRectangle(&GameState->ProgramIcon, GameState->rect_pos, (struct v2){ GameState->rect_pos.X + 20.0f, GameState->rect_pos.Y + 20.0f }, 0.8f, 0.8f, 0.8f);*/ /*Memory->SetProgramIcon(&GameState->ProgramIcon);*/ } } GameOutputSound(GameState, SoundBuffer, 400); } /* static void RenderWeirdGradient(game_offscreen_buffer *Buffer, int XOffset, int YOffset) { int Width, Height, Y; U8 *Row; Width = Buffer->Width; Height = Buffer->Height; Row = (U8 *)Buffer->Memory; for(Y = 0; Y < Height; Y++) { unsigned int *Pixel = (unsigned int *)Row; int X; Pixel = (unsigned int *)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; } } */