Preserve 16:9 tile aspect on resize

This commit is contained in:
Johanness
2026-05-19 00:37:12 +03:00
parent 52e9898701
commit 3df545e95c
3 changed files with 157 additions and 83 deletions
+98 -19
View File
@@ -21,45 +21,115 @@ std::vector<Vertex> makeQuad(
{{x0, y1}, {0.0f, 1.0f}}, {{x0, y1}, {0.0f, 1.0f}},
}; };
} }
float toNdcX(float x, float viewportWidth)
{
return x * 2.0f / viewportWidth - 1.0f;
} }
std::vector<Vertex> makeGridLayout( float toNdcY(float y, float viewportHeight)
{
return y * 2.0f / viewportHeight - 1.0f;
}
}
std::vector<TileRect> makeGridTileRects(
uint32_t cols, uint32_t cols,
uint32_t rows, uint32_t rows,
float gapX, float viewportWidth,
float gapY) float viewportHeight,
float gapPixels,
float targetAspect)
{ {
std::vector<Vertex> vertices; std::vector<TileRect> rects;
vertices.reserve( rects.reserve(static_cast<size_t>(cols) * rows);
static_cast<size_t>(cols) * rows * 6);
const float tileW = if (cols == 0 || rows == 0 ||
(2.0f - gapX * static_cast<float>(cols - 1)) / 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); static_cast<float>(cols);
const float tileH = const float cellH =
(2.0f - gapY * static_cast<float>(rows - 1)) / (viewportHeight - gapY * static_cast<float>(rows - 1)) /
static_cast<float>(rows); 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 row = 0; row < rows; ++row)
{ {
for (uint32_t col = 0; col < cols; ++col) for (uint32_t col = 0; col < cols; ++col)
{ {
const float x0 = const float x0 =
-1.0f + static_cast<float>(col) * (cellW + gapX) +
static_cast<float>(col) * (tileW + gapX); insetX;
const float y0 = const float y0 =
-1.0f + static_cast<float>(row) * (cellH + gapY) +
static_cast<float>(row) * (tileH + gapY); insetY;
const float x1 = x0 + tileW; const float x1 = x0 + tileW;
const float y1 = y0 + tileH; const float y1 = y0 + tileH;
auto quad = makeQuad(x0, y0, x1, y1); 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.insert(
vertices.end(), vertices.end(),
quad.begin(), quad.begin(),
quad.end()); quad.end());
} }
}
return vertices; return vertices;
} }
@@ -68,11 +138,20 @@ void updateGridLayout(
Vertex* vertices, Vertex* vertices,
uint32_t cols, uint32_t cols,
uint32_t rows, uint32_t rows,
float gapX, float viewportWidth,
float gapY) float viewportHeight,
float gapPixels,
float targetAspect)
{ {
std::vector<Vertex> updated = std::vector<Vertex> updated =
makeGridLayout(cols, rows, gapX, gapY); makeGridLayout(
cols,
rows,
viewportWidth,
viewportHeight,
gapPixels,
targetAspect
);
std::copy( std::copy(
updated.begin(), updated.begin(),
+24 -4
View File
@@ -9,18 +9,38 @@ struct Vertex
float uv[2]; float uv[2];
}; };
struct TileRect
{
float x0;
float y0;
float x1;
float y1;
};
std::vector<TileRect> makeGridTileRects(
uint32_t cols,
uint32_t rows,
float viewportWidth,
float viewportHeight,
float gapPixels,
float targetAspect);
std::vector<Vertex> makeGridLayout( std::vector<Vertex> makeGridLayout(
uint32_t cols, uint32_t cols,
uint32_t rows, uint32_t rows,
float gapX, float viewportWidth,
float gapY); float viewportHeight,
float gapPixels,
float targetAspect);
void updateGridLayout( void updateGridLayout(
Vertex* vertices, Vertex* vertices,
uint32_t cols, uint32_t cols,
uint32_t rows, uint32_t rows,
float gapX, float viewportWidth,
float gapY); float viewportHeight,
float gapPixels,
float targetAspect);
void updateUvForAspectRatio( void updateUvForAspectRatio(
Vertex* vertices, Vertex* vertices,
+32 -57
View File
@@ -37,6 +37,7 @@ constexpr uint32_t TEXTURE_WIDTH = 512;
constexpr uint32_t TEXTURE_HEIGHT = 288; constexpr uint32_t TEXTURE_HEIGHT = 288;
constexpr uint32_t VERTICES_PER_QUAD = 6; constexpr uint32_t VERTICES_PER_QUAD = 6;
constexpr float TILE_GAP_PIXELS = 8.0f; constexpr float TILE_GAP_PIXELS = 8.0f;
constexpr float TILE_ASPECT = 16.0f / 9.0f;
static std::atomic<bool> g_running{true}; static std::atomic<bool> g_running{true};
@@ -465,32 +466,23 @@ static void drawTileLabels(
ImDrawList* drawList = ImGui::GetForegroundDrawList(); ImDrawList* drawList = ImGui::GetForegroundDrawList();
const ImVec2 displaySize = ImGui::GetIO().DisplaySize; const ImVec2 displaySize = ImGui::GetIO().DisplaySize;
const float gapX = const std::vector<TileRect> tileRects =
std::min(TILE_GAP_PIXELS, displaySize.x * 0.1f); makeGridTileRects(
const float gapY = gridCols,
std::min(TILE_GAP_PIXELS, displaySize.y * 0.1f); gridRows,
const float tileW = displaySize.x,
(displaySize.x - displaySize.y,
gapX * static_cast<float>(gridCols - 1)) / TILE_GAP_PIXELS,
static_cast<float>(gridCols); TILE_ASPECT
const float tileH = );
(displaySize.y -
gapY * static_cast<float>(gridRows - 1)) /
static_cast<float>(gridRows);
const float labelH = const float labelH =
std::max(24.0f, ImGui::GetFontSize() + 10.0f); std::max(24.0f, ImGui::GetFontSize() + 10.0f);
for (uint32_t i = 0; i < feeds.size(); ++i) for (uint32_t i = 0;
i < feeds.size() && i < tileRects.size();
++i)
{ {
const uint32_t col = i % gridCols; const TileRect& tileRect = tileRects[i];
const uint32_t row = i / gridCols;
const float x0 =
static_cast<float>(col) * (tileW + gapX);
const float y0 =
static_cast<float>(row) * (tileH + gapY);
const float x1 = x0 + tileW;
const float y1 = y0 + tileH;
const FeedRuntimeStatus status = const FeedRuntimeStatus status =
feeds[i]->status(); feeds[i]->status();
@@ -503,9 +495,15 @@ static void drawTileLabels(
? feedRuntimeStatusDisplayName(status) ? feedRuntimeStatusDisplayName(status)
: sourceInfo); : sourceInfo);
const ImVec2 labelMin(x0, y1 - labelH); const ImVec2 labelMin(
const ImVec2 labelMax(x1, y1); tileRect.x0,
const ImVec2 textPos(x0 + 10.0f, y1 - labelH + 5.0f); tileRect.y1 - labelH
);
const ImVec2 labelMax(tileRect.x1, tileRect.y1);
const ImVec2 textPos(
tileRect.x0 + 10.0f,
tileRect.y1 - labelH + 5.0f
);
drawList->AddRectFilled( drawList->AddRectFilled(
labelMin, labelMin,
@@ -630,19 +628,14 @@ int main(int argc, char* argv[])
// Vertex buffer (quad tiles) // Vertex buffer (quad tiles)
// ---------------------------------------- // ----------------------------------------
const float initialGapX =
2.0f * TILE_GAP_PIXELS /
static_cast<float>(winWidth);
const float initialGapY =
2.0f * TILE_GAP_PIXELS /
static_cast<float>(winHeight);
std::vector<Vertex> quadVertices = std::vector<Vertex> quadVertices =
makeGridLayout( makeGridLayout(
config.gridCols, config.gridCols,
config.gridRows, config.gridRows,
initialGapX, static_cast<float>(winWidth),
initialGapY); static_cast<float>(winHeight),
TILE_GAP_PIXELS,
TILE_ASPECT);
VkDeviceSize vbSize = VkDeviceSize vbSize =
sizeof(quadVertices[0]) * quadVertices.size(); sizeof(quadVertices[0]) * quadVertices.size();
@@ -1680,34 +1673,16 @@ int main(int argc, char* argv[])
SDL_GetPerformanceCounter(); SDL_GetPerformanceCounter();
VkExtent2D swapExtent = swapchain.extent(); VkExtent2D swapExtent = swapchain.extent();
const float gapX =
2.0f * TILE_GAP_PIXELS /
static_cast<float>(swapExtent.width);
const float gapY =
2.0f * TILE_GAP_PIXELS /
static_cast<float>(swapExtent.height);
updateGridLayout( updateGridLayout(
quadVertices.data(), quadVertices.data(),
config.gridCols, config.gridCols,
config.gridRows, config.gridRows,
gapX, static_cast<float>(swapExtent.width),
gapY static_cast<float>(swapExtent.height),
TILE_GAP_PIXELS,
TILE_ASPECT
); );
const float tileWidthPx =
(static_cast<float>(swapExtent.width) -
TILE_GAP_PIXELS *
static_cast<float>(config.gridCols - 1)) /
static_cast<float>(config.gridCols);
const float tileHeightPx =
(static_cast<float>(swapExtent.height) -
TILE_GAP_PIXELS *
static_cast<float>(config.gridRows - 1)) /
static_cast<float>(config.gridRows);
const float tileAspect =
tileWidthPx / tileHeightPx;
for (uint32_t i = 0; i < feedCount; ++i) for (uint32_t i = 0; i < feedCount; ++i)
{ {
float srcAspect = feeds[i]->srcAspectRatio(); float srcAspect = feeds[i]->srcAspectRatio();
@@ -1716,7 +1691,7 @@ int main(int argc, char* argv[])
quadVertices.data(), quadVertices.data(),
i, i,
srcAspect, srcAspect,
tileAspect); TILE_ASPECT);
} }
std::memcpy( std::memcpy(