185 lines
6.0 KiB
C
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
|
|
}
|