This commit is contained in:
2025-08-10 14:08:57 +02:00
parent d55490d7d1
commit 391e50ad7f
2 changed files with 146 additions and 0 deletions

View File

@@ -11,4 +11,5 @@ target_include_directories(trnr-lib INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/oversampling ${CMAKE_CURRENT_SOURCE_DIR}/oversampling
${CMAKE_CURRENT_SOURCE_DIR}/synth ${CMAKE_CURRENT_SOURCE_DIR}/synth
${CMAKE_CURRENT_SOURCE_DIR}/util ${CMAKE_CURRENT_SOURCE_DIR}/util
${CMAKE_CURRENT_SOURCE_DIR}/gfx
) )

145
gfx/dice.h Normal file
View File

@@ -0,0 +1,145 @@
#pragma once
#include <array>
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<point, 6> border_points;
array<rect, 7> pips;
array<quad, 6> 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