diff --git a/CMakeLists.txt b/CMakeLists.txt index 9519a38..5ea9c43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,28 @@ add_executable(factorygame util/font.h util/audio.c util/audio.h - main.c) # Ensure the target is defined before linking + util/util.c + util/util.h + items/item.c + items/item.h + tiles/tile.c + tiles/tile.h + tiles/belt.c + tiles/belt.h + main.c + player/player.c + player/player.h) # Ensure the target is defined before linking + +# Define the path to the assets folder +set(ASSETS_SOURCE_DIR "${CMAKE_SOURCE_DIR}/assets") +set(ASSETS_BINARY_DIR "${CMAKE_BINARY_DIR}/assets") + +# Copy assets directory after build +add_custom_command(TARGET factorygame POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + "${ASSETS_SOURCE_DIR}" "${ASSETS_BINARY_DIR}" + COMMENT "Copying assets directory to build output..." +) + target_link_libraries(factorygame SDL2 SDL2_ttf SDL2_image SDL2_gfx SDL2_mixer SDL2_net m) \ No newline at end of file diff --git a/assets/dopravnik.png b/assets/dopravnik.png deleted file mode 100644 index f4d4b20..0000000 Binary files a/assets/dopravnik.png and /dev/null differ diff --git a/assets/items/gold_ingot.png b/assets/items/gold_ingot.png new file mode 100644 index 0000000..e9bbb8d Binary files /dev/null and b/assets/items/gold_ingot.png differ diff --git a/assets/items/gold_ore.png b/assets/items/gold_ore.png new file mode 100644 index 0000000..540cec5 Binary files /dev/null and b/assets/items/gold_ore.png differ diff --git a/assets/items/iron_ingot.png b/assets/items/iron_ingot.png new file mode 100644 index 0000000..ea8eeda Binary files /dev/null and b/assets/items/iron_ingot.png differ diff --git a/assets/items/iron_ore.png b/assets/items/iron_ore.png new file mode 100644 index 0000000..2e9875a Binary files /dev/null and b/assets/items/iron_ore.png differ diff --git a/assets/items/log.png b/assets/items/log.png new file mode 100644 index 0000000..41aa21e Binary files /dev/null and b/assets/items/log.png differ diff --git a/assets/items/platinum_ingot.png b/assets/items/platinum_ingot.png new file mode 100644 index 0000000..975c49b Binary files /dev/null and b/assets/items/platinum_ingot.png differ diff --git a/assets/items/platinum_ore.png b/assets/items/platinum_ore.png new file mode 100644 index 0000000..f2022cd Binary files /dev/null and b/assets/items/platinum_ore.png differ diff --git a/assets/items/silver_ingot.png b/assets/items/silver_ingot.png new file mode 100644 index 0000000..9bd8d33 Binary files /dev/null and b/assets/items/silver_ingot.png differ diff --git a/assets/items/silver_ore.png b/assets/items/silver_ore.png new file mode 100644 index 0000000..a7adbc0 Binary files /dev/null and b/assets/items/silver_ore.png differ diff --git a/assets/tiles/dopravnik.png b/assets/tiles/dopravnik.png new file mode 100644 index 0000000..53c5dea Binary files /dev/null and b/assets/tiles/dopravnik.png differ diff --git a/items/item.c b/items/item.c new file mode 100644 index 0000000..262b280 --- /dev/null +++ b/items/item.c @@ -0,0 +1,127 @@ +// +// Created by bruno on 4/24/25. +// + +#include "item.h" +#include "../tiles/tile.h" +#include "../util/util.h" +#include "../player/player.h" +#include + +Item ItemRegistry[ITEMREGISTRY_SIZE]; + +uint16_t itemRegistryIndex = 0; + +void updateItems() { + for (int y = 0; y < MAP_HEIGHT; y++) { + for (int x = 0; x < MAP_WIDTH; x++) { + Tile *t = &tileMap[y][x]; + if (t->type != TYPE_BELT || !t->item.active) continue; + + if ( + (t->item.x < 0 && t->direction == ORIENT_LEFT) || + (t->item.x > 0.75f && t->direction == ORIENT_RIGHT) || + (t->item.y < 0.25f && t->direction == ORIENT_UP) || + (t->item.y > 0.625f && t->direction == ORIENT_DOWN) + ) { + int nx = x, ny = y; + if (t->direction == ORIENT_LEFT) nx--; + if (t->direction == ORIENT_RIGHT) nx++; + if (t->direction == ORIENT_UP) ny--; + if (t->direction == ORIENT_DOWN) ny++; + if (nx >= 0 && nx < MAP_WIDTH && ny >= 0 && ny < MAP_HEIGHT) { + Tile *next = &tileMap[ny][nx]; + if (next->type == TYPE_BELT && !next->item.active) { + memcpy(&next->item, &t->item, sizeof(ItemOnBelt)); + printf("Moved to X=%d, Y=%d", nx, ny); + next->item.tileX = nx; + next->item.tileY = ny; + if (t->direction == ORIENT_LEFT) next->item.x = 0.5f; + if (t->direction == ORIENT_RIGHT) next->item.x = 0.25f; + if (t->direction == ORIENT_UP) next->item.y = 0.5f; + if (t->direction == ORIENT_DOWN) next->item.y = 0; + next->item.active = true; + t->item.active = false; + } else { + continue; + } + } else { + t->item.active = false; + } + } + + float speed = 0.02f; + switch (t->direction) { + case ORIENT_LEFT: + t->item.x -= speed; + break; + case ORIENT_RIGHT: + t->item.x += speed; + break; + case ORIENT_UP: + t->item.y -= speed; + break; + case ORIENT_DOWN: + t->item.y += speed; + break; + default: + break; + } + } + } +} + +void registerItem(char name[20], SDL_Renderer *renderer) { + const char *dot = strchr(name, '.'); + memcpy(ItemRegistry[itemRegistryIndex].name, name, dot - name); + char texturePath[80]; + snprintf(texturePath, 80, "./assets/items/%s", name); + ItemRegistry[itemRegistryIndex].texture = IMG_LoadTexture(renderer, texturePath); + SDL_SetTextureBlendMode(ItemRegistry[itemRegistryIndex].texture, SDL_BLENDMODE_BLEND); + ItemRegistry[itemRegistryIndex].textureOnBelt = ScaleTexture(renderer, ItemRegistry[itemRegistryIndex].texture, + TILE_SIZE / 2, TILE_SIZE / 2); + SDL_SetTextureBlendMode(ItemRegistry[itemRegistryIndex].textureOnBelt, SDL_BLENDMODE_BLEND); + ItemRegistry[itemRegistryIndex].type = itemRegistryIndex; + + itemRegistryIndex++; +} + +void renderItem(ItemOnBelt item, SDL_Renderer *renderer) { + SDL_Rect rect = {0}; + rect.x = (item.tileX * TILE_SIZE) + (item.x * TILE_SIZE); + rect.y = (item.tileY * TILE_SIZE) + (item.y * TILE_SIZE); + rect.w = TILE_SIZE / 2; + rect.h = TILE_SIZE / 2; + adjustRect(&rect); + SDL_RenderCopy(renderer, ItemRegistry[item.type].textureOnBelt, NULL, &rect); +} + +void renderBeltItems(SDL_Renderer *renderer) { + +} + +void putItem(int x, int y, uint16_t itemType) { + tileMap[y][x].item.type = itemType; + tileMap[y][x].item.x = 0.25f; + tileMap[y][x].item.y = 0.25f; + if (tileMap[y][x].direction == ORIENT_LEFT) tileMap[y][x].item.x = 0.5f; + if (tileMap[y][x].direction == ORIENT_RIGHT) tileMap[y][x].item.x = 0.25f; + if (tileMap[y][x].direction == ORIENT_UP) tileMap[y][x].item.y = 0.5f; + if (tileMap[y][x].direction == ORIENT_DOWN) tileMap[y][x].item.y = 0.25f; + tileMap[y][x].item.active = true; + tileMap[y][x].item.tileX = x; + tileMap[y][x].item.tileY = y; +} + +void loadItems(SDL_Renderer *renderer) { + DIR *dir = opendir("./assets/items"); + if (dir) { + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) { + if (entry->d_name[0] == '.') { + continue; + } + registerItem(entry->d_name, renderer); + } + } +} \ No newline at end of file diff --git a/items/item.h b/items/item.h new file mode 100644 index 0000000..7f36d01 --- /dev/null +++ b/items/item.h @@ -0,0 +1,35 @@ +// +// Created by bruno on 4/24/25. +// + +#include + +#ifndef FACTORYGAME_ITEM_H +#define FACTORYGAME_ITEM_H + +typedef struct { + uint16_t type; + char name[20]; + SDL_Texture * texture; + SDL_Texture * textureOnBelt; +} Item; + +#define ITEMREGISTRY_SIZE 512 + +extern Item ItemRegistry[ITEMREGISTRY_SIZE]; + +typedef struct { + float x, y; // local position in tile (0.0–1.0) + int tileX, tileY; + bool active; + uint16_t type; +} ItemOnBelt; + +void updateItems(); + +void loadItems(SDL_Renderer *renderer); + +void renderItem(ItemOnBelt item, SDL_Renderer *renderer); + +void putItem(int x, int y, uint16_t itemType); +#endif //FACTORYGAME_ITEM_H diff --git a/main.c b/main.c index 91c7f06..05f59b6 100644 --- a/main.c +++ b/main.c @@ -3,42 +3,10 @@ #include #include "util/font.h" #include "util/audio.h" -#include - -#define MAP_WIDTH 64 -#define MAP_HEIGHT 36 - -#define TILE_SIZE 16 - -#define DISPLAY_WIDTH MAP_WIDTH * TILE_SIZE -#define DISPLAY_HEIGHT MAP_HEIGHT * TILE_SIZE - -typedef enum { - BELT_LEFT_DOWN, - BELT_LEFT, - BELT_LEFT_UP, - BELT_UP, - BELT_RIGHT_UP, - BELT_RIGHT, - BELT_RIGHT_DOWN, - BELT_DOWN -} BeltDirection; - -typedef struct { - float x, y; // local position in tile (0.0–1.0) - bool active; -} Item; - - - -typedef struct { - bool hasBelt; - BeltDirection direction; - int frameOffset; - Item item; -} Tile; - -Tile tileMap[MAP_HEIGHT][MAP_WIDTH]; +#include "tiles/tile.h" +#include "tiles/belt.h" +#include "items/item.h" +#include "player/player.h" //Screen dimension constants const int SCREEN_WIDTH = DISPLAY_WIDTH; @@ -63,9 +31,6 @@ BitmapFont fonts[fontCount]; unsigned long frames = 0; bool cursor = true; - -SDL_Texture *beltTex; - void msleep(unsigned int milliseconds) { struct timespec ts; ts.tv_sec = milliseconds / 1000; @@ -73,28 +38,10 @@ void msleep(unsigned int milliseconds) { nanosleep(&ts, NULL); } -void generateTestMap() { - for (int y = 0; y < MAP_HEIGHT; y++) { - for (int x = 0; x < MAP_WIDTH; x++) { - tileMap[y][x] = (Tile){0}; - } - } - - for (int x = 5; x < 5 + (4*2); x+=2) { - tileMap[10][x].hasBelt = true; - tileMap[10][x].frameOffset = 0; - } - tileMap[10][5].direction = BELT_LEFT; - tileMap[10][7].direction = BELT_RIGHT; - tileMap[10][9].direction = BELT_UP; - tileMap[10][11].direction = BELT_DOWN; - - tileMap[10][5].item = (Item){.x = 0.5f, .y = 0.5f, .active = true}; -} - int init() { //Initialize SDL + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, NULL); SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1"); SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"); @@ -123,6 +70,8 @@ int init() { return 1; } + loadItems(renderer); + loadTiles(renderer); // Create OpenGL context SDL_GLContext glContext = SDL_GL_CreateContext(window); if (!glContext) { @@ -162,112 +111,12 @@ int init() { smallerFont = prepText(renderer, 8, "PublicPixel.ttf", 255, 255, 255, 255); SDL_RenderSetLogicalSize(renderer, SCREEN_WIDTH, SCREEN_HEIGHT); - beltTex = IMG_LoadTexture(renderer, "../assets/dopravnik.png"); - generateTestMap(); return 0; } -void updateItems() { - for (int y = 0; y < MAP_HEIGHT; y++) { - for (int x = 0; x < MAP_WIDTH; x++) { - Tile *t = &tileMap[y][x]; - if (!t->hasBelt || !t->item.active) continue; - - float speed = 0.05f; - switch (t->direction) { - case BELT_LEFT: t->item.x -= speed; break; - case BELT_RIGHT: t->item.x += speed; break; - case BELT_UP: t->item.y -= speed; break; - case BELT_DOWN: t->item.y += speed; break; - default: break; - } - - if (t->item.x < 0 || t->item.x > 1 || t->item.y < 0 || t->item.y > 1) { - int nx = x, ny = y; - if (t->direction == BELT_LEFT) nx--; - if (t->direction == BELT_RIGHT) nx++; - if (t->direction == BELT_UP) ny--; - if (t->direction == BELT_DOWN) ny++; - if (nx >= 0 && nx < MAP_WIDTH && ny >= 0 && ny < MAP_HEIGHT) { - Tile *next = &tileMap[ny][nx]; - if (next->hasBelt && next->direction == t->direction && !next->item.active) { - next->item = (Item){ .x = 0.5f, .y = 0.5f, .active = true }; - t->item.active = false; - } - } else { - t->item.active = false; - } - } - } - } -} -void renderBelt(SDL_Texture *tex, int x, int y, int w, int h, BeltDirection dir) { - int texW, texH; - SDL_QueryTexture(tex, NULL, NULL, &texW, &texH); - - static int scrollFrame = 0; - int scrollSpeed = 1; // pixels per step - int scrollDelay = 15; // frames between steps - - if (frames % scrollDelay == 0) { - scrollFrame += scrollSpeed; - } - - SDL_Rect src1, src2, dst1, dst2; - - if (dir == BELT_LEFT || dir == BELT_RIGHT) { - int offset = scrollFrame % texW; - - if (dir == BELT_LEFT) { - offset = texW - offset; // reverse scroll - } - - src1 = (SDL_Rect){offset, 0, texW - offset, texH}; - dst1 = (SDL_Rect){x, y, w - offset, h}; - - src2 = (SDL_Rect){0, 0, offset, texH}; - dst2 = (SDL_Rect){x + (w - offset), y, offset, h}; - - SDL_RenderCopy(renderer, tex, &src1, &dst1); - SDL_RenderCopy(renderer, tex, &src2, &dst2); - } else { - int offset = scrollFrame % texH; - - if (dir == BELT_UP) { - offset = texH - offset; // reverse scroll - } - - src1 = (SDL_Rect){0, offset, texW, texH - offset}; - dst1 = (SDL_Rect){x, y, w, h - offset}; - - src2 = (SDL_Rect){0, 0, texW, offset}; - dst2 = (SDL_Rect){x, y + (h - offset), w, offset}; - - SDL_RenderCopy(renderer, tex, &src1, &dst1); - SDL_RenderCopy(renderer, tex, &src2, &dst2); - } -} - - - - -void renderAllBelts() { - int tileSize = TILE_SIZE; - for (int y = 0; y < MAP_HEIGHT; y++) { - for (int x = 0; x < MAP_WIDTH; x++) { - Tile t = tileMap[y][x]; - if (!t.hasBelt) continue; - int px = x * tileSize; - int py = y * tileSize; - renderBelt(beltTex, px, py, tileSize, tileSize, t.direction); - } - } -} - - int render() { SDL_SetRenderDrawColor(renderer, 32, 32, 32, 255); SDL_RenderClear(renderer); @@ -278,7 +127,7 @@ int render() { rect2.w = 0; rect2.h = 0; - renderAllBelts(); + renderAllBelts(renderer); SDL_RenderPresent(renderer); @@ -331,6 +180,14 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[]) return status; } + uint8_t type = 0; + for (int x = 149; x < 152; x++) { + for(int y = 87; y < 90; y++) { + putItem(x, y, type++); + } + } + + //Hack to get window to stay up SDL_Event e; Uint64 start; @@ -358,7 +215,6 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[]) for (uint8_t i = 0; i < fontCount; i++) { destroyFont(&fonts[i]); } - puts(SDL_GetError()); if (renderer) SDL_DestroyRenderer(renderer); if (window) SDL_DestroyWindow(window); diff --git a/player/player.c b/player/player.c new file mode 100644 index 0000000..c4e22c8 --- /dev/null +++ b/player/player.c @@ -0,0 +1,48 @@ +// +// Created by bruno on 4/24/25. +// + +#include +#include "player.h" +#include "../tiles/tile.h" + +int playerX = (MAP_WIDTH / 2) * 16; +int playerY = (MAP_HEIGHT / 2) * 16; + +void adjustRect(SDL_Rect * rect) { + rect->x -= playerX; + rect->y -= playerY; + rect->x += DISPLAY_WIDTH / 2; + rect->y += DISPLAY_HEIGHT / 2; +} + +bool isInboundsTile(int x, int y) { + return (playerX / TILE_SIZE) - (DISPLAY_MAP_WIDTH / 2) < x && (playerY / TILE_SIZE) - (DISPLAY_MAP_HEIGHT / 2) < y && + (playerX / TILE_SIZE) + (DISPLAY_MAP_WIDTH / 2) > x && (playerX / TILE_SIZE) + (DISPLAY_MAP_WIDTH / 2) > y; +} + +bool isInbounds(int x, int y) { + return x > 0 && y > 0 && x < DISPLAY_WIDTH && y < DISPLAY_HEIGHT; +} + +bool isInboundsRect(SDL_Rect rect) { + if (isInbounds(rect.x, rect.y)) { + return true; + } + if (rect.x < 0) { + rect.x += rect.w; + } + if (rect.y < 0) { + rect.y += rect.h; + } + if (isInbounds(rect.x, rect.y)) { + return true; + } + if (rect.x > DISPLAY_WIDTH) { + rect.x -= rect.w; + } + if (rect.y > DISPLAY_HEIGHT) { + rect.y -= rect.h; + } + return isInbounds(rect.x, rect.y); +} \ No newline at end of file diff --git a/player/player.h b/player/player.h new file mode 100644 index 0000000..fdee410 --- /dev/null +++ b/player/player.h @@ -0,0 +1,16 @@ +// +// Created by bruno on 4/24/25. +// + +#ifndef FACTORYGAME_PLAYER_H +#define FACTORYGAME_PLAYER_H + +extern int playerX; +extern int playerY; + +bool isInbounds(int x, int y); +bool isInboundsRect(SDL_Rect rect); +bool isInboundsTile(int x, int y); +void adjustRect(SDL_Rect * rect); + +#endif //FACTORYGAME_PLAYER_H diff --git a/tiles/belt.c b/tiles/belt.c new file mode 100644 index 0000000..7ce317f --- /dev/null +++ b/tiles/belt.c @@ -0,0 +1,85 @@ +// +// Created by bruno on 4/24/25. +// + +#include "belt.h" + +#include "../util/util.h" +#include "tile.h" +#include "../player/player.h" + +static int scrollFrame = 0; +unsigned long beltFrames = 0; + + +void renderBelt(int x, int y, int w, int h, OrientDirection dir, SDL_Renderer * renderer) { + + int px = x * TILE_SIZE; + int py = y * TILE_SIZE; + + uint16_t tileType = tileMap[y][x].type; + + SDL_Rect src1, src2, dst1, dst2; + + if (dir == ORIENT_LEFT || dir == ORIENT_RIGHT) { + int offset = scrollFrame % TILE_SIZE; + + if (dir == ORIENT_RIGHT) { + offset = TILE_SIZE - offset; // reverse scroll + } + + src1 = (SDL_Rect) {offset, 0, TILE_SIZE - offset, TILE_SIZE}; + dst1 = (SDL_Rect) {px, py, (w - offset), h}; + + src2 = (SDL_Rect) {0, 0, offset, TILE_SIZE}; + dst2 = (SDL_Rect) {px + (w - offset), py, offset, h}; + + adjustRect(&dst1); + adjustRect(&dst2); + + SDL_RenderCopy(renderer, TileRegistry[tileType].textures[dir], &src1, &dst1); + SDL_RenderCopy(renderer, TileRegistry[tileType].textures[dir], &src2, &dst2); + } else { + int offset = scrollFrame % TILE_SIZE; + + if (dir == ORIENT_DOWN) { + offset = TILE_SIZE - offset; // reverse scroll + } + + src1 = (SDL_Rect) {0, offset, TILE_SIZE, TILE_SIZE - offset}; + dst1 = (SDL_Rect) {px, py, w, h - offset}; + + src2 = (SDL_Rect) {0, 0, TILE_SIZE, offset}; + dst2 = (SDL_Rect) {px, py + (h - offset), w, offset}; + + adjustRect(&dst1); + adjustRect(&dst2); + + + // Rotate to make the belt vertical + SDL_RenderCopy(renderer, TileRegistry[tileType].textures[dir], &src1, &dst1); + SDL_RenderCopy(renderer, TileRegistry[tileType].textures[dir], &src2, &dst2); + } +} + + +void renderAllBelts(SDL_Renderer * renderer) { + int scrollSpeed = 1; // pixels per step + int scrollDelay = 1; // frames between steps + + if (beltFrames++ % scrollDelay == 0) { + scrollFrame += scrollSpeed; + } + + int tileSize = TILE_SIZE; + for (int y = (playerY / TILE_SIZE) - (DISPLAY_MAP_HEIGHT / 2); y < (playerY / TILE_SIZE) + (DISPLAY_MAP_HEIGHT / 2); y++) { + for (int x = (playerX / TILE_SIZE) - (DISPLAY_MAP_WIDTH / 2); x < (playerX / TILE_SIZE) + (DISPLAY_MAP_WIDTH / 2); x++) { + Tile t = tileMap[y][x]; + if (t.type != TYPE_BELT) continue; + renderBelt(x, y, tileSize, tileSize, t.direction, renderer); + if (t.item.active) { + renderItem(t.item, renderer); + } + } + } +} \ No newline at end of file diff --git a/tiles/belt.h b/tiles/belt.h new file mode 100644 index 0000000..b0db68c --- /dev/null +++ b/tiles/belt.h @@ -0,0 +1,16 @@ +// +// Created by bruno on 4/24/25. +// + +#ifndef FACTORYGAME_BELT_H +#define FACTORYGAME_BELT_H +#include +#include +#include "tile.h" +#include "../util/util.h" + +void renderBelt(int px, int py, int w, int h, OrientDirection dir, SDL_Renderer * renderer); + +void renderAllBelts(SDL_Renderer * renderer); + +#endif //FACTORYGAME_BELT_H diff --git a/tiles/tile.c b/tiles/tile.c new file mode 100644 index 0000000..d339e3e --- /dev/null +++ b/tiles/tile.c @@ -0,0 +1,67 @@ +// +// Created by bruno on 4/24/25. +// + +#include +#include "tile.h" +#include "../player/player.h" +#include "../util/util.h" + +Tile tileMap[MAP_HEIGHT][MAP_WIDTH]; + +uint16_t tileTypeIndex = 0; + +TileType TileRegistry[TILEREGISTRY_SIZE]; + +void generateTestMap() { + for (int y = 0; y < DISPLAY_MAP_HEIGHT; y++) { + for (int x = 0; x < DISPLAY_MAP_WIDTH; x++) { + Tile tile = {0}; + tile.x = x; + tile.y = y; + tileMap[y][x] = tile; + } + } + + for (int x = (playerX / TILE_SIZE) - (DISPLAY_MAP_WIDTH / 2); + x < (playerX / TILE_SIZE) + (DISPLAY_MAP_WIDTH / 2); x += 1) { + for (int y = (playerY / TILE_SIZE) - (DISPLAY_MAP_HEIGHT / 2); + y < (playerY / TILE_SIZE) + (DISPLAY_MAP_HEIGHT / 2); y += 1) { + + tileMap[y][x].type = TYPE_BELT; + tileMap[y][x].frameOffset = 0; + //tileMap[y][x].direction = ((x + y) % 4 * 2) + 1; + tileMap[y][x].direction = 5; + } + } +} + + +void registerTile(char name[20], SDL_Renderer *renderer) { + const char *dot = strchr(name, '.'); + memcpy(TileRegistry[tileTypeIndex].name, name, dot - name); + char texturePath[80]; + snprintf(texturePath, 80, "./assets/tiles/%s", name); + SDL_Texture * texture = IMG_LoadTexture(renderer, texturePath); + TileRegistry[tileTypeIndex].textures[ORIENT_LEFT] = texture; + TileRegistry[tileTypeIndex].textures[ORIENT_RIGHT] = createFlippedTexture(renderer, texture, SDL_FLIP_HORIZONTAL); + TileRegistry[tileTypeIndex].textures[ORIENT_UP] = createRotatedTexture(renderer, texture, 90); + TileRegistry[tileTypeIndex].textures[ORIENT_DOWN] = createRotatedTexture(renderer, texture, 270); + TileRegistry[tileTypeIndex].type = tileTypeIndex; + + tileTypeIndex++; +} + + +void loadTiles(SDL_Renderer *renderer) { + DIR *dir = opendir("./assets/tiles"); + if (dir) { + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) { + if (entry->d_name[0] == '.') { + continue; + } + registerTile(entry->d_name, renderer); + } + } +} \ No newline at end of file diff --git a/tiles/tile.h b/tiles/tile.h new file mode 100644 index 0000000..dc50e5f --- /dev/null +++ b/tiles/tile.h @@ -0,0 +1,49 @@ +// +// Created by bruno on 4/24/25. +// + +#ifndef FACTORYGAME_TILE_H +#define FACTORYGAME_TILE_H + +#include "belt.h" +#include "../items/item.h" +#include "../util/util.h" + +#define MAP_WIDTH 600 +#define MAP_HEIGHT 340 + +#define DISPLAY_MAP_WIDTH 30 +#define DISPLAY_MAP_HEIGHT 16 + +#define TILE_SIZE 32 + +#define DISPLAY_WIDTH DISPLAY_MAP_WIDTH * TILE_SIZE +#define DISPLAY_HEIGHT DISPLAY_MAP_HEIGHT * TILE_SIZE + +typedef struct { + uint16_t type; + char name[20]; + SDL_Texture *textures[ORIENT_DIRECTION_COUNT]; +} TileType; + +#define TILEREGISTRY_SIZE 512 + +extern TileType TileRegistry[TILEREGISTRY_SIZE]; + +#define TYPE_BELT 0 + +typedef struct { + OrientDirection direction; + uint16_t type; + int frameOffset; + ItemOnBelt item; + int x; + int y; +} Tile; + +extern Tile tileMap[MAP_HEIGHT][MAP_WIDTH]; + +void generateTestMap(); +void loadTiles(SDL_Renderer *renderer); + +#endif //FACTORYGAME_TILE_H diff --git a/util/util.c b/util/util.c new file mode 100644 index 0000000..51234ed --- /dev/null +++ b/util/util.c @@ -0,0 +1,55 @@ +// +// Created by bruno on 4/24/25. +// + +#include "util.h" +SDL_Texture* createFlippedTexture(SDL_Renderer* renderer, SDL_Texture* src, SDL_RendererFlip flip) { + int w, h; + SDL_QueryTexture(src, NULL, NULL, &w, &h); + + SDL_Texture* target = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, w, h); + SDL_SetRenderTarget(renderer, target); + SDL_RenderCopyEx(renderer, src, NULL, NULL, 0, NULL, flip); + SDL_SetRenderTarget(renderer, NULL); + + return target; +} + +SDL_Texture* createRotatedTexture(SDL_Renderer* renderer, SDL_Texture* src, double angle) { + int w, h; + SDL_QueryTexture(src, NULL, NULL, &w, &h); + + SDL_Texture* target = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, w, h); + SDL_SetRenderTarget(renderer, target); + SDL_RenderCopyEx(renderer, src, NULL, NULL, angle, NULL, SDL_FLIP_NONE); + SDL_SetRenderTarget(renderer, NULL); + + return target; +} + +SDL_Texture* ScaleTexture(SDL_Renderer* renderer, SDL_Texture* src, int newWidth, int newHeight) { + SDL_Texture* scaledTex = SDL_CreateTexture(renderer, + SDL_PIXELFORMAT_RGBA8888, + SDL_TEXTUREACCESS_TARGET, + newWidth, + newHeight); + + if (!scaledTex) { + SDL_Log("Failed to create target texture: %s", SDL_GetError()); + return nullptr; + } + + // Save current render target + SDL_Texture* oldTarget = SDL_GetRenderTarget(renderer); + + SDL_SetRenderTarget(renderer, scaledTex); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); + SDL_RenderClear(renderer); + + SDL_Rect dst = { 0, 0, newWidth, newHeight }; + SDL_RenderCopy(renderer, src, NULL, &dst); + + SDL_SetRenderTarget(renderer, oldTarget); // Restore + + return scaledTex; +} diff --git a/util/util.h b/util/util.h new file mode 100644 index 0000000..7677579 --- /dev/null +++ b/util/util.h @@ -0,0 +1,28 @@ +// +// Created by bruno on 4/24/25. +// + +#ifndef FACTORYGAME_UTIL_H +#define FACTORYGAME_UTIL_H + +#include + +typedef enum { + ORIENT_LEFT_DOWN, + ORIENT_LEFT, + ORIENT_LEFT_UP, + ORIENT_UP, + ORIENT_RIGHT_UP, + ORIENT_RIGHT, + ORIENT_RIGHT_DOWN, + ORIENT_DOWN, + ORIENT_DIRECTION_COUNT +} OrientDirection; + +SDL_Texture *createRotatedTexture(SDL_Renderer *renderer, SDL_Texture *src, double angle); + +SDL_Texture *createFlippedTexture(SDL_Renderer *renderer, SDL_Texture *src, SDL_RendererFlip flip); + +SDL_Texture* ScaleTexture(SDL_Renderer* renderer, SDL_Texture* src, int newWidth, int newHeight); + +#endif //FACTORYGAME_UTIL_H