Preserve 16:9 tile aspect on resize
This commit is contained in:
+101
-22
@@ -21,46 +21,116 @@ 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});
|
||||||
vertices.insert(
|
|
||||||
vertices.end(),
|
|
||||||
quad.begin(),
|
|
||||||
quad.end());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
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
@@ -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,
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
Reference in New Issue
Block a user