import 'dart:math'; import 'dart:typed_data'; import '../../thermion_dart.dart'; class GeometryHelper { static Geometry sphere({bool normals = true, bool uvs = true}) { int latitudeBands = 20; int longitudeBands = 20; List verticesList = []; List normalsList = []; List uvsList = []; List indices = []; for (int latNumber = 0; latNumber <= latitudeBands; latNumber++) { double theta = latNumber * pi / latitudeBands; double sinTheta = sin(theta); double cosTheta = cos(theta); for (int longNumber = 0; longNumber <= longitudeBands; longNumber++) { double phi = longNumber * 2 * pi / longitudeBands; double sinPhi = sin(phi); double cosPhi = cos(phi); double x = cosPhi * sinTheta; double y = cosTheta; double z = sinPhi * sinTheta; verticesList.addAll([x, y, z]); normalsList.addAll([x, y, z]); uvsList.addAll([longNumber / longitudeBands, latNumber / latitudeBands]); } } for (int latNumber = 0; latNumber < latitudeBands; latNumber++) { for (int longNumber = 0; longNumber < longitudeBands; longNumber++) { int first = (latNumber * (longitudeBands + 1)) + longNumber; int second = first + longitudeBands + 1; indices.addAll([first, second, first + 1, second, second + 1, first + 1]); } } Float32List vertices = Float32List.fromList(verticesList); Float32List? _normals = normals ? Float32List.fromList(normalsList) : null; Float32List? _uvs = uvs ? Float32List.fromList(uvsList) : null; return Geometry(vertices, indices, normals: _normals, uvs: _uvs); } static Geometry cube({bool normals = true, bool uvs = true}) { final vertices = Float32List.fromList([ // Front face -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, // Back face -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, // Top face -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, // Bottom face -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, // Right face 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, // Left face -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, ]); final _normals = normals ? Float32List.fromList([ // Front face 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // Back face 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, // Top face 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // Bottom face 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, // Right face 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // Left face -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, ]) : null; final _uvs = uvs ? Float32List.fromList([ // Front face 1/3, 1/3, 2/3, 1/3, 2/3, 2/3, 1/3, 2/3, // Back face 2/3, 2/3, 2/3, 1, 1, 1, 1, 2/3, // Top face 1/3, 0, 1/3, 1/3, 2/3, 1/3, 2/3, 0, // Bottom face 1/3, 2/3, 2/3, 2/3, 2/3, 1, 1/3, 1, // Right face 2/3, 1/3, 2/3, 2/3, 1, 2/3, 1, 1/3, // Left face 0, 1/3, 1/3, 1/3, 1/3, 2/3, 0, 2/3, ]) : null; final indices = [ // Front face 0, 1, 2, 0, 2, 3, // Back face 4, 5, 6, 4, 6, 7, // Top face 8, 9, 10, 8, 10, 11, // Bottom face 12, 13, 14, 12, 14, 15, // Right face 16, 17, 18, 16, 18, 19, // Left face 20, 21, 22, 20, 22, 23 ]; return Geometry(vertices, indices, normals: _normals, uvs: _uvs); } static Geometry cylinder({double radius = 1.0, double length = 1.0, bool normals = true, bool uvs = true }) { int segments = 32; List verticesList = []; List normalsList = []; List uvsList = []; List indices = []; // Create vertices, normals, and UVs for (int i = 0; i <= segments; i++) { double theta = i * 2 * pi / segments; double x = radius * cos(theta); double z = radius * sin(theta); // Top circle verticesList.addAll([x, length / 2, z]); normalsList.addAll([x / radius, 0, z / radius]); uvsList.addAll([i / segments, 1]); // Bottom circle verticesList.addAll([x, -length / 2, z]); normalsList.addAll([x / radius, 0, z / radius]); uvsList.addAll([i / segments, 0]); } // Create indices for (int i = 0; i < segments; i++) { int topFirst = i * 2; int topSecond = (i + 1) * 2; int bottomFirst = topFirst + 1; int bottomSecond = topSecond + 1; // Top face (counter-clockwise) indices.addAll([segments * 2, topSecond, topFirst]); // Bottom face (counter-clockwise when viewed from below) indices.addAll([segments * 2 + 1, bottomFirst, bottomSecond]); // Side faces (counter-clockwise) indices.addAll([topFirst, bottomFirst, topSecond]); indices.addAll([bottomFirst, bottomSecond, topSecond]); } // Add center vertices, normals, and UVs for top and bottom faces verticesList.addAll([0, length / 2, 0]); // Top center normalsList.addAll([0, 1, 0]); uvsList.addAll([0.5, 0.5]); // Center of top face verticesList.addAll([0, -length / 2, 0]); // Bottom center normalsList.addAll([0, -1, 0]); uvsList.addAll([0.5, 0.5]); // Center of bottom face // Add top and bottom face normals and UVs for (int i = 0; i <= segments; i++) { normalsList.addAll([0, 1, 0]); // Top face normal normalsList.addAll([0, -1, 0]); // Bottom face normal double u = 0.5 + 0.5 * cos(i * 2 * pi / segments); double v = 0.5 + 0.5 * sin(i * 2 * pi / segments); uvsList.addAll([u, v]); // Top face UV uvsList.addAll([u, v]); // Bottom face UV } Float32List vertices = Float32List.fromList(verticesList); Float32List? _normals = normals ? Float32List.fromList(normalsList) : null; Float32List? _uvs = uvs ? Float32List.fromList(uvsList) : null; return Geometry(vertices, indices, normals: _normals, uvs: _uvs); } static Geometry conic({double radius = 1.0, double length = 1.0, bool normals = true, bool uvs = true}) { int segments = 32; List verticesList = []; List normalsList = []; List uvsList = []; List indices = []; // Create vertices, normals, and UVs for (int i = 0; i <= segments; i++) { double theta = i * 2 * pi / segments; double x = radius * cos(theta); double z = radius * sin(theta); // Base circle verticesList.addAll([x, 0, z]); // Calculate normal for the side double nx = x / sqrt(x * x + length * length); double nz = z / sqrt(z * z + length * length); double ny = radius / sqrt(radius * radius + length * length); normalsList.addAll([nx, ny, nz]); // UV coordinates uvsList.addAll([i / segments, 0]); } // Apex verticesList.addAll([0, length, 0]); normalsList.addAll([0, 1, 0]); // Normal at apex points straight up uvsList.addAll([0.5, 1]); // UV for apex // Create indices for (int i = 0; i < segments; i++) { // Base face (fixed to counterclockwise) indices.addAll([segments + 1, i + 1, i]); // Side faces (already correct) indices.addAll([i, segments, i + 1]); } // Add base face normals and UVs for (int i = 0; i <= segments; i++) { normalsList.addAll([0, -1, 0]); // Base face normal double u = 0.5 + 0.5 * cos(i * 2 * pi / segments); double v = 0.5 + 0.5 * sin(i * 2 * pi / segments); uvsList.addAll([u, v]); // Base face UV } Float32List vertices = Float32List.fromList(verticesList); Float32List? _normals = normals ? Float32List.fromList(normalsList) : null; Float32List? _uvs = uvs ? Float32List.fromList(uvsList) : null; return Geometry(vertices, indices, normals: _normals, uvs: _uvs); } static Geometry plane({double width = 1.0, double height = 1.0, bool normals = true, bool uvs = true}) { Float32List vertices = Float32List.fromList([ -width / 2, 0, -height / 2, width / 2, 0, -height / 2, width / 2, 0, height / 2, -width / 2, 0, height / 2, ]); Float32List? _normals = normals ? Float32List.fromList([ 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, ]) : null; Float32List? _uvs = uvs ? Float32List.fromList([ 0, 0, 1, 0, 1, 1, 0, 1, ]) : null; List indices = [ 0, 2, 1, 0, 3, 2, ]; return Geometry(vertices, indices, normals: _normals, uvs: _uvs); } }