#include "TileLayout.hpp" #include #include namespace { std::vector makeQuad( float x0, float y0, float x1, float y1) { return { {{x0, y0}, {0.0f, 0.0f}}, {{x1, y0}, {1.0f, 0.0f}}, {{x1, y1}, {1.0f, 1.0f}}, {{x0, y0}, {0.0f, 0.0f}}, {{x1, y1}, {1.0f, 1.0f}}, {{x0, y1}, {0.0f, 1.0f}}, }; } float toNdcX(float x, float viewportWidth) { return x * 2.0f / viewportWidth - 1.0f; } float toNdcY(float y, float viewportHeight) { return y * 2.0f / viewportHeight - 1.0f; } } std::vector makeGridTileRects( uint32_t cols, uint32_t rows, float viewportWidth, float viewportHeight, float gapPixels, float targetAspect) { std::vector rects; rects.reserve(static_cast(cols) * rows); if (cols == 0 || rows == 0 || viewportWidth <= 0.0f || viewportHeight <= 0.0f || targetAspect <= 0.0f) { return rects; } const float gapX = std::min(gapPixels, viewportWidth * 0.1f); const float gapY = std::min(gapPixels, viewportHeight * 0.1f); const float cellW = (viewportWidth - gapX * static_cast(cols - 1)) / static_cast(cols); const float cellH = (viewportHeight - gapY * static_cast(rows - 1)) / static_cast(rows); float tileW = cellW; float tileH = tileW / targetAspect; if (tileH > cellH) { tileH = cellH; tileW = tileH * targetAspect; } const float insetX = (cellW - tileW) * 0.5f; const float insetY = (cellH - tileH) * 0.5f; for (uint32_t row = 0; row < rows; ++row) { for (uint32_t col = 0; col < cols; ++col) { const float x0 = static_cast(col) * (cellW + gapX) + insetX; const float y0 = static_cast(row) * (cellH + gapY) + insetY; const float x1 = x0 + tileW; const float y1 = y0 + tileH; rects.push_back({x0, y0, x1, y1}); } } return rects; } std::vector makeGridLayout( uint32_t cols, uint32_t rows, float viewportWidth, float viewportHeight, float gapPixels, float targetAspect) { std::vector vertices; vertices.reserve( static_cast(cols) * rows * 6); std::vector rects = makeGridTileRects( cols, rows, viewportWidth, viewportHeight, gapPixels, targetAspect ); for (const TileRect& rect : rects) { auto quad = makeQuad( toNdcX(rect.x0, viewportWidth), toNdcY(rect.y0, viewportHeight), toNdcX(rect.x1, viewportWidth), toNdcY(rect.y1, viewportHeight) ); vertices.insert( vertices.end(), quad.begin(), quad.end()); } return vertices; } void updateGridLayout( Vertex* vertices, uint32_t cols, uint32_t rows, float viewportWidth, float viewportHeight, float gapPixels, float targetAspect) { std::vector updated = makeGridLayout( cols, rows, viewportWidth, viewportHeight, gapPixels, targetAspect ); std::copy( updated.begin(), updated.end(), vertices ); } void updateUvForAspectRatio( Vertex* vertices, uint32_t quadIndex, float srcAspect, float tileAspect) { Vertex* quad = vertices + quadIndex * 6; float uMin = 0.0f; float uMax = 1.0f; float vMin = 0.0f; float vMax = 1.0f; if (srcAspect > tileAspect) { float scale = tileAspect / srcAspect; float bar = (1.0f - scale) * 0.5f; vMin = bar; vMax = 1.0f - bar; } else if (srcAspect < tileAspect) { float scale = srcAspect / tileAspect; float bar = (1.0f - scale) * 0.5f; uMin = bar; uMax = 1.0f - bar; } // Triangle 1: vertices 0-2 quad[0].uv[0] = uMin; quad[0].uv[1] = vMin; quad[1].uv[0] = uMax; quad[1].uv[1] = vMin; quad[2].uv[0] = uMax; quad[2].uv[1] = vMax; // Triangle 2: vertices 3-5 quad[3].uv[0] = uMin; quad[3].uv[1] = vMin; quad[4].uv[0] = uMax; quad[4].uv[1] = vMax; quad[5].uv[0] = uMin; quad[5].uv[1] = vMax; }