// // Created by bruno on 4/24/25. // #include #include "tile.h" #include "../player/player.h" #include "furnace.h" #include "../util/atlas.h" int scrollFrame = 0; unsigned long beltFrames = 0; SDL_Texture *backgroundTexture; SDL_Texture *tilesTexture; SDL_Texture *itemsTexture; Tile tileMap[MAP_HEIGHT][MAP_WIDTH]; BackgroundTile backgroundMap[MAP_HEIGHT][MAP_WIDTH]; uint16_t tileTypeIndex = 0; uint16_t backgroundTileTypeIndex = 0; TileTypeReg TileRegistry[TILEREGISTRY_SIZE]; BackgroundTileType BackgroundTileRegistry[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 = 0; x < MAP_WIDTH; x += 1) { for (int y = 0; y < MAP_HEIGHT; y += 1) { tileMap[y][x].type = TYPE_BELT; tileMap[y][x].miscVal = 0; //tileMap[y][x].direction = ((x + y) % 4 * 2) + 1; //tileMap[y][x].direction = 5; tileMap[y][x].direction = (rand() % 4 * 2) + 1; } } uint8_t type = 0; for (int x = 142; x < 154; x += 3) { for (int y = 80; y < 94; y += 3) { putItem(x, y, type++ % ITEMREGISTRY_SIZE, 0); } } } 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); if (tileTypeIndex == 0) { SDL_SetTextureAlphaMod(TileRegistry[0].textures[ORIENT_LEFT], 64); SDL_SetTextureAlphaMod(TileRegistry[0].textures[ORIENT_RIGHT], 64); SDL_SetTextureAlphaMod(TileRegistry[0].textures[ORIENT_UP], 64); SDL_SetTextureAlphaMod(TileRegistry[0].textures[ORIENT_DOWN], 64); } SDL_SetTextureBlendMode(TileRegistry[tileTypeIndex].textures[ORIENT_LEFT], SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(TileRegistry[tileTypeIndex].textures[ORIENT_RIGHT], SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(TileRegistry[tileTypeIndex].textures[ORIENT_UP], SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(TileRegistry[tileTypeIndex].textures[ORIENT_DOWN], SDL_BLENDMODE_BLEND); TileRegistry[tileTypeIndex].atlasRects[ORIENT_LEFT] = allocate_32x32(TileRegistry[tileTypeIndex].textures[ORIENT_LEFT], renderer); TileRegistry[tileTypeIndex].atlasRects[ORIENT_RIGHT] = allocate_32x32(TileRegistry[tileTypeIndex].textures[ORIENT_RIGHT], renderer); TileRegistry[tileTypeIndex].atlasRects[ORIENT_UP] = allocate_32x32(TileRegistry[tileTypeIndex].textures[ORIENT_UP], renderer); TileRegistry[tileTypeIndex].atlasRects[ORIENT_DOWN] = allocate_32x32(TileRegistry[tileTypeIndex].textures[ORIENT_DOWN], renderer); TileRegistry[tileTypeIndex].type = tileTypeIndex; TileRegistry[tileTypeIndex].breakTime = 15; tileTypeIndex++; } void registerBackgroundTile(char name[20], SDL_Renderer *renderer) { const char *dot = strchr(name, '.'); memcpy(BackgroundTileRegistry[backgroundTileTypeIndex].name, name, dot - name); char texturePath[80]; snprintf(texturePath, 80, "./assets/backgrounds/%s", name); SDL_Texture *texture = IMG_LoadTexture(renderer, texturePath); BackgroundTileRegistry[backgroundTileTypeIndex].texture = texture; SDL_SetTextureBlendMode(BackgroundTileRegistry[backgroundTileTypeIndex].texture, SDL_BLENDMODE_NONE); BackgroundTileRegistry[backgroundTileTypeIndex].atlasRect = allocate_32x32(BackgroundTileRegistry[backgroundTileTypeIndex].texture, renderer); BackgroundTileRegistry[backgroundTileTypeIndex].type = backgroundTileTypeIndex; backgroundTileTypeIndex++; } void loadTiles(SDL_Renderer *renderer) { iterateSortedDir("./assets/tiles", (DirEntryCallback) registerTile, renderer); iterateSortedDir("./assets/backgrounds", (DirEntryCallback) registerBackgroundTile, renderer); } void setupTiles() { TileRegistry[TYPE_AIR].breakTime = 0; TileRegistry[TYPE_BELT].itemMoves = true; for (uint16_t i = 0; i < ItemSlotCount; i++) { TileRegistry[TYPE_BELT].outputLane[i] = true; } for (uint16_t l = 0; l < ItemSlotCount; l++) { for (ItemType i = 0; i < itemRegistryIndex; i++) { TileRegistry[TYPE_BELT].allowedInItems[l][i] = true; } } for (ItemType i = 0; i < itemRegistryIndex; i++) { if (FurnaceRecipes[i] != 0) { TileRegistry[TYPE_FURNACE].allowedInItems[FURNACE_INPUT_SLOT][i] = true; } } TileRegistry[TYPE_FURNACE].outputLane[FURNACE_OUTPUT_SLOT] = 1; } uint16_t getBreakTime(int type) { if (type >= tileTypeIndex) { return 0; } return TileRegistry[type].breakTime; } void initTiles() { itemsTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, screenRect.w, screenRect.h); tilesTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, screenRect.w, screenRect.h); backgroundTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, screenRect.w, screenRect.h); SDL_SetTextureBlendMode(itemsTexture, SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(tilesTexture, SDL_BLENDMODE_BLEND); } void renderAllTiles(SDL_Renderer *renderer, SDL_Rect playerRect) { SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); SDL_Texture *oldTarget = SDL_GetRenderTarget(renderer); int tileSize = TILE_SIZE; int minTileX = (playerRect.x / TILE_SIZE) - (DISPLAY_MAP_WIDTH / 2) - 1; int maxTileX = (playerRect.x / TILE_SIZE) + (DISPLAY_MAP_WIDTH / 2) + 1; int minTileY = (playerRect.y / TILE_SIZE) - (DISPLAY_MAP_HEIGHT / 2) - 1; int maxTileY = (playerRect.y / TILE_SIZE) + (DISPLAY_MAP_HEIGHT / 2) + 1; int scrollSpeed = 1; // pixels per step int scrollDelay = 1; // frames between steps if (beltFrames++ % scrollDelay == 0) { scrollFrame += scrollSpeed; } // --- Render background tiles --- SDL_SetRenderTarget(renderer, backgroundTexture); SDL_RenderClear(renderer); for (int y = minTileY; y < maxTileY; y++) { if (y < 0 || y >= MAP_HEIGHT) continue; for (int x = minTileX; x < maxTileX; x++) { if (x < 0 || x >= MAP_WIDTH) continue; SDL_Rect dstRect = { .x = x * TILE_SIZE, .y = y * TILE_SIZE, .w = TILE_SIZE, .h = TILE_SIZE }; adjustRect(&dstRect, playerRect); BackgroundTile bt = backgroundMap[y][x]; SDL_Texture *tex = BackgroundTileRegistry[bt.type].texture; if (tex != NULL) { SDL_RenderCopy(renderer, tex, NULL, &dstRect); } } } SDL_SetRenderTarget(renderer, tilesTexture); SDL_RenderClear(renderer); for (int y = minTileY; y < maxTileY; y++) { if (y < 0 || y >= MAP_HEIGHT) continue; for (int x = minTileX; x < maxTileX; x++) { if (x < 0 || x >= MAP_WIDTH) continue; SDL_Rect dstRect = { .x = x * TILE_SIZE, .y = y * TILE_SIZE, .w = TILE_SIZE, .h = TILE_SIZE }; adjustRect(&dstRect, playerRect); Tile t = tileMap[y][x]; switch (t.type) { case TYPE_BELT: renderBelt(x, y, tileSize, tileSize, t.direction, playerRect, renderer); break; default: { SDL_Texture *tex = TileRegistry[t.type].textures[t.direction]; if (tex == NULL) tex = TileRegistry[t.type].textures[ORIENT_LEFT]; if (tex != NULL) { SDL_RenderCopy(renderer, tex, NULL, &dstRect); } } } } } SDL_SetRenderTarget(renderer, itemsTexture); SDL_RenderClear(renderer); for (int y = minTileY; y < maxTileY; y++) { if (y < 0 || y >= MAP_HEIGHT) continue; for (int x = minTileX; x < maxTileX; x++) { if (x < 0 || x >= MAP_WIDTH) continue; Tile t = tileMap[y][x]; if (t.type == TYPE_BELT || itemViewing) { for (uint8_t lane = 0; lane < ItemSlotCount; lane++) { if (t.items[lane].type != 0) { renderItem(t.items[lane], renderer, lane, playerRect); } } } } } SDL_SetRenderTarget(renderer, oldTarget); } void updateTiles() { }