diff options
| author | Miles Macklin <[email protected]> | 2017-03-10 14:51:31 +1300 |
|---|---|---|
| committer | Miles Macklin <[email protected]> | 2017-03-10 14:51:31 +1300 |
| commit | ad3d90fafe5ee79964bdfe1f1e0704c3ffcdfd5f (patch) | |
| tree | 4cc6f3288363889d7342f7f8407c0251e6904819 /core/mesh.cpp | |
| download | flex-ad3d90fafe5ee79964bdfe1f1e0704c3ffcdfd5f.tar.xz flex-ad3d90fafe5ee79964bdfe1f1e0704c3ffcdfd5f.zip | |
Initial 1.1.0 binary release
Diffstat (limited to 'core/mesh.cpp')
| -rw-r--r-- | core/mesh.cpp | 968 |
1 files changed, 968 insertions, 0 deletions
diff --git a/core/mesh.cpp b/core/mesh.cpp new file mode 100644 index 0000000..371e664 --- /dev/null +++ b/core/mesh.cpp @@ -0,0 +1,968 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2013-2016 NVIDIA Corporation. All rights reserved. + +#include "mesh.h" +#include "platform.h" + +#include <map> +#include <fstream> +#include <iostream> + +using namespace std; + +void Mesh::DuplicateVertex(uint32_t i) +{ + assert(m_positions.size() > i); + m_positions.push_back(m_positions[i]); + + if (m_normals.size() > i) + m_normals.push_back(m_normals[i]); + + if (m_colours.size() > i) + m_colours.push_back(m_colours[i]); + + if (m_texcoords[0].size() > i) + m_texcoords[0].push_back(m_texcoords[0][i]); + + if (m_texcoords[1].size() > i) + m_texcoords[1].push_back(m_texcoords[1][i]); + +} + +void Mesh::Normalize(float s) +{ + Vec3 lower, upper; + GetBounds(lower, upper); + Vec3 edges = upper-lower; + + Transform(TranslationMatrix(Point3(-lower))); + + float maxEdge = max(edges.x, max(edges.y, edges.z)); + Transform(ScaleMatrix(s/maxEdge)); +} + +void Mesh::CalculateNormals() +{ + m_normals.resize(0); + m_normals.resize(m_positions.size()); + + int numTris = int(GetNumFaces()); + + for (int i=0; i < numTris; ++i) + { + int a = m_indices[i*3+0]; + int b = m_indices[i*3+1]; + int c = m_indices[i*3+2]; + + Vec3 n = Cross(m_positions[b]-m_positions[a], m_positions[c]-m_positions[a]); + + m_normals[a] += n; + m_normals[b] += n; + m_normals[c] += n; + } + + int numVertices = int(GetNumVertices()); + + for (int i=0; i < numVertices; ++i) + m_normals[i] = ::Normalize(m_normals[i]); +} + +namespace +{ + + enum PlyFormat + { + eAscii, + eBinaryBigEndian + }; + + template <typename T> + T PlyRead(ifstream& s, PlyFormat format) + { + T data = eAscii; + + switch (format) + { + case eAscii: + { + s >> data; + break; + } + case eBinaryBigEndian: + { + char c[sizeof(T)]; + s.read(c, sizeof(T)); + reverse(c, c+sizeof(T)); + data = *(T*)c; + break; + } + default: + assert(0); + } + + return data; + } + +} // namespace anonymous + + +Mesh* ImportMesh(const char* path) +{ + std::string ext = GetExtension(path); + + Mesh* mesh = NULL; + + if (ext == "ply") + mesh = ImportMeshFromPly(path); + else if (ext == "obj") + mesh = ImportMeshFromObj(path); + + + return mesh; +} + +Mesh* ImportMeshFromBin(const char* path) +{ + double start = GetSeconds(); + + FILE* f = fopen(path, "rb"); + + if (f) + { + int numVertices; + int numIndices; + + size_t len; + len = fread(&numVertices, sizeof(numVertices), 1, f); + len = fread(&numIndices, sizeof(numIndices), 1, f); + + Mesh* m = new Mesh(); + m->m_positions.resize(numVertices); + m->m_normals.resize(numVertices); + m->m_indices.resize(numIndices); + + len = fread(&m->m_positions[0], sizeof(Vec3)*numVertices, 1, f); + len = fread(&m->m_normals[0], sizeof(Vec3)*numVertices, 1, f); + len = fread(&m->m_indices[0], sizeof(int)*numIndices, 1, f); + + (void)len; + + fclose(f); + + double end = GetSeconds(); + + printf("Imported mesh %s in %f ms\n", path, (end-start)*1000.0f); + + return m; + } + + return NULL; +} + +void ExportMeshToBin(const char* path, const Mesh* m) +{ + FILE* f = fopen(path, "wb"); + + if (f) + { + int numVertices = int(m->m_positions.size()); + int numIndices = int(m->m_indices.size()); + + fwrite(&numVertices, sizeof(numVertices), 1, f); + fwrite(&numIndices, sizeof(numIndices), 1, f); + + // write data blocks + fwrite(&m->m_positions[0], sizeof(Vec3)*numVertices, 1, f); + fwrite(&m->m_normals[0], sizeof(Vec3)*numVertices, 1, f); + fwrite(&m->m_indices[0], sizeof(int)*numIndices, 1, f); + + fclose(f); + } +} + +Mesh* ImportMeshFromPly(const char* path) +{ + ifstream file(path, ios_base::in | ios_base::binary); + + if (!file) + return NULL; + + // some scratch memory + const uint32_t kMaxLineLength = 1024; + char buffer[kMaxLineLength]; + + //double startTime = GetSeconds(); + + file >> buffer; + if (strcmp(buffer, "ply") != 0) + return NULL; + + PlyFormat format = eAscii; + + uint32_t numFaces = 0; + uint32_t numVertices = 0; + + const uint32_t kMaxProperties = 16; + uint32_t numProperties = 0; + float properties[kMaxProperties]; + + bool vertexElement = false; + + while (file) + { + file >> buffer; + + if (strcmp(buffer, "element") == 0) + { + file >> buffer; + + if (strcmp(buffer, "face") == 0) + { + vertexElement = false; + file >> numFaces; + } + + else if (strcmp(buffer, "vertex") == 0) + { + vertexElement = true; + file >> numVertices; + } + } + else if (strcmp(buffer, "format") == 0) + { + file >> buffer; + if (strcmp(buffer, "ascii") == 0) + { + format = eAscii; + } + else if (strcmp(buffer, "binary_big_endian") == 0) + { + format = eBinaryBigEndian; + } + else + { + printf("Ply: unknown format\n"); + return NULL; + } + } + else if (strcmp(buffer, "property") == 0) + { + if (vertexElement) + ++numProperties; + } + else if (strcmp(buffer, "end_header") == 0) + { + break; + } + } + + // eat newline + char nl; + file.read(&nl, 1); + + // debug +#if ENABLE_VERBOSE_OUTPUT + printf ("Loaded mesh: %s numFaces: %d numVertices: %d format: %d numProperties: %d\n", path, numFaces, numVertices, format, numProperties); +#endif + + Mesh* mesh = new Mesh; + + mesh->m_positions.resize(numVertices); + mesh->m_normals.resize(numVertices); + mesh->m_colours.resize(numVertices, Colour(1.0f, 1.0f, 1.0f, 1.0f)); + + mesh->m_indices.reserve(numFaces*3); + + // read vertices + for (uint32_t v=0; v < numVertices; ++v) + { + for (uint32_t i=0; i < numProperties; ++i) + { + properties[i] = PlyRead<float>(file, format); + } + + mesh->m_positions[v] = Point3(properties[0], properties[1], properties[2]); + mesh->m_normals[v] = Vector3(0.0f, 0.0f, 0.0f); + } + + // read indices + for (uint32_t f=0; f < numFaces; ++f) + { + uint32_t numIndices = (format == eAscii)?PlyRead<uint32_t>(file, format):PlyRead<uint8_t>(file, format); + uint32_t indices[4]; + + for (uint32_t i=0; i < numIndices; ++i) + { + indices[i] = PlyRead<uint32_t>(file, format); + } + + switch (numIndices) + { + case 3: + mesh->m_indices.push_back(indices[0]); + mesh->m_indices.push_back(indices[1]); + mesh->m_indices.push_back(indices[2]); + break; + case 4: + mesh->m_indices.push_back(indices[0]); + mesh->m_indices.push_back(indices[1]); + mesh->m_indices.push_back(indices[2]); + + mesh->m_indices.push_back(indices[2]); + mesh->m_indices.push_back(indices[3]); + mesh->m_indices.push_back(indices[0]); + break; + + default: + assert(!"invalid number of indices, only support tris and quads"); + break; + }; + + // calculate vertex normals as we go + Point3& v0 = mesh->m_positions[indices[0]]; + Point3& v1 = mesh->m_positions[indices[1]]; + Point3& v2 = mesh->m_positions[indices[2]]; + + Vector3 n = SafeNormalize(Cross(v1-v0, v2-v0), Vector3(0.0f, 1.0f, 0.0f)); + + for (uint32_t i=0; i < numIndices; ++i) + { + mesh->m_normals[indices[i]] += n; + } + } + + for (uint32_t i=0; i < numVertices; ++i) + { + mesh->m_normals[i] = SafeNormalize(mesh->m_normals[i], Vector3(0.0f, 1.0f, 0.0f)); + } + + //cout << "Imported mesh " << path << " in " << (GetSeconds()-startTime)*1000.f << "ms" << endl; + + return mesh; + +} + +// map of Material name to Material +struct VertexKey +{ + VertexKey() : v(0), vt(0), vn(0) {} + + uint32_t v, vt, vn; + + bool operator == (const VertexKey& rhs) const + { + return v == rhs.v && vt == rhs.vt && vn == rhs.vn; + } + + bool operator < (const VertexKey& rhs) const + { + if (v != rhs.v) + return v < rhs.v; + else if (vt != rhs.vt) + return vt < rhs.vt; + else + return vn < rhs.vn; + } +}; + +Mesh* ImportMeshFromObj(const char* path) +{ + ifstream file(path); + + if (!file) + return NULL; + + Mesh* m = new Mesh(); + + vector<Point3> positions; + vector<Vector3> normals; + vector<Vector2> texcoords; + vector<Vector3> colors; + vector<uint32_t>& indices = m->m_indices; + + //typedef unordered_map<VertexKey, uint32_t, MemoryHash<VertexKey> > VertexMap; + typedef map<VertexKey, uint32_t> VertexMap; + VertexMap vertexLookup; + + // some scratch memory + const uint32_t kMaxLineLength = 1024; + char buffer[kMaxLineLength]; + + //double startTime = GetSeconds(); + + while (file) + { + file >> buffer; + + if (strcmp(buffer, "vn") == 0) + { + // normals + float x, y, z; + file >> x >> y >> z; + + normals.push_back(Vector3(x, y, z)); + } + else if (strcmp(buffer, "vt") == 0) + { + // texture coords + float u, v; + file >> u >> v; + + texcoords.push_back(Vector2(u, v)); + } + else if (buffer[0] == 'v') + { + // positions + float x, y, z; + file >> x >> y >> z; + + positions.push_back(Point3(x, y, z)); + } + else if (buffer[0] == 's' || buffer[0] == 'g' || buffer[0] == 'o') + { + // ignore smoothing groups, groups and objects + char linebuf[256]; + file.getline(linebuf, 256); + } + else if (strcmp(buffer, "mtllib") == 0) + { + // ignored + std::string MaterialFile; + file >> MaterialFile; + } + else if (strcmp(buffer, "usemtl") == 0) + { + // read Material name + std::string materialName; + file >> materialName; + } + else if (buffer[0] == 'f') + { + // faces + uint32_t faceIndices[4]; + uint32_t faceIndexCount = 0; + + for (int i=0; i < 4; ++i) + { + VertexKey key; + + file >> key.v; + + if (!file.eof()) + { + // failed to read another index continue on + if (file.fail()) + { + file.clear(); + break; + } + + if (file.peek() == '/') + { + file.ignore(); + + if (file.peek() != '/') + { + file >> key.vt; + } + + if (file.peek() == '/') + { + file.ignore(); + file >> key.vn; + } + } + + // find / add vertex, index + VertexMap::iterator iter = vertexLookup.find(key); + + if (iter != vertexLookup.end()) + { + faceIndices[faceIndexCount++] = iter->second; + } + else + { + // add vertex + uint32_t newIndex = uint32_t(m->m_positions.size()); + faceIndices[faceIndexCount++] = newIndex; + + vertexLookup.insert(make_pair(key, newIndex)); + + // push back vertex data + assert(key.v > 0); + + m->m_positions.push_back(positions[key.v-1]); + + // obj format doesn't support mesh colours so add default value + m->m_colours.push_back(Colour(1.0f, 1.0f, 1.0f)); + + // normal [optional] + if (key.vn) + { + m->m_normals.push_back(normals[key.vn-1]); + } + + // texcoord [optional] + if (key.vt) + { + m->m_texcoords[0].push_back(texcoords[key.vt-1]); + } + } + } + } + + if (faceIndexCount == 3) + { + // a triangle + indices.insert(indices.end(), faceIndices, faceIndices+3); + } + else if (faceIndexCount == 4) + { + // a quad, triangulate clockwise + indices.insert(indices.end(), faceIndices, faceIndices+3); + + indices.push_back(faceIndices[2]); + indices.push_back(faceIndices[3]); + indices.push_back(faceIndices[0]); + } + else + { + cout << "Face with more than 4 vertices are not supported" << endl; + } + + } + else if (buffer[0] == '#') + { + // comment + char linebuf[256]; + file.getline(linebuf, 256); + } + } + + // calculate normals if none specified in file + m->m_normals.resize(m->m_positions.size()); + + const uint32_t numFaces = uint32_t(indices.size())/3; + for (uint32_t i=0; i < numFaces; ++i) + { + uint32_t a = indices[i*3+0]; + uint32_t b = indices[i*3+1]; + uint32_t c = indices[i*3+2]; + + Point3& v0 = m->m_positions[a]; + Point3& v1 = m->m_positions[b]; + Point3& v2 = m->m_positions[c]; + + Vector3 n = SafeNormalize(Cross(v1-v0, v2-v0), Vector3(0.0f, 1.0f, 0.0f)); + + m->m_normals[a] += n; + m->m_normals[b] += n; + m->m_normals[c] += n; + } + + for (uint32_t i=0; i < m->m_normals.size(); ++i) + { + m->m_normals[i] = SafeNormalize(m->m_normals[i], Vector3(0.0f, 1.0f, 0.0f)); + } + + //cout << "Imported mesh " << path << " in " << (GetSeconds()-startTime)*1000.f << "ms" << endl; + + return m; +} + +void ExportToObj(const char* path, const Mesh& m) +{ + ofstream file(path); + + if (!file) + return; + + file << "# positions" << endl; + + for (uint32_t i=0; i < m.m_positions.size(); ++i) + { + Point3 v = m.m_positions[i]; + file << "v " << v.x << " " << v.y << " " << v.z << endl; + } + + file << "# texcoords" << endl; + + for (uint32_t i=0; i < m.m_texcoords[0].size(); ++i) + { + Vec2 t = m.m_texcoords[0][i]; + file << "vt " << t.x << " " << t.y << endl; + } + + file << "# normals" << endl; + + for (uint32_t i=0; i < m.m_normals.size(); ++i) + { + Vec3 n = m.m_normals[0][i]; + file << "vn " << n.x << " " << n.y << " " << n.z << endl; + } + + file << "# faces" << endl; + + for (uint32_t i=0; i < m.m_indices.size()/3; ++i) + { + uint32_t j = i+1; + + // no sharing, assumes there is a unique position, texcoord and normal for each vertex + file << "f " << j << "/" << j << "/" << j << endl; + } +} + +void Mesh::AddMesh(const Mesh& m) +{ + uint32_t offset = uint32_t(m_positions.size()); + + // add new vertices + m_positions.insert(m_positions.end(), m.m_positions.begin(), m.m_positions.end()); + m_normals.insert(m_normals.end(), m.m_normals.begin(), m.m_normals.end()); + m_colours.insert(m_colours.end(), m.m_colours.begin(), m.m_colours.end()); + + // add new indices with offset + for (uint32_t i=0; i < m.m_indices.size(); ++i) + { + m_indices.push_back(m.m_indices[i]+offset); + } +} + +void Mesh::Transform(const Matrix44& m) +{ + for (uint32_t i=0; i < m_positions.size(); ++i) + { + m_positions[i] = m*m_positions[i]; + m_normals[i] = m*m_normals[i]; + } +} + +void Mesh::GetBounds(Vector3& outMinExtents, Vector3& outMaxExtents) const +{ + Point3 minExtents(FLT_MAX); + Point3 maxExtents(-FLT_MAX); + + // calculate face bounds + for (uint32_t i=0; i < m_positions.size(); ++i) + { + const Point3& a = m_positions[i]; + + minExtents = Min(a, minExtents); + maxExtents = Max(a, maxExtents); + } + + outMinExtents = Vector3(minExtents); + outMaxExtents = Vector3(maxExtents); +} + +Mesh* CreateTriMesh(float size, float y) +{ + uint32_t indices[] = { 0, 1, 2 }; + Point3 positions[3]; + Vector3 normals[3]; + + positions[0] = Point3(-size, y, size); + positions[1] = Point3(size, y, size); + positions[2] = Point3(size, y, -size); + + normals[0] = Vector3(0.0f, 1.0f, 0.0f); + normals[1] = Vector3(0.0f, 1.0f, 0.0f); + normals[2] = Vector3(0.0f, 1.0f, 0.0f); + + Mesh* m = new Mesh(); + m->m_indices.insert(m->m_indices.begin(), indices, indices + 3); + m->m_positions.insert(m->m_positions.begin(), positions, positions + 3); + m->m_normals.insert(m->m_normals.begin(), normals, normals + 3); + + return m; +} + +Mesh* CreateCubeMesh() +{ + const Point3 vertices[24] = + { + Point3(0.5, 0.5, 0.5), + Point3(-0.5, 0.5, 0.5), + Point3(0.5, -0.5, 0.5), + Point3(-0.5, -0.5, 0.5), + Point3(0.5, 0.5, -0.5), + Point3(-0.5, 0.5, -0.5), + Point3(0.5, -0.5, -0.5), + Point3(-0.5, -0.5, -0.5), + Point3(0.5, 0.5, 0.5), + Point3(0.5, -0.5, 0.5), + Point3(0.5, 0.5, 0.5), + Point3(0.5, 0.5, -0.5), + Point3(-0.5, 0.5, 0.5), + Point3(-0.5, 0.5, -0.5), + Point3(0.5, -0.5, -0.5), + Point3(0.5, 0.5, -0.5), + Point3(-0.5, -0.5, -0.5), + Point3(0.5, -0.5, -0.5), + Point3(-0.5, -0.5, 0.5), + Point3(0.5, -0.5, 0.5), + Point3(-0.5, -0.5, -0.5), + Point3(-0.5, -0.5, 0.5), + Point3(-0.5, 0.5, -0.5), + Point3(-0.5, 0.5, 0.5) + }; + + const Vec3 normals[24] = + { + Vec3(0.0f, 0.0f, 1.0f), + Vec3(0.0f, 0.0f, 1.0f), + Vec3(0.0f, 0.0f, 1.0f), + Vec3(0.0f, 0.0f, 1.0f), + Vec3(1.0f, 0.0f, 0.0f), + Vec3(0.0f, 1.0f, 0.0f), + Vec3(1.0f, 0.0f, 0.0f), + Vec3(0.0f, 0.0f, -1.0f), + Vec3(1.0f, 0.0f, 0.0f), + Vec3(1.0f, 0.0f, 0.0f), + Vec3(0.0f, 1.0f, 0.0f), + Vec3(0.0f, 1.0f, 0.0f), + Vec3(0.0f, 1.0f, 0.0f), + Vec3(0.0f, 0.0f, -1.0f), + Vec3(0.0f, 0.0f, -1.0f), + Vec3(-0.0f, -0.0f, -1.0f), + Vec3(0.0f, -1.0f, 0.0f), + Vec3(0.0f, -1.0f, 0.0f), + Vec3(0.0f, -1.0f, 0.0f), + Vec3(-0.0f, -1.0f, -0.0f), + Vec3(-1.0f, 0.0f, 0.0f), + Vec3(-1.0f, 0.0f, 0.0f), + Vec3(-1.0f, 0.0f, 0.0f), + Vec3(-1.0f, -0.0f, -0.0f) + }; + + const int indices[36] = + { + 0, 1, 2, + 3, 2, 1, + 8, 9, 4, + 6, 4, 9, + 10, 11, 12, + 5, 12, 11, + 7, 13, 14, + 15, 14, 13, + 16, 17, 18, + 19, 18, 17, + 20, 21, 22, + 23, 22, 21 + }; + + Mesh* m = new Mesh(); + m->m_positions.assign(vertices, vertices+24); + m->m_normals.assign(normals, normals+24); + m->m_indices.assign(indices, indices+36); + + return m; + +} + +Mesh* CreateQuadMesh(float size, float y) +{ + uint32_t indices[] = { 0, 1, 2, 2, 3, 0 }; + Point3 positions[4]; + Vector3 normals[4]; + + positions[0] = Point3(-size, y, size); + positions[1] = Point3(size, y, size); + positions[2] = Point3(size, y, -size); + positions[3] = Point3(-size, y, -size); + + normals[0] = Vector3(0.0f, 1.0f, 0.0f); + normals[1] = Vector3(0.0f, 1.0f, 0.0f); + normals[2] = Vector3(0.0f, 1.0f, 0.0f); + normals[3] = Vector3(0.0f, 1.0f, 0.0f); + + Mesh* m = new Mesh(); + m->m_indices.insert(m->m_indices.begin(), indices, indices+6); + m->m_positions.insert(m->m_positions.begin(), positions, positions+4); + m->m_normals.insert(m->m_normals.begin(), normals, normals+4); + + return m; +} + +Mesh* CreateDiscMesh(float radius, uint32_t segments) +{ + const uint32_t numVerts = 1 + segments; + + Mesh* m = new Mesh(); + m->m_positions.resize(numVerts); + m->m_normals.resize(numVerts); + + m->m_positions[0] = Point3(0.0f); + m->m_positions[1] = Point3(0.0f, 0.0f, radius); + + for (uint32_t i=1; i <= segments; ++i) + { + uint32_t nextVert = (i+1)%numVerts; + + if (nextVert == 0) + nextVert = 1; + + m->m_positions[nextVert] = Point3(radius*Sin((float(i)/segments)*k2Pi), 0.0f, radius*Cos((float(i)/segments)*k2Pi)); + m->m_normals[nextVert] = Vector3(0.0f, 1.0f, 0.0f); + + m->m_indices.push_back(0); + m->m_indices.push_back(i); + m->m_indices.push_back(nextVert); + } + + return m; +} + +Mesh* CreateTetrahedron(float ground, float height) +{ + Mesh* m = new Mesh(); + + const float dimValue = 1.0f / sqrtf(2.0f); + const Point3 vertices[4] = + { + Point3(-1.0f, ground, -dimValue), + Point3(1.0f, ground, -dimValue), + Point3(0.0f, ground + height, dimValue), + Point3(0.0f, ground, dimValue) + }; + + const int indices[12] = + { + //winding order is counter-clockwise + 0, 2, 1, + 2, 3, 1, + 2, 0, 3, + 3, 0, 1 + }; + + m->m_positions.assign(vertices, vertices+4); + m->m_indices.assign(indices, indices+12); + + m->CalculateNormals(); + + return m; +} + + +Mesh* CreateSphere(int slices, int segments, float radius) +{ + float dTheta = kPi / slices; + float dPhi = k2Pi / segments; + + int vertsPerRow = segments + 1; + + Mesh* mesh = new Mesh(); + + for (int i = 0; i <= slices; ++i) + { + float theta = dTheta*i; + + for (int j = 0; j <= segments; ++j) + { + float phi = dPhi*j; + + float x = sinf(theta)*cosf(phi); + float y = cosf(theta); + float z = sinf(theta)*sinf(phi); + + mesh->m_positions.push_back(Point3(x, y, z)*radius); + mesh->m_normals.push_back(Vec3(x, y, z)); + + if (i > 0 && j > 0) + { + int a = i*vertsPerRow + j; + int b = (i - 1)*vertsPerRow + j; + int c = (i - 1)*vertsPerRow + j - 1; + int d = i*vertsPerRow + j - 1; + + // add a quad for this slice + mesh->m_indices.push_back(b); + mesh->m_indices.push_back(a); + mesh->m_indices.push_back(d); + + mesh->m_indices.push_back(b); + mesh->m_indices.push_back(d); + mesh->m_indices.push_back(c); + } + } + } + + return mesh; +} + +Mesh* CreateCapsule(int slices, int segments, float radius, float halfHeight) +{ + float dTheta = kPi / (slices * 2); + float dPhi = k2Pi / segments; + + int vertsPerRow = segments + 1; + + Mesh* mesh = new Mesh(); + + float theta = 0.0f; + + for (int i = 0; i <= 2 * slices + 1; ++i) + { + for (int j = 0; j <= segments; ++j) + { + float phi = dPhi*j; + + float x = sinf(theta)*cosf(phi); + float y = cosf(theta); + float z = sinf(theta)*sinf(phi); + + // add y offset based on which hemisphere we're in + float yoffset = (i < slices) ? halfHeight : -halfHeight; + + mesh->m_positions.push_back(Point3(x, y, z)*radius + Vec3(0.0f, yoffset, 0.0f)); + mesh->m_normals.push_back(Vec3(x, y, z)); + + if (i > 0 && j > 0) + { + int a = i*vertsPerRow + j; + int b = (i - 1)*vertsPerRow + j; + int c = (i - 1)*vertsPerRow + j - 1; + int d = i*vertsPerRow + j - 1; + + // add a quad for this slice + mesh->m_indices.push_back(b); + mesh->m_indices.push_back(a); + mesh->m_indices.push_back(d); + + mesh->m_indices.push_back(b); + mesh->m_indices.push_back(d); + mesh->m_indices.push_back(c); + } + } + + // don't update theta for the middle slice + if (i != slices) + theta += dTheta; + } + + return mesh; +} |