/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "GeometryFactory.hpp" #include "Vertex.hpp" #define _USE_MATH_DEFINES #include #include namespace OpenVulkano::Scene { Geometry GeometryFactory::MakeCube(float x, float y, float z, const Math::Vector4f& color) { Geometry result; const int indexCount = 36; result.Init(24, indexCount); uint32_t indices[indexCount] = { 0, 1, 2, 0, 2, 3, // front face index data 4, 5, 6, 4, 6, 7, // back face index data 8, 9, 10, 8, 10, 11, // top face index data 12, 13, 14, 12, 14, 15, // bottom face index data 16, 17, 18, 16, 18, 19, // left face index data 20, 21, 22, 20, 22, 23 // right face index data }; result.SetIndices(indices, result.indexCount); x *= 0.5f; y *= 0.5f; z *= 0.5f; uint32_t i = 0; // front face vertex data result.vertices[i++].Set(+x, -y, +z, +0, +0, +1, +0, +1); result.vertices[i++].Set(+x, +y, +z, +0, +0, +1, +0, +0); result.vertices[i++].Set(-x, +y, +z, +0, +0, +1, +1, +0); result.vertices[i++].Set(-x, -y, +z, +0, +0, +1, +1, +1); // back face vertex data result.vertices[i++].Set(+x, -y, -z, +0, +0, -1, +1, +1); result.vertices[i++].Set(-x, -y, -z, +0, +0, -1, +0, +1); result.vertices[i++].Set(-x, +y, -z, +0, +0, -1, +0, +0); result.vertices[i++].Set(+x, +y, -z, +0, +0, -1, +1, +0); // top face vertex data result.vertices[i++].Set(+x, +y, +z, +0, -1, +0, +0, +1); result.vertices[i++].Set(+x, +y, -z, +0, -1, +0, +0, +0); result.vertices[i++].Set(-x, +y, -z, +0, -1, +0, +1, +0); result.vertices[i++].Set(-x, +y, +z, +0, -1, +0, +1, +1); // bottom face vertex data result.vertices[i++].Set(+x, -y, +z, +0, +1, +0, +1, +1); result.vertices[i++].Set(-x, -y, +z, +0, +1, +0, +0, +1); result.vertices[i++].Set(-x, -y, -z, +0, +1, +0, +0, +0); result.vertices[i++].Set(+x, -y, -z, +0, +1, +0, +1, +0); // Fill in the left face vertex data result.vertices[i++].Set(-x, -y, -z, -1, +0, +0, +1, +1); result.vertices[i++].Set(-x, -y, +z, -1, +0, +0, +0, +1); result.vertices[i++].Set(-x, +y, +z, -1, +0, +0, +0, +0); result.vertices[i++].Set(-x, +y, -z, -1, +0, +0, +1, +0); // Fill in the right face vertex data result.vertices[i++].Set(+x, -y, +z, +1, +0, +0, +1, +1); result.vertices[i++].Set(+x, -y, -z, +1, +0, +0, +0, +1); result.vertices[i++].Set(+x, +y, -z, +1, +0, +0, +0, +0); result.vertices[i].Set(+x, +y, +z, +1, +0, +0, +1, +0); for(i = 0; i < result.vertexCount; i++) { result.vertices[i].color = color; } return result; } Geometry GeometryFactory::MakePlane(float width, float height, const Math::Vector4f& color) { Geometry result; result.Init(4, 6); uint32_t indices[] = { 0, 2, 1, 0, 3, 2 }; result.SetIndices(indices, result.indexCount); width *= 0.5f; height *= 0.5f; result.vertices[0].Set(-width, -height, 0, 0, 0, 1, 0, 1); result.vertices[1].Set(-width, height, 0, 0, 0, 1, 0, 0); result.vertices[2].Set(width, height, 0, 0, 0, 1, 1, 0); result.vertices[3].Set(width, -height, 0, 0, 0, 1, 1, 1); for (uint32_t i = 0; i < result.vertexCount; i++) { result.vertices[i].color = color; } return result; } Geometry GeometryFactory::MakeSphere(float radius, uint32_t segments, uint32_t rings, const Math::Vector4f& color) { Geometry result; uint32_t vertexCount = (rings + 1) * (segments + 1); uint32_t indexCount = 6 * rings * segments; result.Init(vertexCount, indexCount); uint32_t i = 0; for (uint32_t ring = 0; ring <= rings; ++ring) { float theta = ring * M_PI / rings; float sinTheta = sin(theta); float cosTheta = cos(theta); for (uint32_t segment = 0; segment <= segments; ++segment) { float phi = segment * 2 * M_PI / segments; float sinPhi = sin(phi); float cosPhi = cos(phi); float x = cosPhi * sinTheta; float y = cosTheta; float z = sinPhi * sinTheta; float u = 1 - (float(segment) / segments); float v = float(ring) / rings; result.vertices[i].Set(radius * x, radius * y, radius * z, x, y, z, u, v); result.vertices[i].color = color; ++i; } } i = 0; uint32_t* indices = new uint32_t[indexCount]; for (uint32_t ring = 0; ring < rings; ++ring) { for (uint32_t segment = 0; segment < segments; ++segment) { uint32_t first = (ring * (segments + 1)) + segment; uint32_t second = first + segments + 1; indices[i++] = first; indices[i++] = first + 1; indices[i++] = second; indices[i++] = second; indices[i++] = first + 1; indices[i++] = second + 1; } } result.SetIndices(indices, indexCount); delete[] indices; return result; } Geometry GeometryFactory::MakeHemisphere(float radius, uint32_t segments, uint32_t rings, const Math::Vector4f& color) { Geometry result; uint32_t vertexCount = (rings + 1) * (segments + 1); uint32_t indexCount = 6 * rings * segments; result.Init(vertexCount, indexCount); uint32_t i = 0; for (uint32_t ring = 0; ring <= rings; ++ring) { float theta = (ring * M_PI_2) / rings; float sinTheta = sin(theta); float cosTheta = cos(theta); for (uint32_t segment = 0; segment <= segments; ++segment) { float phi = segment * 2 * M_PI / segments; float sinPhi = sin(phi); float cosPhi = cos(phi); float x = cosPhi * sinTheta; float y = cosTheta; float z = sinPhi * sinTheta; float u = 1 - (float(segment) / segments); float v = float(ring) / rings; result.vertices[i].Set(radius * x, radius * y, radius * z, x, y, z, u, v); result.vertices[i].color = color; ++i; } } i = 0; uint32_t* indices = new uint32_t[indexCount]; for (uint32_t ring = 0; ring < rings; ++ring) { for (uint32_t segment = 0; segment < segments; ++segment) { uint32_t first = (ring * (segments + 1)) + segment; uint32_t second = first + segments + 1; indices[i++] = first; indices[i++] = first + 1; indices[i++] = second; indices[i++] = second; indices[i++] = first + 1; indices[i++] = second + 1; } } result.SetIndices(indices, indexCount); delete[] indices; return result; } Geometry GeometryFactory::MakeTriangle(const Math::Vector3f& p1, const Math::Vector3f& p2, const Math::Vector3f& p3, const Math::Vector4f& color) { Geometry result; result.Init(3, 3); uint32_t indices[] = { 0, 1, 2 }; result.SetIndices(indices, result.indexCount); result.vertices[0].Set(p1.x, p1.y, p1.z, 0, 0, 1, 0, 0); result.vertices[1].Set(p2.x, p2.y, p2.z, 0, 0, 1, 1, 0); result.vertices[2].Set(p3.x, p3.y, p3.z, 0, 0, 1, 0, 1); for (uint32_t i = 0; i < result.vertexCount; i++) { result.vertices[i].color = color; } return result; } Geometry GeometryFactory::MakeCylinder(float radius, float height, uint32_t segments, const Math::Vector4f& color) { Geometry result; uint32_t vertexCount = 2 * (segments + 1); uint32_t indexCount = 12 * segments; result.Init(vertexCount, indexCount); float halfHeight = height * 0.5f; uint32_t i = 0; for (uint32_t segment = 0; segment <= segments; ++segment) { float theta = segment * 2 * M_PI / segments; float x = radius * cos(theta); float z = radius * sin(theta); float u = float(segment) / segments; result.vertices[i].Set(x, -halfHeight, z, x, 0, z, u, 0); result.vertices[i++].color = color; result.vertices[i].Set(x, halfHeight, z, x, 0, z, u, 1); result.vertices[i++].color = color; } i = 0; uint32_t* indices = new uint32_t[indexCount]; for (uint32_t segment = 0; segment < segments; ++segment) { uint32_t first = segment * 2; uint32_t second = first + 1; indices[i++] = first; indices[i++] = second; indices[i++] = first + 2; indices[i++] = second; indices[i++] = second + 2; indices[i++] = first + 2; indices[i++] = first; indices[i++] = first + 2; indices[i++] = second + 2; indices[i++] = second; indices[i++] = first; indices[i++] = second + 2; } result.SetIndices(indices, indexCount); delete[] indices; return result; } Geometry GeometryFactory::MakePyramid(float baseLength, float height, const Math::Vector4f& color) { Geometry result; result.Init(5, 18); uint32_t indices[] = { // Base 1, 2, 3, 1, 3, 4, // Sides 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 1 }; result.SetIndices(indices, result.indexCount); float halfBase = baseLength * 0.5f; // Top vertex result.vertices[0].Set(0, height, 0, 0, 1, 0, 0.5f, 1); // Base vertices result.vertices[1].Set(-halfBase, 0, halfBase, 0, -1, 0, 0, 0); result.vertices[2].Set(halfBase, 0, halfBase, 0, -1, 0, 1, 0); result.vertices[3].Set(halfBase, 0, -halfBase, 0, -1, 0, 1, 1); result.vertices[4].Set(-halfBase, 0, -halfBase, 0, -1, 0, 0, 1); for (uint32_t i = 0; i < result.vertexCount; i++) { result.vertices[i].color = color; } return result; } Geometry GeometryFactory::MakeArchStrip(float radius, float width, float endRadius, uint32_t segments, const Math::Vector4f& color, float endVCoord, bool indexBuffer) { Geometry result; segments = std::max(2u, segments); result.Init(2 * segments, indexBuffer ? 6 * segments : 0); const float segmentAngle = endRadius / static_cast(segments - 1); width /= 2; const float segmentV = endVCoord / (segments - 1); float segV = 0; for(uint32_t i = 0, seg = 0; seg < segments; seg++) { float angle = seg * segmentAngle; float z = std::cos(angle) * radius; float y = std::sin(angle) * radius; //TODO normals result.vertices[i].color = color; result.vertices[i++].Set(width, y, z, +0, +0, +1, +1, +segV); result.vertices[i].color = color; result.vertices[i++].Set(-width, y, z, +0, +0, +1, +0, +segV); segV += segmentV; } if (indexBuffer) { uint32_t* indices = new uint32_t[result.GetIndexCount()]; for (uint32_t i = 0, segment = 0; segment < segments; ++segment) { uint32_t first = segment * 2; uint32_t second = first + 1; indices[i++] = first; indices[i++] = second; indices[i++] = first + 2; indices[i++] = first + 2; indices[i++] = second; indices[i++] = second + 2; } result.SetIndices(indices, result.GetIndexCount()); } return result; } }