diff --git a/src/handmade.cpp b/src/handmade.cpp index 17dac47..b9ac232 100644 --- a/src/handmade.cpp +++ b/src/handmade.cpp @@ -2,14 +2,23 @@ #define PI32 3.141592653589f -internal int32 roundReal32ToUInt32(real32 realNum) { +inline int32 roundReal32ToUInt32(real32 realNum) { return (uint32)(realNum + 0.5f); } -internal int32 roundReal32ToInt32(real32 realNum) { +inline int32 roundReal32ToInt32(real32 realNum) { return (int32)(realNum + 0.5f); } +#include "math.h" +inline int32 floorReal32ToInt32(real32 realNum) { + return (int32)floorf(realNum); +} + +inline int32 truncateReal32ToInt32(real32 realNum) { + return (int32)realNum; +} + internal void drawRectangle(GameOffscreenBuffer *buffer, real32 realMinX, real32 realMinY, real32 realMaxX, real32 realMaxY, real32 R, real32 G, real32 B) { int32 minX = roundReal32ToInt32(realMinX); int32 minY = roundReal32ToInt32(realMinY); @@ -57,6 +66,76 @@ internal void outputSound(GameSoundOutputBuffer *soundBuffer, GameState *state) } } +inline uint32 getTileValueUnchecked(World *world, TileMap *tileMap, int32 testTileX, int32 testTileY) { + Assert(tileMap); + Assert( + (testTileX >= 0) && (testTileX < world->tileCountX) && + (testTileY >= 0) && (testTileY < world->tileCountY) + ); + return tileMap->tiles[testTileY * world->tileCountX + testTileX]; +} + +inline TileMap *getTileMap(World *world, int32 tileMapX, int32 tileMapY) { + TileMap *tileMap = NULL; + + if ((tileMapX >= 0) && (tileMapX < world->tileMapCountX) && + (tileMapY >= 0) && (tileMapY < world->tileMapCountY) + ) { + tileMap = &world->tileMaps[tileMapY * world->tileMapCountX + tileMapX]; + } + + return tileMap; +} + +inline CanonicalPosition getCanonicalPosition(World* world, RawPosition pos) { + CanonicalPosition result = {}; + + result.tileMapX = pos.tileMapX; + result.tileMapY = pos.tileMapY; + + real32 x = pos.x - world->upperLeftX; + real32 y = pos.y - world->upperLeftY; + + result.tileX = floorReal32ToInt32(x / world->tileWidth); + result.tileY = floorReal32ToInt32(y / world->tileHeight); + + result.x = pos.x - result.tileX*world->tileWidth; + result.y = pos.y - result.tileY*world->tileHeight; + + if (result.tileX < 0) { + result.tileX += world->tileCountX; + result.tileMapX -= 1; + } + + if (result.tileY < 0) { + result.tileY += world->tileCountY; + result.tileMapY -= 1; + } + + if (result.tileX >= world->tileCountX) { + result.tileX -= world->tileCountX; + result.tileMapX += 1; + } + + if (result.tileY >= world->tileCountY) { + result.tileY -= world->tileCountY; + result.tileMapY += 1; + } + + return result; +} + +internal bool32 isWorldPointEmpty(World *world, RawPosition testPos) { + bool32 isEmpty = false; + + CanonicalPosition canPos = getCanonicalPosition(world, testPos); + TileMap *tileMap = getTileMap(world, canPos.tileMapX, canPos.tileMapY); + + isEmpty = (getTileValueUnchecked(world, tileMap, canPos.tileX, canPos.tileY) == 0); + + return isEmpty; +} + extern "C" GAME_UPDATE_AND_RENDER(gameUpdateAndRender) { Assert(sizeof(GameState) <= memory->permanentStorageSize); @@ -64,10 +143,97 @@ extern "C" GAME_UPDATE_AND_RENDER(gameUpdateAndRender) { if (!memory->isInitialised) { memory->isInitialised = true; - state->playerX = 20.0f; - state->playerY = 20.0f; + state->playerX = 150.0f; + state->playerY = 150.0f; + state->tileMapX = 0; + state->tileMapY = 0; } + const int TILEMAP_WIDTH = 16; + const int TILEMAP_HEIGHT = 9; + + const int WORLD_WIDTH = 2; + const int WORLD_HEIGHT = 2; + + uint32 tiles00[TILEMAP_HEIGHT][TILEMAP_WIDTH] = { + {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, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {1, 0, 0, 0, 0, 1, 1, 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, 1}, + {1, 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, 1}, + {1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1}, + }; + + uint32 tiles01[TILEMAP_HEIGHT][TILEMAP_WIDTH] = { + {1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1}, + {1, 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, 1}, + {1, 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, 1}, + {1, 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, 1}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + }; + + uint32 tiles10[TILEMAP_HEIGHT][TILEMAP_WIDTH] = { + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, + {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, + {1, 0, 0, 0, 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, 1, 0, 1}, + {1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1}, + }; + + uint32 tiles11[TILEMAP_HEIGHT][TILEMAP_WIDTH] = { + {1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1}, + {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, + {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, + {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, + {1, 0, 0, 0, 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, 1, 0, 1}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + }; + + World world = {}; + world.tileCountX = TILEMAP_WIDTH; + world.tileCountY = TILEMAP_HEIGHT; + world.tileMapCountX = WORLD_WIDTH; + world.tileMapCountY = WORLD_HEIGHT; + world.upperLeftX = 0; + world.upperLeftY = 0; + world.tileWidth = 60; + world.tileHeight = 60; + + TileMap maps[WORLD_HEIGHT][WORLD_WIDTH]; + maps[0][0].tiles = (uint32*)tiles00; + + maps[1][0] = maps[0][0]; + maps[1][0].tiles = (uint32*)tiles01; + + maps[0][1] = maps[0][0]; + maps[0][1].tiles = (uint32*)tiles10; + + maps[1][1] = maps[0][0]; + maps[1][1].tiles = (uint32*)tiles11; + + world.tileMaps = (TileMap*)maps; + + // player + real32 playerR = 1.0f; + real32 playerG = 1.0f; + real32 playerB = 0.5f; + real32 playerWidth = 50.0f; + real32 playerHeight = 70.0f; + for (int controllerIndex = 0; controllerIndex < ArrayCount(input->controllers); controllerIndex++) { GameControllerInput *controller = &input->controllers[controllerIndex]; @@ -75,67 +241,79 @@ extern "C" GAME_UPDATE_AND_RENDER(gameUpdateAndRender) { real32 dPlayerY = 0.0f; if (controller->stickUp.endedDown) { - dPlayerY = -128.0f; + dPlayerY = -1.0f; } if (controller->stickDown.endedDown) { - dPlayerY = 128.0f; + dPlayerY = 1.0f; } if (controller->stickLeft.endedDown) { - dPlayerX = -128.0f; + dPlayerX = -1.0f; } if (controller->stickRight.endedDown) { - dPlayerX = 128.0f; + dPlayerX = 1.0f; } - state->playerX += dPlayerX * input->dtForFrame; - state->playerY += dPlayerY * input->dtForFrame; - } + dPlayerX *= 96.0f; + dPlayerY *= 96.0f; - const int TILEMAP_WIDTH = 16; - const int TILEMAP_HEIGHT = 9; - real32 upperLeftX = 0; - real32 upperLeftY = 0; - real32 tileWidth = 60; - real32 tileHeight = 60; + real32 newPlayerX = state->playerX + dPlayerX * input->dtForFrame; + real32 newPlayerY = state->playerY + dPlayerY * input->dtForFrame; - uint32 tileMap[TILEMAP_HEIGHT][TILEMAP_WIDTH] = { - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, - {1, 0, 0, 0, 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, 1, 0, 1}, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, - }; + RawPosition playerPos = { + state->tileMapX, + state->tileMapY, + newPlayerX, + newPlayerY, + }; + + RawPosition playerBottomLeft = playerPos; + playerBottomLeft.x -= 0.5f * playerWidth; + + RawPosition playerTopLeft = playerPos; + playerTopLeft.x -= 0.5f * playerWidth; + playerTopLeft.y -= playerWidth; + + RawPosition playerBottomRight = playerPos; + playerBottomRight.x += 0.5f * playerWidth; + + RawPosition playerTopRight = playerPos; + playerTopRight.x += 0.5f * playerWidth; + playerTopRight.y -= playerWidth; + + if ( + isWorldPointEmpty(&world, playerTopLeft) && + isWorldPointEmpty(&world, playerTopRight) && + isWorldPointEmpty(&world, playerBottomLeft) && + isWorldPointEmpty(&world, playerBottomRight) + ) { + CanonicalPosition canPos = getCanonicalPosition(&world, playerPos); + + state->tileMapX = canPos.tileMapX; + state->tileMapY = canPos.tileMapY; + + state->playerX = world.upperLeftX + world.tileWidth*canPos.tileX + canPos.x; + state->playerY = world.upperLeftY + world.tileHeight*canPos.tileY + canPos.y; + } + } // clearscreen drawRectangle(videoBuf, 0.0f, 0.0f, (real32)videoBuf->width, (real32)videoBuf->height, 1.0f, 0.0f, 1.0f); - // tilemap - for (int row = 0; row < TILEMAP_HEIGHT; row++) { - for (int col = 0; col < TILEMAP_WIDTH; col++) { - uint32 tileID = tileMap[row][col]; - real32 fill = tileID == 1 ? 1.0f : 0.5f; - real32 minX = upperLeftX + ((real32)col)*tileWidth; - real32 minY = upperLeftY + ((real32)row)*tileHeight; - real32 maxX = minX + tileWidth; - real32 maxY = minY + tileHeight; + TileMap *currMap = getTileMap(&world, state->tileMapX, state->tileMapY); + for (int row = 0; row < world.tileCountY; row++) { + for (int col = 0; col < world.tileCountX; col++) { + real32 fill = getTileValueUnchecked(&world, currMap, col, row) == 1 ? 1.0f : 0.5f; + real32 minX = world.upperLeftX + ((real32)col)*world.tileWidth; + real32 minY = world.upperLeftY + ((real32)row)*world.tileHeight; + real32 maxX = minX + world.tileWidth; + real32 maxY = minY + world.tileHeight; drawRectangle(videoBuf, minX, minY, maxX, maxY, fill, fill, fill); } } - // player - real32 playerR = 1.0f; - real32 playerG = 0.5f; - real32 playerB = 0.0f; - real32 playerWidth = 25.0f; - real32 playerHeight = 40.0f; real32 playerLeft = state->playerX - 0.5f * playerWidth; - real32 playerTop = state->playerY - 0.5f * playerHeight; - - drawRectangle(videoBuf, playerLeft, playerTop, state->playerX + playerWidth, state->playerY + playerHeight, playerR, playerG, playerB); + real32 playerTop = state->playerY - playerHeight; + drawRectangle(videoBuf, playerLeft, playerTop, state->playerX + playerWidth*0.5f, state->playerY, playerR, playerG, playerB); } extern "C" GAME_GET_SOUND_SAMPLES(gameGetSoundSamples) { diff --git a/src/handmade.h b/src/handmade.h index 154e4e3..e31b11d 100644 --- a/src/handmade.h +++ b/src/handmade.h @@ -153,7 +153,52 @@ struct GameMemory { DebugPrintfFn *debug_printf; }; +struct TileMap { + uint32 *tiles; +}; + +struct CanonicalPosition { + // Which tilemap? + int32 tileMapX; + int32 tileMapY; + + // Which tile in tilemap? + int32 tileX; + int32 tileY; + + // Sub-tile position + real32 x; + real32 y; +}; + +struct RawPosition { + // Which tilemap? + int32 tileMapX; + int32 tileMapY; + + // Raw tilemap position + real32 x; + real32 y; +}; + +struct World { + int32 tileMapCountX; + int32 tileMapCountY; + + real32 upperLeftX; + real32 upperLeftY; + real32 tileWidth; + real32 tileHeight; + + int32 tileCountY; + int32 tileCountX; + + TileMap *tileMaps; +}; + struct GameState { + int32 tileMapX; + int32 tileMapY; real32 playerX; real32 playerY; }; diff --git a/src/win32_handmade.cpp b/src/win32_handmade.cpp index f1b14d3..54458c4 100644 --- a/src/win32_handmade.cpp +++ b/src/win32_handmade.cpp @@ -128,9 +128,18 @@ internal Win32WindowDimensions win32GetWindowDimensions(HWND window) { internal void win32DrawBufferInWindow(Win32OffscreenBuffer *buffer, HWND window) { Win32WindowDimensions winDims = win32GetWindowDimensions(window); - StretchDIBits( - GetDC(window), - 0, 0, winDims.width, winDims.height, + HDC dc = GetDC(window); + + int offsetX = 10; + int offsetY = 10; + + PatBlt(dc, 0, 0, winDims.width, offsetY, BLACKNESS); + PatBlt(dc, 0, offsetY + buffer->height, winDims.width, winDims.height, BLACKNESS); + PatBlt(dc, 0, 0, offsetX, winDims.height, BLACKNESS); + PatBlt(dc, offsetX + buffer->width, 0, winDims.width, winDims.height, BLACKNESS); + + StretchDIBits(dc, + offsetX, offsetY, buffer->width, buffer->height, 0, 0, buffer->width, buffer->height, buffer->memory, &buffer->info,