From 391e50ad7f912e1b27619e8785237c99bbf7cc69 Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 10 Aug 2025 14:08:57 +0200 Subject: [PATCH] add dice --- CMakeLists.txt | 1 + gfx/dice.h | 145 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 gfx/dice.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 20e5554..db7f8a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,4 +11,5 @@ target_include_directories(trnr-lib INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/oversampling ${CMAKE_CURRENT_SOURCE_DIR}/synth ${CMAKE_CURRENT_SOURCE_DIR}/util + ${CMAKE_CURRENT_SOURCE_DIR}/gfx ) diff --git a/gfx/dice.h b/gfx/dice.h new file mode 100644 index 0000000..f649866 --- /dev/null +++ b/gfx/dice.h @@ -0,0 +1,145 @@ +#pragma once +#include + +using namespace std; + +namespace trnr { +struct point { + float x; + float y; +}; + +struct rect { + float x; + float y; + float width; + float height; +}; + +struct quad { + point p1, p2, p3, p4; +}; + +struct dice { + int width; + int height; + array border_points; + array pips; + array segments_left; +}; + +inline void dice_init(dice& d, float width, float height) +{ + const float shortening = 0.866f; + + float face_height, dice_width; + face_height = dice_width = height / 2.f; + float mid_x = width / 2.f; + float face_half_height = face_height / 2.f; + float face_width = dice_width * shortening; + + // border points + point b_p1 = point {mid_x, 0}; + point b_p2 = point {mid_x + face_width, face_half_height}; + point b_p3 = point {mid_x + face_width, face_half_height + face_height}; + point b_p4 = point {mid_x, height}; + point b_p5 = point {mid_x - face_width, face_half_height + face_height}; + point b_p6 = point {mid_x - face_width, face_half_height}; + + d.border_points = {b_p1, b_p2, b_p3, b_p4, b_p5, b_p6}; + + const float padding = face_height * 0.09f; + const float pad_x = padding * shortening; + const float pad_y = padding; + const float padded_face_height = face_height - 2 * pad_y; + + const int segments = d.segments_left.size(); + // define the ratio between segments and gaps as 3:1 + const int segment_parts = 3; + const int gap_part = 1; + // the number of parts per segment + const int parts_per_segment = segment_parts + gap_part; + const int parts = segments * parts_per_segment - 2; // remove last gap + + const float segment_height = (padded_face_height / parts) * segment_parts; + const float gap_height = padded_face_height / parts; + + // calculate segments of the left face + for (int i = 0; i < d.segments_left.size(); i++) { + const point base_p1 = point {mid_x - face_width + pad_x, face_half_height + pad_y}; + const point base_p2 = point {mid_x - pad_x, face_height}; + float seg_y = i * (segment_height + gap_height); + point p1 = {base_p1.x, base_p1.y + seg_y}; + point p2 = {base_p2.x, base_p2.y + seg_y}; + point p3 = {base_p2.x, base_p2.y + seg_y + segment_height}; + point p4 = {base_p1.x, base_p1.y + seg_y + segment_height}; + d.segments_left[i] = {p1, p2, p3, p4}; + } + + // calculate pip positions for top face (30-degree isometric perspective) + // correct center of the diamond face + // the diamond spans from b_p1 (top) to the middle of the left face + float diamond_center_x = mid_x; + float diamond_center_y = face_half_height / 2.0f + face_half_height / 2.0f; // move down to actual center + + // for 30-degree isometric, the grid directions are: + float cos30 = 1.f; // cos(30°) = √3/2 ≈ 0.866 + float sin30 = 0.5f; // sin(30°) = 1/2 + + // scale the grid vectors to fit properly within the diamond + float grid_scale = 0.25f; // smaller scale to fit within diamond bounds + + // grid vector 1: 30 degrees from horizontal (toward top-left of diamond) + float grid1_x = -cos30 * face_width * grid_scale; + float grid1_y = -sin30 * face_height * grid_scale; + + // grid vector 2: -30 degrees from horizontal (toward top-right of diamond) + float grid2_x = cos30 * face_width * grid_scale; + float grid2_y = -sin30 * face_height * grid_scale; + + const float pip_h = face_height * 0.1f; + const float pip_w = pip_h * 2 * shortening; + + // position pips in the 30-degree isometric grid + for (int i = 0; i < 7; i++) { + float u = 0, v = 0; // grid coordinates + + switch (i) { + case 0: + u = 0; + v = 0; + break; // center + case 1: + u = -1; + v = 1; + break; // top-left + case 2: + u = 1; + v = -1; + break; // bottom-right + case 3: + u = 1; + v = 1; + break; // top-right + case 4: + u = -1; + v = -1; + break; // bottom-left + case 5: + u = -1; + v = 0; + break; // center-left + case 6: + u = 1; + v = 0; + break; // center-right + } + + // convert grid coordinates to world coordinates using 30-degree vectors + float pip_x = diamond_center_x + u * grid1_x + v * grid2_x; + float pip_y = diamond_center_y + u * grid1_y + v * grid2_y; + + d.pips[i] = {pip_x - pip_w / 2, pip_y - pip_h / 2, pip_w, pip_h}; + } +} +} // namespace trnr