Files
handmadehero/handmade.c
T

974 lines
30 KiB
C

#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 <stdio.h>
#include <string.h> /* 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;
}
}
*/