201 lines
4.4 KiB
C++
201 lines
4.4 KiB
C++
#include "TileLayout.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
namespace
|
|
{
|
|
std::vector<Vertex> 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<TileRect> makeGridTileRects(
|
|
uint32_t cols,
|
|
uint32_t rows,
|
|
float viewportWidth,
|
|
float viewportHeight,
|
|
float gapPixels,
|
|
float targetAspect)
|
|
{
|
|
std::vector<TileRect> rects;
|
|
rects.reserve(static_cast<size_t>(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<float>(cols - 1)) /
|
|
static_cast<float>(cols);
|
|
const float cellH =
|
|
(viewportHeight - gapY * static_cast<float>(rows - 1)) /
|
|
static_cast<float>(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<float>(col) * (cellW + gapX) +
|
|
insetX;
|
|
const float y0 =
|
|
static_cast<float>(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<Vertex> makeGridLayout(
|
|
uint32_t cols,
|
|
uint32_t rows,
|
|
float viewportWidth,
|
|
float viewportHeight,
|
|
float gapPixels,
|
|
float targetAspect)
|
|
{
|
|
std::vector<Vertex> vertices;
|
|
vertices.reserve(
|
|
static_cast<size_t>(cols) * rows * 6);
|
|
|
|
std::vector<TileRect> 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<Vertex> 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;
|
|
}
|