/** * Copyright (c) 2026 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "sphere.h" #include "assert/assert.h" mesh_t SPHERE_MESH_SIMPLE; meshvertex_t SPHERE_MESH_SIMPLE_VERTICES[SPHERE_VERTEX_COUNT]; errorret_t sphereInit() { vec3 center = { 0.0f, 0.0f, 0.0f }; sphereBuffer( SPHERE_MESH_SIMPLE_VERTICES, center, 0.5f, SPHERE_STACKS, SPHERE_SECTORS #if MESH_ENABLE_COLOR , COLOR_WHITE_4B #endif ); errorChain(meshInit( &SPHERE_MESH_SIMPLE, SPHERE_PRIMITIVE_TYPE, SPHERE_VERTEX_COUNT, SPHERE_MESH_SIMPLE_VERTICES )); errorOk(); } void sphereBuffer( meshvertex_t *vertices, const vec3 center, const float_t radius, const int32_t stacks, 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 stackStep = (float_t)GLM_PI / (float_t)stacks; const float_t sectorStep = 2.0f * (float_t)GLM_PI / (float_t)sectors; int32_t vi = 0; for(int32_t i = 0; i < stacks; i++) { /* Latitude angles: top of band -> bottom of band */ const float_t phi1 = (float_t)GLM_PI_2 - (float_t)i * stackStep; const float_t phi2 = (float_t)GLM_PI_2 - (float_t)(i + 1) * stackStep; const float_t y1 = radius * sinf(phi1); const float_t y2 = radius * sinf(phi2); const float_t xz1 = radius * cosf(phi1); const float_t xz2 = radius * cosf(phi2); const float_t v1 = 1.0f - (float_t)i / (float_t)stacks; const float_t v2 = 1.0f - (float_t)(i + 1) / (float_t)stacks; for(int32_t j = 0; j < sectors; j++) { const float_t theta1 = (float_t)j * sectorStep; const float_t theta2 = (float_t)(j + 1) * sectorStep; const float_t x11 = xz1 * cosf(theta1); const float_t z11 = xz1 * sinf(theta1); const float_t x12 = xz1 * cosf(theta2); const float_t z12 = xz1 * sinf(theta2); const float_t x21 = xz2 * cosf(theta1); const float_t z21 = xz2 * sinf(theta1); const float_t x22 = xz2 * cosf(theta2); const float_t z22 = xz2 * sinf(theta2); const float_t u1 = (float_t)j / (float_t)sectors; const float_t u2 = (float_t)(j + 1) / (float_t)sectors; /* Triangle 1: top-left, bottom-left, top-right */ #if MESH_ENABLE_COLOR vertices[vi].color = color; #endif vertices[vi].pos[0] = center[0] + x11; vertices[vi].pos[1] = center[1] + y1; vertices[vi].pos[2] = center[2] + z11; vertices[vi].uv[0] = u1; vertices[vi].uv[1] = v1; vi++; #if MESH_ENABLE_COLOR vertices[vi].color = color; #endif vertices[vi].pos[0] = center[0] + x21; vertices[vi].pos[1] = center[1] + y2; vertices[vi].pos[2] = center[2] + z21; vertices[vi].uv[0] = u1; vertices[vi].uv[1] = v2; vi++; #if MESH_ENABLE_COLOR vertices[vi].color = color; #endif vertices[vi].pos[0] = center[0] + x12; vertices[vi].pos[1] = center[1] + y1; vertices[vi].pos[2] = center[2] + z12; vertices[vi].uv[0] = u2; vertices[vi].uv[1] = v1; vi++; /* Triangle 2: top-right, bottom-left, bottom-right */ #if MESH_ENABLE_COLOR vertices[vi].color = color; #endif vertices[vi].pos[0] = center[0] + x12; vertices[vi].pos[1] = center[1] + y1; vertices[vi].pos[2] = center[2] + z12; vertices[vi].uv[0] = u2; vertices[vi].uv[1] = v1; vi++; #if MESH_ENABLE_COLOR vertices[vi].color = color; #endif vertices[vi].pos[0] = center[0] + x21; vertices[vi].pos[1] = center[1] + y2; vertices[vi].pos[2] = center[2] + z21; vertices[vi].uv[0] = u1; vertices[vi].uv[1] = v2; vi++; #if MESH_ENABLE_COLOR vertices[vi].color = color; #endif vertices[vi].pos[0] = center[0] + x22; vertices[vi].pos[1] = center[1] + y2; vertices[vi].pos[2] = center[2] + z22; vertices[vi].uv[0] = u2; vertices[vi].uv[1] = v2; vi++; } } }