From ebda550bf29bfd4892f1cb9d8079f003f0d03aec Mon Sep 17 00:00:00 2001 From: Klemen Plestenjak Date: Tue, 19 Dec 2023 14:40:11 +0100 Subject: [PATCH] Add simplified grid and flex layout calculation --- CMakeLists.txt | 2 + game/ui.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++ game/ui.h | 49 ++++++++++++++++ 3 files changed, 203 insertions(+) create mode 100644 game/ui.c create mode 100644 game/ui.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ab09fb0..4e69c4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,8 @@ add_executable(PixelDefense game/systems_entity.c game/systems_input.c game/systems_ui.c + game/ui.c + game/ui.h game/unit_actions.c game/unit_actions.h game/unit_ai.c diff --git a/game/ui.c b/game/ui.c new file mode 100644 index 0000000..045c499 --- /dev/null +++ b/game/ui.c @@ -0,0 +1,152 @@ +#include "ui.h" + +UIGrid uiGridFromRoot(i32 width, i32 height) { + return (UIGrid) {.bounds = {0, 0, width, height}}; +} +UIGrid uiGridFromGrid(const UIGrid grid, i32 row, i32 col) { + return uiGridFromGridSpan(grid, row, col, 1, 1); +} +UIGrid uiGridFromGridSpan(const UIGrid grid, i32 row, i32 col, i32 rowSpan, i32 colSpan) { + Rectangle bounds = uiGridCellSpan(grid, row, col, rowSpan, colSpan); + return (UIGrid) { + .rowPadding = grid.rowPadding, + .cellPadding = grid.cellPadding, + .bounds = bounds + }; +} + +Rectangle uiGridCell(const UIGrid grid, i32 row, i32 col) { + return uiGridCellSpan(grid, row, col, 1, 1); +} +Rectangle uiGridCellSpan(const UIGrid grid, i32 row, i32 col, i32 rowSpan, i32 colSpan) { + BZ_ASSERT(grid.rows > 0 && grid.cols > 0); + BZ_ASSERT(rowSpan > 0 && colSpan > 0); + BZ_ASSERT(row >= 0 && col >= 0); + BZ_ASSERT(row + rowSpan <= grid.rows); + BZ_ASSERT(col + colSpan <= grid.cols); + + f32 cellWidth = (grid.bounds.width - (grid.cols - 1) * grid.cellPadding) / grid.cols; + f32 cellHeight = (grid.bounds.height - (grid.rows - 1) * grid.rowPadding) / grid.rows; + + Rectangle cellBounds = { + .width = cellWidth * colSpan, + .height = cellHeight * rowSpan, + .x = (cellWidth + grid.cellPadding) * col, + .y = (cellHeight + grid.rowPadding) * row, + }; + return cellBounds; +} + +void uiGridDrawCells(const UIGrid grid) { + BZ_ASSERT(grid.rows > 0 && grid.cols > 0); + DrawRectangleLines(grid.bounds.x, grid.bounds.y, grid.bounds.width, grid.bounds.height, RED); + + for (i32 rowIdx = 0; rowIdx < grid.rows; rowIdx++) { + for (i32 colIdx = 0; colIdx < grid.cols; colIdx++) { + Rectangle rec = uiGridCell(grid, rowIdx, colIdx); + DrawRectangleLines(rec.x, rec.y, rec.width, rec.height, BLUE); + } + } + +} + +static f32 getX(const Rectangle rec) { + return rec.x; +} +static f32 getY(const Rectangle rec) { + return rec.y; +} +static f32 getWidth(const Rectangle rec) { + return rec.width; +} +static f32 getHeight(const Rectangle rec) { + return rec.height; +} + +typedef f32 (*FlexBoxGetFunc)(const Rectangle rec); + +void uiFlexBoxCalc(const FlexBoxDesc *desc, i32 numElements, ...) { + if (numElements <= 0) return; + f32 totalWidth = 0; + f32 totalHeight = 0; + + UIFlexBoxFlag flags = desc->flags; + + // Calculate total size of elements in the main axis + va_list ap; + va_start(ap, numElements); + for (i32 i = 0; i < numElements; i++) { + const Rectangle *rec = va_arg(ap, Rectangle *); + totalWidth += rec->width; + totalHeight += rec->height; + } + va_end(ap); + + // Default: DIR_ROW + FlexBoxGetFunc axisX = getX, axisY = getY, axisWidth = getWidth, axisHeight = getHeight; + FlexBoxGetFunc crossX = getY, crossY = getX, crossWidth = getHeight, crossHeight = getWidth; + f32 mainAxisSize = totalWidth; + if (flags & UI_FLEX_DIR_COLUMN) { + axisX = getY; + axisY = getX; + axisWidth = getHeight; + axisHeight = getWidth; + crossX = getX; + crossY = getY; + crossWidth = getWidth; + crossHeight = getHeight; + mainAxisSize = totalHeight; + } + + + f32 spacingWidth = 0.0f; + f32 spacingHeight = 0.0f; + + f32 mainAxisTotalSpacing = getWidth(desc->window) - mainAxisSize; + f32 mainAxisPadding = desc->padding * (numElements - 1); + + f32 mainAxisSpacing = mainAxisTotalSpacing - mainAxisPadding; + if (mainAxisSpacing < 0) mainAxisSpacing = 0; + + // Default: JUSTIFY_START + f32 mainAxisOffset = 0; + if (flags & UI_FLEX_JUSTIFY_CENTER) { + mainAxisOffset = mainAxisSpacing * 0.5f; + } else if (flags & UI_FLEX_JUSTIFY_END) { + mainAxisOffset = mainAxisSpacing; + } + + bool rowDir = flags & UI_FLEX_DIR_ROW; + + f32 offsetX = desc->window.x; + f32 offsetY = desc->window.y; + if (rowDir) offsetX += mainAxisOffset; + else offsetY += mainAxisOffset; + + va_start(ap, numElements); + for (i32 i = 0; i < numElements; i++) { + f32 x = offsetX; + f32 y = offsetY; + + Rectangle *rec = va_arg(ap, Rectangle *); + f32 crossOffset = 0; + if (flags & UI_FLEX_ALIGN_CENTER) { + crossOffset = (getHeight(desc->window) - getHeight(*rec)) * 0.5f; + } else if (flags & UI_FLEX_ALIGN_END) { + crossOffset = (getHeight(desc->window) - getHeight(*rec)); + } + if (rowDir) { + offsetX += rec->width + spacingWidth + desc->padding; + y += crossOffset; + } else { + offsetY += rec->height + spacingHeight + desc->padding; + x += crossOffset; + } + + + rec->x = x; + rec->y = y; + + } + va_end(ap); +} diff --git a/game/ui.h b/game/ui.h new file mode 100644 index 0000000..d417fa9 --- /dev/null +++ b/game/ui.h @@ -0,0 +1,49 @@ +#ifndef PIXELDEFENSE_UI_H +#define PIXELDEFENSE_UI_H + +#include +#include + +typedef struct UIGrid { + i32 rows; + i32 cols; + f32 rowPadding; + f32 cellPadding; + Rectangle bounds; +} UIGrid; + +UIGrid uiGridFromRoot(i32 width, i32 height); +UIGrid uiGridFromGrid(const UIGrid grid, i32 row, i32 col); +UIGrid uiGridFromGridSpan(const UIGrid grid, i32 row, i32 col, i32 rowSpan, i32 colSpan); + +Rectangle uiGridCell(const UIGrid grid, i32 row, i32 col); +Rectangle uiGridCellSpan(const UIGrid grid, i32 row, i32 col, i32 rowSpan, i32 colSpan); + +void uiGridDrawCells(const UIGrid grid); + +typedef enum UIFlexBoxFlag { + UI_FLEX_NONE = 0, + UI_FLEX_DIR_ROW = 0b1, + UI_FLEX_DIR_COLUMN = 0b10, + UI_FLEX_ALIGN_START = 0b100, + UI_FLEX_ALIGN_CENTER = 0b1000, + UI_FLEX_ALIGN_END = 0b10000, + UI_FLEX_JUSTIFY_START = 0b100000, + UI_FLEX_JUSTIFY_CENTER = 0b1000000, + UI_FLEX_JUSTIFY_END = 0b10000000, +} UIFlexBoxFlag; + +typedef struct FlexBoxDesc { + Rectangle window; + UIFlexBoxFlag flags; + f32 padding; +} FlexBoxDesc; + +void uiFlexBoxCalc(const FlexBoxDesc *desc, i32 numElements, ...); + +static f32 uiScale() { + return GetScreenHeight() / 720.0f; +} + + +#endif //PIXELDEFENSE_UI_H