Remove pointers from mesh and model vectors
- Hold models in unique_ptrpull/1196/head
parent
3a02e59b83
commit
7c5c903f47
|
@ -77,7 +77,7 @@ NoiseDisplacementFunc(float u, float v, void* info)
|
||||||
|
|
||||||
|
|
||||||
// TODO: The Celestia mesh format is deprecated
|
// TODO: The Celestia mesh format is deprecated
|
||||||
cmod::Model*
|
std::unique_ptr<cmod::Model>
|
||||||
LoadCelestiaMesh(const fs::path& filename)
|
LoadCelestiaMesh(const fs::path& filename)
|
||||||
{
|
{
|
||||||
std::ifstream meshFile(filename.string(), std::ios::in);
|
std::ifstream meshFile(filename.string(), std::ios::in);
|
||||||
|
@ -137,21 +137,19 @@ LoadCelestiaMesh(const fs::path& filename)
|
||||||
|
|
||||||
delete meshDefValue;
|
delete meshDefValue;
|
||||||
|
|
||||||
cmod::Model* model = new cmod::Model();
|
auto model = std::make_unique<cmod::Model>();
|
||||||
SphereMesh* sphereMesh = new SphereMesh(params.size,
|
SphereMesh sphereMesh(params.size,
|
||||||
static_cast<int>(params.rings),
|
static_cast<int>(params.rings),
|
||||||
static_cast<int>(params.slices),
|
static_cast<int>(params.slices),
|
||||||
NoiseDisplacementFunc,
|
NoiseDisplacementFunc,
|
||||||
(void*) ¶ms);
|
(void*) ¶ms);
|
||||||
cmod::Mesh* mesh = sphereMesh->convertToMesh();
|
model->addMesh(sphereMesh.convertToMesh());
|
||||||
model->addMesh(mesh);
|
|
||||||
delete sphereMesh;
|
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
cmod::Mesh*
|
cmod::Mesh
|
||||||
ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
const M3DScene& scene)
|
const M3DScene& scene)
|
||||||
{
|
{
|
||||||
|
@ -191,16 +189,12 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
|
|
||||||
// bool smooth = (mesh.getSmoothingGroupCount() == nFaces);
|
// bool smooth = (mesh.getSmoothingGroupCount() == nFaces);
|
||||||
|
|
||||||
Eigen::Vector3f* faceNormals = new Eigen::Vector3f[nFaces];
|
std::vector<Eigen::Vector3f> faceNormals;
|
||||||
Eigen::Vector3f* vertexNormals = new Eigen::Vector3f[nFaces * 3];
|
faceNormals.reserve(nFaces);
|
||||||
auto* faceCounts = new int[nVertices];
|
std::vector<Eigen::Vector3f> vertexNormals;
|
||||||
auto** vertexFaces = new int*[nVertices];
|
vertexNormals.reserve(nFaces * 3);
|
||||||
|
std::vector<int> faceCounts(nVertices, 0);
|
||||||
for (int i = 0; i < nVertices; i++)
|
std::vector<std::vector<int>> vertexFaces(nVertices);
|
||||||
{
|
|
||||||
faceCounts[i] = 0;
|
|
||||||
vertexFaces[i] = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate face normals
|
// generate face normals
|
||||||
for (int i = 0; i < nFaces; i++)
|
for (int i = 0; i < nFaces; i++)
|
||||||
|
@ -215,7 +209,7 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
Eigen::Vector3f p0 = mesh.getVertex(v0);
|
Eigen::Vector3f p0 = mesh.getVertex(v0);
|
||||||
Eigen::Vector3f p1 = mesh.getVertex(v1);
|
Eigen::Vector3f p1 = mesh.getVertex(v1);
|
||||||
Eigen::Vector3f p2 = mesh.getVertex(v2);
|
Eigen::Vector3f p2 = mesh.getVertex(v2);
|
||||||
faceNormals[i] = (p1 - p0).cross(p2 - p1).normalized();
|
faceNormals.push_back((p1 - p0).cross(p2 - p1).normalized());
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -223,9 +217,9 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
{
|
{
|
||||||
for (int i = 0; i < nFaces; i++)
|
for (int i = 0; i < nFaces; i++)
|
||||||
{
|
{
|
||||||
vertexNormals[i * 3] = faceNormals[i];
|
vertexNormals.push_back(faceNormals[i]);
|
||||||
vertexNormals[i * 3 + 1] = faceNormals[i];
|
vertexNormals.push_back(faceNormals[i]);
|
||||||
vertexNormals[i * 3 + 2] = faceNormals[i];
|
vertexNormals.push_back(faceNormals[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -234,7 +228,7 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
// allocate space for vertex face indices
|
// allocate space for vertex face indices
|
||||||
for (int i = 0; i < nVertices; i++)
|
for (int i = 0; i < nVertices; i++)
|
||||||
{
|
{
|
||||||
vertexFaces[i] = new int[faceCounts[i] + 1];
|
vertexFaces[i].resize(faceCounts[i] + 1);
|
||||||
vertexFaces[i][0] = faceCounts[i];
|
vertexFaces[i][0] = faceCounts[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +256,7 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
if (faceNormals[i].dot(faceNormals[k]) > 0.5f)
|
if (faceNormals[i].dot(faceNormals[k]) > 0.5f)
|
||||||
v += faceNormals[k];
|
v += faceNormals[k];
|
||||||
}
|
}
|
||||||
vertexNormals[i * 3] = v.normalized();
|
vertexNormals.push_back(v.normalized());
|
||||||
|
|
||||||
v = Eigen::Vector3f::Zero();
|
v = Eigen::Vector3f::Zero();
|
||||||
for (int j = 1; j <= vertexFaces[v1][0]; j++)
|
for (int j = 1; j <= vertexFaces[v1][0]; j++)
|
||||||
|
@ -272,7 +266,7 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
if (faceNormals[i].dot(faceNormals[k]) > 0.5f)
|
if (faceNormals[i].dot(faceNormals[k]) > 0.5f)
|
||||||
v += faceNormals[k];
|
v += faceNormals[k];
|
||||||
}
|
}
|
||||||
vertexNormals[i * 3 + 1] = v.normalized();
|
vertexNormals.push_back(v.normalized());
|
||||||
|
|
||||||
v = Eigen::Vector3f::Zero();
|
v = Eigen::Vector3f::Zero();
|
||||||
for (int j = 1; j <= vertexFaces[v2][0]; j++)
|
for (int j = 1; j <= vertexFaces[v2][0]; j++)
|
||||||
|
@ -282,7 +276,7 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
if (faceNormals[i].dot(faceNormals[k]) > 0.5f)
|
if (faceNormals[i].dot(faceNormals[k]) > 0.5f)
|
||||||
v += faceNormals[k];
|
v += faceNormals[k];
|
||||||
}
|
}
|
||||||
vertexNormals[i * 3 + 2] = v.normalized();
|
vertexNormals.push_back(v.normalized());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,9 +306,9 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the mesh
|
// Create the mesh
|
||||||
cmod::Mesh* newMesh = new cmod::Mesh();
|
cmod::Mesh newMesh;
|
||||||
newMesh->setVertexDescription(cmod::VertexDescription(std::move(attributes)));
|
newMesh.setVertexDescription(cmod::VertexDescription(std::move(attributes)));
|
||||||
newMesh->setVertices(nFaces * 3, std::move(vertexData));
|
newMesh.setVertices(nFaces * 3, std::move(vertexData));
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mesh.getMeshMaterialGroupCount(); ++i)
|
for (uint32_t i = 0; i < mesh.getMeshMaterialGroupCount(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -345,40 +339,30 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newMesh->addGroup(cmod::PrimitiveGroupType::TriList, materialIndex, std::move(indices));
|
newMesh.addGroup(cmod::PrimitiveGroupType::TriList, materialIndex, std::move(indices));
|
||||||
}
|
}
|
||||||
|
|
||||||
// clean up
|
|
||||||
delete[] faceNormals;
|
|
||||||
delete[] vertexNormals;
|
|
||||||
delete[] faceCounts;
|
|
||||||
for (int i = 0; i < nVertices; i++)
|
|
||||||
{
|
|
||||||
delete[] vertexFaces[i];
|
|
||||||
}
|
|
||||||
delete[] vertexFaces;
|
|
||||||
|
|
||||||
return newMesh;
|
return newMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
cmod::Model*
|
std::unique_ptr<cmod::Model>
|
||||||
Convert3DSModel(const M3DScene& scene, const fs::path& texPath)
|
Convert3DSModel(const M3DScene& scene, const fs::path& texPath)
|
||||||
{
|
{
|
||||||
cmod::Model* model = new cmod::Model();
|
auto model = std::make_unique<cmod::Model>();
|
||||||
|
|
||||||
// Convert the materials
|
// Convert the materials
|
||||||
for (std::uint32_t i = 0; i < scene.getMaterialCount(); i++)
|
for (std::uint32_t i = 0; i < scene.getMaterialCount(); i++)
|
||||||
{
|
{
|
||||||
const M3DMaterial* material = scene.getMaterial(i);
|
const M3DMaterial* material = scene.getMaterial(i);
|
||||||
cmod::Material* newMaterial = new cmod::Material();
|
cmod::Material newMaterial;
|
||||||
|
|
||||||
M3DColor diffuse = material->getDiffuseColor();
|
M3DColor diffuse = material->getDiffuseColor();
|
||||||
newMaterial->diffuse = cmod::Color(diffuse.red, diffuse.green, diffuse.blue);
|
newMaterial.diffuse = cmod::Color(diffuse.red, diffuse.green, diffuse.blue);
|
||||||
newMaterial->opacity = material->getOpacity();
|
newMaterial.opacity = material->getOpacity();
|
||||||
|
|
||||||
M3DColor specular = material->getSpecularColor();
|
M3DColor specular = material->getSpecularColor();
|
||||||
newMaterial->specular = cmod::Color(specular.red, specular.green, specular.blue);
|
newMaterial.specular = cmod::Color(specular.red, specular.green, specular.blue);
|
||||||
|
|
||||||
float shininess = material->getShininess();
|
float shininess = material->getShininess();
|
||||||
|
|
||||||
|
@ -386,17 +370,17 @@ Convert3DSModel(const M3DScene& scene, const fs::path& texPath)
|
||||||
// range that OpenGL uses for the specular exponent. The
|
// range that OpenGL uses for the specular exponent. The
|
||||||
// current equation is just a guess at the mapping that
|
// current equation is just a guess at the mapping that
|
||||||
// 3DS actually uses.
|
// 3DS actually uses.
|
||||||
newMaterial->specularPower = std::pow(2.0f, 1.0f + 0.1f * shininess);
|
newMaterial.specularPower = std::pow(2.0f, 1.0f + 0.1f * shininess);
|
||||||
if (newMaterial->specularPower > 128.0f)
|
if (newMaterial.specularPower > 128.0f)
|
||||||
newMaterial->specularPower = 128.0f;
|
newMaterial.specularPower = 128.0f;
|
||||||
|
|
||||||
if (!material->getTextureMap().empty())
|
if (!material->getTextureMap().empty())
|
||||||
{
|
{
|
||||||
ResourceHandle tex = GetTextureManager()->getHandle(TextureInfo(material->getTextureMap(), texPath, TextureInfo::WrapTexture));
|
ResourceHandle tex = GetTextureManager()->getHandle(TextureInfo(material->getTextureMap(), texPath, TextureInfo::WrapTexture));
|
||||||
newMaterial->setMap(cmod::TextureSemantic::DiffuseMap, tex);
|
newMaterial.setMap(cmod::TextureSemantic::DiffuseMap, tex);
|
||||||
}
|
}
|
||||||
|
|
||||||
model->addMaterial(newMaterial);
|
model->addMaterial(std::move(newMaterial));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert all models in the scene. Some confusing terminology: a 3ds 'scene' is the same
|
// Convert all models in the scene. Some confusing terminology: a 3ds 'scene' is the same
|
||||||
|
@ -411,8 +395,7 @@ Convert3DSModel(const M3DScene& scene, const fs::path& texPath)
|
||||||
const M3DTriangleMesh* mesh = model3ds->getTriMesh(j);
|
const M3DTriangleMesh* mesh = model3ds->getTriMesh(j);
|
||||||
if (mesh)
|
if (mesh)
|
||||||
{
|
{
|
||||||
cmod::Mesh* newMesh = ConvertTriangleMesh(*mesh, scene);
|
model->addMesh(ConvertTriangleMesh(*mesh, scene));
|
||||||
model->addMesh(newMesh);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -474,7 +457,7 @@ GeometryInfo::load(const fs::path& resolvedFilename)
|
||||||
fs::path filename = resolvedFilename.native().substr(0, uniquifyingSuffixStart);
|
fs::path filename = resolvedFilename.native().substr(0, uniquifyingSuffixStart);
|
||||||
|
|
||||||
std::clog << fmt::sprintf(_("Loading model: %s\n"), filename);
|
std::clog << fmt::sprintf(_("Loading model: %s\n"), filename);
|
||||||
cmod::Model* model = nullptr;
|
std::unique_ptr<cmod::Model> model = nullptr;
|
||||||
ContentType fileType = DetermineFileType(filename);
|
ContentType fileType = DetermineFileType(filename);
|
||||||
|
|
||||||
if (fileType == Content_3DStudio)
|
if (fileType == Content_3DStudio)
|
||||||
|
@ -561,7 +544,7 @@ GeometryInfo::load(const fs::path& resolvedFilename)
|
||||||
originalMaterialCount,
|
originalMaterialCount,
|
||||||
model->getMaterialCount());
|
model->getMaterialCount());
|
||||||
|
|
||||||
return new ModelGeometry(std::unique_ptr<cmod::Model>(model));
|
return new ModelGeometry(std::move(model));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -78,7 +78,7 @@ ModelGeometry::render(RenderContext& rc, double /* t */)
|
||||||
|
|
||||||
for (unsigned int i = 0; i < m_model->getMeshCount(); ++i)
|
for (unsigned int i = 0; i < m_model->getMeshCount(); ++i)
|
||||||
{
|
{
|
||||||
cmod::Mesh* mesh = m_model->getMesh(i);
|
const cmod::Mesh* mesh = m_model->getMesh(i);
|
||||||
const cmod::VertexDescription& vertexDesc = mesh->getVertexDescription();
|
const cmod::VertexDescription& vertexDesc = mesh->getVertexDescription();
|
||||||
|
|
||||||
GLuint vboId = 0;
|
GLuint vboId = 0;
|
||||||
|
@ -124,7 +124,7 @@ ModelGeometry::render(RenderContext& rc, double /* t */)
|
||||||
// Iterate over all meshes in the model
|
// Iterate over all meshes in the model
|
||||||
for (unsigned int meshIndex = 0; meshIndex < m_model->getMeshCount(); ++meshIndex)
|
for (unsigned int meshIndex = 0; meshIndex < m_model->getMeshCount(); ++meshIndex)
|
||||||
{
|
{
|
||||||
cmod::Mesh* mesh = m_model->getMesh(meshIndex);
|
const cmod::Mesh* mesh = m_model->getMesh(meshIndex);
|
||||||
|
|
||||||
const void* currentData = nullptr;
|
const void* currentData = nullptr;
|
||||||
GLuint currentVboId = 0;
|
GLuint currentVboId = 0;
|
||||||
|
|
|
@ -336,7 +336,7 @@ void SphereMesh::displace(DisplacementMapFunc func, void* info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
cmod::Mesh* SphereMesh::convertToMesh() const
|
cmod::Mesh SphereMesh::convertToMesh() const
|
||||||
{
|
{
|
||||||
static_assert(sizeof(float) == sizeof(cmod::VWord), "Float size mismatch with vertex data word size");
|
static_assert(sizeof(float) == sizeof(cmod::VWord), "Float size mismatch with vertex data word size");
|
||||||
constexpr std::uint32_t stride = 8;
|
constexpr std::uint32_t stride = 8;
|
||||||
|
@ -353,9 +353,9 @@ cmod::Mesh* SphereMesh::convertToMesh() const
|
||||||
6),
|
6),
|
||||||
};
|
};
|
||||||
|
|
||||||
cmod::Mesh* mesh = new cmod::Mesh();
|
cmod::Mesh mesh;
|
||||||
|
|
||||||
mesh->setVertexDescription(cmod::VertexDescription(std::move(attributes)));
|
mesh.setVertexDescription(cmod::VertexDescription(std::move(attributes)));
|
||||||
|
|
||||||
// Copy the vertex data from the separate position, normal, and texture coordinate
|
// Copy the vertex data from the separate position, normal, and texture coordinate
|
||||||
// arrays into a single array.
|
// arrays into a single array.
|
||||||
|
@ -369,7 +369,7 @@ cmod::Mesh* SphereMesh::convertToMesh() const
|
||||||
std::memcpy(vertex + 6, texCoords + (i * 2), sizeof(float) * 2);
|
std::memcpy(vertex + 6, texCoords + (i * 2), sizeof(float) * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh->setVertices(nVertices, std::move(vertexData));
|
mesh.setVertices(nVertices, std::move(vertexData));
|
||||||
|
|
||||||
for (int i = 0; i < nRings - 1; i++)
|
for (int i = 0; i < nRings - 1; i++)
|
||||||
{
|
{
|
||||||
|
@ -381,7 +381,7 @@ cmod::Mesh* SphereMesh::convertToMesh() const
|
||||||
indexData.push_back((i + 1) * (nSlices + 1) + j);
|
indexData.push_back((i + 1) * (nSlices + 1) + j);
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh->addGroup(cmod::PrimitiveGroupType::TriStrip, ~0u, std::move(indexData));
|
mesh.addGroup(cmod::PrimitiveGroupType::TriStrip, ~0u, std::move(indexData));
|
||||||
}
|
}
|
||||||
|
|
||||||
return mesh;
|
return mesh;
|
||||||
|
|
|
@ -43,7 +43,7 @@ public:
|
||||||
~SphereMesh();
|
~SphereMesh();
|
||||||
|
|
||||||
//! Convert this object into a standard Celestia mesh.
|
//! Convert this object into a standard Celestia mesh.
|
||||||
cmod::Mesh* convertToMesh() const;
|
cmod::Mesh convertToMesh() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createSphere(float radius, int _nRings, int _nSlices);
|
void createSphere(float radius, int _nRings, int _nSlices);
|
||||||
|
|
|
@ -116,6 +116,10 @@ class Material
|
||||||
public:
|
public:
|
||||||
Material();
|
Material();
|
||||||
~Material() = default;
|
~Material() = default;
|
||||||
|
Material(Material&&) = default;
|
||||||
|
Material& operator=(Material&&) = default;
|
||||||
|
|
||||||
|
Material clone() const { return *this; }
|
||||||
|
|
||||||
inline ResourceHandle getMap(TextureSemantic semantic) const
|
inline ResourceHandle getMap(TextureSemantic semantic) const
|
||||||
{
|
{
|
||||||
|
@ -141,6 +145,10 @@ public:
|
||||||
// Define an ordering for materials; required for elimination of duplicate
|
// Define an ordering for materials; required for elimination of duplicate
|
||||||
// materials.
|
// materials.
|
||||||
bool operator<(const Material& other) const;
|
bool operator<(const Material& other) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Material(const Material&) = default;
|
||||||
|
Material& operator=(const Material&) = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cmod
|
} // namespace cmod
|
||||||
|
|
|
@ -119,6 +119,22 @@ bool operator<(const VertexDescription& a, const VertexDescription& b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PrimitiveGroup
|
||||||
|
PrimitiveGroup::clone() const
|
||||||
|
{
|
||||||
|
PrimitiveGroup newGroup;
|
||||||
|
newGroup.prim = prim;
|
||||||
|
newGroup.materialIndex = materialIndex;
|
||||||
|
newGroup.indices = indices;
|
||||||
|
newGroup.primOverride = primOverride;
|
||||||
|
newGroup.vertexOverride = vertexOverride;
|
||||||
|
newGroup.vertexCountOverride = vertexCountOverride;
|
||||||
|
newGroup.indicesOverride = indicesOverride;
|
||||||
|
newGroup.vertexDescriptionOverride = vertexDescriptionOverride.clone();
|
||||||
|
return newGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
PrimitiveGroup::getPrimitiveCount() const
|
PrimitiveGroup::getPrimitiveCount() const
|
||||||
{
|
{
|
||||||
|
@ -143,10 +159,18 @@ PrimitiveGroup::getPrimitiveCount() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Mesh::~Mesh()
|
Mesh
|
||||||
|
Mesh::clone() const
|
||||||
{
|
{
|
||||||
for (const auto group : groups)
|
Mesh newMesh;
|
||||||
delete group;
|
newMesh.vertexDesc = vertexDesc.clone();
|
||||||
|
newMesh.nVertices = nVertices;
|
||||||
|
newMesh.vertices = vertices;
|
||||||
|
newMesh.groups.reserve(groups.size());
|
||||||
|
std::transform(groups.cbegin(), groups.cend(), std::back_inserter(newMesh.groups),
|
||||||
|
[](const PrimitiveGroup& group) { return group.clone(); });
|
||||||
|
newMesh.name = name;
|
||||||
|
return newMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -181,7 +205,7 @@ Mesh::getGroup(unsigned int index) const
|
||||||
if (index >= groups.size())
|
if (index >= groups.size())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return groups[index];
|
return &groups[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -191,19 +215,19 @@ Mesh::getGroup(unsigned int index)
|
||||||
if (index >= groups.size())
|
if (index >= groups.size())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return groups[index];
|
return &groups[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
Mesh::addGroup(PrimitiveGroup* group)
|
Mesh::addGroup(PrimitiveGroup&& group)
|
||||||
{
|
{
|
||||||
groups.push_back(group);
|
groups.push_back(std::move(group));
|
||||||
return groups.size();
|
return groups.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PrimitiveGroup*
|
PrimitiveGroup
|
||||||
Mesh::createLinePrimitiveGroup(bool lineStrip, const std::vector<Index32>& indices)
|
Mesh::createLinePrimitiveGroup(bool lineStrip, const std::vector<Index32>& indices)
|
||||||
{
|
{
|
||||||
// Transform LINE_STRIP/LINES to triangle vertices
|
// Transform LINE_STRIP/LINES to triangle vertices
|
||||||
|
@ -281,12 +305,13 @@ Mesh::createLinePrimitiveGroup(bool lineStrip, const std::vector<Index32>& indic
|
||||||
VertexAttribute(VertexAttributeSemantic::NextPosition, positionAttributes.format, originalStride),
|
VertexAttribute(VertexAttributeSemantic::NextPosition, positionAttributes.format, originalStride),
|
||||||
VertexAttribute(VertexAttributeSemantic::ScaleFactor, VertexAttributeFormat::Float1, originalStride + positionSize),
|
VertexAttribute(VertexAttributeSemantic::ScaleFactor, VertexAttributeFormat::Float1, originalStride + positionSize),
|
||||||
};
|
};
|
||||||
auto* g = new PrimitiveGroup();
|
|
||||||
g->vertexOverride = data;
|
PrimitiveGroup g;
|
||||||
g->vertexCountOverride = lineVertexCount;
|
g.vertexOverride = std::move(data);
|
||||||
g->vertexDescriptionOverride = appendingAttributes(vertexDesc, newAttributes.cbegin(), newAttributes.cend());
|
g.vertexCountOverride = lineVertexCount;
|
||||||
g->indicesOverride = std::move(newIndices);
|
g.vertexDescriptionOverride = appendingAttributes(vertexDesc, newAttributes.cbegin(), newAttributes.cend());
|
||||||
g->primOverride = PrimitiveGroupType::TriList;
|
g.indicesOverride = std::move(newIndices);
|
||||||
|
g.primOverride = PrimitiveGroupType::TriList;
|
||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,21 +321,21 @@ Mesh::addGroup(PrimitiveGroupType prim,
|
||||||
unsigned int materialIndex,
|
unsigned int materialIndex,
|
||||||
std::vector<Index32>&& indices)
|
std::vector<Index32>&& indices)
|
||||||
{
|
{
|
||||||
PrimitiveGroup* g;
|
PrimitiveGroup g;
|
||||||
if (prim == PrimitiveGroupType::LineStrip || prim == PrimitiveGroupType::LineList)
|
if (prim == PrimitiveGroupType::LineStrip || prim == PrimitiveGroupType::LineList)
|
||||||
{
|
{
|
||||||
g = createLinePrimitiveGroup(prim == PrimitiveGroupType::LineStrip, indices);
|
g = createLinePrimitiveGroup(prim == PrimitiveGroupType::LineStrip, indices);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g = new PrimitiveGroup();
|
g.primOverride = prim;
|
||||||
g->primOverride = prim;
|
|
||||||
}
|
}
|
||||||
g->indices = std::move(indices);
|
|
||||||
g->prim = prim;
|
|
||||||
g->materialIndex = materialIndex;
|
|
||||||
|
|
||||||
return addGroup(g);
|
g.indices = std::move(indices);
|
||||||
|
g.prim = prim;
|
||||||
|
g.materialIndex = materialIndex;
|
||||||
|
|
||||||
|
return addGroup(std::move(g));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -324,9 +349,6 @@ Mesh::getGroupCount() const
|
||||||
void
|
void
|
||||||
Mesh::clearGroups()
|
Mesh::clearGroups()
|
||||||
{
|
{
|
||||||
for (const auto group : groups)
|
|
||||||
delete group;
|
|
||||||
|
|
||||||
groups.clear();
|
groups.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,9 +370,9 @@ Mesh::setName(std::string&& _name)
|
||||||
void
|
void
|
||||||
Mesh::remapIndices(const std::vector<Index32>& indexMap)
|
Mesh::remapIndices(const std::vector<Index32>& indexMap)
|
||||||
{
|
{
|
||||||
for (auto group : groups)
|
for (auto& group : groups)
|
||||||
{
|
{
|
||||||
for (auto& index : group->indices)
|
for (auto& index : group.indices)
|
||||||
{
|
{
|
||||||
index = indexMap[index];
|
index = indexMap[index];
|
||||||
}
|
}
|
||||||
|
@ -361,8 +383,8 @@ Mesh::remapIndices(const std::vector<Index32>& indexMap)
|
||||||
void
|
void
|
||||||
Mesh::remapMaterials(const std::vector<unsigned int>& materialMap)
|
Mesh::remapMaterials(const std::vector<unsigned int>& materialMap)
|
||||||
{
|
{
|
||||||
for (auto group : groups)
|
for (auto& group : groups)
|
||||||
group->materialIndex = materialMap[group->materialIndex];
|
group.materialIndex = materialMap[group.materialIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -370,9 +392,9 @@ void
|
||||||
Mesh::aggregateByMaterial()
|
Mesh::aggregateByMaterial()
|
||||||
{
|
{
|
||||||
std::sort(groups.begin(), groups.end(),
|
std::sort(groups.begin(), groups.end(),
|
||||||
[](const PrimitiveGroup* g0, const PrimitiveGroup* g1)
|
[](const PrimitiveGroup& g0, const PrimitiveGroup& g1)
|
||||||
{
|
{
|
||||||
return g0->materialIndex < g1->materialIndex;
|
return g0.materialIndex < g1.materialIndex;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,10 +418,10 @@ Mesh::pick(const Eigen::Vector3d& rayOrigin, const Eigen::Vector3d& rayDirection
|
||||||
const VWord* vdata = vertices.data();
|
const VWord* vdata = vertices.data();
|
||||||
|
|
||||||
// Iterate over all primitive groups in the mesh
|
// Iterate over all primitive groups in the mesh
|
||||||
for (const auto group : groups)
|
for (const auto& group : groups)
|
||||||
{
|
{
|
||||||
PrimitiveGroupType primType = group->prim;
|
PrimitiveGroupType primType = group.prim;
|
||||||
Index32 nIndices = group->indices.size();
|
Index32 nIndices = group.indices.size();
|
||||||
|
|
||||||
// Only attempt to compute the intersection of the ray with triangle
|
// Only attempt to compute the intersection of the ray with triangle
|
||||||
// groups.
|
// groups.
|
||||||
|
@ -411,9 +433,9 @@ Mesh::pick(const Eigen::Vector3d& rayOrigin, const Eigen::Vector3d& rayDirection
|
||||||
{
|
{
|
||||||
unsigned int primitiveIndex = 0;
|
unsigned int primitiveIndex = 0;
|
||||||
Index32 index = 0;
|
Index32 index = 0;
|
||||||
Index32 i0 = group->indices[0];
|
Index32 i0 = group.indices[0];
|
||||||
Index32 i1 = group->indices[1];
|
Index32 i1 = group.indices[1];
|
||||||
Index32 i2 = group->indices[2];
|
Index32 i2 = group.indices[2];
|
||||||
|
|
||||||
// Iterate over the triangles in the primitive group
|
// Iterate over the triangles in the primitive group
|
||||||
do
|
do
|
||||||
|
@ -462,7 +484,7 @@ Mesh::pick(const Eigen::Vector3d& rayOrigin, const Eigen::Vector3d& rayDirection
|
||||||
closest = t;
|
closest = t;
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
result->group = group;
|
result->group = &group;
|
||||||
result->primitiveIndex = primitiveIndex;
|
result->primitiveIndex = primitiveIndex;
|
||||||
result->distance = closest;
|
result->distance = closest;
|
||||||
}
|
}
|
||||||
|
@ -477,9 +499,9 @@ Mesh::pick(const Eigen::Vector3d& rayOrigin, const Eigen::Vector3d& rayDirection
|
||||||
index += 3;
|
index += 3;
|
||||||
if (index < nIndices)
|
if (index < nIndices)
|
||||||
{
|
{
|
||||||
i0 = group->indices[index + 0];
|
i0 = group.indices[index + 0];
|
||||||
i1 = group->indices[index + 1];
|
i1 = group.indices[index + 1];
|
||||||
i2 = group->indices[index + 2];
|
i2 = group.indices[index + 2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (primType == PrimitiveGroupType::TriStrip)
|
else if (primType == PrimitiveGroupType::TriStrip)
|
||||||
|
@ -489,7 +511,7 @@ Mesh::pick(const Eigen::Vector3d& rayOrigin, const Eigen::Vector3d& rayDirection
|
||||||
{
|
{
|
||||||
i0 = i1;
|
i0 = i1;
|
||||||
i1 = i2;
|
i1 = i2;
|
||||||
i2 = group->indices[index];
|
i2 = group.indices[index];
|
||||||
// TODO: alternate orientation of triangles in a strip
|
// TODO: alternate orientation of triangles in a strip
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -500,7 +522,7 @@ Mesh::pick(const Eigen::Vector3d& rayOrigin, const Eigen::Vector3d& rayDirection
|
||||||
{
|
{
|
||||||
index += 1;
|
index += 1;
|
||||||
i1 = i2;
|
i1 = i2;
|
||||||
i2 = group->indices[index];
|
i2 = group.indices[index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -638,8 +660,8 @@ Mesh::getPrimitiveCount() const
|
||||||
{
|
{
|
||||||
unsigned int count = 0;
|
unsigned int count = 0;
|
||||||
|
|
||||||
for (const auto group : groups)
|
for (const auto& group : groups)
|
||||||
count += group->getPrimitiveCount();
|
count += group.getPrimitiveCount();
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,7 +161,10 @@ struct PrimitiveGroup
|
||||||
~PrimitiveGroup() = default;
|
~PrimitiveGroup() = default;
|
||||||
PrimitiveGroup(const PrimitiveGroup&) = delete;
|
PrimitiveGroup(const PrimitiveGroup&) = delete;
|
||||||
PrimitiveGroup& operator=(const PrimitiveGroup&) = delete;
|
PrimitiveGroup& operator=(const PrimitiveGroup&) = delete;
|
||||||
|
PrimitiveGroup(PrimitiveGroup&&) = default;
|
||||||
|
PrimitiveGroup& operator=(PrimitiveGroup&&) = default;
|
||||||
|
|
||||||
|
PrimitiveGroup clone() const;
|
||||||
unsigned int getPrimitiveCount() const;
|
unsigned int getPrimitiveCount() const;
|
||||||
|
|
||||||
PrimitiveGroupType prim{ PrimitiveGroupType::InvalidPrimitiveGroupType };
|
PrimitiveGroupType prim{ PrimitiveGroupType::InvalidPrimitiveGroupType };
|
||||||
|
@ -183,25 +186,28 @@ class Mesh
|
||||||
public:
|
public:
|
||||||
PickResult() = default;
|
PickResult() = default;
|
||||||
|
|
||||||
Mesh* mesh{ nullptr };
|
const Mesh* mesh{ nullptr };
|
||||||
PrimitiveGroup* group{ nullptr };
|
const PrimitiveGroup* group{ nullptr };
|
||||||
unsigned int primitiveIndex{ 0 };
|
unsigned int primitiveIndex{ 0 };
|
||||||
double distance{ -1.0 };
|
double distance{ -1.0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
Mesh() = default;
|
Mesh() = default;
|
||||||
~Mesh();
|
~Mesh() = default;
|
||||||
Mesh(const Mesh&) = delete;
|
Mesh(const Mesh&) = delete;
|
||||||
Mesh& operator=(const Mesh&) = delete;
|
Mesh& operator=(const Mesh&) = delete;
|
||||||
|
Mesh(Mesh&&) = default;
|
||||||
|
Mesh& operator=(Mesh&&) = default;
|
||||||
|
|
||||||
|
Mesh clone() const;
|
||||||
|
|
||||||
void setVertices(unsigned int _nVertices, std::vector<VWord>&& vertexData);
|
void setVertices(unsigned int _nVertices, std::vector<VWord>&& vertexData);
|
||||||
bool setVertexDescription(VertexDescription&& desc);
|
bool setVertexDescription(VertexDescription&& desc);
|
||||||
const VertexDescription& getVertexDescription() const;
|
const VertexDescription& getVertexDescription() const;
|
||||||
|
|
||||||
PrimitiveGroup* createLinePrimitiveGroup(bool lineStrip, const std::vector<Index32>& indices);
|
|
||||||
const PrimitiveGroup* getGroup(unsigned int index) const;
|
const PrimitiveGroup* getGroup(unsigned int index) const;
|
||||||
PrimitiveGroup* getGroup(unsigned int index);
|
PrimitiveGroup* getGroup(unsigned int index);
|
||||||
unsigned int addGroup(PrimitiveGroup* group);
|
unsigned int addGroup(PrimitiveGroup&& group);
|
||||||
unsigned int addGroup(PrimitiveGroupType prim,
|
unsigned int addGroup(PrimitiveGroupType prim,
|
||||||
unsigned int materialIndex,
|
unsigned int materialIndex,
|
||||||
std::vector<Index32>&& indices);
|
std::vector<Index32>&& indices);
|
||||||
|
@ -232,14 +238,14 @@ class Mesh
|
||||||
unsigned int getPrimitiveCount() const;
|
unsigned int getPrimitiveCount() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void recomputeBoundingBox();
|
PrimitiveGroup createLinePrimitiveGroup(bool lineStrip, const std::vector<Index32>& indices);
|
||||||
|
|
||||||
VertexDescription vertexDesc{ };
|
VertexDescription vertexDesc{ };
|
||||||
|
|
||||||
unsigned int nVertices{ 0 };
|
unsigned int nVertices{ 0 };
|
||||||
std::vector<VWord> vertices{ };
|
std::vector<VWord> vertices{ };
|
||||||
|
|
||||||
std::vector<PrimitiveGroup*> groups;
|
std::vector<PrimitiveGroup> groups;
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,9 @@
|
||||||
// of the License, or (at your option) any later version.
|
// of the License, or (at your option) any later version.
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <Eigen/Geometry>
|
#include <Eigen/Geometry>
|
||||||
|
|
||||||
|
@ -42,13 +44,6 @@ Model::Model()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Model::~Model()
|
|
||||||
{
|
|
||||||
for (const auto mesh : meshes)
|
|
||||||
delete mesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! Return the material with the specified index, or nullptr if
|
/*! Return the material with the specified index, or nullptr if
|
||||||
* the index is out of range. The returned material pointer
|
* the index is out of range. The returned material pointer
|
||||||
* is const.
|
* is const.
|
||||||
|
@ -57,7 +52,7 @@ const Material*
|
||||||
Model::getMaterial(unsigned int index) const
|
Model::getMaterial(unsigned int index) const
|
||||||
{
|
{
|
||||||
if (index < materials.size())
|
if (index < materials.size())
|
||||||
return materials[index];
|
return &materials[index];
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -67,7 +62,7 @@ Model::getMaterial(unsigned int index) const
|
||||||
* return value is the number of materials in the model.
|
* return value is the number of materials in the model.
|
||||||
*/
|
*/
|
||||||
unsigned int
|
unsigned int
|
||||||
Model::addMaterial(const Material* m)
|
Model::addMaterial(Material&& m)
|
||||||
{
|
{
|
||||||
// Update the texture map usage information for the model. Since
|
// Update the texture map usage information for the model. Since
|
||||||
// the material being added isn't necessarily used by a mesh within
|
// the material being added isn't necessarily used by a mesh within
|
||||||
|
@ -76,13 +71,13 @@ Model::addMaterial(const Material* m)
|
||||||
// if it forces multipass rendering when it's not required.
|
// if it forces multipass rendering when it's not required.
|
||||||
for (int i = 0; i < static_cast<int>(TextureSemantic::TextureSemanticMax); i++)
|
for (int i = 0; i < static_cast<int>(TextureSemantic::TextureSemanticMax); i++)
|
||||||
{
|
{
|
||||||
if (m->maps[i] != InvalidResource)
|
if (m.maps[i] != InvalidResource)
|
||||||
{
|
{
|
||||||
textureUsage[i] = true;
|
textureUsage[i] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
materials.push_back(m);
|
materials.push_back(std::move(m));
|
||||||
return materials.size();
|
return materials.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,8 +94,8 @@ Model::getVertexCount() const
|
||||||
{
|
{
|
||||||
unsigned int count = 0;
|
unsigned int count = 0;
|
||||||
|
|
||||||
for (const auto mesh : meshes)
|
for (const auto& mesh : meshes)
|
||||||
count += mesh->getVertexCount();
|
count += mesh.getVertexCount();
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -111,8 +106,8 @@ Model::getPrimitiveCount() const
|
||||||
{
|
{
|
||||||
unsigned int count = 0;
|
unsigned int count = 0;
|
||||||
|
|
||||||
for (const auto mesh : meshes)
|
for (const auto& mesh : meshes)
|
||||||
count += mesh->getPrimitiveCount();
|
count += mesh.getPrimitiveCount();
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -126,19 +121,29 @@ Model::getMeshCount() const
|
||||||
|
|
||||||
|
|
||||||
Mesh*
|
Mesh*
|
||||||
|
Model::getMesh(unsigned int index)
|
||||||
|
{
|
||||||
|
if (index < meshes.size())
|
||||||
|
return &meshes[index];
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Mesh*
|
||||||
Model::getMesh(unsigned int index) const
|
Model::getMesh(unsigned int index) const
|
||||||
{
|
{
|
||||||
if (index < meshes.size())
|
if (index < meshes.size())
|
||||||
return meshes[index];
|
return &meshes[index];
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
Model::addMesh(Mesh* m)
|
Model::addMesh(Mesh&& m)
|
||||||
{
|
{
|
||||||
meshes.push_back(m);
|
meshes.push_back(std::move(m));
|
||||||
return meshes.size();
|
return meshes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,15 +157,15 @@ Model::pick(const Eigen::Vector3d& rayOrigin,
|
||||||
double closest = maxDistance;
|
double closest = maxDistance;
|
||||||
Mesh::PickResult closestResult;
|
Mesh::PickResult closestResult;
|
||||||
|
|
||||||
for (const auto mesh : meshes)
|
for (const auto& mesh : meshes)
|
||||||
{
|
{
|
||||||
Mesh::PickResult result;
|
Mesh::PickResult result;
|
||||||
if (mesh->pick(rayOrigin, rayDirection, &result))
|
if (mesh.pick(rayOrigin, rayDirection, &result))
|
||||||
{
|
{
|
||||||
if (result.distance < closest)
|
if (result.distance < closest)
|
||||||
{
|
{
|
||||||
closestResult = result;
|
closestResult = result;
|
||||||
closestResult.mesh = mesh;
|
closestResult.mesh = &mesh;
|
||||||
closest = result.distance;
|
closest = result.distance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,8 +205,8 @@ Model::pick(const Eigen::Vector3d& rayOrigin, const Eigen::Vector3d& rayDirectio
|
||||||
void
|
void
|
||||||
Model::transform(const Eigen::Vector3f& translation, float scale)
|
Model::transform(const Eigen::Vector3f& translation, float scale)
|
||||||
{
|
{
|
||||||
for (const auto mesh : meshes)
|
for (auto& mesh : meshes)
|
||||||
mesh->transform(translation, scale);
|
mesh.transform(translation, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -210,8 +215,8 @@ Model::normalize(const Eigen::Vector3f& centerOffset)
|
||||||
{
|
{
|
||||||
Eigen::AlignedBox<float, 3> bbox;
|
Eigen::AlignedBox<float, 3> bbox;
|
||||||
|
|
||||||
for (const auto mesh : meshes)
|
for (const auto& mesh : meshes)
|
||||||
bbox.extend(mesh->getBoundingBox());
|
bbox.extend(mesh.getBoundingBox());
|
||||||
|
|
||||||
Eigen::Vector3f center = (bbox.min() + bbox.max()) * 0.5f + centerOffset;
|
Eigen::Vector3f center = (bbox.min() + bbox.max()) * 0.5f + centerOffset;
|
||||||
Eigen::Vector3f extents = bbox.max() - bbox.min();
|
Eigen::Vector3f extents = bbox.max() - bbox.min();
|
||||||
|
@ -236,22 +241,22 @@ Model::uniquifyMaterials()
|
||||||
|
|
||||||
// Sort the material indices so that we can uniquify the materials
|
// Sort the material indices so that we can uniquify the materials
|
||||||
std::sort(indices.begin(), indices.end(),
|
std::sort(indices.begin(), indices.end(),
|
||||||
[&](unsigned int a, unsigned int b) { return *materials[a] < *materials[b]; });
|
[&](unsigned int a, unsigned int b) { return materials[a] < materials[b]; });
|
||||||
|
|
||||||
// From the sorted index list construct the list of unique materials
|
// From the sorted index list construct the list of unique materials
|
||||||
// and a map to convert old material indices into indices that can be
|
// and a map to convert old material indices into indices that can be
|
||||||
// used with the uniquified material list.
|
// used with the uniquified material list.
|
||||||
std::vector<unsigned int> materialMap(materials.size());
|
std::vector<unsigned int> materialMap(materials.size());
|
||||||
|
|
||||||
std::vector<const Material*> uniqueMaterials;
|
std::vector<Material> uniqueMaterials;
|
||||||
uniqueMaterials.reserve(materials.size());
|
uniqueMaterials.reserve(materials.size());
|
||||||
|
|
||||||
for (std::size_t i = 0; i < indices.size(); ++i)
|
for (std::size_t i = 0; i < indices.size(); ++i)
|
||||||
{
|
{
|
||||||
unsigned int index = indices[i];
|
unsigned int index = indices[i];
|
||||||
if (i == 0 || *materials[index] != *uniqueMaterials.back())
|
if (i == 0 || materials[index] != uniqueMaterials.back())
|
||||||
{
|
{
|
||||||
uniqueMaterials.push_back(materials[index]);
|
uniqueMaterials.push_back(std::move(materials[index]));
|
||||||
}
|
}
|
||||||
|
|
||||||
materialMap[index] = uniqueMaterials.size() - 1;
|
materialMap[index] = uniqueMaterials.size() - 1;
|
||||||
|
@ -260,9 +265,9 @@ Model::uniquifyMaterials()
|
||||||
// Remap all the material indices in the model. Even if no materials have
|
// Remap all the material indices in the model. Even if no materials have
|
||||||
// been eliminated we've still sorted them by opacity, which is useful
|
// been eliminated we've still sorted them by opacity, which is useful
|
||||||
// when reordering meshes so that translucent ones are rendered last.
|
// when reordering meshes so that translucent ones are rendered last.
|
||||||
for (Mesh* mesh : meshes)
|
for (auto& mesh : meshes)
|
||||||
{
|
{
|
||||||
mesh->remapMaterials(materialMap);
|
mesh.remapMaterials(materialMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
materials = std::move(uniqueMaterials);
|
materials = std::move(uniqueMaterials);
|
||||||
|
@ -274,8 +279,8 @@ Model::determineOpacity()
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < materials.size(); i++)
|
for (unsigned int i = 0; i < materials.size(); i++)
|
||||||
{
|
{
|
||||||
if ((materials[i]->opacity > 0.01f && materials[i]->opacity < 1.0f) ||
|
if ((materials[i].opacity > 0.01f && materials[i].opacity < 1.0f) ||
|
||||||
materials[i]->blend == BlendMode::AdditiveBlend)
|
materials[i].blend == BlendMode::AdditiveBlend)
|
||||||
{
|
{
|
||||||
opaque = false;
|
opaque = false;
|
||||||
return;
|
return;
|
||||||
|
@ -308,12 +313,11 @@ Model::sortMeshes(const MeshComparator& comparator)
|
||||||
{
|
{
|
||||||
// Sort submeshes by material; if materials have been uniquified,
|
// Sort submeshes by material; if materials have been uniquified,
|
||||||
// then the submeshes will be ordered so that opaque ones are first.
|
// then the submeshes will be ordered so that opaque ones are first.
|
||||||
for (const auto mesh : meshes)
|
for (auto& mesh : meshes)
|
||||||
mesh->aggregateByMaterial();
|
mesh.aggregateByMaterial();
|
||||||
|
|
||||||
// Sort the meshes so that completely opaque ones are first
|
// Sort the meshes so that completely opaque ones are first
|
||||||
std::sort(meshes.begin(), meshes.end(),
|
std::sort(meshes.begin(), meshes.end(), std::ref(comparator));
|
||||||
[&](const Mesh* a, const Mesh* b) { return comparator(*a, *b); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end namespace cmod
|
} // end namespace cmod
|
||||||
|
|
|
@ -36,11 +36,11 @@ class Model
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Model();
|
Model();
|
||||||
~Model();
|
~Model() = default;
|
||||||
|
|
||||||
const Material* getMaterial(unsigned int index) const;
|
const Material* getMaterial(unsigned int index) const;
|
||||||
void setMaterial(unsigned int index, const Material* material);
|
void setMaterial(unsigned int index, const Material* material);
|
||||||
unsigned int addMaterial(const Material* material);
|
unsigned int addMaterial(Material&& material);
|
||||||
|
|
||||||
/*! Return the number of materials in the model
|
/*! Return the number of materials in the model
|
||||||
*/
|
*/
|
||||||
|
@ -54,10 +54,12 @@ class Model
|
||||||
*/
|
*/
|
||||||
unsigned int getPrimitiveCount() const;
|
unsigned int getPrimitiveCount() const;
|
||||||
|
|
||||||
|
Mesh* getMesh(unsigned int index);
|
||||||
|
|
||||||
/*! Return the mesh with the specified index, or nullptr if the
|
/*! Return the mesh with the specified index, or nullptr if the
|
||||||
* index is out of range.
|
* index is out of range.
|
||||||
*/
|
*/
|
||||||
Mesh* getMesh(unsigned int index) const;
|
const Mesh* getMesh(unsigned int index) const;
|
||||||
|
|
||||||
/*! Return the total number of meshes withing the model.
|
/*! Return the total number of meshes withing the model.
|
||||||
*/
|
*/
|
||||||
|
@ -66,7 +68,7 @@ class Model
|
||||||
/*! Add a new mesh to the model; the return value is the
|
/*! Add a new mesh to the model; the return value is the
|
||||||
* total number of meshes in the model.
|
* total number of meshes in the model.
|
||||||
*/
|
*/
|
||||||
unsigned int addMesh(Mesh* mesh);
|
unsigned int addMesh(Mesh&& mesh);
|
||||||
|
|
||||||
/** Find the closest intersection between the ray (given
|
/** Find the closest intersection between the ray (given
|
||||||
* by origin and direction) and the model. If the ray
|
* by origin and direction) and the model. If the ray
|
||||||
|
@ -148,14 +150,12 @@ class Model
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OpacityComparator() = default;
|
OpacityComparator() = default;
|
||||||
virtual ~OpacityComparator() = default;
|
bool operator()(const Mesh&, const Mesh&) const override;
|
||||||
|
|
||||||
virtual bool operator()(const Mesh&, const Mesh&) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<const Material*> materials;
|
std::vector<Material> materials{ };
|
||||||
std::vector<Mesh*> meshes;
|
std::vector<Mesh> meshes{ };
|
||||||
|
|
||||||
std::array<bool, static_cast<std::size_t>(TextureSemantic::TextureSemanticMax)> textureUsage;
|
std::array<bool, static_cast<std::size_t>(TextureSemantic::TextureSemanticMax)> textureUsage;
|
||||||
bool opaque{ true };
|
bool opaque{ true };
|
||||||
|
|
|
@ -90,7 +90,7 @@ public:
|
||||||
explicit ModelLoader(HandleGetter& _handleGetter) : handleGetter(_handleGetter) {}
|
explicit ModelLoader(HandleGetter& _handleGetter) : handleGetter(_handleGetter) {}
|
||||||
virtual ~ModelLoader() = default;
|
virtual ~ModelLoader() = default;
|
||||||
|
|
||||||
virtual Model* load() = 0;
|
virtual std::unique_ptr<Model> load() = 0;
|
||||||
|
|
||||||
const std::string& getErrorMessage() const { return errorMessage; }
|
const std::string& getErrorMessage() const { return errorMessage; }
|
||||||
ResourceHandle getHandle(const fs::path& path) { return handleGetter(path); }
|
ResourceHandle getHandle(const fs::path& path) { return handleGetter(path); }
|
||||||
|
@ -281,12 +281,12 @@ public:
|
||||||
{}
|
{}
|
||||||
~AsciiModelLoader() override = default;
|
~AsciiModelLoader() override = default;
|
||||||
|
|
||||||
Model* load() override;
|
std::unique_ptr<Model> load() override;
|
||||||
void reportError(const std::string& /*msg*/) override;
|
void reportError(const std::string& msg) override;
|
||||||
|
|
||||||
Material* loadMaterial();
|
bool loadMaterial(Material& material);
|
||||||
VertexDescription loadVertexDescription();
|
VertexDescription loadVertexDescription();
|
||||||
Mesh* loadMesh();
|
bool loadMesh(Mesh& mesh);
|
||||||
std::vector<VWord> loadVertices(const VertexDescription& vertexDesc,
|
std::vector<VWord> loadVertices(const VertexDescription& vertexDesc,
|
||||||
unsigned int& vertexCount);
|
unsigned int& vertexCount);
|
||||||
|
|
||||||
|
@ -303,22 +303,20 @@ AsciiModelLoader::reportError(const std::string& msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Material*
|
bool
|
||||||
AsciiModelLoader::loadMaterial()
|
AsciiModelLoader::loadMaterial(Material& material)
|
||||||
{
|
{
|
||||||
if (tok.nextToken() != Tokenizer::TokenName || tok.getNameValue() != MaterialToken)
|
if (tok.nextToken() != Tokenizer::TokenName || tok.getNameValue() != MaterialToken)
|
||||||
{
|
{
|
||||||
reportError("Material definition expected");
|
reportError("Material definition expected");
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* material = new Material();
|
material.diffuse = DefaultDiffuse;
|
||||||
|
material.specular = DefaultSpecular;
|
||||||
material->diffuse = DefaultDiffuse;
|
material.emissive = DefaultEmissive;
|
||||||
material->specular = DefaultSpecular;
|
material.specularPower = DefaultSpecularPower;
|
||||||
material->emissive = DefaultEmissive;
|
material.opacity = DefaultOpacity;
|
||||||
material->specularPower = DefaultSpecularPower;
|
|
||||||
material->opacity = DefaultOpacity;
|
|
||||||
|
|
||||||
while (tok.nextToken() == Tokenizer::TokenName && tok.getNameValue() != EndMaterialToken)
|
while (tok.nextToken() == Tokenizer::TokenName && tok.getNameValue() != EndMaterialToken)
|
||||||
{
|
{
|
||||||
|
@ -330,14 +328,13 @@ AsciiModelLoader::loadMaterial()
|
||||||
if (tok.nextToken() != Tokenizer::TokenString)
|
if (tok.nextToken() != Tokenizer::TokenString)
|
||||||
{
|
{
|
||||||
reportError("Texture name expected");
|
reportError("Texture name expected");
|
||||||
delete material;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string textureName = tok.getStringValue();
|
std::string textureName = tok.getStringValue();
|
||||||
|
|
||||||
ResourceHandle tex = getHandle(textureName);
|
ResourceHandle tex = getHandle(textureName);
|
||||||
material->setMap(texType, tex);
|
material.setMap(texType, tex);
|
||||||
}
|
}
|
||||||
else if (property == "blend")
|
else if (property == "blend")
|
||||||
{
|
{
|
||||||
|
@ -357,11 +354,10 @@ AsciiModelLoader::loadMaterial()
|
||||||
if (blendMode == BlendMode::InvalidBlend)
|
if (blendMode == BlendMode::InvalidBlend)
|
||||||
{
|
{
|
||||||
reportError("Bad blend mode in material");
|
reportError("Bad blend mode in material");
|
||||||
delete material;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
material->blend = blendMode;
|
material.blend = blendMode;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -379,8 +375,7 @@ AsciiModelLoader::loadMaterial()
|
||||||
if (tok.nextToken() != Tokenizer::TokenNumber)
|
if (tok.nextToken() != Tokenizer::TokenNumber)
|
||||||
{
|
{
|
||||||
reportError("Bad property value in material");
|
reportError("Bad property value in material");
|
||||||
delete material;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
data[i] = tok.getNumberValue();
|
data[i] = tok.getNumberValue();
|
||||||
}
|
}
|
||||||
|
@ -395,34 +390,33 @@ AsciiModelLoader::loadMaterial()
|
||||||
|
|
||||||
if (property == "diffuse")
|
if (property == "diffuse")
|
||||||
{
|
{
|
||||||
material->diffuse = colorVal;
|
material.diffuse = colorVal;
|
||||||
}
|
}
|
||||||
else if (property == "specular")
|
else if (property == "specular")
|
||||||
{
|
{
|
||||||
material->specular = colorVal;
|
material.specular = colorVal;
|
||||||
}
|
}
|
||||||
else if (property == "emissive")
|
else if (property == "emissive")
|
||||||
{
|
{
|
||||||
material->emissive = colorVal;
|
material.emissive = colorVal;
|
||||||
}
|
}
|
||||||
else if (property == "opacity")
|
else if (property == "opacity")
|
||||||
{
|
{
|
||||||
material->opacity = (float) data[0];
|
material.opacity = static_cast<float>(data[0]);
|
||||||
}
|
}
|
||||||
else if (property == "specpower")
|
else if (property == "specpower")
|
||||||
{
|
{
|
||||||
material->specularPower = (float) data[0];
|
material.specularPower = static_cast<float>(data[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tok.getTokenType() != Tokenizer::TokenName)
|
if (tok.getTokenType() != Tokenizer::TokenName)
|
||||||
{
|
{
|
||||||
delete material;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return material;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -599,29 +593,28 @@ AsciiModelLoader::loadVertices(const VertexDescription& vertexDesc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Mesh*
|
bool
|
||||||
AsciiModelLoader::loadMesh()
|
AsciiModelLoader::loadMesh(Mesh& mesh)
|
||||||
{
|
{
|
||||||
if (tok.nextToken() != Tokenizer::TokenName && tok.getNameValue() != MeshToken)
|
if (tok.nextToken() != Tokenizer::TokenName && tok.getNameValue() != MeshToken)
|
||||||
{
|
{
|
||||||
reportError("Mesh definition expected");
|
reportError("Mesh definition expected");
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
VertexDescription vertexDesc = loadVertexDescription();
|
VertexDescription vertexDesc = loadVertexDescription();
|
||||||
if (vertexDesc.attributes.empty())
|
if (vertexDesc.attributes.empty())
|
||||||
return nullptr;
|
return false;
|
||||||
|
|
||||||
unsigned int vertexCount = 0;
|
unsigned int vertexCount = 0;
|
||||||
std::vector<VWord> vertexData = loadVertices(vertexDesc, vertexCount);
|
std::vector<VWord> vertexData = loadVertices(vertexDesc, vertexCount);
|
||||||
if (vertexData.empty())
|
if (vertexData.empty())
|
||||||
{
|
{
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* mesh = new Mesh();
|
mesh.setVertexDescription(std::move(vertexDesc));
|
||||||
mesh->setVertexDescription(std::move(vertexDesc));
|
mesh.setVertices(vertexCount, std::move(vertexData));
|
||||||
mesh->setVertices(vertexCount, std::move(vertexData));
|
|
||||||
|
|
||||||
while (tok.nextToken() == Tokenizer::TokenName && tok.getNameValue() != EndMeshToken)
|
while (tok.nextToken() == Tokenizer::TokenName && tok.getNameValue() != EndMeshToken)
|
||||||
{
|
{
|
||||||
|
@ -629,15 +622,13 @@ AsciiModelLoader::loadMesh()
|
||||||
if (type == PrimitiveGroupType::InvalidPrimitiveGroupType)
|
if (type == PrimitiveGroupType::InvalidPrimitiveGroupType)
|
||||||
{
|
{
|
||||||
reportError("Bad primitive group type: " + tok.getStringValue());
|
reportError("Bad primitive group type: " + tok.getStringValue());
|
||||||
delete mesh;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tok.nextToken() != Tokenizer::TokenNumber || !tok.isInteger())
|
if (tok.nextToken() != Tokenizer::TokenNumber || !tok.isInteger())
|
||||||
{
|
{
|
||||||
reportError("Material index expected in primitive group");
|
reportError("Material index expected in primitive group");
|
||||||
delete mesh;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int materialIndex;
|
unsigned int materialIndex;
|
||||||
|
@ -653,8 +644,7 @@ AsciiModelLoader::loadMesh()
|
||||||
if (tok.nextToken() != Tokenizer::TokenNumber || !tok.isInteger())
|
if (tok.nextToken() != Tokenizer::TokenNumber || !tok.isInteger())
|
||||||
{
|
{
|
||||||
reportError("Index count expected in primitive group");
|
reportError("Index count expected in primitive group");
|
||||||
delete mesh;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int indexCount = (unsigned int) tok.getIntegerValue();
|
unsigned int indexCount = (unsigned int) tok.getIntegerValue();
|
||||||
|
@ -667,32 +657,30 @@ AsciiModelLoader::loadMesh()
|
||||||
if (tok.nextToken() != Tokenizer::TokenNumber || !tok.isInteger())
|
if (tok.nextToken() != Tokenizer::TokenNumber || !tok.isInteger())
|
||||||
{
|
{
|
||||||
reportError("Incomplete index list in primitive group");
|
reportError("Incomplete index list in primitive group");
|
||||||
delete mesh;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int index = (unsigned int) tok.getIntegerValue();
|
unsigned int index = (unsigned int) tok.getIntegerValue();
|
||||||
if (index >= vertexCount)
|
if (index >= vertexCount)
|
||||||
{
|
{
|
||||||
reportError("Index out of range");
|
reportError("Index out of range");
|
||||||
delete mesh;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
indices.push_back(index);
|
indices.push_back(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh->addGroup(type, materialIndex, std::move(indices));
|
mesh.addGroup(type, materialIndex, std::move(indices));
|
||||||
}
|
}
|
||||||
|
|
||||||
return mesh;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Model*
|
std::unique_ptr<Model>
|
||||||
AsciiModelLoader::load()
|
AsciiModelLoader::load()
|
||||||
{
|
{
|
||||||
auto* model = new Model();
|
auto model = std::make_unique<Model>();
|
||||||
bool seenMeshes = false;
|
bool seenMeshes = false;
|
||||||
|
|
||||||
// Parse material and mesh definitions
|
// Parse material and mesh definitions
|
||||||
|
@ -708,43 +696,38 @@ AsciiModelLoader::load()
|
||||||
if (seenMeshes)
|
if (seenMeshes)
|
||||||
{
|
{
|
||||||
reportError("Materials must be defined before meshes");
|
reportError("Materials must be defined before meshes");
|
||||||
delete model;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Material* material = loadMaterial();
|
Material material;
|
||||||
if (material == nullptr)
|
if (!loadMaterial(material))
|
||||||
{
|
{
|
||||||
delete model;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
model->addMaterial(material);
|
model->addMaterial(std::move(material));
|
||||||
}
|
}
|
||||||
else if (name == "mesh")
|
else if (name == "mesh")
|
||||||
{
|
{
|
||||||
seenMeshes = true;
|
seenMeshes = true;
|
||||||
|
|
||||||
Mesh* mesh = loadMesh();
|
Mesh mesh;
|
||||||
if (mesh == nullptr)
|
if (!loadMesh(mesh))
|
||||||
{
|
{
|
||||||
delete model;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
model->addMesh(mesh);
|
model->addMesh(std::move(mesh));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
reportError(fmt::format("Error: Unknown block type {}", name));
|
reportError(fmt::format("Error: Unknown block type {}", name));
|
||||||
delete model;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
reportError("Block name expected");
|
reportError("Block name expected");
|
||||||
delete model;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1240,12 +1223,12 @@ public:
|
||||||
{}
|
{}
|
||||||
~BinaryModelLoader() override = default;
|
~BinaryModelLoader() override = default;
|
||||||
|
|
||||||
Model* load() override;
|
std::unique_ptr<Model> load() override;
|
||||||
void reportError(const std::string& /*msg*/) override;
|
void reportError(const std::string& /*msg*/) override;
|
||||||
|
|
||||||
Material* loadMaterial();
|
bool loadMaterial(Material& material);
|
||||||
VertexDescription loadVertexDescription();
|
VertexDescription loadVertexDescription();
|
||||||
Mesh* loadMesh();
|
bool loadMesh(Mesh& mesh);
|
||||||
std::vector<VWord> loadVertices(const VertexDescription& vertexDesc,
|
std::vector<VWord> loadVertices(const VertexDescription& vertexDesc,
|
||||||
unsigned int& vertexCount);
|
unsigned int& vertexCount);
|
||||||
|
|
||||||
|
@ -1262,10 +1245,10 @@ BinaryModelLoader::reportError(const std::string& msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Model*
|
std::unique_ptr<Model>
|
||||||
BinaryModelLoader::load()
|
BinaryModelLoader::load()
|
||||||
{
|
{
|
||||||
auto* model = new Model();
|
auto model = std::make_unique<Model>();
|
||||||
bool seenMeshes = false;
|
bool seenMeshes = false;
|
||||||
|
|
||||||
// Parse material and mesh definitions
|
// Parse material and mesh definitions
|
||||||
|
@ -1276,7 +1259,6 @@ BinaryModelLoader::load()
|
||||||
{
|
{
|
||||||
if (in.eof()) { break; }
|
if (in.eof()) { break; }
|
||||||
reportError("Failed to read token");
|
reportError("Failed to read token");
|
||||||
delete model;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1285,36 +1267,32 @@ BinaryModelLoader::load()
|
||||||
if (seenMeshes)
|
if (seenMeshes)
|
||||||
{
|
{
|
||||||
reportError("Materials must be defined before meshes");
|
reportError("Materials must be defined before meshes");
|
||||||
delete model;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Material* material = loadMaterial();
|
Material material;
|
||||||
if (material == nullptr)
|
if (!loadMaterial(material))
|
||||||
{
|
{
|
||||||
delete model;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
model->addMaterial(material);
|
model->addMaterial(std::move(material));
|
||||||
}
|
}
|
||||||
else if (tok == CMOD_Mesh)
|
else if (tok == CMOD_Mesh)
|
||||||
{
|
{
|
||||||
seenMeshes = true;
|
seenMeshes = true;
|
||||||
|
|
||||||
Mesh* mesh = loadMesh();
|
Mesh mesh;
|
||||||
if (mesh == nullptr)
|
if (!loadMesh(mesh))
|
||||||
{
|
{
|
||||||
delete model;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
model->addMesh(mesh);
|
model->addMesh(std::move(mesh));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
reportError("Error: Unknown block type in model");
|
reportError("Error: Unknown block type in model");
|
||||||
delete model;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1323,16 +1301,14 @@ BinaryModelLoader::load()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Material*
|
bool
|
||||||
BinaryModelLoader::loadMaterial()
|
BinaryModelLoader::loadMaterial(Material& material)
|
||||||
{
|
{
|
||||||
auto* material = new Material();
|
material.diffuse = DefaultDiffuse;
|
||||||
|
material.specular = DefaultSpecular;
|
||||||
material->diffuse = DefaultDiffuse;
|
material.emissive = DefaultEmissive;
|
||||||
material->specular = DefaultSpecular;
|
material.specularPower = DefaultSpecularPower;
|
||||||
material->emissive = DefaultEmissive;
|
material.opacity = DefaultOpacity;
|
||||||
material->specularPower = DefaultSpecularPower;
|
|
||||||
material->opacity = DefaultOpacity;
|
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
@ -1340,54 +1316,48 @@ BinaryModelLoader::loadMaterial()
|
||||||
if (!readToken(in, tok))
|
if (!readToken(in, tok))
|
||||||
{
|
{
|
||||||
reportError("Error reading token type");
|
reportError("Error reading token type");
|
||||||
delete material;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (tok)
|
switch (tok)
|
||||||
{
|
{
|
||||||
case CMOD_Diffuse:
|
case CMOD_Diffuse:
|
||||||
if (!readTypeColor(in, material->diffuse))
|
if (!readTypeColor(in, material.diffuse))
|
||||||
{
|
{
|
||||||
reportError("Incorrect type for diffuse color");
|
reportError("Incorrect type for diffuse color");
|
||||||
delete material;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMOD_Specular:
|
case CMOD_Specular:
|
||||||
if (!readTypeColor(in, material->specular))
|
if (!readTypeColor(in, material.specular))
|
||||||
{
|
{
|
||||||
reportError("Incorrect type for specular color");
|
reportError("Incorrect type for specular color");
|
||||||
delete material;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMOD_Emissive:
|
case CMOD_Emissive:
|
||||||
if (!readTypeColor(in, material->emissive))
|
if (!readTypeColor(in, material.emissive))
|
||||||
{
|
{
|
||||||
reportError("Incorrect type for emissive color");
|
reportError("Incorrect type for emissive color");
|
||||||
delete material;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMOD_SpecularPower:
|
case CMOD_SpecularPower:
|
||||||
if (!readTypeFloat1(in, material->specularPower))
|
if (!readTypeFloat1(in, material.specularPower))
|
||||||
{
|
{
|
||||||
reportError("Float expected for specularPower");
|
reportError("Float expected for specularPower");
|
||||||
delete material;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMOD_Opacity:
|
case CMOD_Opacity:
|
||||||
if (!readTypeFloat1(in, material->opacity))
|
if (!readTypeFloat1(in, material.opacity))
|
||||||
{
|
{
|
||||||
reportError("Float expected for opacity");
|
reportError("Float expected for opacity");
|
||||||
delete material;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1398,10 +1368,9 @@ BinaryModelLoader::loadMaterial()
|
||||||
|| blendMode < 0 || blendMode >= static_cast<std::int16_t>(BlendMode::BlendMax))
|
|| blendMode < 0 || blendMode >= static_cast<std::int16_t>(BlendMode::BlendMax))
|
||||||
{
|
{
|
||||||
reportError("Bad blend mode");
|
reportError("Bad blend mode");
|
||||||
delete material;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
material->blend = static_cast<BlendMode>(blendMode);
|
material.blend = static_cast<BlendMode>(blendMode);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1412,39 +1381,35 @@ BinaryModelLoader::loadMaterial()
|
||||||
|| texType < 0 || texType >= static_cast<std::int16_t>(TextureSemantic::TextureSemanticMax))
|
|| texType < 0 || texType >= static_cast<std::int16_t>(TextureSemantic::TextureSemanticMax))
|
||||||
{
|
{
|
||||||
reportError("Bad texture type");
|
reportError("Bad texture type");
|
||||||
delete material;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string texfile;
|
std::string texfile;
|
||||||
if (!readTypeString(in, texfile))
|
if (!readTypeString(in, texfile))
|
||||||
{
|
{
|
||||||
reportError("String expected for texture filename");
|
reportError("String expected for texture filename");
|
||||||
delete material;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (texfile.empty())
|
if (texfile.empty())
|
||||||
{
|
{
|
||||||
reportError("Zero length texture name in material definition");
|
reportError("Zero length texture name in material definition");
|
||||||
delete material;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceHandle tex = getHandle(texfile);
|
ResourceHandle tex = getHandle(texfile);
|
||||||
material->maps[texType] = tex;
|
material.maps[texType] = tex;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMOD_EndMaterial:
|
case CMOD_EndMaterial:
|
||||||
return material;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Skip unrecognized tokens
|
// Skip unrecognized tokens
|
||||||
if (!ignoreValue(in))
|
if (!ignoreValue(in))
|
||||||
{
|
{
|
||||||
delete material;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
} // switch
|
} // switch
|
||||||
} // for
|
} // for
|
||||||
|
@ -1520,23 +1485,18 @@ BinaryModelLoader::loadVertexDescription()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Mesh*
|
bool
|
||||||
BinaryModelLoader::loadMesh()
|
BinaryModelLoader::loadMesh(Mesh& mesh)
|
||||||
{
|
{
|
||||||
VertexDescription vertexDesc = loadVertexDescription();
|
VertexDescription vertexDesc = loadVertexDescription();
|
||||||
if (vertexDesc.attributes.empty())
|
if (vertexDesc.attributes.empty()) { return false; }
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
unsigned int vertexCount = 0;
|
unsigned int vertexCount = 0;
|
||||||
std::vector<VWord> vertexData = loadVertices(vertexDesc, vertexCount);
|
std::vector<VWord> vertexData = loadVertices(vertexDesc, vertexCount);
|
||||||
if (vertexData.empty())
|
if (vertexData.empty()) { return false; }
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* mesh = new Mesh();
|
mesh.setVertexDescription(std::move(vertexDesc));
|
||||||
mesh->setVertexDescription(std::move(vertexDesc));
|
mesh.setVertices(vertexCount, std::move(vertexData));
|
||||||
mesh->setVertices(vertexCount, std::move(vertexData));
|
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
@ -1544,8 +1504,7 @@ BinaryModelLoader::loadMesh()
|
||||||
if (!celutil::readLE<std::int16_t>(in, tok))
|
if (!celutil::readLE<std::int16_t>(in, tok))
|
||||||
{
|
{
|
||||||
reportError("Failed to read token type");
|
reportError("Failed to read token type");
|
||||||
delete mesh;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tok == CMOD_EndMesh)
|
if (tok == CMOD_EndMesh)
|
||||||
|
@ -1555,8 +1514,7 @@ BinaryModelLoader::loadMesh()
|
||||||
if (tok < 0 || tok >= static_cast<std::int16_t>(PrimitiveGroupType::PrimitiveTypeMax))
|
if (tok < 0 || tok >= static_cast<std::int16_t>(PrimitiveGroupType::PrimitiveTypeMax))
|
||||||
{
|
{
|
||||||
reportError("Bad primitive group type");
|
reportError("Bad primitive group type");
|
||||||
delete mesh;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PrimitiveGroupType type = static_cast<PrimitiveGroupType>(tok);
|
PrimitiveGroupType type = static_cast<PrimitiveGroupType>(tok);
|
||||||
|
@ -1565,8 +1523,7 @@ BinaryModelLoader::loadMesh()
|
||||||
|| !celutil::readLE<std::uint32_t>(in, indexCount))
|
|| !celutil::readLE<std::uint32_t>(in, indexCount))
|
||||||
{
|
{
|
||||||
reportError("Could not read primitive indices");
|
reportError("Could not read primitive indices");
|
||||||
delete mesh;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Index32> indices;
|
std::vector<Index32> indices;
|
||||||
|
@ -1578,17 +1535,16 @@ BinaryModelLoader::loadMesh()
|
||||||
if (!celutil::readLE<std::uint32_t>(in, index) || index >= vertexCount)
|
if (!celutil::readLE<std::uint32_t>(in, index) || index >= vertexCount)
|
||||||
{
|
{
|
||||||
reportError("Index out of range");
|
reportError("Index out of range");
|
||||||
delete mesh;
|
return false;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
indices.push_back(index);
|
indices.push_back(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh->addGroup(type, materialIndex, std::move(indices));
|
mesh.addGroup(type, materialIndex, std::move(indices));
|
||||||
}
|
}
|
||||||
|
|
||||||
return mesh;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1942,7 +1898,8 @@ BinaryModelWriter::writeMaterial(const Material& material)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ModelLoader* OpenModel(std::istream& in, HandleGetter& getHandle)
|
std::unique_ptr<ModelLoader>
|
||||||
|
OpenModel(std::istream& in, HandleGetter& getHandle)
|
||||||
{
|
{
|
||||||
char header[CEL_MODEL_HEADER_LENGTH];
|
char header[CEL_MODEL_HEADER_LENGTH];
|
||||||
if (!in.read(header, CEL_MODEL_HEADER_LENGTH).good())
|
if (!in.read(header, CEL_MODEL_HEADER_LENGTH).good())
|
||||||
|
@ -1953,11 +1910,11 @@ ModelLoader* OpenModel(std::istream& in, HandleGetter& getHandle)
|
||||||
|
|
||||||
if (std::strncmp(header, CEL_MODEL_HEADER_ASCII, CEL_MODEL_HEADER_LENGTH) == 0)
|
if (std::strncmp(header, CEL_MODEL_HEADER_ASCII, CEL_MODEL_HEADER_LENGTH) == 0)
|
||||||
{
|
{
|
||||||
return new AsciiModelLoader(in, getHandle);
|
return std::make_unique<AsciiModelLoader>(in, getHandle);
|
||||||
}
|
}
|
||||||
if (std::strncmp(header, CEL_MODEL_HEADER_BINARY, CEL_MODEL_HEADER_LENGTH) == 0)
|
if (std::strncmp(header, CEL_MODEL_HEADER_BINARY, CEL_MODEL_HEADER_LENGTH) == 0)
|
||||||
{
|
{
|
||||||
return new BinaryModelLoader(in, getHandle);
|
return std::make_unique<BinaryModelLoader>(in, getHandle);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1970,20 +1927,19 @@ ModelLoader* OpenModel(std::istream& in, HandleGetter& getHandle)
|
||||||
} // end unnamed namespace
|
} // end unnamed namespace
|
||||||
|
|
||||||
|
|
||||||
Model* LoadModel(std::istream& in, HandleGetter handleGetter)
|
std::unique_ptr<Model>
|
||||||
|
LoadModel(std::istream& in, HandleGetter handleGetter)
|
||||||
{
|
{
|
||||||
ModelLoader* loader = OpenModel(in, handleGetter);
|
std::unique_ptr<ModelLoader> loader = OpenModel(in, handleGetter);
|
||||||
if (loader == nullptr)
|
if (loader == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
Model* model = loader->load();
|
std::unique_ptr<Model> model = loader->load();
|
||||||
if (model == nullptr)
|
if (model == nullptr)
|
||||||
{
|
{
|
||||||
std::cerr << "Error in model file: " << loader->getErrorMessage() << '\n';
|
std::cerr << "Error in model file: " << loader->getErrorMessage() << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
delete loader;
|
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,19 +12,19 @@
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <celcompat/filesystem.h>
|
#include <celcompat/filesystem.h>
|
||||||
#include <celutil/reshandle.h>
|
#include <celutil/reshandle.h>
|
||||||
#include "material.h"
|
#include "model.h"
|
||||||
|
|
||||||
namespace cmod
|
namespace cmod
|
||||||
{
|
{
|
||||||
class Model;
|
|
||||||
|
|
||||||
using HandleGetter = std::function<ResourceHandle(const fs::path&)>;
|
using HandleGetter = std::function<ResourceHandle(const fs::path&)>;
|
||||||
using SourceGetter = std::function<fs::path(ResourceHandle)>;
|
using SourceGetter = std::function<fs::path(ResourceHandle)>;
|
||||||
|
|
||||||
Model* LoadModel(std::istream& in, HandleGetter getHandle);
|
std::unique_ptr<Model> LoadModel(std::istream& in, HandleGetter getHandle);
|
||||||
|
|
||||||
bool SaveModelAscii(const Model* model, std::ostream& out, SourceGetter getSource);
|
bool SaveModelAscii(const Model* model, std::ostream& out, SourceGetter getSource);
|
||||||
bool SaveModelBinary(const Model* model, std::ostream& out, SourceGetter getSource);
|
bool SaveModelBinary(const Model* model, std::ostream& out, SourceGetter getSource);
|
||||||
|
|
|
@ -46,7 +46,7 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr << "Converting...\n";
|
std::cerr << "Converting...\n";
|
||||||
cmod::Model* model = Convert3DSModel(*scene, GetPathManager()->getHandle);
|
std::unique_ptr<cmod::Model> model = Convert3DSModel(*scene, GetPathManager()->getHandle);
|
||||||
if (!model)
|
if (!model)
|
||||||
{
|
{
|
||||||
std::cerr << "Error converting 3DS file to Celestia model\n";
|
std::cerr << "Error converting 3DS file to Celestia model\n";
|
||||||
|
@ -58,25 +58,22 @@ int main(int argc, char* argv[])
|
||||||
double weldTolerance = 1.0e-6;
|
double weldTolerance = 1.0e-6;
|
||||||
bool weldVertices = true;
|
bool weldVertices = true;
|
||||||
|
|
||||||
cmod::Model* newModel = GenerateModelNormals(*model, celmath::degToRad(smoothAngle), weldVertices, weldTolerance);
|
model = GenerateModelNormals(*model, celmath::degToRad(smoothAngle), weldVertices, weldTolerance);
|
||||||
delete model;
|
|
||||||
|
|
||||||
if (!newModel)
|
if (!model)
|
||||||
{
|
{
|
||||||
std::cerr << "Ran out of memory while generating surface normals.\n";
|
std::cerr << "Ran out of memory while generating surface normals.\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Automatically uniquify vertices
|
// Automatically uniquify vertices
|
||||||
for (unsigned int i = 0; newModel->getMesh(i) != nullptr; i++)
|
for (unsigned int i = 0; model->getMesh(i) != nullptr; i++)
|
||||||
{
|
{
|
||||||
cmod::Mesh* mesh = newModel->getMesh(i);
|
cmod::Mesh* mesh = model->getMesh(i);
|
||||||
UniquifyVertices(*mesh);
|
UniquifyVertices(*mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
model = newModel;
|
SaveModelAscii(model.get(), std::cout, GetPathManager()->getSource);
|
||||||
|
|
||||||
SaveModelAscii(model, std::cout, GetPathManager()->getSource);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,9 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <celmodel/mesh.h>
|
#include <celmodel/mesh.h>
|
||||||
#include <celmodel/model.h>
|
#include <celmodel/model.h>
|
||||||
|
@ -151,7 +153,7 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
PathManager pathManager;
|
PathManager pathManager;
|
||||||
|
|
||||||
cmod::Model* model = nullptr;
|
std::unique_ptr<cmod::Model> model = nullptr;
|
||||||
if (!inputFilename.empty())
|
if (!inputFilename.empty())
|
||||||
{
|
{
|
||||||
std::ifstream in(inputFilename, std::ios::in | std::ios::binary);
|
std::ifstream in(inputFilename, std::ios::in | std::ios::binary);
|
||||||
|
@ -172,52 +174,50 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
if (genNormals || genTangents)
|
if (genNormals || genTangents)
|
||||||
{
|
{
|
||||||
cmod::Model* newModel = new cmod::Model();
|
auto newModel = std::make_unique<cmod::Model>();
|
||||||
std::uint32_t i;
|
std::uint32_t i;
|
||||||
|
|
||||||
// Copy materials
|
// Copy materials
|
||||||
for (i = 0; model->getMaterial(i) != nullptr; i++)
|
for (i = 0; model->getMaterial(i) != nullptr; i++)
|
||||||
{
|
{
|
||||||
newModel->addMaterial(model->getMaterial(i));
|
newModel->addMaterial(model->getMaterial(i)->clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate normals and/or tangents for each model in the mesh
|
// Generate normals and/or tangents for each model in the mesh
|
||||||
for (i = 0; model->getMesh(i) != nullptr; i++)
|
for (i = 0; model->getMesh(i) != nullptr; i++)
|
||||||
{
|
{
|
||||||
cmod::Mesh* mesh = model->getMesh(i);
|
cmod::Mesh mesh = model->getMesh(i)->clone();
|
||||||
cmod::Mesh* newMesh = nullptr;
|
|
||||||
|
|
||||||
if (genNormals)
|
if (genNormals)
|
||||||
{
|
{
|
||||||
newMesh = GenerateNormals(*mesh,
|
cmod::Mesh newMesh = GenerateNormals(mesh,
|
||||||
celmath::degToRad(smoothAngle),
|
celmath::degToRad(smoothAngle),
|
||||||
weldVertices);
|
weldVertices);
|
||||||
if (newMesh == nullptr)
|
if (newMesh.getVertexCount() == 0)
|
||||||
{
|
{
|
||||||
std::cerr << "Error generating normals!\n";
|
std::cerr << "Error generating normals!\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// TODO: clean up old mesh
|
|
||||||
mesh = newMesh;
|
mesh = std::move(newMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (genTangents)
|
if (genTangents)
|
||||||
{
|
{
|
||||||
newMesh = GenerateTangents(*mesh, weldVertices);
|
cmod::Mesh newMesh = GenerateTangents(mesh, weldVertices);
|
||||||
if (newMesh == nullptr)
|
if (newMesh.getVertexCount() == 0)
|
||||||
{
|
{
|
||||||
std::cerr << "Error generating tangents!\n";
|
std::cerr << "Error generating tangents!\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// TODO: clean up old mesh
|
// TODO: clean up old mesh
|
||||||
mesh = newMesh;
|
mesh = std::move(newMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
newModel->addMesh(mesh);
|
newModel->addMesh(std::move(mesh));
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete model;
|
model = std::move(newModel);
|
||||||
model = newModel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mergeMeshes)
|
if (mergeMeshes)
|
||||||
|
@ -249,9 +249,9 @@ int main(int argc, char* argv[])
|
||||||
if (outputFilename.empty())
|
if (outputFilename.empty())
|
||||||
{
|
{
|
||||||
if (outputBinary)
|
if (outputBinary)
|
||||||
SaveModelBinary(model, std::cout, GetPathManager()->getSource);
|
SaveModelBinary(model.get(), std::cout, GetPathManager()->getSource);
|
||||||
else
|
else
|
||||||
SaveModelAscii(model, std::cout, GetPathManager()->getSource);
|
SaveModelAscii(model.get(), std::cout, GetPathManager()->getSource);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -270,9 +270,9 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outputBinary)
|
if (outputBinary)
|
||||||
SaveModelBinary(model, out, GetPathManager()->getSource);
|
SaveModelBinary(model.get(), out, GetPathManager()->getSource);
|
||||||
else
|
else
|
||||||
SaveModelAscii(model, out, GetPathManager()->getSource);
|
SaveModelAscii(model.get(), out, GetPathManager()->getSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <QActionGroup>
|
#include <QActionGroup>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
@ -60,22 +60,6 @@ namespace
|
||||||
// value whenever new tool widgets are added or removed.
|
// value whenever new tool widgets are added or removed.
|
||||||
constexpr int CMODVIEW_STATE_VERSION = 1;
|
constexpr int CMODVIEW_STATE_VERSION = 1;
|
||||||
|
|
||||||
|
|
||||||
cmod::Material*
|
|
||||||
cloneMaterial(const cmod::Material* other)
|
|
||||||
{
|
|
||||||
cmod::Material* material = new cmod::Material();
|
|
||||||
material->diffuse = other->diffuse;
|
|
||||||
material->specular = other->specular;
|
|
||||||
material->emissive = other->emissive;
|
|
||||||
material->specularPower = other->specularPower;
|
|
||||||
material->opacity = other->opacity;
|
|
||||||
material->blend = other->blend;
|
|
||||||
material->maps = other->maps;
|
|
||||||
|
|
||||||
return material;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end unnamed namespace
|
} // end unnamed namespace
|
||||||
|
|
||||||
|
|
||||||
|
@ -277,11 +261,11 @@ MainWindow::eventFilter(QObject* obj, QEvent* e)
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MainWindow::setModel(const QString& fileName, cmod::Model* model)
|
MainWindow::setModel(const QString& fileName, std::unique_ptr<cmod::Model>&& model)
|
||||||
{
|
{
|
||||||
QFileInfo info(fileName);
|
QFileInfo info(fileName);
|
||||||
QString modelDir = info.absoluteDir().path();
|
QString modelDir = info.absoluteDir().path();
|
||||||
m_modelView->setModel(model, modelDir);
|
m_modelView->setModel(std::move(model), modelDir);
|
||||||
|
|
||||||
// Only reset the camera when we've loaded a new model. Leaving
|
// Only reset the camera when we've loaded a new model. Leaving
|
||||||
// the camera fixed allows to see model changes more easily.
|
// the camera fixed allows to see model changes more easily.
|
||||||
|
@ -300,7 +284,7 @@ MainWindow::setModel(const QString& fileName, cmod::Model* model)
|
||||||
void
|
void
|
||||||
MainWindow::showModelStatistics()
|
MainWindow::showModelStatistics()
|
||||||
{
|
{
|
||||||
cmod::Model* model = m_modelView->model();
|
const cmod::Model* model = m_modelView->model();
|
||||||
if (model)
|
if (model)
|
||||||
{
|
{
|
||||||
// Count triangles and vertices in the mesh
|
// Count triangles and vertices in the mesh
|
||||||
|
@ -410,7 +394,7 @@ MainWindow::openModel(const QString& fileName)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmod::Model* model = Convert3DSModel(*scene, GetPathManager()->getHandle);
|
std::unique_ptr<cmod::Model> model = Convert3DSModel(*scene, GetPathManager()->getHandle);
|
||||||
if (model == nullptr)
|
if (model == nullptr)
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, "Load error", tr("Internal error converting 3DS file %1").arg(fileName));
|
QMessageBox::warning(this, "Load error", tr("Internal error converting 3DS file %1").arg(fileName));
|
||||||
|
@ -422,28 +406,29 @@ MainWindow::openModel(const QString& fileName)
|
||||||
double weldTolerance = 1.0e-6;
|
double weldTolerance = 1.0e-6;
|
||||||
bool weldVertices = true;
|
bool weldVertices = true;
|
||||||
|
|
||||||
cmod::Model* newModel = GenerateModelNormals(*model, celmath::degToRad(smoothAngle), weldVertices, weldTolerance);
|
model = GenerateModelNormals(*model,
|
||||||
delete model;
|
celmath::degToRad(smoothAngle),
|
||||||
|
weldVertices,
|
||||||
|
weldTolerance);
|
||||||
|
|
||||||
if (!newModel)
|
if (!model)
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, tr("Mesh Load Error"), tr("Internal error when loading mesh"));
|
QMessageBox::warning(this, tr("Mesh Load Error"), tr("Internal error when loading mesh"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Automatically uniquify vertices
|
// Automatically uniquify vertices
|
||||||
for (unsigned int i = 0; newModel->getMesh(i) != nullptr; i++)
|
for (unsigned int i = 0; model->getMesh(i) != nullptr; i++)
|
||||||
{
|
{
|
||||||
cmod::Mesh* mesh = newModel->getMesh(i);
|
cmod::Mesh* mesh = model->getMesh(i);
|
||||||
UniquifyVertices(*mesh);
|
UniquifyVertices(*mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
setModel(fileName, newModel);
|
setModel(fileName, std::move(model));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (info.suffix().toLower() == "obj")
|
else if (info.suffix().toLower() == "obj")
|
||||||
{
|
{
|
||||||
cmod::Model* model = nullptr;
|
|
||||||
std::ifstream in(fileNameStd, std::ios::in | std::ios::binary);
|
std::ifstream in(fileNameStd, std::ios::in | std::ios::binary);
|
||||||
if (!in.good())
|
if (!in.good())
|
||||||
{
|
{
|
||||||
|
@ -452,7 +437,7 @@ MainWindow::openModel(const QString& fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
WavefrontLoader loader(in);
|
WavefrontLoader loader(in);
|
||||||
model = loader.load();
|
std::unique_ptr<cmod::Model> model = loader.load();
|
||||||
|
|
||||||
if (model == nullptr)
|
if (model == nullptr)
|
||||||
{
|
{
|
||||||
|
@ -467,11 +452,10 @@ MainWindow::openModel(const QString& fileName)
|
||||||
UniquifyVertices(*mesh);
|
UniquifyVertices(*mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
setModel(fileName, model);
|
setModel(fileName, std::move(model));
|
||||||
}
|
}
|
||||||
else if (info.suffix().toLower() == "cmod")
|
else if (info.suffix().toLower() == "cmod")
|
||||||
{
|
{
|
||||||
cmod::Model* model = nullptr;
|
|
||||||
std::ifstream in(fileNameStd, std::ios::in | std::ios::binary);
|
std::ifstream in(fileNameStd, std::ios::in | std::ios::binary);
|
||||||
if (!in.good())
|
if (!in.good())
|
||||||
{
|
{
|
||||||
|
@ -479,14 +463,14 @@ MainWindow::openModel(const QString& fileName)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
model = cmod::LoadModel(in, GetPathManager()->getHandle);
|
std::unique_ptr<cmod::Model> model = cmod::LoadModel(in, GetPathManager()->getHandle);
|
||||||
if (model == nullptr)
|
if (model == nullptr)
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, "Load error", tr("Error reading CMOD file %1").arg(fileName));
|
QMessageBox::warning(this, "Load error", tr("Error reading CMOD file %1").arg(fileName));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setModel(fileName, model);
|
setModel(fileName, std::move(model));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -580,7 +564,7 @@ MainWindow::setRenderPath(QAction* action)
|
||||||
void
|
void
|
||||||
MainWindow::generateNormals()
|
MainWindow::generateNormals()
|
||||||
{
|
{
|
||||||
cmod::Model* model = m_modelView->model();
|
const cmod::Model* model = m_modelView->model();
|
||||||
if (!model)
|
if (!model)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -624,17 +608,17 @@ MainWindow::generateNormals()
|
||||||
double weldTolerance = toleranceEdit->text().toDouble();
|
double weldTolerance = toleranceEdit->text().toDouble();
|
||||||
bool weldVertices = true;
|
bool weldVertices = true;
|
||||||
|
|
||||||
cmod::Model* newModel = GenerateModelNormals(*model,
|
std::unique_ptr<cmod::Model> newModel = GenerateModelNormals(*model,
|
||||||
celmath::degToRad(smoothAngle),
|
celmath::degToRad(smoothAngle),
|
||||||
weldVertices,
|
weldVertices,
|
||||||
weldTolerance);
|
weldTolerance);
|
||||||
if (!newModel)
|
if (!newModel)
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, tr("Internal Error"), tr("Out of memory error during normal generation"));
|
QMessageBox::warning(this, tr("Internal Error"), tr("Out of memory error during normal generation"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
setModel(modelFileName(), newModel);
|
setModel(modelFileName(), std::move(newModel));
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.setValue("SmoothAngle", smoothAngle);
|
settings.setValue("SmoothAngle", smoothAngle);
|
||||||
|
@ -646,7 +630,7 @@ MainWindow::generateNormals()
|
||||||
void
|
void
|
||||||
MainWindow::generateTangents()
|
MainWindow::generateTangents()
|
||||||
{
|
{
|
||||||
cmod::Model* model = m_modelView->model();
|
const cmod::Model* model = m_modelView->model();
|
||||||
if (!model)
|
if (!model)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -678,32 +662,30 @@ MainWindow::generateTangents()
|
||||||
double weldTolerance = toleranceEdit->text().toDouble();
|
double weldTolerance = toleranceEdit->text().toDouble();
|
||||||
bool weldVertices = true;
|
bool weldVertices = true;
|
||||||
|
|
||||||
cmod::Model* newModel = new cmod::Model();
|
auto newModel = std::make_unique<cmod::Model>();
|
||||||
|
|
||||||
// Copy materials
|
// Copy materials
|
||||||
for (unsigned int i = 0; model->getMaterial(i) != nullptr; i++)
|
for (unsigned int i = 0; model->getMaterial(i) != nullptr; i++)
|
||||||
{
|
{
|
||||||
newModel->addMaterial(cloneMaterial(model->getMaterial(i)));
|
newModel->addMaterial(model->getMaterial(i)->clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; model->getMesh(i) != nullptr; i++)
|
for (unsigned int i = 0; model->getMesh(i) != nullptr; i++)
|
||||||
{
|
{
|
||||||
cmod::Mesh* mesh = model->getMesh(i);
|
const cmod::Mesh* mesh = model->getMesh(i);
|
||||||
cmod::Mesh* newMesh = nullptr;
|
cmod::Mesh newMesh = GenerateTangents(*mesh, weldVertices);
|
||||||
|
if (newMesh.getVertexCount() == 0)
|
||||||
newMesh = GenerateTangents(*mesh, weldVertices);
|
|
||||||
if (newMesh == nullptr)
|
|
||||||
{
|
{
|
||||||
std::cerr << "Error generating normals!\n";
|
std::cerr << "Error generating normals!\n";
|
||||||
// TODO: Clone the mesh and add it to the model
|
// TODO: Clone the mesh and add it to the model
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newModel->addMesh(newMesh);
|
newModel->addMesh(std::move(newMesh));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setModel(modelFileName(), newModel);
|
setModel(modelFileName(), std::move(newModel));
|
||||||
|
|
||||||
settings.setValue("WeldTolerance", weldTolerance);
|
settings.setValue("WeldTolerance", weldTolerance);
|
||||||
}
|
}
|
||||||
|
@ -733,14 +715,13 @@ MainWindow::uniquifyVertices()
|
||||||
void
|
void
|
||||||
MainWindow::mergeMeshes()
|
MainWindow::mergeMeshes()
|
||||||
{
|
{
|
||||||
cmod::Model* model = m_modelView->model();
|
const cmod::Model* model = m_modelView->model();
|
||||||
if (!model)
|
if (!model)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmod::Model* newModel = MergeModelMeshes(*model);
|
setModel(modelFileName(), MergeModelMeshes(*model));
|
||||||
setModel(modelFileName(), newModel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -754,8 +735,8 @@ MainWindow::updateSelectionInfo()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_materialWidget->setEnabled(true);
|
m_materialWidget->setEnabled(true);
|
||||||
QSetIterator<cmod::PrimitiveGroup*> iter(m_modelView->selection());
|
QSetIterator<const cmod::PrimitiveGroup*> iter(m_modelView->selection());
|
||||||
cmod::PrimitiveGroup* selectedGroup = iter.next();
|
const cmod::PrimitiveGroup* selectedGroup = iter.next();
|
||||||
const cmod::Material* material = m_modelView->model()->getMaterial(selectedGroup->materialIndex);
|
const cmod::Material* material = m_modelView->model()->getMaterial(selectedGroup->materialIndex);
|
||||||
if (material)
|
if (material)
|
||||||
{
|
{
|
||||||
|
@ -770,8 +751,8 @@ MainWindow::changeCurrentMaterial(const cmod::Material& material)
|
||||||
{
|
{
|
||||||
if (!m_modelView->selection().isEmpty())
|
if (!m_modelView->selection().isEmpty())
|
||||||
{
|
{
|
||||||
QSetIterator<cmod::PrimitiveGroup*> iter(m_modelView->selection());
|
QSetIterator<const cmod::PrimitiveGroup*> iter(m_modelView->selection());
|
||||||
cmod::PrimitiveGroup* selectedGroup = iter.next();
|
const cmod::PrimitiveGroup* selectedGroup = iter.next();
|
||||||
m_modelView->setMaterial(selectedGroup->materialIndex, material);
|
m_modelView->setMaterial(selectedGroup->materialIndex, material);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
|
@ -34,7 +36,7 @@ class MainWindow : public QMainWindow
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MainWindow();
|
MainWindow();
|
||||||
void setModel(const QString& filename, cmod::Model* model);
|
void setModel(const QString& filename, std::unique_ptr<cmod::Model>&& model);
|
||||||
void setModelFileName(const QString& fileName);
|
void setModelFileName(const QString& fileName);
|
||||||
QString modelFileName() const
|
QString modelFileName() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QIODevice>
|
#include <QIODevice>
|
||||||
|
@ -282,18 +283,13 @@ ModelViewWidget::ModelViewWidget(QWidget *parent) :
|
||||||
ModelViewWidget::~ModelViewWidget()
|
ModelViewWidget::~ModelViewWidget()
|
||||||
{
|
{
|
||||||
delete m_materialLibrary;
|
delete m_materialLibrary;
|
||||||
delete m_model;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ModelViewWidget::setModel(cmod::Model* model, const QString& modelDirPath)
|
ModelViewWidget::setModel(std::unique_ptr<cmod::Model>&& model, const QString& modelDirPath)
|
||||||
{
|
{
|
||||||
if (m_model && m_model != model)
|
m_model = std::move(model);
|
||||||
{
|
|
||||||
delete m_model;
|
|
||||||
}
|
|
||||||
m_model = model;
|
|
||||||
delete m_materialLibrary;
|
delete m_materialLibrary;
|
||||||
|
|
||||||
m_materialLibrary = new MaterialLibrary(this, modelDirPath);
|
m_materialLibrary = new MaterialLibrary(this, modelDirPath);
|
||||||
|
@ -634,12 +630,12 @@ ModelViewWidget::paintGL()
|
||||||
|
|
||||||
if (m_model)
|
if (m_model)
|
||||||
{
|
{
|
||||||
renderModel(m_model);
|
renderModel(m_model.get());
|
||||||
if (!m_selection.isEmpty())
|
if (!m_selection.isEmpty())
|
||||||
{
|
{
|
||||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||||
glPolygonOffset(-0.0f, -1.0f);
|
glPolygonOffset(-0.0f, -1.0f);
|
||||||
renderSelection(m_model);
|
renderSelection(m_model.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1589,7 +1585,7 @@ ModelViewWidget::renderShadow(unsigned int lightIndex)
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glLoadMatrixf(directionalLightMatrix(lightDirection).data());
|
glLoadMatrixf(directionalLightMatrix(lightDirection).data());
|
||||||
|
|
||||||
renderDepthOnly(m_model);
|
renderDepthOnly(m_model.get());
|
||||||
|
|
||||||
shadowBuffer->unbind();
|
shadowBuffer->unbind();
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QGLWidget>
|
#include <QGLWidget>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
@ -146,11 +148,9 @@ public:
|
||||||
ModelViewWidget(QWidget *parent);
|
ModelViewWidget(QWidget *parent);
|
||||||
~ModelViewWidget();
|
~ModelViewWidget();
|
||||||
|
|
||||||
void setModel(cmod::Model* model, const QString& modelDir);
|
void setModel(std::unique_ptr<cmod::Model>&& model, const QString& modelDir);
|
||||||
cmod::Model* model() const
|
cmod::Model* model() { return m_model.get(); }
|
||||||
{
|
const cmod::Model* model() const { return m_model.get(); }
|
||||||
return m_model;
|
|
||||||
}
|
|
||||||
|
|
||||||
void resetCamera();
|
void resetCamera();
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ public:
|
||||||
void wheelEvent(QWheelEvent* event);
|
void wheelEvent(QWheelEvent* event);
|
||||||
|
|
||||||
void select(const Eigen::Vector2f& point);
|
void select(const Eigen::Vector2f& point);
|
||||||
QSet<cmod::PrimitiveGroup*> selection()
|
QSet<const cmod::PrimitiveGroup*> selection()
|
||||||
{
|
{
|
||||||
return m_selection;
|
return m_selection;
|
||||||
}
|
}
|
||||||
|
@ -238,7 +238,7 @@ private:
|
||||||
GLShaderProgram* createShader(const ShaderKey& shaderKey);
|
GLShaderProgram* createShader(const ShaderKey& shaderKey);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
cmod::Model* m_model;
|
std::unique_ptr<cmod::Model> m_model;
|
||||||
double m_modelBoundingRadius;
|
double m_modelBoundingRadius;
|
||||||
Eigen::Vector3d m_cameraPosition;
|
Eigen::Vector3d m_cameraPosition;
|
||||||
Eigen::Quaterniond m_cameraOrientation;
|
Eigen::Quaterniond m_cameraOrientation;
|
||||||
|
@ -249,7 +249,7 @@ private:
|
||||||
|
|
||||||
MaterialLibrary* m_materialLibrary;
|
MaterialLibrary* m_materialLibrary;
|
||||||
|
|
||||||
QSet<cmod::PrimitiveGroup*> m_selection;
|
QSet<const cmod::PrimitiveGroup*> m_selection;
|
||||||
QHash<ShaderKey, GLShaderProgram*> m_shaderCache;
|
QHash<ShaderKey, GLShaderProgram*> m_shaderCache;
|
||||||
|
|
||||||
QColor m_backgroundColor;
|
QColor m_backgroundColor;
|
||||||
|
|
|
@ -351,28 +351,6 @@ addGroupWithOffset(cmod::Mesh& mesh,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
cmod::Material*
|
|
||||||
cloneMaterial(const cmod::Material* other)
|
|
||||||
{
|
|
||||||
cmod::Material* material = new cmod::Material();
|
|
||||||
material->diffuse = other->diffuse;
|
|
||||||
material->specular = other->specular;
|
|
||||||
material->emissive = other->emissive;
|
|
||||||
material->specularPower = other->specularPower;
|
|
||||||
material->opacity = other->opacity;
|
|
||||||
material->blend = other->blend;
|
|
||||||
for (int i = 0; i < static_cast<int>(cmod::TextureSemantic::TextureSemanticMax); ++i)
|
|
||||||
{
|
|
||||||
if (other->maps[i] != InvalidResource)
|
|
||||||
{
|
|
||||||
material->maps[i] = other->maps[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return material;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<typename T, typename U> void
|
template<typename T, typename U> void
|
||||||
joinVertices(std::vector<Face>& faces,
|
joinVertices(std::vector<Face>& faces,
|
||||||
const cmod::VWord* vertexData,
|
const cmod::VWord* vertexData,
|
||||||
|
@ -448,7 +426,7 @@ joinVertices(std::vector<Face>& faces,
|
||||||
* @param weldTolerance maximum difference between positions that should be
|
* @param weldTolerance maximum difference between positions that should be
|
||||||
* considered identical during the weld step.
|
* considered identical during the weld step.
|
||||||
*/
|
*/
|
||||||
cmod::Mesh*
|
cmod::Mesh
|
||||||
GenerateNormals(const cmod::Mesh& mesh, float smoothAngle, bool weld, float weldTolerance)
|
GenerateNormals(const cmod::Mesh& mesh, float smoothAngle, bool weld, float weldTolerance)
|
||||||
{
|
{
|
||||||
std::uint32_t nVertices = mesh.getVertexCount();
|
std::uint32_t nVertices = mesh.getVertexCount();
|
||||||
|
@ -459,7 +437,7 @@ GenerateNormals(const cmod::Mesh& mesh, float smoothAngle, bool weld, float weld
|
||||||
if (desc.getAttribute(cmod::VertexAttributeSemantic::Position).format != cmod::VertexAttributeFormat::Float3)
|
if (desc.getAttribute(cmod::VertexAttributeSemantic::Position).format != cmod::VertexAttributeFormat::Float3)
|
||||||
{
|
{
|
||||||
std::cerr << "Vertex position must be a float3\n";
|
std::cerr << "Vertex position must be a float3\n";
|
||||||
return nullptr;
|
return cmod::Mesh();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t posOffset = desc.getAttribute(cmod::VertexAttributeSemantic::Position).offsetWords;
|
std::uint32_t posOffset = desc.getAttribute(cmod::VertexAttributeSemantic::Position).offsetWords;
|
||||||
|
@ -477,7 +455,7 @@ GenerateNormals(const cmod::Mesh& mesh, float smoothAngle, bool weld, float weld
|
||||||
if (group->indices.size() < 3 || group->indices.size() % 3 != 0)
|
if (group->indices.size() < 3 || group->indices.size() % 3 != 0)
|
||||||
{
|
{
|
||||||
std::cerr << "Triangle list has invalid number of indices\n";
|
std::cerr << "Triangle list has invalid number of indices\n";
|
||||||
return nullptr;
|
return cmod::Mesh();
|
||||||
}
|
}
|
||||||
nFaces += group->indices.size() / 3;
|
nFaces += group->indices.size() / 3;
|
||||||
break;
|
break;
|
||||||
|
@ -487,14 +465,14 @@ GenerateNormals(const cmod::Mesh& mesh, float smoothAngle, bool weld, float weld
|
||||||
if (group->indices.size() < 3)
|
if (group->indices.size() < 3)
|
||||||
{
|
{
|
||||||
std::cerr << "Error: tri strip or fan has less than three indices\n";
|
std::cerr << "Error: tri strip or fan has less than three indices\n";
|
||||||
return nullptr;
|
return cmod::Mesh();
|
||||||
}
|
}
|
||||||
nFaces += group->indices.size() - 2;
|
nFaces += group->indices.size() - 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
std::cerr << "Cannot generate normals for non-triangle primitives\n";
|
std::cerr << "Cannot generate normals for non-triangle primitives\n";
|
||||||
return nullptr;
|
return cmod::Mesh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -581,15 +559,8 @@ GenerateNormals(const cmod::Mesh& mesh, float smoothAngle, bool weld, float weld
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each vertex, create a list of faces that contain it
|
// For each vertex, create a list of faces that contain it
|
||||||
std::uint32_t* faceCounts = new std::uint32_t[nVertices];
|
std::vector<std::uint32_t> faceCounts(nVertices, 0);
|
||||||
std::uint32_t** vertexFaces = new std::uint32_t*[nVertices];
|
std::vector<std::vector<std::uint32_t>> vertexFaces(nVertices);
|
||||||
|
|
||||||
// Initialize the lists
|
|
||||||
for (i = 0; i < nVertices; i++)
|
|
||||||
{
|
|
||||||
faceCounts[i] = 0;
|
|
||||||
vertexFaces[i] = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're welding vertices before generating normals, find identical
|
// If we're welding vertices before generating normals, find identical
|
||||||
// points and merge them. Otherwise, the point indices will be the same
|
// points and merge them. Otherwise, the point indices will be the same
|
||||||
|
@ -624,7 +595,7 @@ GenerateNormals(const cmod::Mesh& mesh, float smoothAngle, bool weld, float weld
|
||||||
{
|
{
|
||||||
if (faceCounts[i] > 0)
|
if (faceCounts[i] > 0)
|
||||||
{
|
{
|
||||||
vertexFaces[i] = new uint32_t[faceCounts[i] + 1];
|
vertexFaces[i].resize(faceCounts[i] + 1);
|
||||||
vertexFaces[i][0] = faceCounts[i];
|
vertexFaces[i][0] = faceCounts[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -708,9 +679,9 @@ GenerateNormals(const cmod::Mesh& mesh, float smoothAngle, bool weld, float weld
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the Celestia mesh
|
// Create the Celestia mesh
|
||||||
cmod::Mesh* newMesh = new cmod::Mesh();
|
cmod::Mesh newMesh;
|
||||||
newMesh->setVertexDescription(std::move(newDesc));
|
newMesh.setVertexDescription(std::move(newDesc));
|
||||||
newMesh->setVertices(nFaces * 3, std::move(newVertexData));
|
newMesh.setVertices(nFaces * 3, std::move(newVertexData));
|
||||||
|
|
||||||
std::uint32_t firstIndex = 0;
|
std::uint32_t firstIndex = 0;
|
||||||
for (std::uint32_t groupIndex = 0; mesh.getGroup(groupIndex) != 0; ++groupIndex)
|
for (std::uint32_t groupIndex = 0; mesh.getGroup(groupIndex) != 0; ++groupIndex)
|
||||||
|
@ -736,26 +707,17 @@ GenerateNormals(const cmod::Mesh& mesh, float smoothAngle, bool weld, float weld
|
||||||
std::vector<cmod::Index32> indices(faceCount * 3);
|
std::vector<cmod::Index32> indices(faceCount * 3);
|
||||||
std::iota(indices.begin(), indices.end(), firstIndex);
|
std::iota(indices.begin(), indices.end(), firstIndex);
|
||||||
|
|
||||||
newMesh->addGroup(cmod::PrimitiveGroupType::TriList,
|
newMesh.addGroup(cmod::PrimitiveGroupType::TriList,
|
||||||
mesh.getGroup(groupIndex)->materialIndex,
|
mesh.getGroup(groupIndex)->materialIndex,
|
||||||
std::move(indices));
|
std::move(indices));
|
||||||
firstIndex += faceCount * 3;
|
firstIndex += faceCount * 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up
|
|
||||||
delete[] faceCounts;
|
|
||||||
for (i = 0; i < nVertices; i++)
|
|
||||||
{
|
|
||||||
if (vertexFaces[i] != nullptr)
|
|
||||||
delete[] vertexFaces[i];
|
|
||||||
}
|
|
||||||
delete[] vertexFaces;
|
|
||||||
|
|
||||||
return newMesh;
|
return newMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
cmod::Mesh*
|
cmod::Mesh
|
||||||
GenerateTangents(const cmod::Mesh& mesh, bool weld)
|
GenerateTangents(const cmod::Mesh& mesh, bool weld)
|
||||||
{
|
{
|
||||||
uint32_t nVertices = mesh.getVertexCount();
|
uint32_t nVertices = mesh.getVertexCount();
|
||||||
|
@ -766,25 +728,25 @@ GenerateTangents(const cmod::Mesh& mesh, bool weld)
|
||||||
if (desc.getAttribute(cmod::VertexAttributeSemantic::Position).format != cmod::VertexAttributeFormat::Float3)
|
if (desc.getAttribute(cmod::VertexAttributeSemantic::Position).format != cmod::VertexAttributeFormat::Float3)
|
||||||
{
|
{
|
||||||
std::cerr << "Vertex position must be a float3\n";
|
std::cerr << "Vertex position must be a float3\n";
|
||||||
return nullptr;
|
return cmod::Mesh();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (desc.getAttribute(cmod::VertexAttributeSemantic::Normal).format != cmod::VertexAttributeFormat::Float3)
|
if (desc.getAttribute(cmod::VertexAttributeSemantic::Normal).format != cmod::VertexAttributeFormat::Float3)
|
||||||
{
|
{
|
||||||
std::cerr << "float3 format vertex normal required\n";
|
std::cerr << "float3 format vertex normal required\n";
|
||||||
return nullptr;
|
return cmod::Mesh();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (desc.getAttribute(cmod::VertexAttributeSemantic::Texture0).format == cmod::VertexAttributeFormat::InvalidFormat)
|
if (desc.getAttribute(cmod::VertexAttributeSemantic::Texture0).format == cmod::VertexAttributeFormat::InvalidFormat)
|
||||||
{
|
{
|
||||||
std::cerr << "Texture coordinates must be present in mesh to generate tangents\n";
|
std::cerr << "Texture coordinates must be present in mesh to generate tangents\n";
|
||||||
return nullptr;
|
return cmod::Mesh();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (desc.getAttribute(cmod::VertexAttributeSemantic::Texture0).format != cmod::VertexAttributeFormat::Float2)
|
if (desc.getAttribute(cmod::VertexAttributeSemantic::Texture0).format != cmod::VertexAttributeFormat::Float2)
|
||||||
{
|
{
|
||||||
std::cerr << "Texture coordinate must be a float2\n";
|
std::cerr << "Texture coordinate must be a float2\n";
|
||||||
return nullptr;
|
return cmod::Mesh();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count the number of faces in the mesh.
|
// Count the number of faces in the mesh.
|
||||||
|
@ -802,7 +764,7 @@ GenerateTangents(const cmod::Mesh& mesh, bool weld)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr << "Mesh should contain just triangle lists\n";
|
std::cerr << "Mesh should contain just triangle lists\n";
|
||||||
return nullptr;
|
return cmod::Mesh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -987,9 +949,9 @@ GenerateTangents(const cmod::Mesh& mesh, bool weld)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the Celestia mesh
|
// Create the Celestia mesh
|
||||||
cmod::Mesh* newMesh = new cmod::Mesh();
|
cmod::Mesh newMesh;
|
||||||
newMesh->setVertexDescription(std::move(newDesc));
|
newMesh.setVertexDescription(std::move(newDesc));
|
||||||
newMesh->setVertices(nFaces * 3, std::move(newVertexData));
|
newMesh.setVertices(nFaces * 3, std::move(newVertexData));
|
||||||
|
|
||||||
std::uint32_t firstIndex = 0;
|
std::uint32_t firstIndex = 0;
|
||||||
for (std::uint32_t groupIndex = 0; mesh.getGroup(groupIndex) != 0; ++groupIndex)
|
for (std::uint32_t groupIndex = 0; mesh.getGroup(groupIndex) != 0; ++groupIndex)
|
||||||
|
@ -1015,9 +977,9 @@ GenerateTangents(const cmod::Mesh& mesh, bool weld)
|
||||||
std::vector<cmod::Index32> indices(faceCount * 3);
|
std::vector<cmod::Index32> indices(faceCount * 3);
|
||||||
std::iota(indices.begin(), indices.end(), firstIndex);
|
std::iota(indices.begin(), indices.end(), firstIndex);
|
||||||
|
|
||||||
newMesh->addGroup(cmod::PrimitiveGroupType::TriList,
|
newMesh.addGroup(cmod::PrimitiveGroupType::TriList,
|
||||||
mesh.getGroup(groupIndex)->materialIndex,
|
mesh.getGroup(groupIndex)->materialIndex,
|
||||||
std::move(indices));
|
std::move(indices));
|
||||||
firstIndex += faceCount * 3;
|
firstIndex += faceCount * 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1100,10 +1062,10 @@ UniquifyVertices(cmod::Mesh& mesh)
|
||||||
|
|
||||||
|
|
||||||
// Merge all meshes that share the same vertex description
|
// Merge all meshes that share the same vertex description
|
||||||
cmod::Model*
|
std::unique_ptr<cmod::Model>
|
||||||
MergeModelMeshes(const cmod::Model& model)
|
MergeModelMeshes(const cmod::Model& model)
|
||||||
{
|
{
|
||||||
std::vector<cmod::Mesh*> meshes;
|
std::vector<const cmod::Mesh*> meshes;
|
||||||
|
|
||||||
for (std::uint32_t i = 0; model.getMesh(i) != nullptr; i++)
|
for (std::uint32_t i = 0; model.getMesh(i) != nullptr; i++)
|
||||||
{
|
{
|
||||||
|
@ -1114,12 +1076,12 @@ MergeModelMeshes(const cmod::Model& model)
|
||||||
std::sort(meshes.begin(), meshes.end(),
|
std::sort(meshes.begin(), meshes.end(),
|
||||||
[](const cmod::Mesh* a, const cmod::Mesh* b) { return a->getVertexDescription() < b->getVertexDescription(); });
|
[](const cmod::Mesh* a, const cmod::Mesh* b) { return a->getVertexDescription() < b->getVertexDescription(); });
|
||||||
|
|
||||||
cmod::Model* newModel = new cmod::Model();
|
auto newModel = std::make_unique<cmod::Model>();
|
||||||
|
|
||||||
// Copy materials into the new model
|
// Copy materials into the new model
|
||||||
for (std::uint32_t i = 0; model.getMaterial(i) != nullptr; i++)
|
for (std::uint32_t i = 0; model.getMaterial(i) != nullptr; i++)
|
||||||
{
|
{
|
||||||
newModel->addMaterial(model.getMaterial(i));
|
newModel->addMaterial(model.getMaterial(i)->clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t meshIndex = 0;
|
std::uint32_t meshIndex = 0;
|
||||||
|
@ -1162,9 +1124,9 @@ MergeModelMeshes(const cmod::Model& model)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the new empty mesh
|
// Create the new empty mesh
|
||||||
cmod::Mesh* mergedMesh = new cmod::Mesh();
|
cmod::Mesh mergedMesh;
|
||||||
mergedMesh->setVertexDescription(desc.clone());
|
mergedMesh.setVertexDescription(desc.clone());
|
||||||
mergedMesh->setVertices(totalVertices, std::move(vertexData));
|
mergedMesh.setVertices(totalVertices, std::move(vertexData));
|
||||||
|
|
||||||
// Reindex and add primitive groups
|
// Reindex and add primitive groups
|
||||||
vertexCount = 0;
|
vertexCount = 0;
|
||||||
|
@ -1173,7 +1135,7 @@ MergeModelMeshes(const cmod::Model& model)
|
||||||
const cmod::Mesh* mesh = meshes[j];
|
const cmod::Mesh* mesh = meshes[j];
|
||||||
for (std::uint32_t k = 0; mesh->getGroup(k) != nullptr; k++)
|
for (std::uint32_t k = 0; mesh->getGroup(k) != nullptr; k++)
|
||||||
{
|
{
|
||||||
addGroupWithOffset(*mergedMesh, *mesh->getGroup(k),
|
addGroupWithOffset(mergedMesh, *mesh->getGroup(k),
|
||||||
vertexCount);
|
vertexCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1181,7 +1143,7 @@ MergeModelMeshes(const cmod::Model& model)
|
||||||
}
|
}
|
||||||
assert(vertexCount == totalVertices);
|
assert(vertexCount == totalVertices);
|
||||||
|
|
||||||
newModel->addMesh(mergedMesh);
|
newModel->addMesh(std::move(mergedMesh));
|
||||||
|
|
||||||
meshIndex += nMatchingMeshes;
|
meshIndex += nMatchingMeshes;
|
||||||
}
|
}
|
||||||
|
@ -1193,31 +1155,29 @@ MergeModelMeshes(const cmod::Model& model)
|
||||||
/*! Generate normals for an entire model. Return the new model, or null if
|
/*! Generate normals for an entire model. Return the new model, or null if
|
||||||
* normal generation failed due to an out of memory error.
|
* normal generation failed due to an out of memory error.
|
||||||
*/
|
*/
|
||||||
cmod::Model*
|
std::unique_ptr<cmod::Model>
|
||||||
GenerateModelNormals(const cmod::Model& model, float smoothAngle, bool weldVertices, float weldTolerance)
|
GenerateModelNormals(const cmod::Model& model, float smoothAngle, bool weldVertices, float weldTolerance)
|
||||||
{
|
{
|
||||||
cmod::Model* newModel = new cmod::Model();
|
auto newModel = std::make_unique<cmod::Model>();
|
||||||
|
|
||||||
// Copy materials
|
// Copy materials
|
||||||
for (unsigned int i = 0; model.getMaterial(i) != nullptr; i++)
|
for (unsigned int i = 0; model.getMaterial(i) != nullptr; i++)
|
||||||
{
|
{
|
||||||
newModel->addMaterial(cloneMaterial(model.getMaterial(i)));
|
newModel->addMaterial(model.getMaterial(i)->clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
for (unsigned int i = 0; model.getMesh(i) != nullptr; i++)
|
for (unsigned int i = 0; model.getMesh(i) != nullptr; i++)
|
||||||
{
|
{
|
||||||
cmod::Mesh* mesh = model.getMesh(i);
|
const cmod::Mesh* mesh = model.getMesh(i);
|
||||||
cmod::Mesh* newMesh = nullptr;
|
cmod::Mesh newMesh = GenerateNormals(*mesh, smoothAngle, weldVertices, weldTolerance);
|
||||||
|
if (newMesh.getVertexCount() == 0)
|
||||||
newMesh = GenerateNormals(*mesh, smoothAngle, weldVertices, weldTolerance);
|
|
||||||
if (newMesh == nullptr)
|
|
||||||
{
|
{
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newModel->addMesh(newMesh);
|
newModel->addMesh(std::move(newMesh));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1226,8 +1186,7 @@ GenerateModelNormals(const cmod::Model& model, float smoothAngle, bool weldVerti
|
||||||
// If all of the meshes weren't processed due to an out of memory error,
|
// If all of the meshes weren't processed due to an out of memory error,
|
||||||
// delete the new model and return nullptr rather than a partially processed
|
// delete the new model and return nullptr rather than a partially processed
|
||||||
// model.
|
// model.
|
||||||
delete newModel;
|
return nullptr;
|
||||||
newModel = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return newModel;
|
return newModel;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <Eigen/Core>
|
#include <Eigen/Core>
|
||||||
|
|
||||||
|
@ -25,13 +26,16 @@ class Model;
|
||||||
|
|
||||||
|
|
||||||
// Mesh operations
|
// Mesh operations
|
||||||
extern cmod::Mesh* GenerateNormals(const cmod::Mesh& mesh, float smoothAngle, bool weld, float weldTolerance = 0.0f);
|
extern cmod::Mesh GenerateNormals(const cmod::Mesh& mesh, float smoothAngle, bool weld, float weldTolerance = 0.0f);
|
||||||
extern cmod::Mesh* GenerateTangents(const cmod::Mesh& mesh, bool weld);
|
extern cmod::Mesh GenerateTangents(const cmod::Mesh& mesh, bool weld);
|
||||||
extern bool UniquifyVertices(cmod::Mesh& mesh);
|
extern bool UniquifyVertices(cmod::Mesh& mesh);
|
||||||
|
|
||||||
// Model operations
|
// Model operations
|
||||||
extern cmod::Model* MergeModelMeshes(const cmod::Model& model);
|
extern std::unique_ptr<cmod::Model> MergeModelMeshes(const cmod::Model& model);
|
||||||
extern cmod::Model* GenerateModelNormals(const cmod::Model& model, float smoothAngle, bool weldVertices, float weldTolerance);
|
extern std::unique_ptr<cmod::Model> GenerateModelNormals(const cmod::Model& model,
|
||||||
|
float smoothAngle,
|
||||||
|
bool weldVertices,
|
||||||
|
float weldTolerance);
|
||||||
#ifdef TRISTRIP
|
#ifdef TRISTRIP
|
||||||
extern bool ConvertToStrips(cmod::Mesh& mesh);
|
extern bool ConvertToStrips(cmod::Mesh& mesh);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -23,17 +23,18 @@
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
cmod::Material*
|
|
||||||
|
cmod::Material
|
||||||
convert3dsMaterial(const M3DMaterial* material3ds, cmod::HandleGetter& handleGetter)
|
convert3dsMaterial(const M3DMaterial* material3ds, cmod::HandleGetter& handleGetter)
|
||||||
{
|
{
|
||||||
cmod::Material* newMaterial = new cmod::Material();
|
cmod::Material newMaterial;
|
||||||
|
|
||||||
M3DColor diffuse = material3ds->getDiffuseColor();
|
M3DColor diffuse = material3ds->getDiffuseColor();
|
||||||
newMaterial->diffuse = cmod::Color(diffuse.red, diffuse.green, diffuse.blue);
|
newMaterial.diffuse = cmod::Color(diffuse.red, diffuse.green, diffuse.blue);
|
||||||
newMaterial->opacity = material3ds->getOpacity();
|
newMaterial.opacity = material3ds->getOpacity();
|
||||||
|
|
||||||
M3DColor specular = material3ds->getSpecularColor();
|
M3DColor specular = material3ds->getSpecularColor();
|
||||||
newMaterial->specular = cmod::Color(specular.red, specular.green, specular.blue);
|
newMaterial.specular = cmod::Color(specular.red, specular.green, specular.blue);
|
||||||
|
|
||||||
float shininess = material3ds->getShininess();
|
float shininess = material3ds->getShininess();
|
||||||
|
|
||||||
|
@ -41,24 +42,22 @@ convert3dsMaterial(const M3DMaterial* material3ds, cmod::HandleGetter& handleGet
|
||||||
// range that OpenGL uses for the specular exponent. The
|
// range that OpenGL uses for the specular exponent. The
|
||||||
// current equation is just a guess at the mapping that
|
// current equation is just a guess at the mapping that
|
||||||
// 3DS actually uses.
|
// 3DS actually uses.
|
||||||
newMaterial->specularPower = std::pow(2.0f, 1.0f + 0.1f * shininess);
|
newMaterial.specularPower = std::pow(2.0f, 1.0f + 0.1f * shininess);
|
||||||
if (newMaterial->specularPower > 128.0f)
|
if (newMaterial.specularPower > 128.0f)
|
||||||
newMaterial->specularPower = 128.0f;
|
newMaterial.specularPower = 128.0f;
|
||||||
|
|
||||||
if (!material3ds->getTextureMap().empty())
|
if (!material3ds->getTextureMap().empty())
|
||||||
{
|
{
|
||||||
newMaterial->setMap(cmod::TextureSemantic::DiffuseMap, handleGetter(material3ds->getTextureMap()));
|
newMaterial.setMap(cmod::TextureSemantic::DiffuseMap, handleGetter(material3ds->getTextureMap()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return newMaterial;
|
return newMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end unnamed namespace
|
} // end unnamed namespace
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Convert3DSMesh(cmod::Model& model,
|
Convert3DSMesh(cmod::Model& model,
|
||||||
const M3DTriangleMesh& mesh3ds,
|
const M3DTriangleMesh& mesh3ds,
|
||||||
|
@ -108,11 +107,11 @@ Convert3DSMesh(cmod::Model& model,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the Celestia mesh
|
// Create the Celestia mesh
|
||||||
cmod::Mesh* mesh = new cmod::Mesh();
|
cmod::Mesh mesh;
|
||||||
mesh->setVertexDescription(cmod::VertexDescription(std::move(attributes)));
|
mesh.setVertexDescription(cmod::VertexDescription(std::move(attributes)));
|
||||||
mesh->setVertices(nVertices, std::move(vertices));
|
mesh.setVertices(nVertices, std::move(vertices));
|
||||||
|
|
||||||
mesh->setName(std::move(meshName));
|
mesh.setName(std::move(meshName));
|
||||||
|
|
||||||
if (mesh3ds.getMeshMaterialGroupCount() == 0)
|
if (mesh3ds.getMeshMaterialGroupCount() == 0)
|
||||||
{
|
{
|
||||||
|
@ -131,7 +130,7 @@ Convert3DSMesh(cmod::Model& model,
|
||||||
indices.push_back(v2);
|
indices.push_back(v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh->addGroup(cmod::PrimitiveGroupType::TriList, ~0, std::move(indices));
|
mesh.addGroup(cmod::PrimitiveGroupType::TriList, ~0, std::move(indices));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -170,18 +169,18 @@ Convert3DSMesh(cmod::Model& model,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh->addGroup(cmod::PrimitiveGroupType::TriList, materialIndex, std::move(indices));
|
mesh.addGroup(cmod::PrimitiveGroupType::TriList, materialIndex, std::move(indices));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
model.addMesh(mesh);
|
model.addMesh(std::move(mesh));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
cmod::Model*
|
std::unique_ptr<cmod::Model>
|
||||||
Convert3DSModel(const M3DScene& scene, cmod::HandleGetter handleGetter)
|
Convert3DSModel(const M3DScene& scene, cmod::HandleGetter handleGetter)
|
||||||
{
|
{
|
||||||
cmod::Model* model = new cmod::Model();
|
auto model = std::make_unique<cmod::Model>();
|
||||||
|
|
||||||
// Convert materials
|
// Convert materials
|
||||||
for (unsigned int i = 0; i < scene.getMaterialCount(); i++)
|
for (unsigned int i = 0; i < scene.getMaterialCount(); i++)
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <cel3ds/3dsmodel.h>
|
#include <cel3ds/3dsmodel.h>
|
||||||
|
@ -22,5 +23,6 @@ extern void Convert3DSMesh(cmod::Model& model,
|
||||||
M3DTriangleMesh& mesh3ds,
|
M3DTriangleMesh& mesh3ds,
|
||||||
const M3DScene& scene,
|
const M3DScene& scene,
|
||||||
std::string&& meshName);
|
std::string&& meshName);
|
||||||
extern cmod::Model* Convert3DSModel(const M3DScene& scene,
|
|
||||||
cmod::HandleGetter handleGetter);
|
extern std::unique_ptr<cmod::Model> Convert3DSModel(const M3DScene& scene,
|
||||||
|
cmod::HandleGetter handleGetter);
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
#include <celmodel/material.h>
|
#include <celmodel/material.h>
|
||||||
#include <celmodel/mesh.h>
|
#include <celmodel/mesh.h>
|
||||||
#include <celmodel/model.h>
|
|
||||||
|
|
||||||
#include "convertobj.h"
|
#include "convertobj.h"
|
||||||
|
|
||||||
|
@ -78,7 +77,7 @@ WavefrontLoader::WavefrontLoader(std::istream& in) :
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
cmod::Model*
|
std::unique_ptr<cmod::Model>
|
||||||
WavefrontLoader::load()
|
WavefrontLoader::load()
|
||||||
{
|
{
|
||||||
std::string line;
|
std::string line;
|
||||||
|
@ -87,7 +86,7 @@ WavefrontLoader::load()
|
||||||
ObjVertex::VertexType lastVertexType = ObjVertex::Point;
|
ObjVertex::VertexType lastVertexType = ObjVertex::Point;
|
||||||
int currentMaterialIndex = -1;
|
int currentMaterialIndex = -1;
|
||||||
|
|
||||||
m_model = new cmod::Model();
|
m_model = std::make_unique<cmod::Model>();
|
||||||
|
|
||||||
while (std::getline(m_in, line))
|
while (std::getline(m_in, line))
|
||||||
{
|
{
|
||||||
|
@ -135,12 +134,12 @@ WavefrontLoader::load()
|
||||||
}
|
}
|
||||||
else if (keyword == "usemtl")
|
else if (keyword == "usemtl")
|
||||||
{
|
{
|
||||||
cmod::Material* material = new cmod::Material();
|
cmod::Material material;
|
||||||
material->diffuse = cmod::Color(1.0f, 1.0f, 1.0f);
|
material.diffuse = cmod::Color(1.0f, 1.0f, 1.0f);
|
||||||
currentMaterialIndex = m_model->addMaterial(material) - 1;
|
currentMaterialIndex = m_model->addMaterial(std::move(material)) - 1;
|
||||||
if (!m_materialGroups.empty())
|
if (!m_materialGroups.empty())
|
||||||
{
|
{
|
||||||
if (m_materialGroups.back().firstIndex == (int) m_indexData.size())
|
if (m_materialGroups.back().firstIndex == static_cast<int>(m_indexData.size()))
|
||||||
{
|
{
|
||||||
m_materialGroups.back().materialIndex = currentMaterialIndex;
|
m_materialGroups.back().materialIndex = currentMaterialIndex;
|
||||||
}
|
}
|
||||||
|
@ -293,7 +292,7 @@ WavefrontLoader::load()
|
||||||
createMesh(lastVertexType, vertexCount);
|
createMesh(lastVertexType, vertexCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_model;
|
return std::move(m_model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -305,7 +304,6 @@ WavefrontLoader::reportError(const std::string& message)
|
||||||
os << "Line " << m_lineNumber << ": " << message;
|
os << "Line " << m_lineNumber << ": " << message;
|
||||||
m_errorMessage = os.str();
|
m_errorMessage = os.str();
|
||||||
|
|
||||||
delete m_model;
|
|
||||||
m_model = nullptr;
|
m_model = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,9 +358,9 @@ WavefrontLoader::createMesh(ObjVertex::VertexType vertexType, unsigned int verte
|
||||||
std::memcpy(vertexDataCopy.data(), m_vertexData.data(), m_vertexData.size() * sizeof(cmod::VWord));
|
std::memcpy(vertexDataCopy.data(), m_vertexData.data(), m_vertexData.size() * sizeof(cmod::VWord));
|
||||||
|
|
||||||
// Create the Celestia mesh
|
// Create the Celestia mesh
|
||||||
cmod::Mesh* mesh = new cmod::Mesh();
|
cmod::Mesh mesh;
|
||||||
mesh->setVertexDescription(cmod::VertexDescription(std::move(attributes)));
|
mesh.setVertexDescription(cmod::VertexDescription(std::move(attributes)));
|
||||||
mesh->setVertices(vertexCount, std::move(vertexDataCopy));
|
mesh.setVertices(vertexCount, std::move(vertexDataCopy));
|
||||||
|
|
||||||
// Add primitive groups
|
// Add primitive groups
|
||||||
for (unsigned int i = 0; i < m_materialGroups.size(); ++i)
|
for (unsigned int i = 0; i < m_materialGroups.size(); ++i)
|
||||||
|
@ -381,9 +379,9 @@ WavefrontLoader::createMesh(ObjVertex::VertexType vertexType, unsigned int verte
|
||||||
if (indexCount > 0)
|
if (indexCount > 0)
|
||||||
{
|
{
|
||||||
auto copyStart = m_indexData.begin() + firstIndex;
|
auto copyStart = m_indexData.begin() + firstIndex;
|
||||||
mesh->addGroup(cmod::PrimitiveGroupType::TriList,
|
mesh.addGroup(cmod::PrimitiveGroupType::TriList,
|
||||||
m_materialGroups[i].materialIndex,
|
m_materialGroups[i].materialIndex,
|
||||||
std::vector<cmod::Index32>(copyStart, copyStart + indexCount));
|
std::vector<cmod::Index32>(copyStart, copyStart + indexCount));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,5 +389,5 @@ WavefrontLoader::createMesh(ObjVertex::VertexType vertexType, unsigned int verte
|
||||||
m_indexData.clear();
|
m_indexData.clear();
|
||||||
m_materialGroups.clear();
|
m_materialGroups.clear();
|
||||||
|
|
||||||
m_model->addMesh(mesh);
|
m_model->addMesh(std::move(mesh));
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,15 +13,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <Eigen/Core>
|
#include <Eigen/Core>
|
||||||
|
|
||||||
namespace cmod
|
#include <celmodel/model.h>
|
||||||
{
|
|
||||||
class Model;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class WavefrontLoader
|
class WavefrontLoader
|
||||||
|
@ -30,7 +28,7 @@ public:
|
||||||
WavefrontLoader(std::istream& in);
|
WavefrontLoader(std::istream& in);
|
||||||
~WavefrontLoader() = default;
|
~WavefrontLoader() = default;
|
||||||
|
|
||||||
cmod::Model* load();
|
std::unique_ptr<cmod::Model> load();
|
||||||
std::string errorMessage() const
|
std::string errorMessage() const
|
||||||
{
|
{
|
||||||
return m_errorMessage;
|
return m_errorMessage;
|
||||||
|
@ -100,7 +98,7 @@ private:
|
||||||
std::vector<cmod::Index32> m_indexData;
|
std::vector<cmod::Index32> m_indexData;
|
||||||
std::vector<MaterialGroup> m_materialGroups;
|
std::vector<MaterialGroup> m_materialGroups;
|
||||||
|
|
||||||
cmod::Model* m_model;
|
std::unique_ptr<cmod::Model> m_model;
|
||||||
|
|
||||||
std::string m_errorMessage;
|
std::string m_errorMessage;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,12 +2,14 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <ios>
|
#include <ios>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <catch.hpp>
|
#include <catch.hpp>
|
||||||
|
|
||||||
#include <celcompat/filesystem.h>
|
#include <celcompat/filesystem.h>
|
||||||
|
#include <celmodel/model.h>
|
||||||
#include <celmodel/modelfile.h>
|
#include <celmodel/modelfile.h>
|
||||||
#include <celutil/reshandle.h>
|
#include <celutil/reshandle.h>
|
||||||
|
|
||||||
|
@ -35,17 +37,17 @@ TEST_CASE("CMOD binary to ASCII roundtrip", "[cmod] [integration]")
|
||||||
std::stringstream sourceData;
|
std::stringstream sourceData;
|
||||||
sourceData << f.rdbuf();
|
sourceData << f.rdbuf();
|
||||||
|
|
||||||
cmod::Model* modelFromBinary = cmod::LoadModel(sourceData, handleGetter);
|
std::unique_ptr<cmod::Model> modelFromBinary = cmod::LoadModel(sourceData, handleGetter);
|
||||||
REQUIRE(modelFromBinary != nullptr);
|
REQUIRE(modelFromBinary != nullptr);
|
||||||
|
|
||||||
std::stringstream asciiData;
|
std::stringstream asciiData;
|
||||||
REQUIRE(cmod::SaveModelAscii(modelFromBinary, asciiData, sourceGetter));
|
REQUIRE(cmod::SaveModelAscii(modelFromBinary.get(), asciiData, sourceGetter));
|
||||||
|
|
||||||
cmod::Model* modelFromAscii = cmod::LoadModel(asciiData, handleGetter);
|
std::unique_ptr<cmod::Model> modelFromAscii = cmod::LoadModel(asciiData, handleGetter);
|
||||||
REQUIRE(modelFromAscii != nullptr);
|
REQUIRE(modelFromAscii != nullptr);
|
||||||
|
|
||||||
std::stringstream roundtrippedData;
|
std::stringstream roundtrippedData;
|
||||||
REQUIRE(cmod::SaveModelBinary(modelFromAscii, roundtrippedData, sourceGetter));
|
REQUIRE(cmod::SaveModelBinary(modelFromAscii.get(), roundtrippedData, sourceGetter));
|
||||||
|
|
||||||
sourceData.clear();
|
sourceData.clear();
|
||||||
REQUIRE(sourceData.seekg(0, std::ios_base::beg).good());
|
REQUIRE(sourceData.seekg(0, std::ios_base::beg).good());
|
||||||
|
|
Loading…
Reference in New Issue