#include "engine/tilemap_draw.h" #include #include #include "engine/view2d.h" namespace { // Запас за краями кадра: спрайт, торчащий внутрь краем, обязан дорисоваться. // Считается по самому большому тайлу, а не по текущей проекции, — это верхняя // оценка, и лишние блиты по кромке дешевле мигающих стен. constexpr int MARGIN_X = TILE_MAX_W; constexpr int MARGIN_Y = WALL_H + TILE_MAX_H; bool OffScreen(int sx, int sy) { return sx < -MARGIN_X || sx > INTERNAL_W + MARGIN_X || sy < -MARGIN_Y || sy > INTERNAL_H + MARGIN_Y; } } // namespace void DrawTilemap(Framebuffer& fb, const Tilemap& map, const TileSet& tiles, int ox, int oy) { // Пол — сплошным проходом: он лежит ПОД всем, и сортировать его не с чем. for (int ty = 0; ty < MAP_H; ++ty) for (int tx = 0; tx < MAP_W; ++tx) { if (map.IsWall(tx, ty)) continue; // под стеной пола не видно const Vec2 c = v2d::WorldToScreen({float(tx) + 0.5f, float(ty) + 0.5f}); const int sx = int(std::lround(c.x)) + ox; const int sy = int(std::lround(c.y)) + oy; if (OffScreen(sx, sy)) continue; fb.Blit(tiles.Floor(tx, ty, map.ThemeAt(tx, ty)), sx, sy); } // Стены — по возрастанию глубины, и глубину считает ПРОЕКЦИЯ: в изометрии // это x+y, при виде сверху — строка экрана. Обход «по диагоналям x+y» // выглядел бы правильным и молча ломался при смене вида, поэтому порядок // не зашит в обход, а взят у v2d::Depth через общий список отрисовки. static std::vector items; items.clear(); for (int ty = 0; ty < MAP_H; ++ty) for (int tx = 0; tx < MAP_W; ++tx) { if (!map.IsWall(tx, ty)) continue; const Vec2 world{float(tx) + 0.5f, float(ty) + 0.5f}; const Vec2 c = v2d::WorldToScreen(world); const int sx = int(std::lround(c.x)) + ox; const int sy = int(std::lround(c.y)) + oy; if (OffScreen(sx, sy)) continue; v2d::DrawItem it; it.depth = v2d::Depth(world); it.spr = &tiles.Wall(tx, ty, map.ThemeAt(tx, ty)); it.x = sx; it.y = sy; items.push_back(it); } v2d::SortByDepth(items); v2d::FlushDrawList(fb, items); }