Files
dusk/src/dusk/display/mesh/capsule.c
T
2026-04-14 14:29:48 -05:00

185 lines
6.0 KiB
C

/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "capsule.h"
#include "assert/assert.h"
mesh_t CAPSULE_MESH_SIMPLE;
meshvertex_t CAPSULE_MESH_SIMPLE_VERTICES[CAPSULE_VERTEX_COUNT];
errorret_t capsuleInit() {
vec3 center = { 0.0f, 0.0f, 0.0f };
capsuleBuffer(
CAPSULE_MESH_SIMPLE_VERTICES,
center,
0.5f,
0.5f,
CAPSULE_CAP_RINGS,
CAPSULE_SECTORS
#if MESH_ENABLE_COLOR
, COLOR_WHITE_4B
#endif
);
errorChain(meshInit(
&CAPSULE_MESH_SIMPLE,
CAPSULE_PRIMITIVE_TYPE,
CAPSULE_VERTEX_COUNT,
CAPSULE_MESH_SIMPLE_VERTICES
));
errorOk();
}
void capsuleBuffer(
meshvertex_t *vertices,
const vec3 center,
const float_t radius,
const float_t halfHeight,
const int32_t capRings,
const int32_t sectors
#if MESH_ENABLE_COLOR
, const color_t color
#endif
) {
assertNotNull(vertices, "Vertices cannot be NULL");
assertNotNull(center, "Center vector cannot be NULL");
const float_t cx = center[0];
const float_t cy = center[1];
const float_t cz = center[2];
const float_t sectorStep = 2.0f * (float_t)GLM_PI / (float_t)sectors;
int32_t vi = 0;
/* Helper macro: write one vertex. */
#if MESH_ENABLE_COLOR
#define CAP_VERT(px, py, pz, u, v) \
vertices[vi].color = color; \
vertices[vi].pos[0] = (px); \
vertices[vi].pos[1] = (py); \
vertices[vi].pos[2] = (pz); \
vertices[vi].uv[0] = (u); \
vertices[vi].uv[1] = (v); \
vi++;
#else
#define CAP_VERT(px, py, pz, u, v) \
vertices[vi].pos[0] = (px); \
vertices[vi].pos[1] = (py); \
vertices[vi].pos[2] = (pz); \
vertices[vi].uv[0] = (u); \
vertices[vi].uv[1] = (v); \
vi++;
#endif
/* ---- Top hemisphere ---- */
/* phi ranges from PI/2 (top pole) down to 0 (equator). */
const float_t capStep = (float_t)GLM_PI_2 / (float_t)capRings;
for(int32_t i = 0; i < capRings; i++) {
const float_t phi1 = (float_t)GLM_PI_2 - (float_t)i * capStep;
const float_t phi2 = (float_t)GLM_PI_2 - (float_t)(i + 1) * capStep;
const float_t ly1 = radius * sinf(phi1);
const float_t ly2 = radius * sinf(phi2);
const float_t lxz1 = radius * cosf(phi1);
const float_t lxz2 = radius * cosf(phi2);
/* UV: top cap occupies v in [0.5 + halfHeightFrac .. 1.0]: we use a
* simple per-band normalisation against the full height. */
const float_t v1 = 1.0f - (float_t)i / (float_t)(2 * capRings + 1);
const float_t v2 = 1.0f - (float_t)(i + 1) / (float_t)(2 * capRings + 1);
for(int32_t j = 0; j < sectors; j++) {
const float_t t1 = (float_t)j * sectorStep;
const float_t t2 = (float_t)(j + 1) * sectorStep;
const float_t u1 = (float_t)j / (float_t)sectors;
const float_t u2 = (float_t)(j + 1) / (float_t)sectors;
const float_t x11 = lxz1 * cosf(t1), z11 = lxz1 * sinf(t1);
const float_t x12 = lxz1 * cosf(t2), z12 = lxz1 * sinf(t2);
const float_t x21 = lxz2 * cosf(t1), z21 = lxz2 * sinf(t1);
const float_t x22 = lxz2 * cosf(t2), z22 = lxz2 * sinf(t2);
const float_t y1off = cy + halfHeight + ly1;
const float_t y2off = cy + halfHeight + ly2;
CAP_VERT(cx+x11, y1off, cz+z11, u1, v1)
CAP_VERT(cx+x21, y2off, cz+z21, u1, v2)
CAP_VERT(cx+x12, y1off, cz+z12, u2, v1)
CAP_VERT(cx+x12, y1off, cz+z12, u2, v1)
CAP_VERT(cx+x21, y2off, cz+z21, u1, v2)
CAP_VERT(cx+x22, y2off, cz+z22, u2, v2)
}
}
/* ---- Cylindrical body ---- */
{
const float_t yTop = cy + halfHeight;
const float_t yBot = cy - halfHeight;
const float_t vTop = 1.0f - (float_t)capRings / (float_t)(2 * capRings + 1);
const float_t vBot = 1.0f - (float_t)(capRings + 1) / (float_t)(2 * capRings + 1);
for(int32_t j = 0; j < sectors; j++) {
const float_t t1 = (float_t)j * sectorStep;
const float_t t2 = (float_t)(j + 1) * sectorStep;
const float_t u1 = (float_t)j / (float_t)sectors;
const float_t u2 = (float_t)(j + 1) / (float_t)sectors;
const float_t x1 = radius * cosf(t1), z1 = radius * sinf(t1);
const float_t x2 = radius * cosf(t2), z2 = radius * sinf(t2);
CAP_VERT(cx+x1, yTop, cz+z1, u1, vTop)
CAP_VERT(cx+x1, yBot, cz+z1, u1, vBot)
CAP_VERT(cx+x2, yTop, cz+z2, u2, vTop)
CAP_VERT(cx+x2, yTop, cz+z2, u2, vTop)
CAP_VERT(cx+x1, yBot, cz+z1, u1, vBot)
CAP_VERT(cx+x2, yBot, cz+z2, u2, vBot)
}
}
// Bottom hemisphere
for(int32_t i = 0; i < capRings; i++) {
const float_t phi1 = -(float_t)i * capStep;
const float_t phi2 = -(float_t)(i + 1) * capStep;
const float_t ly1 = radius * sinf(phi1);
const float_t ly2 = radius * sinf(phi2);
const float_t lxz1 = radius * cosf(phi1);
const float_t lxz2 = radius * cosf(phi2);
const float_t v1 = 1.0f - (float_t)(capRings + 1 + i) / (float_t)(2 * capRings + 1);
const float_t v2 = 1.0f - (float_t)(capRings + 1 + i + 1) / (float_t)(2 * capRings + 1);
for(int32_t j = 0; j < sectors; j++) {
const float_t t1 = (float_t)j * sectorStep;
const float_t t2 = (float_t)(j + 1) * sectorStep;
const float_t u1 = (float_t)j / (float_t)sectors;
const float_t u2 = (float_t)(j + 1) / (float_t)sectors;
const float_t x11 = lxz1 * cosf(t1), z11 = lxz1 * sinf(t1);
const float_t x12 = lxz1 * cosf(t2), z12 = lxz1 * sinf(t2);
const float_t x21 = lxz2 * cosf(t1), z21 = lxz2 * sinf(t1);
const float_t x22 = lxz2 * cosf(t2), z22 = lxz2 * sinf(t2);
const float_t y1off = cy - halfHeight + ly1;
const float_t y2off = cy - halfHeight + ly2;
CAP_VERT(cx+x11, y1off, cz+z11, u1, v1)
CAP_VERT(cx+x21, y2off, cz+z21, u1, v2)
CAP_VERT(cx+x12, y1off, cz+z12, u2, v1)
CAP_VERT(cx+x12, y1off, cz+z12, u2, v1)
CAP_VERT(cx+x21, y2off, cz+z21, u1, v2)
CAP_VERT(cx+x22, y2off, cz+z22, u2, v2)
}
}
#undef CAP_VERT
}