Files
mxl-multiviewer/TileLayout.cpp
2026-05-19 00:37:12 +03:00

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;
}