| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- // ----------------------------------------------------------------
- // From Game Programming in C++ by Sanjay Madhav
- // Copyright (C) 2017 Sanjay Madhav. All rights reserved.
- //
- // Released under the BSD License
- // See LICENSE in root directory for full details.
- // ----------------------------------------------------------------
- #include "Mesh.h"
- #include "Renderer.h"
- #include "Texture.h"
- #include "VertexArray.h"
- #include <fstream>
- #include <sstream>
- #include <rapidjson/document.h>
- #include <SDL/SDL_log.h>
- #include "Math.h"
- namespace
- {
- union Vertex
- {
- float f;
- uint8_t b[4];
- };
- }
- Mesh::Mesh()
- :mBox(Vector3::Infinity, Vector3::NegInfinity)
- ,mVertexArray(nullptr)
- ,mRadius(0.0f)
- ,mSpecPower(100.0f)
- {
- }
- Mesh::~Mesh()
- {
- }
- bool Mesh::Load(const std::string& fileName, Renderer* renderer)
- {
- std::ifstream file(fileName);
- if (!file.is_open())
- {
- SDL_Log("File not found: Mesh %s", fileName.c_str());
- return false;
- }
- std::stringstream fileStream;
- fileStream << file.rdbuf();
- std::string contents = fileStream.str();
- rapidjson::StringStream jsonStr(contents.c_str());
- rapidjson::Document doc;
- doc.ParseStream(jsonStr);
- if (!doc.IsObject())
- {
- SDL_Log("Mesh %s is not valid json", fileName.c_str());
- return false;
- }
- int ver = doc["version"].GetInt();
- // Check the version
- if (ver != 1)
- {
- SDL_Log("Mesh %s not version 1", fileName.c_str());
- return false;
- }
- mShaderName = doc["shader"].GetString();
- // Set the vertex layout/size based on the format in the file
- VertexArray::Layout layout = VertexArray::PosNormTex;
- size_t vertSize = 8;
- std::string vertexFormat = doc["vertexformat"].GetString();
- if (vertexFormat == "PosNormSkinTex")
- {
- layout = VertexArray::PosNormSkinTex;
- // This is the number of "Vertex" unions, which is 8 + 2 (for skinning)s
- vertSize = 10;
- }
- // Load textures
- const rapidjson::Value& textures = doc["textures"];
- if (!textures.IsArray() || textures.Size() < 1)
- {
- SDL_Log("Mesh %s has no textures, there should be at least one", fileName.c_str());
- return false;
- }
- mSpecPower = static_cast<float>(doc["specularPower"].GetDouble());
- for (rapidjson::SizeType i = 0; i < textures.Size(); i++)
- {
- // Is this texture already loaded?
- std::string texName = textures[i].GetString();
- Texture* t = renderer->GetTexture(texName);
- if (t == nullptr)
- {
- // Try loading the texture
- t = renderer->GetTexture(texName);
- if (t == nullptr)
- {
- // If it's still null, just use the default texture
- t = renderer->GetTexture("Assets/Default.png");
- }
- }
- mTextures.emplace_back(t);
- }
- // Load in the vertices
- const rapidjson::Value& vertsJson = doc["vertices"];
- if (!vertsJson.IsArray() || vertsJson.Size() < 1)
- {
- SDL_Log("Mesh %s has no vertices", fileName.c_str());
- return false;
- }
- std::vector<Vertex> vertices;
- vertices.reserve(vertsJson.Size() * vertSize);
- mRadius = 0.0f;
- for (rapidjson::SizeType i = 0; i < vertsJson.Size(); i++)
- {
- // For now, just assume we have 8 elements
- const rapidjson::Value& vert = vertsJson[i];
- if (!vert.IsArray())
- {
- SDL_Log("Unexpected vertex format for %s", fileName.c_str());
- return false;
- }
- Vector3 pos(vert[0].GetDouble(), vert[1].GetDouble(), vert[2].GetDouble());
- mRadius = Math::Max(mRadius, pos.LengthSq());
- mBox.UpdateMinMax(pos);
- if (layout == VertexArray::PosNormTex)
- {
- Vertex v;
- // Add the floats
- for (rapidjson::SizeType j = 0; j < vert.Size(); j++)
- {
- v.f = static_cast<float>(vert[j].GetDouble());
- vertices.emplace_back(v);
- }
- }
- else
- {
- Vertex v;
- // Add pos/normal
- for (rapidjson::SizeType j = 0; j < 6; j++)
- {
- v.f = static_cast<float>(vert[j].GetDouble());
- vertices.emplace_back(v);
- }
- // Add skin information
- for (rapidjson::SizeType j = 6; j < 14; j += 4)
- {
- v.b[0] = vert[j].GetUint();
- v.b[1] = vert[j + 1].GetUint();
- v.b[2] = vert[j + 2].GetUint();
- v.b[3] = vert[j + 3].GetUint();
- vertices.emplace_back(v);
- }
- // Add tex coords
- for (rapidjson::SizeType j = 14; j < vert.Size(); j++)
- {
- v.f = vert[j].GetDouble();
- vertices.emplace_back(v);
- }
- }
- }
- // We were computing length squared earlier
- mRadius = Math::Sqrt(mRadius);
- // Load in the indices
- const rapidjson::Value& indJson = doc["indices"];
- if (!indJson.IsArray() || indJson.Size() < 1)
- {
- SDL_Log("Mesh %s has no indices", fileName.c_str());
- return false;
- }
- std::vector<unsigned int> indices;
- indices.reserve(indJson.Size() * 3);
- for (rapidjson::SizeType i = 0; i < indJson.Size(); i++)
- {
- const rapidjson::Value& ind = indJson[i];
- if (!ind.IsArray() || ind.Size() != 3)
- {
- SDL_Log("Invalid indices for %s", fileName.c_str());
- return false;
- }
- indices.emplace_back(ind[0].GetUint());
- indices.emplace_back(ind[1].GetUint());
- indices.emplace_back(ind[2].GetUint());
- }
- // Now create a vertex array
- mVertexArray = new VertexArray(vertices.data(), static_cast<unsigned>(vertices.size()) / vertSize,
- layout, indices.data(), static_cast<unsigned>(indices.size()));
- return true;
- }
- void Mesh::Unload()
- {
- delete mVertexArray;
- mVertexArray = nullptr;
- }
- Texture* Mesh::GetTexture(size_t index)
- {
- if (index < mTextures.size())
- {
- return mTextures[index];
- }
- else
- {
- return nullptr;
- }
- }
|