Add simplified grid and flex layout calculation
This commit is contained in:
@@ -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
|
||||
|
||||
152
game/ui.c
Normal file
152
game/ui.c
Normal file
@@ -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);
|
||||
}
|
||||
49
game/ui.h
Normal file
49
game/ui.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifndef PIXELDEFENSE_UI_H
|
||||
#define PIXELDEFENSE_UI_H
|
||||
|
||||
#include <breeze.h>
|
||||
#include <raygui.h>
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user