Extract inner types from Material and Mesh

- Remove using namspace cmod
- Convert enums to enum classes
pull/1196/head
Andrew Tribick 2021-11-27 15:29:08 +01:00 committed by ajtribick
parent 474057221b
commit b79959979a
37 changed files with 2277 additions and 2277 deletions

View File

@ -44,7 +44,7 @@ public:
* all within this geometry object. This information is used
* to decide whether multiple rendering passes are required.
*/
virtual bool usesTextureType(cmod::Material::TextureSemantic) const
virtual bool usesTextureType(cmod::TextureSemantic) const
{
return false;
}

View File

@ -11,196 +11,44 @@
// Experimental particle system support
#define PARTICLE_SYSTEM 0
#include <cmath>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <memory>
#include <fmt/ostream.h>
#include <fmt/printf.h>
#include <cel3ds/3dsmodel.h>
#include <cel3ds/3dsread.h>
#include <celmath/randutils.h>
#include <celmodel/material.h>
#include <celmodel/mesh.h>
#include <celmodel/model.h>
#include <celmodel/modelfile.h>
#include <celutil/debug.h>
#include <celutil/filetype.h>
#include <celutil/gettext.h>
#include <celutil/tokenizer.h>
#include "meshmanager.h"
#include "modelgeometry.h"
#include "parser.h"
#include "spheremesh.h"
#include "texmanager.h"
#if PARTICLE_SYSTEM
#include "particlesystem.h"
#include "particlesystemfile.h"
#endif
#include "parser.h"
#include "spheremesh.h"
#include "texmanager.h"
#include "meshmanager.h"
#include "modelgeometry.h"
#include <celutil/tokenizer.h>
#include <cel3ds/3dsmodel.h>
#include <cel3ds/3dsread.h>
#include <celmodel/modelfile.h>
#include <celmath/mathlib.h>
#include <celmath/randutils.h>
#include <celutil/debug.h>
#include <celutil/filetype.h>
#include <celutil/debug.h>
#include <celutil/gettext.h>
#include <iostream>
#include <fstream>
#include <cassert>
#include <utility>
#include <memory>
#include <fmt/ostream.h>
#include <fmt/printf.h>
using namespace cmod;
using namespace Eigen;
using namespace std;
static Model* LoadCelestiaMesh(const fs::path& filename);
static Model* Convert3DSModel(const M3DScene& scene, const fs::path& texPath);
static GeometryManager* geometryManager = nullptr;
constexpr const fs::path::value_type UniqueSuffixChar = '!';
GeometryManager* GetGeometryManager()
namespace
{
if (geometryManager == nullptr)
geometryManager = new GeometryManager("models");
return geometryManager;
}
fs::path GeometryInfo::resolve(const fs::path& baseDir)
{
// Ensure that models with different centers get resolved to different objects by
// adding a 'uniquifying' suffix to the filename that encodes the center value.
// This suffix is stripped before the file is actually loaded.
fs::path::string_type uniquifyingSuffix;
fs::path::string_type format;
#ifdef _WIN32
format = L"%c%f,%f,%f,%f,%d";
#else
format = "%c%f,%f,%f,%f,%d";
#endif
uniquifyingSuffix = fmt::sprintf(format, UniqueSuffixChar, center.x(), center.y(), center.z(), scale, (int) isNormalized);
if (!path.empty())
{
fs::path filename = path / "models" / source;
ifstream in(filename.string());
if (in.good())
{
resolvedToPath = true;
return filename += uniquifyingSuffix;
}
}
return (baseDir / source) += uniquifyingSuffix;
}
Geometry* GeometryInfo::load(const fs::path& resolvedFilename)
{
// Strip off the uniquifying suffix
fs::path::string_type::size_type uniquifyingSuffixStart = resolvedFilename.native().rfind(UniqueSuffixChar);
fs::path filename = resolvedFilename.native().substr(0, uniquifyingSuffixStart);
clog << fmt::sprintf(_("Loading model: %s\n"), filename);
Model* model = nullptr;
ContentType fileType = DetermineFileType(filename);
if (fileType == Content_3DStudio)
{
std::unique_ptr<M3DScene> scene = Read3DSFile(filename);
if (scene != nullptr)
{
if (resolvedToPath)
model = Convert3DSModel(*scene, path);
else
model = Convert3DSModel(*scene, "");
if (isNormalized)
model->normalize(center);
else
model->transform(center, scale);
}
}
else if (fileType == Content_CelestiaModel)
{
ifstream in(filename.string(), ios::binary);
if (in.good())
{
model = LoadModel(in,
[&](const fs::path& name)
{
return GetTextureManager()
->getHandle(TextureInfo(name, path, TextureInfo::WrapTexture));
});
if (model != nullptr)
{
if (isNormalized)
model->normalize(center);
else
model->transform(center, scale);
}
}
}
else if (fileType == Content_CelestiaMesh)
{
model = LoadCelestiaMesh(filename);
if (model != nullptr)
{
if (isNormalized)
model->normalize(center);
else
model->transform(center, scale);
}
}
#if PARTICLE_SYSTEM
else if (fileType == Content_CelestiaParticleSystem)
{
ifstream in(filename);
if (in.good())
{
return LoadParticleSystem(in, path);
}
}
#endif
// Condition the model for optimal rendering
if (model != nullptr)
{
// Many models tend to have a lot of duplicate materials; eliminate
// them, since unnecessarily setting material parameters can adversely
// impact rendering performance. Ideally uniquification of materials
// would be performed just once when the model was created, but
// that's not the case.
uint32_t originalMaterialCount = model->getMaterialCount();
model->uniquifyMaterials();
// Sort the submeshes roughly by opacity. This will eliminate a
// good number of the errors caused when translucent triangles are
// rendered before geometry that they cover.
model->sortMeshes(Model::OpacityComparator());
model->determineOpacity();
// Display some statics for the model
clog << fmt::sprintf(
_(" Model statistics: %u vertices, %u primitives, %u materials (%u unique)\n"),
model->getVertexCount(),
model->getPrimitiveCount(),
originalMaterialCount,
model->getMaterialCount());
return new ModelGeometry(unique_ptr<cmod::Model>(model));
}
else
{
clog << fmt::sprintf(_("Error loading model '%s'\n"), filename);
return nullptr;
}
}
struct NoiseMeshParameters
{
Vector3f size;
Vector3f offset;
Eigen::Vector3f size;
Eigen::Vector3f offset;
float featureHeight;
float octaves;
float slices;
@ -208,26 +56,28 @@ struct NoiseMeshParameters
};
static float NoiseDisplacementFunc(float u, float v, void* info)
float
NoiseDisplacementFunc(float u, float v, void* info)
{
float theta = u * (float) PI * 2;
float phi = (v - 0.5f) * (float) PI;
float x = (float) (cos(phi) * cos(theta));
float y = (float) sin(phi);
float z = (float) (cos(phi) * sin(theta));
float theta = u * static_cast<float>(PI) * 2;
float phi = (v - 0.5f) * static_cast<float>(PI);
// assert(info != nullptr);
auto* params = (NoiseMeshParameters*) info;
auto* params = static_cast<NoiseMeshParameters*>(info);
Vector3f p = Vector3f(x, y, z) + params->offset;
Eigen::Vector3f p = Eigen::Vector3f(std::cos(phi) * std::cos(theta),
std::sin(phi),
std::cos(phi) * std::sin(theta))
+ params->offset;
return celmath::fractalsum(p, params->octaves) * params->featureHeight;
}
// TODO: The Celestia mesh format is deprecated
Model* LoadCelestiaMesh(const fs::path& filename)
cmod::Model*
LoadCelestiaMesh(const fs::path& filename)
{
ifstream meshFile(filename.string(), ios::in);
std::ifstream meshFile(filename.string(), std::ios::in);
if (!meshFile.good())
{
DPRINTF(LOG_LEVEL_ERROR, "Error opening mesh file: %s\n", filename);
@ -268,8 +118,8 @@ Model* LoadCelestiaMesh(const fs::path& filename)
NoiseMeshParameters params{};
params.size = Vector3f::Ones();
params.offset = Vector3f::Constant(10.0f);
params.size = Eigen::Vector3f::Ones();
params.offset = Eigen::Vector3f::Constant(10.0f);
params.featureHeight = 0.0f;
params.octaves = 1;
params.slices = 20;
@ -284,12 +134,13 @@ Model* LoadCelestiaMesh(const fs::path& filename)
delete meshDefValue;
Model* model = new Model();
cmod::Model* model = new cmod::Model();
SphereMesh* sphereMesh = new SphereMesh(params.size,
(int) params.rings, (int) params.slices,
static_cast<int>(params.rings),
static_cast<int>(params.slices),
NoiseDisplacementFunc,
(void*) &params);
Mesh* mesh = sphereMesh->convertToMesh();
cmod::Mesh* mesh = sphereMesh->convertToMesh();
model->addMesh(mesh);
delete sphereMesh;
@ -297,7 +148,7 @@ Model* LoadCelestiaMesh(const fs::path& filename)
}
static Mesh*
cmod::Mesh*
ConvertTriangleMesh(const M3DTriangleMesh& mesh,
const M3DScene& scene)
{
@ -311,33 +162,39 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
// Create the attribute set. Always include positions and normals, texture coords
// are optional.
Mesh::VertexAttribute attributes[8];
uint32_t nAttributes = 0;
uint32_t offset = 0;
cmod::VertexAttribute attributes[8];
std::uint32_t nAttributes = 0;
std::uint32_t offset = 0;
// Position attribute are required
attributes[nAttributes] = Mesh::VertexAttribute(Mesh::Position, Mesh::Float3, 0);
attributes[nAttributes] = cmod::VertexAttribute(cmod::VertexAttributeSemantic::Position,
cmod::VertexAttributeFormat::Float3,
0);
nAttributes++;
offset += 12;
// Normals are always generated
attributes[nAttributes] = Mesh::VertexAttribute(Mesh::Normal, Mesh::Float3, offset);
attributes[nAttributes] = cmod::VertexAttribute(cmod::VertexAttributeSemantic::Normal,
cmod::VertexAttributeFormat::Float3,
offset);
nAttributes++;
offset += 12;
if (hasTextureCoords)
{
attributes[nAttributes] = Mesh::VertexAttribute(Mesh::Texture0, Mesh::Float2, offset);
attributes[nAttributes] = cmod::VertexAttribute(cmod::VertexAttributeSemantic::Texture0,
cmod::VertexAttributeFormat::Float2,
offset);
nAttributes++;
offset += 8;
}
uint32_t vertexSize = offset;
std::uint32_t vertexSize = offset;
// bool smooth = (mesh.getSmoothingGroupCount() == nFaces);
Vector3f* faceNormals = new Vector3f[nFaces];
Vector3f* vertexNormals = new Vector3f[nFaces * 3];
Eigen::Vector3f* faceNormals = new Eigen::Vector3f[nFaces];
Eigen::Vector3f* vertexNormals = new Eigen::Vector3f[nFaces * 3];
auto* faceCounts = new int[nVertices];
auto** vertexFaces = new int*[nVertices];
@ -350,16 +207,16 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
// generate face normals
for (int i = 0; i < nFaces; i++)
{
uint16_t v0, v1, v2;
std::uint16_t v0, v1, v2;
mesh.getFace(i, v0, v1, v2);
faceCounts[v0]++;
faceCounts[v1]++;
faceCounts[v2]++;
Vector3f p0 = mesh.getVertex(v0);
Vector3f p1 = mesh.getVertex(v1);
Vector3f p2 = mesh.getVertex(v2);
Eigen::Vector3f p0 = mesh.getVertex(v0);
Eigen::Vector3f p1 = mesh.getVertex(v1);
Eigen::Vector3f p2 = mesh.getVertex(v2);
faceNormals[i] = (p1 - p0).cross(p2 - p1).normalized();
}
@ -385,7 +242,7 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
for (int i = 0; i < nFaces; i++)
{
uint16_t v0, v1, v2;
std::uint16_t v0, v1, v2;
mesh.getFace(i, v0, v1, v2);
vertexFaces[v0][faceCounts[v0]--] = i;
vertexFaces[v1][faceCounts[v1]--] = i;
@ -395,11 +252,11 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
// average face normals to compute the vertex normals
for (int i = 0; i < nFaces; i++)
{
uint16_t v0, v1, v2;
std::uint16_t v0, v1, v2;
mesh.getFace(i, v0, v1, v2);
// uint32_t smoothingGroups = mesh.getSmoothingGroups(i);
Vector3f v = Vector3f::Zero();
Eigen::Vector3f v = Eigen::Vector3f::Zero();
for (int j = 1; j <= vertexFaces[v0][0]; j++)
{
int k = vertexFaces[v0][j];
@ -409,7 +266,7 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
}
vertexNormals[i * 3] = v.normalized();
v = Vector3f::Zero();
v = Eigen::Vector3f::Zero();
for (int j = 1; j <= vertexFaces[v1][0]; j++)
{
int k = vertexFaces[v1][j];
@ -419,7 +276,7 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
}
vertexNormals[i * 3 + 1] = v.normalized();
v = Vector3f::Zero();
v = Eigen::Vector3f::Zero();
for (int j = 1; j <= vertexFaces[v2][0]; j++)
{
int k = vertexFaces[v2][j];
@ -437,13 +294,13 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
for (int i = 0; i < nFaces; i++)
{
uint16_t triVert[3];
std::uint16_t triVert[3];
mesh.getFace(i, triVert[0], triVert[1], triVert[2]);
for (unsigned int j = 0; j < 3; j++)
{
Vector3f position = mesh.getVertex(triVert[j]);
Vector3f normal = vertexNormals[i * 3 + j];
Eigen::Vector3f position = mesh.getVertex(triVert[j]);
Eigen::Vector3f normal = vertexNormals[i * 3 + j];
int dataOffset = (i * 3 + j) * floatsPerVertex;
vertexData[dataOffset + 0] = position.x();
@ -454,7 +311,7 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
vertexData[dataOffset + 5] = normal.z();
if (hasTextureCoords)
{
Vector2f texCoord = mesh.getTexCoord(triVert[j]);
Eigen::Vector2f texCoord = mesh.getTexCoord(triVert[j]);
vertexData[dataOffset + 6] = texCoord.x();
vertexData[dataOffset + 7] = texCoord.y();
}
@ -462,8 +319,8 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
}
// Create the mesh
Mesh* newMesh = new Mesh();
newMesh->setVertexDescription(Mesh::VertexDescription(vertexSize, nAttributes, attributes));
cmod::Mesh* newMesh = new cmod::Mesh();
newMesh->setVertexDescription(cmod::VertexDescription(vertexSize, nAttributes, attributes));
newMesh->setVertices(nFaces * 3, vertexData);
for (uint32_t i = 0; i < mesh.getMeshMaterialGroupCount(); ++i)
@ -472,20 +329,20 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
// Vertex lists are not indexed, so the conversion to an indexed format is
// trivial (although much space is wasted storing unnecessary indices.)
uint32_t nMatGroupFaces = matGroup->faces.size();
std::uint32_t nMatGroupFaces = matGroup->faces.size();
auto indices = new uint32_t[nMatGroupFaces * 3];
for (uint32_t j = 0; j < nMatGroupFaces; ++j)
auto indices = new std::uint32_t[nMatGroupFaces * 3];
for (std::uint32_t j = 0; j < nMatGroupFaces; ++j)
{
uint16_t faceIndex = matGroup->faces[j];
std::uint16_t faceIndex = matGroup->faces[j];
indices[j * 3 + 0] = faceIndex * 3 + 0;
indices[j * 3 + 1] = faceIndex * 3 + 1;
indices[j * 3 + 2] = faceIndex * 3 + 2;
}
// Lookup the material index
uint32_t materialIndex = 0;
for (uint32_t j = 0; j < scene.getMaterialCount(); ++j)
std::uint32_t materialIndex = 0;
for (std::uint32_t j = 0; j < scene.getMaterialCount(); ++j)
{
if (matGroup->materialName == scene.getMaterial(j)->getName())
{
@ -494,7 +351,7 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
}
}
newMesh->addGroup(Mesh::TriList, materialIndex, nMatGroupFaces * 3, indices);
newMesh->addGroup(cmod::PrimitiveGroupType::TriList, materialIndex, nMatGroupFaces * 3, indices);
}
// clean up
@ -511,32 +368,23 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
}
#if 0
static Material::Color
toMaterialColor(Color c)
{
return {c.red(), c.green(), c.blue()};
}
#endif
static Model*
cmod::Model*
Convert3DSModel(const M3DScene& scene, const fs::path& texPath)
{
Model* model = new Model();
cmod::Model* model = new cmod::Model();
// Convert the materials
for (uint32_t i = 0; i < scene.getMaterialCount(); i++)
for (std::uint32_t i = 0; i < scene.getMaterialCount(); i++)
{
const M3DMaterial* material = scene.getMaterial(i);
Material* newMaterial = new Material();
cmod::Material* newMaterial = new cmod::Material();
M3DColor diffuse = material->getDiffuseColor();
newMaterial->diffuse = Material::Color(diffuse.red, diffuse.green, diffuse.blue);
newMaterial->diffuse = cmod::Color(diffuse.red, diffuse.green, diffuse.blue);
newMaterial->opacity = material->getOpacity();
M3DColor specular = material->getSpecularColor();
newMaterial->specular = Material::Color(specular.red, specular.green, specular.blue);
newMaterial->specular = cmod::Color(specular.red, specular.green, specular.blue);
float shininess = material->getShininess();
@ -544,14 +392,14 @@ Convert3DSModel(const M3DScene& scene, const fs::path& texPath)
// range that OpenGL uses for the specular exponent. The
// current equation is just a guess at the mapping that
// 3DS actually uses.
newMaterial->specularPower = (float) pow(2.0, 1.0 + 0.1 * shininess);
newMaterial->specularPower = std::pow(2.0f, 1.0f + 0.1f * shininess);
if (newMaterial->specularPower > 128.0f)
newMaterial->specularPower = 128.0f;
if (!material->getTextureMap().empty())
{
ResourceHandle tex = GetTextureManager()->getHandle(TextureInfo(material->getTextureMap(), texPath, TextureInfo::WrapTexture));
newMaterial->maps[Material::DiffuseMap] = tex;
newMaterial->setMap(cmod::TextureSemantic::DiffuseMap, tex);
}
model->addMaterial(newMaterial);
@ -559,7 +407,7 @@ Convert3DSModel(const M3DScene& scene, const fs::path& texPath)
// Convert all models in the scene. Some confusing terminology: a 3ds 'scene' is the same
// as a Celestia model, and a 3ds 'model' is the same as a Celestia mesh.
for (uint32_t i = 0; i < scene.getModelCount(); i++)
for (std::uint32_t i = 0; i < scene.getModelCount(); i++)
{
const M3DModel* model3ds = scene.getModel(i);
if (model3ds)
@ -569,7 +417,7 @@ Convert3DSModel(const M3DScene& scene, const fs::path& texPath)
const M3DTriangleMesh* mesh = model3ds->getTriMesh(j);
if (mesh)
{
Mesh* newMesh = ConvertTriangleMesh(*mesh, scene);
cmod::Mesh* newMesh = ConvertTriangleMesh(*mesh, scene);
model->addMesh(newMesh);
}
}
@ -578,3 +426,152 @@ Convert3DSModel(const M3DScene& scene, const fs::path& texPath)
return model;
}
constexpr const fs::path::value_type UniqueSuffixChar = '!';
} // end unnamed namespace
GeometryManager*
GetGeometryManager()
{
static GeometryManager geometryManager("models");
return &geometryManager;
}
fs::path
GeometryInfo::resolve(const fs::path& baseDir)
{
// Ensure that models with different centers get resolved to different objects by
// adding a 'uniquifying' suffix to the filename that encodes the center value.
// This suffix is stripped before the file is actually loaded.
fs::path::string_type uniquifyingSuffix;
fs::path::string_type format;
#ifdef _WIN32
format = L"%c%f,%f,%f,%f,%d";
#else
format = "%c%f,%f,%f,%f,%d";
#endif
uniquifyingSuffix = fmt::sprintf(format, UniqueSuffixChar, center.x(), center.y(), center.z(), scale, (int) isNormalized);
if (!path.empty())
{
fs::path filename = path / "models" / source;
std::ifstream in(filename.string());
if (in.good())
{
resolvedToPath = true;
return filename += uniquifyingSuffix;
}
}
return (baseDir / source) += uniquifyingSuffix;
}
Geometry*
GeometryInfo::load(const fs::path& resolvedFilename)
{
// Strip off the uniquifying suffix
fs::path::string_type::size_type uniquifyingSuffixStart = resolvedFilename.native().rfind(UniqueSuffixChar);
fs::path filename = resolvedFilename.native().substr(0, uniquifyingSuffixStart);
std::clog << fmt::sprintf(_("Loading model: %s\n"), filename);
cmod::Model* model = nullptr;
ContentType fileType = DetermineFileType(filename);
if (fileType == Content_3DStudio)
{
std::unique_ptr<M3DScene> scene = Read3DSFile(filename);
if (scene != nullptr)
{
if (resolvedToPath)
model = Convert3DSModel(*scene, path);
else
model = Convert3DSModel(*scene, "");
if (isNormalized)
model->normalize(center);
else
model->transform(center, scale);
}
}
else if (fileType == Content_CelestiaModel)
{
std::ifstream in(filename.string(), std::ios::binary);
if (in.good())
{
model = cmod::LoadModel(
in,
[&](const fs::path& name)
{
return GetTextureManager()->getHandle(TextureInfo(name, path, TextureInfo::WrapTexture));
});
if (model != nullptr)
{
if (isNormalized)
model->normalize(center);
else
model->transform(center, scale);
}
}
}
else if (fileType == Content_CelestiaMesh)
{
model = LoadCelestiaMesh(filename);
if (model != nullptr)
{
if (isNormalized)
model->normalize(center);
else
model->transform(center, scale);
}
}
#if PARTICLE_SYSTEM
else if (fileType == Content_CelestiaParticleSystem)
{
ifstream in(filename);
if (in.good())
{
return LoadParticleSystem(in, path);
}
}
#endif
// Condition the model for optimal rendering
if (model != nullptr)
{
// Many models tend to have a lot of duplicate materials; eliminate
// them, since unnecessarily setting material parameters can adversely
// impact rendering performance. Ideally uniquification of materials
// would be performed just once when the model was created, but
// that's not the case.
std::uint32_t originalMaterialCount = model->getMaterialCount();
model->uniquifyMaterials();
// Sort the submeshes roughly by opacity. This will eliminate a
// good number of the errors caused when translucent triangles are
// rendered before geometry that they cover.
model->sortMeshes(cmod::Model::OpacityComparator());
model->determineOpacity();
// Display some statics for the model
std::clog << fmt::sprintf(
_(" Model statistics: %u vertices, %u primitives, %u materials (%u unique)\n"),
model->getVertexCount(),
model->getPrimitiveCount(),
originalMaterialCount,
model->getMaterialCount());
return new ModelGeometry(std::unique_ptr<cmod::Model>(model));
}
else
{
std::clog << fmt::sprintf(_("Error loading model '%s'\n"), filename);
return nullptr;
}
}

View File

@ -7,14 +7,13 @@
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#ifndef _CELENGINE_MESHMANAGER_H_
#define _CELENGINE_MESHMANAGER_H_
#pragma once
#include <Eigen/Core>
#include <string>
#include <map>
#include <celutil/resmanager.h>
#include <celengine/geometry.h>
#include <celcompat/filesystem.h>
#include <celutil/resmanager.h>
#include "geometry.h"
class GeometryInfo : public ResourceInfo<Geometry>
@ -75,6 +74,3 @@ inline bool operator<(const GeometryInfo& g0, const GeometryInfo& g1)
typedef ResourceManager<GeometryInfo> GeometryManager;
extern GeometryManager* GetGeometryManager();
#endif // _CELENGINE_MESHMANAGER_H_

View File

@ -8,18 +8,12 @@
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#include <map>
#include <utility>
#include "glsupport.h"
#include "modelgeometry.h"
#include "rendcontext.h"
#include "texmanager.h"
#include <Eigen/Core>
#include <functional>
#include <algorithm>
#include <cassert>
using namespace cmod;
using namespace Eigen;
using namespace std;
using namespace celmath;
// Vertex buffer object support
@ -51,9 +45,9 @@ public:
/** Create a new ModelGeometry wrapping the specified model.
* The ModelGeoemtry takes ownership of the model.
*/
ModelGeometry::ModelGeometry(unique_ptr<cmod::Model>&& model) :
m_model(move(model)),
m_glData(unique_ptr<ModelOpenGLData>(new ModelOpenGLData()))
ModelGeometry::ModelGeometry(std::unique_ptr<cmod::Model>&& model) :
m_model(std::move(model)),
m_glData(std::make_unique<ModelOpenGLData>())
{
}
@ -84,8 +78,8 @@ ModelGeometry::render(RenderContext& rc, double /* t */)
for (unsigned int i = 0; i < m_model->getMeshCount(); ++i)
{
Mesh* mesh = m_model->getMesh(i);
const Mesh::VertexDescription& vertexDesc = mesh->getVertexDescription();
cmod::Mesh* mesh = m_model->getMesh(i);
const cmod::VertexDescription& vertexDesc = mesh->getVertexDescription();
GLuint vboId = 0;
if (mesh->getVertexCount() * vertexDesc.stride > MinVBOSize)
@ -105,8 +99,9 @@ ModelGeometry::render(RenderContext& rc, double /* t */)
for (unsigned int groupIndex = 0; groupIndex < mesh->getGroupCount(); ++groupIndex)
{
const Mesh::PrimitiveGroup* group = mesh->getGroup(groupIndex);
if (group->vertexOverride != nullptr && group->vertexCountOverride * group->vertexDescriptionOverride.stride > MinVBOSize)
const cmod::PrimitiveGroup* group = mesh->getGroup(groupIndex);
if (group->vertexOverride != nullptr
&& group->vertexCountOverride * group->vertexDescriptionOverride.stride > MinVBOSize)
{
glGenBuffers(1, &vboId);
if (vboId != 0)
@ -129,7 +124,7 @@ ModelGeometry::render(RenderContext& rc, double /* t */)
// Iterate over all meshes in the model
for (unsigned int meshIndex = 0; meshIndex < m_model->getMeshCount(); ++meshIndex)
{
Mesh* mesh = m_model->getMesh(meshIndex);
cmod::Mesh* mesh = m_model->getMesh(meshIndex);
const void* currentData = nullptr;
GLuint currentVboId = 0;
@ -137,7 +132,7 @@ ModelGeometry::render(RenderContext& rc, double /* t */)
// Iterate over all primitive groups in the mesh
for (unsigned int groupIndex = 0; groupIndex < mesh->getGroupCount(); ++groupIndex)
{
const Mesh::PrimitiveGroup* group = mesh->getGroup(groupIndex);
const cmod::PrimitiveGroup* group = mesh->getGroup(groupIndex);
bool useOverrideValue = group->vertexOverride != nullptr && rc.shouldDrawLineAsTriangles();
const void* data = useOverrideValue ? group->vertexOverride : mesh->getVertexData();
@ -168,7 +163,7 @@ ModelGeometry::render(RenderContext& rc, double /* t */)
rc.updateShader(vertexDescription, group->prim);
// Set up the material
const Material* material = nullptr;
const cmod::Material* material = nullptr;
unsigned int materialIndex = group->materialIndex;
if (materialIndex != lastMaterial && materialIndex < materialCount)
{
@ -203,7 +198,7 @@ ModelGeometry::isNormalized() const
bool
ModelGeometry::usesTextureType(Material::TextureSemantic t) const
ModelGeometry::usesTextureType(cmod::TextureSemantic t) const
{
return m_model->usesTextureType(t);
}

View File

@ -15,11 +15,11 @@
#include <Eigen/Geometry>
#include <celmodel/model.h>
#include <celutil/resmanager.h>
#include "geometry.h"
class ModelOpenGLData;
class RenderContext;
class ModelGeometry : public Geometry
{
@ -32,14 +32,14 @@ class ModelGeometry : public Geometry
* and set distance; otherwise return false and leave
* distance unmodified.
*/
virtual bool pick(const Eigen::ParametrizedLine<double, 3>& r, double& distance) const;
bool pick(const Eigen::ParametrizedLine<double, 3>& r, double& distance) const override;
//! Render the model in the current OpenGL context
virtual void render(RenderContext&, double t = 0.0);
void render(RenderContext&, double t = 0.0) override;
virtual bool usesTextureType(cmod::Material::TextureSemantic) const;
virtual bool isOpaque() const;
virtual bool isNormalized() const;
bool usesTextureType(cmod::TextureSemantic) const override;
bool isOpaque() const override;
bool isNormalized() const override;
void loadTextures();

View File

@ -8,22 +8,24 @@
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#include <vector>
#include <celmath/geomutil.h>
#include <algorithm>
#include <cstddef>
#include <celutil/color.h>
#include "body.h"
#include "modelgeometry.h"
#include "lightenv.h"
#include "rendcontext.h"
#include "render.h"
#include "shadowmap.h"
#include "texmanager.h"
#include "texture.h"
using namespace cmod;
using namespace Eigen;
using namespace std;
static Material defaultMaterial;
namespace
{
static GLenum GLPrimitiveModes[Mesh::PrimitiveTypeMax] =
const cmod::Material defaultMaterial;
constexpr GLenum GLPrimitiveModes[static_cast<std::size_t>(cmod::PrimitiveGroupType::PrimitiveTypeMax)] =
{
GL_TRIANGLES,
GL_TRIANGLE_STRIP,
@ -34,7 +36,7 @@ static GLenum GLPrimitiveModes[Mesh::PrimitiveTypeMax] =
GL_POINTS,
};
static GLenum GLComponentTypes[Mesh::FormatMax] =
constexpr GLenum GLComponentTypes[static_cast<std::size_t>(cmod::VertexAttributeFormat::FormatMax)] =
{
GL_FLOAT, // Float1
GL_FLOAT, // Float2
@ -43,7 +45,7 @@ static GLenum GLComponentTypes[Mesh::FormatMax] =
GL_UNSIGNED_BYTE, // UByte4
};
static int GLComponentCounts[Mesh::FormatMax] =
constexpr int GLComponentCounts[static_cast<std::size_t>(cmod::VertexAttributeFormat::FormatMax)] =
{
1, // Float1
2, // Float2
@ -53,13 +55,160 @@ static int GLComponentCounts[Mesh::FormatMax] =
};
void
setStandardVertexArrays(const cmod::VertexDescription& desc,
const void* vertexData)
{
const cmod::VertexAttribute& position = desc.getAttribute(cmod::VertexAttributeSemantic::Position);
const cmod::VertexAttribute& normal = desc.getAttribute(cmod::VertexAttributeSemantic::Normal);
const cmod::VertexAttribute& color0 = desc.getAttribute(cmod::VertexAttributeSemantic::Color0);
const cmod::VertexAttribute& texCoord0 = desc.getAttribute(cmod::VertexAttributeSemantic::Texture0);
// Can't render anything unless we have positions
if (position.format != cmod::VertexAttributeFormat::Float3)
return;
// Set up the vertex arrays
glEnableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex,
3, GL_FLOAT, GL_FALSE, desc.stride,
reinterpret_cast<const char*>(vertexData) + position.offset);
// Set up the normal array
switch (normal.format)
{
case cmod::VertexAttributeFormat::Float3:
glEnableVertexAttribArray(CelestiaGLProgram::NormalAttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::NormalAttributeIndex,
3, GLComponentTypes[static_cast<std::size_t>(normal.format)],
GL_FALSE, desc.stride,
reinterpret_cast<const char*>(vertexData) + normal.offset);
break;
default:
glDisableVertexAttribArray(CelestiaGLProgram::NormalAttributeIndex);
break;
}
GLint normalized = GL_TRUE;
// Set up the color array
switch (color0.format)
{
case cmod::VertexAttributeFormat::Float3:
case cmod::VertexAttributeFormat::Float4:
normalized = GL_FALSE;
case cmod::VertexAttributeFormat::UByte4:
glEnableVertexAttribArray(CelestiaGLProgram::ColorAttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::ColorAttributeIndex,
GLComponentCounts[static_cast<std::size_t>(color0.format)],
GLComponentTypes[static_cast<std::size_t>(color0.format)],
normalized, desc.stride,
reinterpret_cast<const char*>(vertexData) + color0.offset);
break;
default:
glDisableVertexAttribArray(CelestiaGLProgram::ColorAttributeIndex);
break;
}
// Set up the texture coordinate array
switch (texCoord0.format)
{
case cmod::VertexAttributeFormat::Float1:
case cmod::VertexAttributeFormat::Float2:
case cmod::VertexAttributeFormat::Float3:
case cmod::VertexAttributeFormat::Float4:
glEnableVertexAttribArray(CelestiaGLProgram::TextureCoord0AttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::TextureCoord0AttributeIndex,
GLComponentCounts[static_cast<std::size_t>(texCoord0.format)],
GLComponentTypes[static_cast<std::size_t>(texCoord0.format)],
GL_FALSE,
desc.stride,
reinterpret_cast<const char*>(vertexData) + texCoord0.offset);
break;
default:
glDisableVertexAttribArray(CelestiaGLProgram::TextureCoord0AttributeIndex);
break;
}
}
void
setExtendedVertexArrays(const cmod::VertexDescription& desc,
const void* vertexData)
{
const cmod::VertexAttribute& tangent = desc.getAttribute(cmod::VertexAttributeSemantic::Tangent);
const auto* vertices = reinterpret_cast<const char*>(vertexData);
switch (tangent.format)
{
case cmod::VertexAttributeFormat::Float3:
glEnableVertexAttribArray(CelestiaGLProgram::TangentAttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::TangentAttributeIndex,
GLComponentCounts[static_cast<std::size_t>(tangent.format)],
GLComponentTypes[static_cast<std::size_t>(tangent.format)],
GL_FALSE,
desc.stride,
vertices + tangent.offset);
break;
default:
glDisableVertexAttribArray(CelestiaGLProgram::TangentAttributeIndex);
break;
}
const cmod::VertexAttribute& pointsize = desc.getAttribute(cmod::VertexAttributeSemantic::PointSize);
switch (pointsize.format)
{
case cmod::VertexAttributeFormat::Float1:
glEnableVertexAttribArray(CelestiaGLProgram::PointSizeAttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::PointSizeAttributeIndex,
GLComponentCounts[static_cast<std::size_t>(pointsize.format)],
GLComponentTypes[static_cast<std::size_t>(pointsize.format)],
GL_FALSE,
desc.stride,
vertices + pointsize.offset);
break;
default:
glDisableVertexAttribArray(CelestiaGLProgram::PointSizeAttributeIndex);
break;
}
const cmod::VertexAttribute& nextPos = desc.getAttribute(cmod::VertexAttributeSemantic::NextPosition);
switch (nextPos.format)
{
case cmod::VertexAttributeFormat::Float3:
glEnableVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::NextVCoordAttributeIndex,
GLComponentCounts[static_cast<std::size_t>(nextPos.format)],
GLComponentTypes[static_cast<std::size_t>(nextPos.format)],
GL_FALSE,
desc.stride,
vertices + nextPos.offset);
break;
default:
glDisableVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex);
break;
}
const cmod::VertexAttribute& scaleFac = desc.getAttribute(cmod::VertexAttributeSemantic::ScaleFactor);
switch (scaleFac.format)
{
case cmod::VertexAttributeFormat::Float1:
glEnableVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::ScaleFactorAttributeIndex,
GLComponentCounts[static_cast<std::size_t>(scaleFac.format)],
GLComponentTypes[static_cast<std::size_t>(scaleFac.format)],
GL_FALSE,
desc.stride,
vertices + scaleFac.offset);
break;
default:
glDisableVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex);
break;
}
}
} // end unnamed namespace
static void
setStandardVertexArrays(const Mesh::VertexDescription& desc,
const void* vertexData);
static void
setExtendedVertexArrays(const Mesh::VertexDescription& desc,
const void* vertexData);
RenderContext::RenderContext(Renderer* _renderer) :
@ -69,7 +218,7 @@ RenderContext::RenderContext(Renderer* _renderer) :
}
RenderContext::RenderContext(const Material* _material)
RenderContext::RenderContext(const cmod::Material* _material)
{
if (_material == nullptr)
material = &defaultMaterial;
@ -78,7 +227,7 @@ RenderContext::RenderContext(const Material* _material)
}
const Material*
const cmod::Material*
RenderContext::getMaterial() const
{
return material;
@ -86,7 +235,7 @@ RenderContext::getMaterial() const
void
RenderContext::setMaterial(const Material* newMaterial)
RenderContext::setMaterial(const cmod::Material* newMaterial)
{
if (!locked)
{
@ -103,8 +252,8 @@ RenderContext::setMaterial(const Material* newMaterial)
}
else if (renderPass == EmissivePass)
{
if (material->maps[Material::EmissiveMap] !=
newMaterial->maps[Material::EmissiveMap])
if (material->getMap(cmod::TextureSemantic::EmissiveMap) !=
newMaterial->getMap(cmod::TextureSemantic::EmissiveMap))
{
material = newMaterial;
makeCurrent(*material);
@ -136,13 +285,13 @@ RenderContext::getPointScale() const
void
RenderContext::setCameraOrientation(const Quaternionf& q)
RenderContext::setCameraOrientation(const Eigen::Quaternionf& q)
{
cameraOrientation = q;
}
Quaternionf
Eigen::Quaternionf
RenderContext::getCameraOrientation() const
{
return cameraOrientation;
@ -150,11 +299,11 @@ RenderContext::getCameraOrientation() const
void
RenderContext::drawGroup(const Mesh::PrimitiveGroup& group, bool useOverride)
RenderContext::drawGroup(const cmod::PrimitiveGroup& group, bool useOverride)
{
// Skip rendering if this is the emissive pass but there's no
// emissive texture.
ResourceHandle emissiveMap = material->maps[Material::EmissiveMap];
ResourceHandle emissiveMap = material->getMap(cmod::TextureSemantic::EmissiveMap);
if (renderPass == EmissivePass && emissiveMap == InvalidResource)
{
@ -162,10 +311,10 @@ RenderContext::drawGroup(const Mesh::PrimitiveGroup& group, bool useOverride)
}
bool drawPoints = false;
if (group.prim == Mesh::SpriteList || group.prim == Mesh::PointList)
if (group.prim == cmod::PrimitiveGroupType::SpriteList || group.prim == cmod::PrimitiveGroupType::PointList)
{
drawPoints = true;
if (group.prim == Mesh::PointList)
if (group.prim == cmod::PrimitiveGroupType::PointList)
glVertexAttrib1f(CelestiaGLProgram::PointSizeAttributeIndex, 1.0f);
#ifndef GL_ES
glEnable(GL_POINT_SPRITE);
@ -189,7 +338,7 @@ RenderContext::drawGroup(const Mesh::PrimitiveGroup& group, bool useOverride)
void
RenderContext::setVertexArrays(const Mesh::VertexDescription& desc,
RenderContext::setVertexArrays(const cmod::VertexDescription& desc,
const void* vertexData)
{
setStandardVertexArrays(desc, vertexData);
@ -197,18 +346,23 @@ RenderContext::setVertexArrays(const Mesh::VertexDescription& desc,
}
void
RenderContext::updateShader(const cmod::Mesh::VertexDescription& desc, Mesh::PrimitiveGroupType primType)
RenderContext::updateShader(const cmod::VertexDescription& desc, cmod::PrimitiveGroupType primType)
{
// Normally, the shader that will be used depends only on the material.
// But the presence of point size and normals can also affect the
// shader, so force an update of the material if those attributes appear
// or disappear in the new set of vertex arrays.
bool usePointSizeNow = (desc.getAttribute(Mesh::PointSize).format == Mesh::Float1);
bool useNormalsNow = (desc.getAttribute(Mesh::Normal).format == Mesh::Float3);
bool useColorsNow = (desc.getAttribute(Mesh::Color0).format != Mesh::InvalidFormat);
bool useTexCoordsNow = (desc.getAttribute(Mesh::Texture0).format != Mesh::InvalidFormat);
bool drawLineNow = (desc.getAttribute(Mesh::NextPosition).format == Mesh::Float3);
bool useStaticPointSizeNow = primType == Mesh::PointList;
bool usePointSizeNow = (desc.getAttribute(cmod::VertexAttributeSemantic::PointSize).format
== cmod::VertexAttributeFormat::Float1);
bool useNormalsNow = (desc.getAttribute(cmod::VertexAttributeSemantic::Normal).format
== cmod::VertexAttributeFormat::Float3);
bool useColorsNow = (desc.getAttribute(cmod::VertexAttributeSemantic::Color0).format
!= cmod::VertexAttributeFormat::InvalidFormat);
bool useTexCoordsNow = (desc.getAttribute(cmod::VertexAttributeSemantic::Texture0).format
!= cmod::VertexAttributeFormat::InvalidFormat);
bool drawLineNow = (desc.getAttribute(cmod::VertexAttributeSemantic::NextPosition).format
== cmod::VertexAttributeFormat::Float3);
bool useStaticPointSizeNow = primType == cmod::PrimitiveGroupType::PointList;
if (usePointSizeNow != usePointSize ||
useStaticPointSizeNow != useStaticPointSize ||
@ -240,168 +394,17 @@ RenderContext::setModelViewMatrix(const Eigen::Matrix4f *m)
modelViewMatrix = m;
}
void
setStandardVertexArrays(const Mesh::VertexDescription& desc,
const void* vertexData)
{
const Mesh::VertexAttribute& position = desc.getAttribute(Mesh::Position);
const Mesh::VertexAttribute& normal = desc.getAttribute(Mesh::Normal);
const Mesh::VertexAttribute& color0 = desc.getAttribute(Mesh::Color0);
const Mesh::VertexAttribute& texCoord0 = desc.getAttribute(Mesh::Texture0);
// Can't render anything unless we have positions
if (position.format != Mesh::Float3)
return;
// Set up the vertex arrays
glEnableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex,
3, GL_FLOAT, GL_FALSE, desc.stride,
reinterpret_cast<const char*>(vertexData) + position.offset);
// Set up the normal array
switch (normal.format)
{
case Mesh::Float3:
glEnableVertexAttribArray(CelestiaGLProgram::NormalAttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::NormalAttributeIndex,
3, GLComponentTypes[(int) normal.format],
GL_FALSE, desc.stride,
reinterpret_cast<const char*>(vertexData) + normal.offset);
break;
default:
glDisableVertexAttribArray(CelestiaGLProgram::NormalAttributeIndex);
break;
}
GLint normalized = GL_TRUE;
// Set up the color array
switch (color0.format)
{
case Mesh::Float3:
case Mesh::Float4:
normalized = GL_FALSE;
case Mesh::UByte4:
glEnableVertexAttribArray(CelestiaGLProgram::ColorAttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::ColorAttributeIndex,
GLComponentCounts[color0.format],
GLComponentTypes[color0.format],
normalized, desc.stride,
reinterpret_cast<const char*>(vertexData) + color0.offset);
break;
default:
glDisableVertexAttribArray(CelestiaGLProgram::ColorAttributeIndex);
break;
}
// Set up the texture coordinate array
switch (texCoord0.format)
{
case Mesh::Float1:
case Mesh::Float2:
case Mesh::Float3:
case Mesh::Float4:
glEnableVertexAttribArray(CelestiaGLProgram::TextureCoord0AttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::TextureCoord0AttributeIndex,
GLComponentCounts[(int) texCoord0.format],
GLComponentTypes[(int) texCoord0.format],
GL_FALSE,
desc.stride,
reinterpret_cast<const char*>(vertexData) + texCoord0.offset);
break;
default:
glDisableVertexAttribArray(CelestiaGLProgram::TextureCoord0AttributeIndex);
break;
}
}
void
setExtendedVertexArrays(const Mesh::VertexDescription& desc,
const void* vertexData)
{
const Mesh::VertexAttribute& tangent = desc.getAttribute(Mesh::Tangent);
const auto* vertices = reinterpret_cast<const char*>(vertexData);
switch (tangent.format)
{
case Mesh::Float3:
glEnableVertexAttribArray(CelestiaGLProgram::TangentAttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::TangentAttributeIndex,
GLComponentCounts[(int) tangent.format],
GLComponentTypes[(int) tangent.format],
GL_FALSE,
desc.stride,
vertices + tangent.offset);
break;
default:
glDisableVertexAttribArray(CelestiaGLProgram::TangentAttributeIndex);
break;
}
const Mesh::VertexAttribute& pointsize = desc.getAttribute(Mesh::PointSize);
switch (pointsize.format)
{
case Mesh::Float1:
glEnableVertexAttribArray(CelestiaGLProgram::PointSizeAttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::PointSizeAttributeIndex,
GLComponentCounts[(int) pointsize.format],
GLComponentTypes[(int) pointsize.format],
GL_FALSE,
desc.stride,
vertices + pointsize.offset);
break;
default:
glDisableVertexAttribArray(CelestiaGLProgram::PointSizeAttributeIndex);
break;
}
const Mesh::VertexAttribute& nextPos = desc.getAttribute(Mesh::NextPosition);
switch (nextPos.format)
{
case Mesh::Float3:
glEnableVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::NextVCoordAttributeIndex,
GLComponentCounts[(int) nextPos.format],
GLComponentTypes[(int) nextPos.format],
GL_FALSE,
desc.stride,
vertices + nextPos.offset);
break;
default:
glDisableVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex);
break;
}
const Mesh::VertexAttribute& scaleFac = desc.getAttribute(Mesh::ScaleFactor);
switch (scaleFac.format)
{
case Mesh::Float1:
glEnableVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::ScaleFactorAttributeIndex,
GLComponentCounts[(int) scaleFac.format],
GLComponentTypes[(int) scaleFac.format],
GL_FALSE,
desc.stride,
vertices + scaleFac.offset);
break;
default:
glDisableVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex);
break;
}
}
/***** GLSL render context ******/
GLSL_RenderContext::GLSL_RenderContext(Renderer* renderer,
const LightingState& ls,
float _objRadius,
const Quaternionf& orientation) :
const Eigen::Quaternionf& orientation) :
RenderContext(renderer),
lightingState(ls),
objRadius(_objRadius),
objScale(Vector3f::Constant(_objRadius)),
objScale(Eigen::Vector3f::Constant(_objRadius)),
objOrientation(orientation)
{
initLightingEnvironment();
@ -411,7 +414,7 @@ GLSL_RenderContext::GLSL_RenderContext(Renderer* renderer,
GLSL_RenderContext::GLSL_RenderContext(Renderer* renderer,
const LightingState& ls,
const Eigen::Vector3f& _objScale,
const Quaternionf& orientation) :
const Eigen::Quaternionf& orientation) :
RenderContext(renderer),
lightingState(ls),
objRadius(_objScale.maxCoeff()),
@ -438,7 +441,7 @@ GLSL_RenderContext::initLightingEnvironment()
{
// Set the light and shadow environment, which is constant for the entire model.
// The material properties will be set per mesh.
shaderProps.nLights = min(lightingState.nLights, MaxShaderLights);
shaderProps.nLights = std::min(lightingState.nLights, MaxShaderLights);
// Set the shadow information.
// Track the total number of shadows; if there are too many, we'll have
@ -448,7 +451,8 @@ GLSL_RenderContext::initLightingEnvironment()
{
if (lightingState.shadows[li] && !lightingState.shadows[li]->empty())
{
unsigned int nShadows = (unsigned int) min((size_t) MaxShaderEclipseShadows, lightingState.shadows[li]->size());
unsigned int nShadows = static_cast<unsigned int>(std::min(static_cast<std::size_t>(MaxShaderEclipseShadows),
lightingState.shadows[li]->size()));
shaderProps.setEclipseShadowCountForLight(li, nShadows);
totalShadows += nShadows;
}
@ -457,7 +461,7 @@ GLSL_RenderContext::initLightingEnvironment()
}
void
GLSL_RenderContext::makeCurrent(const Material& m)
GLSL_RenderContext::makeCurrent(const cmod::Material& m)
{
Texture* textures[4] = { nullptr, nullptr, nullptr, nullptr };
unsigned int nTextures = 0;
@ -490,10 +494,10 @@ GLSL_RenderContext::makeCurrent(const Material& m)
shaderProps.lightModel = ShaderProperties::ParticleDiffuseModel;
}
ResourceHandle diffuseMap = m.maps[Material::DiffuseMap];
ResourceHandle normalMap = m.maps[Material::NormalMap];
ResourceHandle specularMap = m.maps[Material::SpecularMap];
ResourceHandle emissiveMap = m.maps[Material::EmissiveMap];
ResourceHandle diffuseMap = m.getMap(cmod::TextureSemantic::DiffuseMap);
ResourceHandle normalMap = m.getMap(cmod::TextureSemantic::NormalMap);
ResourceHandle specularMap = m.getMap(cmod::TextureSemantic::SpecularMap);
ResourceHandle emissiveMap = m.getMap(cmod::TextureSemantic::EmissiveMap);
if (diffuseMap != InvalidResource && (useTexCoords || usePointSize))
{
@ -519,7 +523,7 @@ GLSL_RenderContext::makeCurrent(const Material& m)
}
}
if (m.specular != Material::Color(0.0f, 0.0f, 0.0f) && useNormals)
if (m.specular != cmod::Color(0.0f, 0.0f, 0.0f) && useNormals)
{
shaderProps.lightModel = ShaderProperties::PerPixelSpecularModel;
specTex = GetTextureManager()->find(specularMap);
@ -634,9 +638,9 @@ GLSL_RenderContext::makeCurrent(const Material& m)
#if GL_ONLY_SHADOWS
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
#endif
Matrix4f shadowBias(Matrix4f::Zero());
shadowBias.diagonal() = Vector4f(0.5f, 0.5f, 0.5f, 1.0f);
shadowBias.col(3) = Vector4f(0.5f, 0.5f, 0.5f, 1.0f);
Eigen::Matrix4f shadowBias(Eigen::Matrix4f::Zero());
shadowBias.diagonal() = Eigen::Vector4f(0.5f, 0.5f, 0.5f, 1.0f);
shadowBias.col(3) = Eigen::Vector4f(0.5f, 0.5f, 0.5f, 1.0f);
prog->ShadowMatrix0 = shadowBias * (*lightMatrix);
prog->floatParam("shadowMapSize") = static_cast<float>(shadowMapWidth);
}
@ -698,7 +702,7 @@ GLSL_RenderContext::makeCurrent(const Material& m)
float ringWidth = rings->outerRadius - rings->innerRadius;
prog->ringRadius = rings->innerRadius / objRadius;
prog->ringWidth = objRadius / ringWidth;
prog->ringPlane = Hyperplane<float, 3>(lightingState.ringPlaneNormal, lightingState.ringCenter / objRadius).coeffs();
prog->ringPlane = Eigen::Hyperplane<float, 3>(lightingState.ringPlaneNormal, lightingState.ringCenter / objRadius).coeffs();
prog->ringCenter = lightingState.ringCenter / objRadius;
for (unsigned int lightIndex = 0; lightIndex < lightingState.nLights; ++lightIndex)
@ -710,9 +714,9 @@ GLSL_RenderContext::makeCurrent(const Material& m)
}
}
Material::BlendMode newBlendMode = Material::InvalidBlend;
cmod::BlendMode newBlendMode = cmod::BlendMode::InvalidBlend;
if (m.opacity != 1.0f ||
m.blend == Material::AdditiveBlend ||
m.blend == cmod::BlendMode::AdditiveBlend ||
(baseTex != nullptr && baseTex->hasAlpha()))
{
newBlendMode = m.blend;
@ -723,7 +727,7 @@ GLSL_RenderContext::makeCurrent(const Material& m)
blendMode = newBlendMode;
switch (blendMode)
{
case Material::NormalBlend:
case cmod::BlendMode::NormalBlend:
renderer->enableBlending();
renderer->setBlendingFactors(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if (disableDepthWriteOnBlend)
@ -731,7 +735,7 @@ GLSL_RenderContext::makeCurrent(const Material& m)
else
renderer->enableDepthMask();
break;
case Material::AdditiveBlend:
case cmod::BlendMode::AdditiveBlend:
renderer->enableBlending();
renderer->setBlendingFactors(GL_SRC_ALPHA, GL_ONE);
if (disableDepthWriteOnBlend)
@ -739,7 +743,7 @@ GLSL_RenderContext::makeCurrent(const Material& m)
else
renderer->enableDepthMask();
break;
case Material::PremultipliedAlphaBlend:
case cmod::BlendMode::PremultipliedAlphaBlend:
renderer->enableBlending();
renderer->setBlendingFactors(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
if (disableDepthWriteOnBlend)
@ -781,7 +785,7 @@ GLSL_RenderContext::setShadowMap(GLuint _shadowMap, GLuint _width, const Eigen::
GLSLUnlit_RenderContext::GLSLUnlit_RenderContext(Renderer* renderer, float _objRadius) :
RenderContext(renderer),
blendMode(Material::InvalidBlend),
blendMode(cmod::BlendMode::InvalidBlend),
objRadius(_objRadius)
{
initLightingEnvironment();
@ -809,7 +813,7 @@ GLSLUnlit_RenderContext::initLightingEnvironment()
void
GLSLUnlit_RenderContext::makeCurrent(const Material& m)
GLSLUnlit_RenderContext::makeCurrent(const cmod::Material& m)
{
Texture* textures[4] = { nullptr, nullptr, nullptr, nullptr };
unsigned int nTextures = 0;
@ -820,7 +824,7 @@ GLSLUnlit_RenderContext::makeCurrent(const Material& m)
shaderProps.lightModel = ShaderProperties::EmissiveModel;
shaderProps.texUsage = ShaderProperties::SharedTextureCoords;
ResourceHandle diffuseMap = m.maps[Material::DiffuseMap];
ResourceHandle diffuseMap = m.getMap(cmod::TextureSemantic::DiffuseMap);
if (diffuseMap != InvalidResource && (useTexCoords || usePointSize))
{
baseTex = GetTextureManager()->find(diffuseMap);
@ -879,9 +883,9 @@ GLSLUnlit_RenderContext::makeCurrent(const Material& m)
prog->lineWidthY = renderer->getLineWidthY();
}
Material::BlendMode newBlendMode = Material::InvalidBlend;
cmod::BlendMode newBlendMode = cmod::BlendMode::InvalidBlend;
if (m.opacity != 1.0f ||
m.blend == Material::AdditiveBlend ||
m.blend == cmod::BlendMode::AdditiveBlend ||
(baseTex != nullptr && baseTex->hasAlpha()))
{
newBlendMode = m.blend;
@ -892,17 +896,17 @@ GLSLUnlit_RenderContext::makeCurrent(const Material& m)
blendMode = newBlendMode;
switch (blendMode)
{
case Material::NormalBlend:
case cmod::BlendMode::NormalBlend:
renderer->enableBlending();
renderer->setBlendingFactors(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
renderer->disableDepthMask();
break;
case Material::AdditiveBlend:
case cmod::BlendMode::AdditiveBlend:
renderer->enableBlending();
renderer->setBlendingFactors(GL_SRC_ALPHA, GL_ONE);
renderer->disableDepthMask();
break;
case Material::PremultipliedAlphaBlend:
case cmod::BlendMode::PremultipliedAlphaBlend:
renderer->enableBlending();
renderer->setBlendingFactors(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
renderer->disableDepthMask();

View File

@ -8,13 +8,21 @@
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#ifndef _CELENGINE_RENDCONTEXT_H_
#define _CELENGINE_RENDCONTEXT_H_
#pragma once
#include "shadermanager.h"
#include <celmodel/mesh.h>
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <celmodel/material.h>
#include <celmodel/mesh.h>
#include "glsupport.h"
#include "shadermanager.h"
class Atmosphere;
class Color;
class LightingState;
class Renderer;
class RenderContext
@ -27,10 +35,10 @@ class RenderContext
virtual ~RenderContext() = default;
virtual void makeCurrent(const cmod::Material&) = 0;
virtual void setVertexArrays(const cmod::Mesh::VertexDescription& desc,
virtual void setVertexArrays(const cmod::VertexDescription& desc,
const void* vertexData);
virtual void updateShader(const cmod::Mesh::VertexDescription& desc, cmod::Mesh::PrimitiveGroupType primType);
virtual void drawGroup(const cmod::Mesh::PrimitiveGroup& group, bool useOverride);
virtual void updateShader(const cmod::VertexDescription& desc, cmod::PrimitiveGroupType primType);
virtual void drawGroup(const cmod::PrimitiveGroup& group, bool useOverride);
const cmod::Material* getMaterial() const;
void setMaterial(const cmod::Material*);
@ -57,13 +65,6 @@ class RenderContext
void setModelViewMatrix(const Eigen::Matrix4f *m);
void setProjectionMatrix(const Eigen::Matrix4f *m);
private:
const cmod::Material* material{ nullptr };
bool locked{ false };
RenderPass renderPass{ PrimaryPass };
float pointScale{ 1.0f };
Eigen::Quaternionf cameraOrientation; // required for drawing billboards
protected:
Renderer* renderer { nullptr };
bool usePointSize{ false };
@ -74,6 +75,13 @@ class RenderContext
bool drawLine { false };
const Eigen::Matrix4f *modelViewMatrix;
const Eigen::Matrix4f *projectionMatrix;
private:
const cmod::Material* material{ nullptr };
bool locked{ false };
RenderPass renderPass{ PrimaryPass };
float pointScale{ 1.0f };
Eigen::Quaternionf cameraOrientation; // required for drawing billboards
};
@ -105,14 +113,13 @@ class GLSL_RenderContext : public RenderContext
void setShadowMap(GLuint, GLuint, const Eigen::Matrix4f*);
private:
void initLightingEnvironment();
void setLightingParameters(CelestiaGLProgram& prog, Color diffuseColor, Color specularColor);
void setShadowParameters(CelestiaGLProgram& prog);
void initLightingEnvironment();
void setLightingParameters(CelestiaGLProgram& prog, Color diffuseColor, Color specularColor);
void setShadowParameters(CelestiaGLProgram& prog);
private:
const LightingState& lightingState;
const Atmosphere* atmosphere{ nullptr };
cmod::Material::BlendMode blendMode{ cmod::Material::InvalidBlend };
cmod::BlendMode blendMode{ cmod::BlendMode::InvalidBlend };
float objRadius;
Eigen::Vector3f objScale;
Eigen::Quaternionf objOrientation;
@ -139,12 +146,8 @@ class GLSLUnlit_RenderContext : public RenderContext
void initLightingEnvironment();
void setLightingParameters(CelestiaGLProgram& prog, Color diffuseColor, Color specularColor);
private:
cmod::Material::BlendMode blendMode;
cmod::BlendMode blendMode;
float objRadius;
ShaderProperties shaderProps;
};
#endif // _CELENGINE_RENDCONTEXT_H_

View File

@ -95,7 +95,6 @@ std::ofstream hdrlog;
#endif
#endif
using namespace cmod;
using namespace Eigen;
using namespace std;
using namespace celestia;

View File

@ -8,14 +8,15 @@
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#ifndef _CELENGINE_RENDER_H_
#define _CELENGINE_RENDER_H_
#pragma once
#include <list>
#include <memory>
#include <string>
#include <vector>
#include <Eigen/Core>
#include <celengine/universe.h>
#include <celengine/selection.h>
#include <celengine/starcolors.h>
@ -965,6 +966,3 @@ class RendererWatcher
virtual void notifyRenderSettingsChanged(const Renderer*) = 0;
};
#endif // _CELENGINE_RENDER_H_

View File

@ -10,59 +10,117 @@
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#include <config.h>
#include <algorithm>
#include <array>
#include <cmath>
#include <cstddef>
#include <memory>
#include <celmath/geomutil.h>
#include <celmath/mathlib.h>
#include <celmodel/material.h>
#include <celutil/color.h>
#include "body.h"
#include "framebuffer.h"
#include "geometry.h"
#include "glsupport.h"
#include "lodspheremesh.h"
#include "meshmanager.h"
#include "modelgeometry.h"
#include "rendcontext.h"
#include "render.h"
#include "renderinfo.h"
#include "renderglsl.h"
#include "renderinfo.h"
#include "shadermanager.h"
#include "texmanager.h"
#include "texture.h"
#include "vecgl.h"
#include <celengine/astro.h>
#include <celmath/frustum.h>
#include <celmath/distance.h>
#include <celmath/geomutil.h>
#include <celmath/intersect.h>
#include <celutil/utf8.h>
#include <celutil/util.h>
#include "shadowmap.h"
using namespace cmod;
using namespace Eigen;
using namespace std;
using namespace celmath;
using namespace celestia;
static
namespace
{
// Calculate the matrix used to render the model from the
// perspective of the light.
Eigen::Matrix4f directionalLightMatrix(const Eigen::Vector3f& lightDirection)
{
const Eigen::Vector3f &viewDir = lightDirection;
Eigen::Vector3f upDir = viewDir.unitOrthogonal();
Eigen::Vector3f rightDir = upDir.cross(viewDir);
Eigen::Matrix4f m = Eigen::Matrix4f::Identity();
m.row(0).head(3) = rightDir;
m.row(1).head(3) = upDir;
m.row(2).head(3) = viewDir;
return m;
}
/*! Render a mesh object
* Parameters:
* tsec : animation clock time in seconds
*/
void renderGeometryShadow_GLSL(Geometry* geometry,
FramebufferObject* shadowFbo,
const LightingState& ls,
int lightIndex,
double tsec,
Renderer* renderer,
Matrix4f *lightMatrix);
Eigen::Matrix4f *lightMatrix)
{
auto *prog = renderer->getShaderManager().getShader("depth");
if (prog == nullptr)
return;
GLint oldFboId;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFboId);
shadowFbo->bind();
glViewport(0, 0, shadowFbo->width(), shadowFbo->height());
// Write only to the depth buffer
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
renderer->enableDepthMask();
renderer->enableDepthTest();
glClear(GL_DEPTH_BUFFER_BIT);
// Render backfaces only in order to reduce self-shadowing artifacts
glCullFace(GL_FRONT);
Shadow_RenderContext rc(renderer);
prog->use();
// Enable poligon offset to decrease "shadow acne"
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(.001f, .001f);
Eigen::Matrix4f projMat = celmath::Ortho(-1.f, 1.f, -1.f, 1.f, -1.f, 1.f);
Eigen::Matrix4f modelViewMat = directionalLightMatrix(ls.lights[lightIndex].direction_obj);
*lightMatrix = projMat * modelViewMat;
prog->setMVPMatrices(projMat, modelViewMat);
geometry->render(rc, tsec);
glDisable(GL_POLYGON_OFFSET_FILL);
// Re-enable the color buffer
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glCullFace(GL_BACK);
shadowFbo->unbind(oldFboId);
}
} // end unnamed namespace
static
Matrix4f directionalLightMatrix(const Vector3f& lightDirection);
// Render a planet sphere with GLSL shaders
void renderEllipsoid_GLSL(const RenderInfo& ri,
const LightingState& ls,
Atmosphere* atmosphere,
float cloudTexOffset,
const Vector3f& semiAxes,
unsigned int textureRes,
uint64_t renderFlags,
const Quaternionf& planetOrientation,
const Frustum& frustum,
const Matrices &m,
Renderer* renderer)
const LightingState& ls,
Atmosphere* atmosphere,
float cloudTexOffset,
const Eigen::Vector3f& semiAxes,
unsigned int textureRes,
std::uint64_t renderFlags,
const Eigen::Quaternionf& planetOrientation,
const celmath::Frustum& frustum,
const Matrices &m,
Renderer* renderer)
{
float radius = semiAxes.maxCoeff();
@ -71,7 +129,7 @@ void renderEllipsoid_GLSL(const RenderInfo& ri,
unsigned int nTextures = 0;
ShaderProperties shadprop;
shadprop.nLights = min(ls.nLights, MaxShaderLights);
shadprop.nLights = std::min(ls.nLights, MaxShaderLights);
// Set up the textures used by this object
if (ri.baseTex != nullptr)
@ -189,7 +247,8 @@ void renderEllipsoid_GLSL(const RenderInfo& ri,
{
if (ls.shadows[li] && !ls.shadows[li]->empty())
{
unsigned int nShadows = (unsigned int) min((size_t) MaxShaderEclipseShadows, ls.shadows[li]->size());
unsigned int nShadows = static_cast<unsigned int>(std::min(static_cast<std::size_t>(MaxShaderEclipseShadows),
ls.shadows[li]->size()));
shadprop.setEclipseShadowCountForLight(li, nShadows);
totalShadows += nShadows;
}
@ -262,7 +321,7 @@ void renderEllipsoid_GLSL(const RenderInfo& ri,
float ringWidth = ls.shadowingRingSystem->outerRadius - ls.shadowingRingSystem->innerRadius;
prog->ringRadius = ls.shadowingRingSystem->innerRadius / radius;
prog->ringWidth = radius / ringWidth;
prog->ringPlane = Hyperplane<float, 3>(ls.ringPlaneNormal, ls.ringCenter / radius).coeffs();
prog->ringPlane = Eigen::Hyperplane<float, 3>(ls.ringPlaneNormal, ls.ringCenter / radius).coeffs();
prog->ringCenter = ls.ringCenter / radius;
for (unsigned int lightIndex = 0; lightIndex < ls.nLights; ++lightIndex)
{
@ -311,14 +370,14 @@ void renderGeometry_GLSL(Geometry* geometry,
const LightingState& ls,
const Atmosphere* atmosphere,
float geometryScale,
uint64_t renderFlags,
const Quaternionf& planetOrientation,
std::uint64_t renderFlags,
const Eigen::Quaternionf& planetOrientation,
double tsec,
const Matrices &m,
Renderer* renderer)
{
auto *shadowBuffer = renderer->getShadowFBO(0);
Matrix4f lightMatrix(Matrix4f::Identity());
Eigen::Matrix4f lightMatrix(Eigen::Matrix4f::Identity());
if (shadowBuffer != nullptr && shadowBuffer->isValid())
{
@ -407,12 +466,12 @@ void renderGeometry_GLSL(Geometry* geometry,
// override all materials specified in the geometry file.
if (texOverride != InvalidResource)
{
Material m;
m.diffuse = Material::Color(ri.color);
m.specular = Material::Color(ri.specularColor);
cmod::Material m;
m.diffuse = cmod::Color(ri.color);
m.specular = cmod::Color(ri.specularColor);
m.specularPower = ri.specularPower;
m.maps[Material::DiffuseMap] = texOverride;
m.setMap(cmod::TextureSemantic::DiffuseMap, texOverride);
rc.setMaterial(&m);
rc.lock();
geometry->render(rc, tsec);
@ -432,8 +491,8 @@ void renderGeometry_GLSL_Unlit(Geometry* geometry,
const RenderInfo& ri,
ResourceHandle texOverride,
float geometryScale,
uint64_t /* renderFlags */,
const Quaternionf& /* planetOrientation */,
std::uint64_t /* renderFlags */,
const Eigen::Quaternionf& /* planetOrientation */,
double tsec,
const Matrices &m,
Renderer* renderer)
@ -448,12 +507,12 @@ void renderGeometry_GLSL_Unlit(Geometry* geometry,
// override all materials specified in the model file.
if (texOverride != InvalidResource)
{
Material m;
m.diffuse = Material::Color(ri.color);
m.specular = Material::Color(ri.specularColor);
cmod::Material m;
m.diffuse = cmod::Color(ri.color);
m.specular = cmod::Color(ri.specularColor);
m.specularPower = ri.specularPower;
m.maps[Material::DiffuseMap] = texOverride;
m.setMap(cmod::TextureSemantic::DiffuseMap, texOverride);
rc.setMaterial(&m);
rc.lock();
geometry->render(rc, tsec);
@ -472,11 +531,11 @@ void renderClouds_GLSL(const RenderInfo& ri,
Texture* cloudTex,
Texture* cloudNormalMap,
float texOffset,
const Vector3f& semiAxes,
const Eigen::Vector3f& semiAxes,
unsigned int /*textureRes*/,
uint64_t renderFlags,
const Quaternionf& planetOrientation,
const Frustum& frustum,
std::uint64_t renderFlags,
const Eigen::Quaternionf& planetOrientation,
const celmath::Frustum& frustum,
const Matrices &m,
Renderer* renderer)
{
@ -546,7 +605,8 @@ void renderClouds_GLSL(const RenderInfo& ri,
{
if (ls.shadows[li] && !ls.shadows[li]->empty())
{
unsigned int nShadows = (unsigned int) min((size_t) MaxShaderEclipseShadows, ls.shadows[li]->size());
unsigned int nShadows = static_cast<unsigned int>(std::min(static_cast<std::size_t>(MaxShaderEclipseShadows),
ls.shadows[li]->size()));
shadprop.setEclipseShadowCountForLight(li, nShadows);
totalShadows += nShadows;
}
@ -604,8 +664,8 @@ renderAtmosphere_GLSL(const RenderInfo& ri,
const LightingState& ls,
Atmosphere* atmosphere,
float radius,
const Quaternionf& /*planetOrientation*/,
const Frustum& frustum,
const Eigen::Quaternionf& /*planetOrientation*/,
const celmath::Frustum& frustum,
const Matrices &m,
Renderer* renderer)
{
@ -629,9 +689,9 @@ renderAtmosphere_GLSL(const RenderInfo& ri,
prog->use();
prog->setLightParameters(ls, ri.color, ri.specularColor, Color::Black);
prog->ambientColor = Vector3f::Zero();
prog->ambientColor = Eigen::Vector3f::Zero();
float atmosphereRadius = radius + -atmosphere->mieScaleHeight * log(AtmosphereExtinctionThreshold);
float atmosphereRadius = radius + -atmosphere->mieScaleHeight * std::log(AtmosphereExtinctionThreshold);
float atmScale = atmosphereRadius / radius;
prog->eyePosition = ls.eyePos_obj / atmScale;
@ -671,19 +731,19 @@ static void renderRingSystem(GLuint *vboId,
GLshort tex[2];
};
constexpr const float angle = 2*static_cast<float>(PI);
constexpr const float angle = 2.0f * static_cast<float>(PI);
if (*vboId == 0)
{
struct RingVertex vertex;
vector<struct RingVertex> ringCoord;
std::vector<struct RingVertex> ringCoord;
ringCoord.reserve(2 * nSections);
for (unsigned i = 0; i <= nSections; i++)
{
float t = (float) i / (float) nSections;
float t = static_cast<float>(i) / static_cast<float>(nSections);
float theta = t * angle;
float s = (float) sin(theta);
float c = (float) cos(theta);
float s = std::sin(theta);
float c = std::cos(theta);
// inner point
vertex.pos[0] = c * innerRadius;
@ -717,7 +777,7 @@ static void renderRingSystem(GLuint *vboId,
glVertexAttribPointer(CelestiaGLProgram::TextureCoord0AttributeIndex,
2, GL_SHORT, GL_FALSE,
sizeof(struct RingVertex),
(GLvoid*) offsetof(struct RingVertex, tex));
reinterpret_cast<GLvoid*>(offsetof(struct RingVertex, tex)));
glEnableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex,
@ -768,7 +828,7 @@ void renderRings_GLSL(RingSystem& rings,
// Set up the shader properties for ring rendering
{
shadprop.lightModel = ShaderProperties::RingIllumModel;
shadprop.nLights = min(ls.nLights, MaxShaderLights);
shadprop.nLights = std::min(ls.nLights, MaxShaderLights);
if (renderShadow)
{
@ -804,8 +864,8 @@ void renderRings_GLSL(RingSystem& rings,
// planet would ever orbit underneath its sun (an orbital
// inclination of 90 degrees), but this should be made
// more robust anyway.
Vector3f axis = Vector3f::UnitY().cross(light.direction_obj);
float cosAngle = Vector3f::UnitY().dot(light.direction_obj);
Eigen::Vector3f axis = Eigen::Vector3f::UnitY().cross(light.direction_obj);
float cosAngle = Eigen::Vector3f::UnitY().dot(light.direction_obj);
axis.normalize();
float tScale = 1.0f;
@ -821,20 +881,20 @@ void renderRings_GLSL(RingSystem& rings,
// Calculate the radius of the ellipse at the incident angle of the
// light on the ring plane + 90 degrees.
float r = a * (float) sqrt((1.0f - ecc2) /
(1.0f - ecc2 * square(cosAngle)));
float r = a * std::sqrt((1.0f - ecc2) /
(1.0f - ecc2 * celmath::square(cosAngle)));
tScale *= a / r;
}
// The s axis is perpendicular to the shadow axis in the plane of the
// of the rings, and the t axis completes the orthonormal basis.
Vector3f sAxis = axis * 0.5f;
Vector3f tAxis = (axis.cross(light.direction_obj)) * 0.5f * tScale;
Vector4f texGenS;
Eigen::Vector3f sAxis = axis * 0.5f;
Eigen::Vector3f tAxis = (axis.cross(light.direction_obj)) * 0.5f * tScale;
Eigen::Vector4f texGenS;
texGenS.head(3) = sAxis;
texGenS[3] = 0.5f;
Vector4f texGenT;
Eigen::Vector4f texGenT;
texGenT.head(3) = tAxis;
texGenT[3] = 0.5f;
@ -862,11 +922,11 @@ void renderRings_GLSL(RingSystem& rings,
ringsTex->bind();
if (rings.renderData == nullptr)
rings.renderData = shared_ptr<GLRingRenderData>(new GLRingRenderData);
rings.renderData = std::make_shared<GLRingRenderData>();
auto data = reinterpret_cast<GLRingRenderData*>(rings.renderData.get());
unsigned nSections = 180;
size_t i = 0;
std::size_t i = 0;
for (i = 0; i < data->vboId.size() - 1; i++)
{
float s = segmentSizeInPixels * tan(PI / nSections);
@ -878,71 +938,3 @@ void renderRings_GLSL(RingSystem& rings,
renderer->setBlendingFactors(GL_SRC_ALPHA, GL_ONE);
}
// Calculate the matrix used to render the model from the
// perspective of the light.
static
Matrix4f directionalLightMatrix(const Vector3f& lightDirection)
{
const Vector3f &viewDir = lightDirection;
Vector3f upDir = viewDir.unitOrthogonal();
Vector3f rightDir = upDir.cross(viewDir);
Matrix4f m = Matrix4f::Identity();
m.row(0).head(3) = rightDir;
m.row(1).head(3) = upDir;
m.row(2).head(3) = viewDir;
return m;
}
/*! Render a mesh object
* Parameters:
* tsec : animation clock time in seconds
*/
static
void renderGeometryShadow_GLSL(Geometry* geometry,
FramebufferObject* shadowFbo,
const LightingState& ls,
int lightIndex,
double tsec,
Renderer* renderer,
Eigen::Matrix4f *lightMatrix)
{
auto *prog = renderer->getShaderManager().getShader("depth");
if (prog == nullptr)
return;
GLint oldFboId;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFboId);
shadowFbo->bind();
glViewport(0, 0, shadowFbo->width(), shadowFbo->height());
// Write only to the depth buffer
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
renderer->enableDepthMask();
renderer->enableDepthTest();
glClear(GL_DEPTH_BUFFER_BIT);
// Render backfaces only in order to reduce self-shadowing artifacts
glCullFace(GL_FRONT);
Shadow_RenderContext rc(renderer);
prog->use();
// Enable poligon offset to decrease "shadow acne"
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(.001f, .001f);
Matrix4f projMat = Ortho(-1.f, 1.f, -1.f, 1.f, -1.f, 1.f);
Matrix4f modelViewMat = directionalLightMatrix(ls.lights[lightIndex].direction_obj);
*lightMatrix = projMat * modelViewMat;
prog->setMVPMatrices(projMat, modelViewMat);
geometry->render(rc, tsec);
glDisable(GL_POLYGON_OFFSET_FILL);
// Re-enable the color buffer
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glCullFace(GL_BACK);
shadowFbo->unbind(oldFboId);
}

View File

@ -10,25 +10,41 @@
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#ifndef _CELENGINE_RENDERGLSL_H_
#define _CELENGINE_RENDERGLSL_H_
#pragma once
#include <celengine/lightenv.h>
#include <cstdint>
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <celutil/reshandle.h>
class Atmosphere;
class Geometry;
class LightingState;
struct Matrices;
class Renderer;
struct RenderInfo;
class RingSystem;
class Texture;
namespace celmath
{
class Frustum;
}
void renderEllipsoid_GLSL(const RenderInfo& ri,
const LightingState& ls,
Atmosphere* atmosphere,
float cloudTexOffset,
const Eigen::Vector3f& semiAxes,
unsigned int textureRes,
uint64_t renderFlags,
const Eigen::Quaternionf& planetOrientation,
const celmath::Frustum& frustum,
const Matrices &m,
Renderer* renderer);
const LightingState& ls,
Atmosphere* atmosphere,
float cloudTexOffset,
const Eigen::Vector3f& semiAxes,
unsigned int textureRes,
std::uint64_t renderFlags,
const Eigen::Quaternionf& planetOrientation,
const celmath::Frustum& frustum,
const Matrices &m,
Renderer* renderer);
void renderGeometry_GLSL(Geometry* geometry,
const RenderInfo& ri,
@ -36,7 +52,7 @@ void renderGeometry_GLSL(Geometry* geometry,
const LightingState& ls,
const Atmosphere* atmosphere,
float geometryScale,
uint64_t renderFlags,
std::uint64_t renderFlags,
const Eigen::Quaternionf& planetOrientation,
double tsec,
const Matrices &m,
@ -50,7 +66,7 @@ void renderClouds_GLSL(const RenderInfo& ri,
float texOffset,
const Eigen::Vector3f& semiAxes,
unsigned int textureRes,
uint64_t renderFlags,
std::uint64_t renderFlags,
const Eigen::Quaternionf& planetOrientation,
const celmath::Frustum& frustum,
const Matrices &m,
@ -80,10 +96,8 @@ void renderGeometry_GLSL_Unlit(Geometry* geometry,
const RenderInfo& ri,
ResourceHandle texOverride,
float geometryScale,
uint64_t renderFlags,
std::uint64_t renderFlags,
const Eigen::Quaternionf& planetOrientation,
double tsec,
const Matrices &m,
Renderer* renderer);
#endif // _CELENGINE_RENDERGLSL_H_

View File

@ -7,6 +7,18 @@
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#pragma once
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <celutil/color.h>
class LODSphereMesh;
class Texture;
struct RenderInfo
{
EIGEN_MAKE_ALIGNED_OPERATOR_NEW

View File

@ -12,12 +12,11 @@
// It's sole function now is to handle the now-deprecated .cms mesh files;
// it will eventually be removed from Celestia.
#include "spheremesh.h"
#include <celmath/mathlib.h>
#include "glsupport.h"
#include <cmath>
#include <cstdint>
using namespace Eigen;
#include <celmodel/mesh.h>
#include "spheremesh.h"
SphereMesh::SphereMesh(float radius, int _nRings, int _nSlices)
@ -25,13 +24,13 @@ SphereMesh::SphereMesh(float radius, int _nRings, int _nSlices)
createSphere(radius, _nRings, _nSlices);
}
SphereMesh::SphereMesh(const Vector3f& size, int _nRings, int _nSlices)
SphereMesh::SphereMesh(const Eigen::Vector3f& size, int _nRings, int _nSlices)
{
createSphere(1.0f, _nRings, _nSlices);
scale(size);
}
SphereMesh::SphereMesh(const Vector3f& size,
SphereMesh::SphereMesh(const Eigen::Vector3f& size,
const DisplacementMap& dispmap,
float height)
{
@ -42,7 +41,7 @@ SphereMesh::SphereMesh(const Vector3f& size,
fixNormals();
}
SphereMesh::SphereMesh(const Vector3f& size,
SphereMesh::SphereMesh(const Eigen::Vector3f& size,
int _nRings, int _nSlices,
DisplacementMapFunc func,
void* info)
@ -79,27 +78,27 @@ void SphereMesh::createSphere(float radius, int _nRings, int _nSlices)
int i;
for (i = 0; i < nRings; i++)
{
float phi = ((float) i / (float) (nRings - 1) - 0.5f) * (float) PI;
float phi = (static_cast<float>(i) / static_cast<float>(nRings - 1) - 0.5f) * static_cast<float>(PI);
for (int j = 0; j <= nSlices; j++)
{
float theta = (float) j / (float) nSlices * (float) PI * 2;
float theta = static_cast<float>(j) / static_cast<float>(nSlices) * static_cast<float>(PI * 2.0);
int n = i * (nSlices + 1) + j;
auto x = (float) (std::cos(phi) * std::cos(theta));
auto y = (float) std::sin(phi);
auto z = (float) (std::cos(phi) * std::sin(theta));
auto x = std::cos(phi) * std::cos(theta);
auto y = std::sin(phi);
auto z = std::cos(phi) * std::sin(theta);
vertices[n * 3] = x * radius;
vertices[n * 3 + 1] = y * radius;
vertices[n * 3 + 2] = z * radius;
normals[n * 3] = x;
normals[n * 3 + 1] = y;
normals[n * 3 + 2] = z;
texCoords[n * 2] = 1.0f - (float) j / (float) nSlices;
texCoords[n * 2 + 1] = 1.0f - (float) i / (float) (nRings - 1);
texCoords[n * 2] = 1.0f - static_cast<float>(j) / static_cast<float>(nSlices);
texCoords[n * 2 + 1] = 1.0f - static_cast<float>(i) / static_cast<float>(nRings - 1);
// Compute the tangent--required for bump mapping
auto tx = (float) (std::sin(phi) * std::sin(theta));
auto ty = (float) -std::cos(phi);
auto tz = (float) (std::sin(phi) * std::cos(theta));
auto tx = std::sin(phi) * std::sin(theta);
auto ty = -std::cos(phi);
auto tz = std::sin(phi) * std::cos(theta);
tangents[n * 3] = tx;
tangents[n * 3 + 1] = ty;
tangents[n * 3 + 2] = tz;
@ -122,7 +121,7 @@ void SphereMesh::createSphere(float radius, int _nRings, int _nSlices)
void SphereMesh::generateNormals()
{
int nQuads = nSlices * (nRings - 1);
Vector3f* faceNormals = new Vector3f[nQuads];
Eigen::Vector3f* faceNormals = new Eigen::Vector3f[nQuads];
int i;
// Compute face normals for the mesh
@ -138,20 +137,20 @@ void SphereMesh::generateNormals()
// Compute the face normal. Watch out for degenerate (zero-length)
// edges. If there are two degenerate edges, the entire face must
// be degenerate and we'll handle that later
Vector3f v0(p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]);
Vector3f v1(p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]);
Eigen::Vector3f v0 = Eigen::Map<Eigen::Vector3f>(p1) - Eigen::Map<Eigen::Vector3f>(p0);
Eigen::Vector3f v1 = Eigen::Map<Eigen::Vector3f>(p2) - Eigen::Map<Eigen::Vector3f>(p1);
if (v0.norm() < 1e-6f)
{
v0 = Vector3f(p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]);
v1 = Vector3f(p3[0] - p2[0], p3[1] - p2[1], p3[2] - p2[2]);
v0 = Eigen::Map<Eigen::Vector3f>(p2) - Eigen::Map<Eigen::Vector3f>(p1);
v1 = Eigen::Map<Eigen::Vector3f>(p3) - Eigen::Map<Eigen::Vector3f>(p2);
}
else if (v1.norm() < 1e-6f)
{
v0 = Vector3f(p3[0] - p2[0], p3[1] - p2[1], p3[2] - p2[2]);
v1 = Vector3f(p0[0] - p3[0], p0[1] - p3[1], p0[2] - p3[2]);
v0 = Eigen::Map<Eigen::Vector3f>(p3) - Eigen::Map<Eigen::Vector3f>(p2);
v1 = Eigen::Map<Eigen::Vector3f>(p0) - Eigen::Map<Eigen::Vector3f>(p3);
}
Vector3f faceNormal = v0.cross(v1);
Eigen::Vector3f faceNormal = v0.cross(v1);
float length = faceNormal.norm();
if (length != 0)
faceNormal *= (1 / length);
@ -224,11 +223,11 @@ void SphereMesh::generateNormals()
{
if (faceCounts[i] > 0)
{
float s = 1.0f / (float) faceCounts[i];
float s = 1.0f / static_cast<float>(faceCounts[i]);
float nx = normals[i * 3] * s;
float ny = normals[i * 3 + 1] * s;
float nz = normals[i * 3 + 2] * s;
auto length = (float) std::sqrt(nx * nx + ny * ny + nz * nz);
auto length = std::sqrt(nx * nx + ny * ny + nz * nz);
if (length > 0)
{
length = 1 / length;
@ -251,9 +250,9 @@ void SphereMesh::fixNormals()
{
float* v0 = normals + (i * (nSlices + 1)) * 3;
float* v1 = normals + ((i + 1) * (nSlices + 1) - 1) * 3;
Vector3f n0(v0[0], v0[1], v0[2]);
Vector3f n1(v0[0], v0[1], v0[2]);
Vector3f normal = n0 + n1;
Eigen::Map<Eigen::Vector3f> n0(v0);
Eigen::Map<Eigen::Vector3f> n1(v1);
Eigen::Vector3f normal = n0 + n1;
normal.normalize();
v0[0] = normal.x();
v0[1] = normal.y();
@ -265,7 +264,7 @@ void SphereMesh::fixNormals()
}
void SphereMesh::scale(const Vector3f& s)
void SphereMesh::scale(const Eigen::Vector3f& s)
{
int i;
for (i = 0; i < nVertices; i++)
@ -280,11 +279,11 @@ void SphereMesh::scale(const Vector3f& s)
{
// TODO: Make a fast special case for uniform scale factors, where
// renormalization is not required.
Vector3f is = s.cwiseInverse();
Eigen::Vector3f is = s.cwiseInverse();
for (i = 0; i < nVertices; i++)
{
int n = i * 3;
Vector3f normal(normals[n] * is.x(), normals[n + 1] * is.y(), normals[n + 2] * is.z());
Eigen::Vector3f normal = Eigen::Map<Eigen::Vector3f>(normals).cwiseProduct(is);
normal.normalize();
normals[n] = normal.x();
normals[n + 1] = normal.y();
@ -297,24 +296,16 @@ void SphereMesh::scale(const Vector3f& s)
void SphereMesh::displace(const DisplacementMap& dispmap,
float height)
{
// assert(dispMap.getWidth() == nSlices);
// assert(dispMap.getHeight() == nRings);
for (int i = 0; i < nRings; i++)
{
for (int j = 0; j <= nSlices; j++)
{
int n = (i * (nSlices + 1) + j) * 3;
/*
float theta = (float) j / (float) nSlices * (float) PI * 2;
float x = (float) (cos(phi) * cos(theta));
float y = (float) sin(phi);
float z = (float) (cos(phi) * sin(theta));
*/
Vector3f normal(normals[n], normals[n + 1], normals[n + 2]);
Eigen::Map<Eigen::Vector3f> normal(normals);
int k = (j == nSlices) ? 0 : j;
Vector3f v = normal * dispmap.getDisplacement(k, i) * height;
Eigen::Vector3f v = normal * dispmap.getDisplacement(k, i) * height;
vertices[n] += v.x();
vertices[n + 1] += v.y();
vertices[n + 2] += v.z();
@ -332,8 +323,8 @@ void SphereMesh::displace(DisplacementMapFunc func, void* info)
{
float u = (float) j / (float) nSlices;
int n = (i * (nSlices + 1) + j) * 3;
Vector3f normal(normals[n], normals[n + 1], normals[n + 2]);
Vector3f vert = normal * func(u, v, info);
Eigen::Map<Eigen::Vector3f> normal(normals);
Eigen::Vector3f vert = normal * func(u, v, info);
vertices[n] += vert.x();
vertices[n + 1] += vert.y();
vertices[n + 2] += vert.z();
@ -344,15 +335,21 @@ void SphereMesh::displace(DisplacementMapFunc func, void* info)
cmod::Mesh* SphereMesh::convertToMesh() const
{
uint32_t stride = 32;
cmod::Mesh::VertexAttribute attributes[3];
attributes[0] = cmod::Mesh::VertexAttribute(cmod::Mesh::Position, cmod::Mesh::Float3, 0);
attributes[1] = cmod::Mesh::VertexAttribute(cmod::Mesh::Normal, cmod::Mesh::Float3, 12);
attributes[2] = cmod::Mesh::VertexAttribute(cmod::Mesh::Texture0, cmod::Mesh::Float2, 24);
std::uint32_t stride = 32;
cmod::VertexAttribute attributes[3];
attributes[0] = cmod::VertexAttribute(cmod::VertexAttributeSemantic::Position,
cmod::VertexAttributeFormat::Float3,
0);
attributes[1] = cmod::VertexAttribute(cmod::VertexAttributeSemantic::Normal,
cmod::VertexAttributeFormat::Float3,
12);
attributes[2] = cmod::VertexAttribute(cmod::VertexAttributeSemantic::Texture0,
cmod::VertexAttributeFormat::Float2,
24);
cmod::Mesh* mesh = new cmod::Mesh();
mesh->setVertexDescription(cmod::Mesh::VertexDescription(stride, 3, attributes));
mesh->setVertexDescription(cmod::VertexDescription(stride, 3, attributes));
// Copy the vertex data from the separate position, normal, and texture coordinate
// arrays into a single array.
@ -375,14 +372,14 @@ cmod::Mesh* SphereMesh::convertToMesh() const
for (int i = 0; i < nRings - 1; i++)
{
auto* indexData = new uint32_t[(nSlices + 1) * 2];
auto* indexData = new std::uint32_t[(nSlices + 1) * 2];
for (int j = 0; j <= nSlices; j++)
{
indexData[j * 2 + 0] = i * (nSlices + 1) + j;
indexData[j * 2 + 1] = (i + 1) * (nSlices + 1) + j;
}
mesh->addGroup(cmod::Mesh::TriStrip, ~0u, (nSlices + 1) * 2, indexData);
mesh->addGroup(cmod::PrimitiveGroupType::TriStrip, ~0u, (nSlices + 1) * 2, indexData);
}
return mesh;

View File

@ -8,16 +8,20 @@
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#ifndef _CELENGINE_SPHEREMESH_H_
#define _CELENGINE_SPHEREMESH_H_
#pragma once
// IMPORTANT: This file is a relic from the early days of Celestia.
// Its sole function now is to handle the now-deprecated .cms mesh files;
// it will eventually be removed from Celestia.
#include <celengine/dispmap.h>
#include <celmodel/mesh.h>
#include <Eigen/Core>
#include <celengine/dispmap.h>
namespace cmod
{
class Mesh;
}
/*! The SphereMesh class is used to generate displacement mapped
* spheres when loading the now-deprecated .cms geometry files.
@ -59,5 +63,3 @@ public:
int nIndices;
unsigned short* indices{ nullptr };
};
#endif // _CELENGINE_SPHEREMESH_H_

View File

@ -14,6 +14,7 @@
namespace cmod
{
Material::Material()
{
maps.fill(InvalidResource);
@ -21,7 +22,7 @@ Material::Material()
bool
operator<(const Material::Color& c0, const Material::Color& c1)
operator<(const Color& c0, const Color& c1)
{
return std::tie(c0.m_red, c0.m_green, c0.m_blue)
< std::tie(c1.m_red, c1.m_green, c1.m_blue);

View File

@ -10,114 +10,131 @@
#pragma once
#include <Eigen/Core>
#include <string>
#include <array>
#include <cstdint>
#include <cstddef>
#include <Eigen/Core>
#include <celutil/color.h>
#include <celutil/reshandle.h>
#include <celcompat/filesystem.h>
namespace cmod
{
class Color
{
public:
constexpr Color() :
m_red(0.0f),
m_green(0.0f),
m_blue(0.0f)
{
}
constexpr Color(float r, float g, float b) :
m_red(r),
m_green(g),
m_blue(b)
{
}
Color(const ::Color& color) :
m_red(color.red()),
m_green(color.green()),
m_blue(color.blue())
{
}
constexpr float red() const
{
return m_red;
}
constexpr float green() const
{
return m_green;
}
constexpr float blue() const
{
return m_blue;
}
Eigen::Vector3f toVector3() const
{
return Eigen::Vector3f(m_red, m_green, m_blue);
}
constexpr bool operator==(const Color& other) const
{
return m_red == other.m_red && m_green == other.m_green && m_blue == other.m_blue;
}
constexpr bool operator!=(const Color& other) const
{
return !(*this == other);
}
friend bool operator<(const Color& c0, const Color& c1);
private:
float m_red;
float m_green;
float m_blue;
};
enum class BlendMode : std::int16_t
{
NormalBlend = 0,
AdditiveBlend = 1,
PremultipliedAlphaBlend = 2,
BlendMax = 3,
InvalidBlend = -1,
};
enum class TextureSemantic : std::int16_t
{
DiffuseMap = 0,
NormalMap = 1,
SpecularMap = 2,
EmissiveMap = 3,
TextureSemanticMax = 4,
InvalidTextureSemantic = -1,
};
class Material
{
public:
Material();
~Material() = default;
class Color
inline ResourceHandle getMap(TextureSemantic semantic) const
{
public:
constexpr Color() :
m_red(0.0f),
m_green(0.0f),
m_blue(0.0f)
{
}
return maps[static_cast<std::size_t>(semantic)];
}
constexpr Color(float r, float g, float b) :
m_red(r),
m_green(g),
m_blue(b)
{
}
Color(const ::Color& color) :
m_red(color.red()),
m_green(color.green()),
m_blue(color.blue())
{
}
constexpr float red() const
{
return m_red;
}
constexpr float green() const
{
return m_green;
}
constexpr float blue() const
{
return m_blue;
}
Eigen::Vector3f toVector3() const
{
return Eigen::Vector3f(m_red, m_green, m_blue);
}
constexpr bool operator==(const Color& other) const
{
return m_red == other.m_red && m_green == other.m_green && m_blue == other.m_blue;
}
constexpr bool operator!=(const Color& other) const
{
return !(*this == other);
}
friend bool operator<(const Color& c0, const Color& c1);
private:
float m_red;
float m_green;
float m_blue;
};
enum BlendMode
inline void setMap(TextureSemantic semantic, ResourceHandle handle)
{
NormalBlend = 0,
AdditiveBlend = 1,
PremultipliedAlphaBlend = 2,
BlendMax = 3,
InvalidBlend = -1,
};
enum TextureSemantic
{
DiffuseMap = 0,
NormalMap = 1,
SpecularMap = 2,
EmissiveMap = 3,
TextureSemanticMax = 4,
InvalidTextureSemantic = -1,
};
maps[static_cast<std::size_t>(semantic)] = handle;
}
Color diffuse{ 0.0f, 0.0f, 0.0f };
Color emissive{ 0.0f, 0.0f, 0.0f };
Color specular{ 0.0f, 0.0f, 0.0f };
float specularPower{ 1.0f };
float opacity{ 1.0f };
BlendMode blend{ NormalBlend };
std::array<ResourceHandle, TextureSemanticMax> maps;
BlendMode blend{ BlendMode::NormalBlend };
std::array<ResourceHandle, static_cast<std::size_t>(TextureSemantic::TextureSemanticMax)> maps;
};
bool operator<(const Material::Color& c0, const Material::Color& c1);
bool operator<(const Color& c0, const Color& c1);
// Define an ordering for materials; required for elimination of duplicate
// materials.

View File

@ -8,34 +8,22 @@
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#include <array>
#include <cstring>
#include "mesh.h"
#include <cassert>
#include <iostream>
#include <algorithm>
#include <Eigen/Core>
#include <Eigen/Geometry>
using namespace cmod;
using namespace Eigen;
using namespace std;
static size_t VertexAttributeFormatSizes[Mesh::FormatMax] =
namespace cmod
{
4, // Float1
8, // Float2
12, // Float3
16, // Float4,
4, // UByte4
};
Mesh::VertexDescription::VertexDescription(unsigned int _stride,
unsigned int _nAttributes,
VertexAttribute* _attributes) :
stride(_stride),
nAttributes(_nAttributes),
attributes(nullptr)
VertexDescription::VertexDescription(unsigned int _stride,
unsigned int _nAttributes,
VertexAttribute* _attributes) :
stride(_stride),
nAttributes(_nAttributes),
attributes(nullptr)
{
if (nAttributes != 0)
{
@ -47,7 +35,7 @@ Mesh::VertexDescription::VertexDescription(unsigned int _stride,
}
Mesh::VertexDescription::VertexDescription(const VertexDescription& desc) :
VertexDescription::VertexDescription(const VertexDescription& desc) :
stride(desc.stride),
nAttributes(desc.nAttributes),
attributes(nullptr)
@ -62,8 +50,8 @@ Mesh::VertexDescription::VertexDescription(const VertexDescription& desc) :
}
Mesh::VertexDescription&
Mesh::VertexDescription::operator=(const Mesh::VertexDescription& desc)
VertexDescription&
VertexDescription::operator=(const VertexDescription& desc)
{
if (this == &desc)
return *this;
@ -88,18 +76,14 @@ Mesh::VertexDescription::operator=(const Mesh::VertexDescription& desc)
// TODO: This should be called in the constructor; we should start using
// exceptions in Celestia.
bool
Mesh::VertexDescription::validate() const
VertexDescription::validate() const
{
for (unsigned int i = 0; i < nAttributes; i++)
{
VertexAttribute& attr = attributes[i];
// Validate the attribute
if (attr.semantic >= SemanticMax || attr.format >= FormatMax)
return false;
if (attr.offset % 4 != 0)
return false;
if (attr.offset + VertexAttributeFormatSizes[attr.format] > stride)
if (attr.offset % 4 != 0 || attr.offset + VertexAttribute::getFormatSize(attr.format) > stride)
return false;
// TODO: check for repetition of attributes
// if (vertexAttributeMap[attr->semantic].format != InvalidFormat)
@ -109,69 +93,62 @@ Mesh::VertexDescription::validate() const
return true;
}
Mesh::VertexDescription Mesh::VertexDescription::appendingAttributes(const VertexAttribute* newAttributes, int count) const
VertexDescription VertexDescription::appendingAttributes(const VertexAttribute* newAttributes, int count) const
{
unsigned int totalAttributeCount = nAttributes + count;
VertexAttribute* allAttributes = new VertexAttribute[totalAttributeCount];
memcpy(allAttributes, attributes, sizeof(VertexAttribute) * nAttributes);
std::memcpy(allAttributes, attributes, sizeof(VertexAttribute) * nAttributes);
unsigned int newStride = stride;
for (int i = 0; i < count; ++i)
{
VertexAttribute attribute = newAttributes[i];
allAttributes[nAttributes + i] = attribute;
newStride += Mesh::getVertexAttributeSize(attribute.format);
newStride += VertexAttribute::getFormatSize(attribute.format);
}
memcpy(allAttributes + nAttributes, newAttributes, sizeof(VertexAttribute) * count);
std::memcpy(allAttributes + nAttributes, newAttributes, sizeof(VertexAttribute) * count);
VertexDescription desc = VertexDescription(newStride, totalAttributeCount, allAttributes);
delete[] allAttributes;
return desc;
}
Mesh::VertexDescription::~VertexDescription()
VertexDescription::~VertexDescription()
{
delete[] attributes;
}
void
Mesh::VertexDescription::buildSemanticMap()
VertexDescription::buildSemanticMap()
{
for (unsigned int i = 0; i < nAttributes; i++)
semanticMap[attributes[i].semantic] = attributes[i];
semanticMap[static_cast<std::size_t>(attributes[i].semantic)] = attributes[i];
}
void
Mesh::VertexDescription::clearSemanticMap()
VertexDescription::clearSemanticMap()
{
for (auto& i : semanticMap)
i = VertexAttribute();
}
//Mesh::PrimitiveGroup::~PrimitiveGroup()
//{
// TODO: probably should free index list; need to sort out
// ownership issues.
//}
unsigned int
Mesh::PrimitiveGroup::getPrimitiveCount() const
PrimitiveGroup::getPrimitiveCount() const
{
switch (prim)
{
case TriList:
case PrimitiveGroupType::TriList:
return nIndices / 3;
case TriStrip:
case TriFan:
case PrimitiveGroupType::TriStrip:
case PrimitiveGroupType::TriFan:
return nIndices - 2;
case LineList:
case PrimitiveGroupType::LineList:
return nIndices / 2;
case LineStrip:
case PrimitiveGroupType::LineStrip:
return nIndices - 2;
case PointList:
case SpriteList:
case PrimitiveGroupType::PointList:
case PrimitiveGroupType::SpriteList:
return nIndices;
default:
// Invalid value
@ -188,7 +165,6 @@ Mesh::~Mesh()
// TODO: this is just to cast away void* and shut up GCC warnings;
// should probably be static_cast<VertexList::VertexPart*>
delete[] static_cast<char*>(vertices);
delete vbResource;
}
@ -219,13 +195,13 @@ Mesh::setVertexDescription(const VertexDescription& desc)
}
const Mesh::VertexDescription& Mesh::getVertexDescription() const
const VertexDescription& Mesh::getVertexDescription() const
{
return vertexDesc;
}
const Mesh::PrimitiveGroup*
const PrimitiveGroup*
Mesh::getGroup(unsigned int index) const
{
if (index >= groups.size())
@ -235,7 +211,7 @@ Mesh::getGroup(unsigned int index) const
}
Mesh::PrimitiveGroup*
PrimitiveGroup*
Mesh::getGroup(unsigned int index)
{
if (index >= groups.size())
@ -253,13 +229,14 @@ Mesh::addGroup(PrimitiveGroup* group)
}
Mesh::PrimitiveGroup* Mesh::createLinePrimitiveGroup(bool lineStrip, unsigned int nIndices, index32* indices)
PrimitiveGroup*
Mesh::createLinePrimitiveGroup(bool lineStrip, unsigned int nIndices, index32* indices)
{
// Transform LINE_STRIP/LINES to triangle vertices
int transformedVertCount = lineStrip ? (nIndices - 1) * 4 : nIndices * 2;
// Get information of the position attributes
auto positionAttributes = vertexDesc.getAttribute(Position);
int positionSize = getVertexAttributeSize(positionAttributes.format);
auto positionAttributes = vertexDesc.getAttribute(VertexAttributeSemantic::Position);
int positionSize = VertexAttribute::getFormatSize(positionAttributes.format);
int positionOffset = positionAttributes.offset;
int originalStride = vertexDesc.stride;
@ -289,23 +266,23 @@ Mesh::PrimitiveGroup* Mesh::createLinePrimitiveGroup(bool lineStrip, unsigned in
float *ffn = (float *)origNextVertLoc;
// Fill the info for the 4 vertices
memcpy(ptr, origThisVertLoc, originalStride);
memcpy(ptr + originalStride, origNextVertLoc + positionOffset, positionSize);
std::memcpy(ptr, origThisVertLoc, originalStride);
std::memcpy(ptr + originalStride, origNextVertLoc + positionOffset, positionSize);
*(float *)&ptr[originalStride + positionSize] = -0.5f;
ptr += stride;
memcpy(ptr, origThisVertLoc, originalStride);
memcpy(ptr + originalStride, origNextVertLoc + positionOffset, positionSize);
std::memcpy(ptr, origThisVertLoc, originalStride);
std::memcpy(ptr + originalStride, origNextVertLoc + positionOffset, positionSize);
*(float *)&ptr[originalStride + positionSize] = 0.5f;
ptr += stride;
memcpy(ptr, origNextVertLoc, originalStride);
memcpy(ptr + originalStride, origThisVertLoc + positionOffset, positionSize);
std::memcpy(ptr, origNextVertLoc, originalStride);
std::memcpy(ptr + originalStride, origThisVertLoc + positionOffset, positionSize);
*(float *)&ptr[originalStride + positionSize] = -0.5f;
ptr += stride;
memcpy(ptr, origNextVertLoc, originalStride);
memcpy(ptr + originalStride, origThisVertLoc + positionOffset, positionSize);
std::memcpy(ptr, origNextVertLoc, originalStride);
std::memcpy(ptr + originalStride, origThisVertLoc + positionOffset, positionSize);
*(float *)&ptr[originalStride + positionSize] = 0.5f;
ptr += stride;
@ -321,9 +298,9 @@ Mesh::PrimitiveGroup* Mesh::createLinePrimitiveGroup(bool lineStrip, unsigned in
newIndices[lineIndex + 5] = newIndex;
}
array<VertexAttribute, 2> newAttributes = {
VertexAttribute(NextPosition, positionAttributes.format, originalStride),
VertexAttribute(ScaleFactor, Float1, originalStride + positionSize),
std::array<VertexAttribute, 2> newAttributes = {
VertexAttribute(VertexAttributeSemantic::NextPosition, positionAttributes.format, originalStride),
VertexAttribute(VertexAttributeSemantic::ScaleFactor, VertexAttributeFormat::Float1, originalStride + positionSize),
};
auto* g = new PrimitiveGroup();
g->vertexOverride = data;
@ -343,9 +320,9 @@ Mesh::addGroup(PrimitiveGroupType prim,
index32* indices)
{
PrimitiveGroup* g;
if (prim == LineStrip || prim == LineList)
if (prim == PrimitiveGroupType::LineStrip || prim == PrimitiveGroupType::LineList)
{
g = createLinePrimitiveGroup(prim == LineStrip, nIndices, indices);
g = createLinePrimitiveGroup(prim == PrimitiveGroupType::LineStrip, nIndices, indices);
}
else
{
@ -382,7 +359,7 @@ Mesh::clearGroups()
}
const string&
const std::string&
Mesh::getName() const
{
return name;
@ -390,14 +367,14 @@ Mesh::getName() const
void
Mesh::setName(const string& _name)
Mesh::setName(const std::string& _name)
{
name = _name;
}
void
Mesh::remapIndices(const vector<index32>& indexMap)
Mesh::remapIndices(const std::vector<index32>& indexMap)
{
for (auto group : groups)
{
@ -410,57 +387,54 @@ Mesh::remapIndices(const vector<index32>& indexMap)
void
Mesh::remapMaterials(const vector<unsigned int>& materialMap)
Mesh::remapMaterials(const std::vector<unsigned int>& materialMap)
{
for (auto group : groups)
group->materialIndex = materialMap[group->materialIndex];
}
struct PrimitiveGroupComparator
{
bool operator()(const Mesh::PrimitiveGroup* g0, const Mesh::PrimitiveGroup* g1) const
{
return g0->materialIndex < g1->materialIndex;
}
};
void
Mesh::aggregateByMaterial()
{
sort(groups.begin(), groups.end(), PrimitiveGroupComparator());
std::sort(groups.begin(), groups.end(),
[](const PrimitiveGroup* g0, const PrimitiveGroup* g1)
{
return g0->materialIndex < g1->materialIndex;
});
}
bool
Mesh::pick(const Vector3d& rayOrigin, const Vector3d& rayDirection, PickResult* result) const
Mesh::pick(const Eigen::Vector3d& rayOrigin, const Eigen::Vector3d& rayDirection, PickResult* result) const
{
double maxDistance = 1.0e30;
double closest = maxDistance;
// Pick will automatically fail without vertex positions--no reasonable
// mesh should lack these.
if (vertexDesc.getAttribute(Position).semantic != Position ||
vertexDesc.getAttribute(Position).format != Float3)
if (vertexDesc.getAttribute(VertexAttributeSemantic::Position).semantic != VertexAttributeSemantic::Position ||
vertexDesc.getAttribute(VertexAttributeSemantic::Position).format != VertexAttributeFormat::Float3)
{
return false;
}
unsigned int posOffset = vertexDesc.getAttribute(Position).offset;
unsigned int posOffset = vertexDesc.getAttribute(VertexAttributeSemantic::Position).offset;
auto* vdata = reinterpret_cast<char*>(vertices);
// Iterate over all primitive groups in the mesh
for (const auto group : groups)
{
Mesh::PrimitiveGroupType primType = group->prim;
PrimitiveGroupType primType = group->prim;
index32 nIndices = group->nIndices;
// Only attempt to compute the intersection of the ray with triangle
// groups.
if ((primType == TriList || primType == TriStrip || primType == TriFan) &&
if ((primType == PrimitiveGroupType::TriList
|| primType == PrimitiveGroupType::TriStrip
|| primType == PrimitiveGroupType::TriFan) &&
(nIndices >= 3) &&
!(primType == TriList && nIndices % 3 != 0))
!(primType == PrimitiveGroupType::TriList && nIndices % 3 != 0))
{
unsigned int primitiveIndex = 0;
index32 index = 0;
@ -472,14 +446,14 @@ Mesh::pick(const Vector3d& rayOrigin, const Vector3d& rayDirection, PickResult*
do
{
// Get the triangle vertices v0, v1, and v2
Vector3d v0 = Map<Vector3f>(reinterpret_cast<float*>(vdata + i0 * vertexDesc.stride + posOffset)).cast<double>();
Vector3d v1 = Map<Vector3f>(reinterpret_cast<float*>(vdata + i1 * vertexDesc.stride + posOffset)).cast<double>();
Vector3d v2 = Map<Vector3f>(reinterpret_cast<float*>(vdata + i2 * vertexDesc.stride + posOffset)).cast<double>();
Eigen::Vector3d v0 = Eigen::Map<Eigen::Vector3f>(reinterpret_cast<float*>(vdata + i0 * vertexDesc.stride + posOffset)).cast<double>();
Eigen::Vector3d v1 = Eigen::Map<Eigen::Vector3f>(reinterpret_cast<float*>(vdata + i1 * vertexDesc.stride + posOffset)).cast<double>();
Eigen::Vector3d v2 = Eigen::Map<Eigen::Vector3f>(reinterpret_cast<float*>(vdata + i2 * vertexDesc.stride + posOffset)).cast<double>();
// Compute the edge vectors e0 and e1, and the normal n
Vector3d e0 = v1 - v0;
Vector3d e1 = v2 - v0;
Vector3d n = e0.cross(e1);
Eigen::Vector3d e0 = v1 - v0;
Eigen::Vector3d e1 = v2 - v0;
Eigen::Vector3d n = e0.cross(e1);
// c is the cosine of the angle between the ray and triangle normal
double c = n.dot(rayDirection);
@ -499,8 +473,8 @@ Mesh::pick(const Vector3d& rayOrigin, const Vector3d& rayDirection, PickResult*
double det = m00 * m11 - m01 * m10;
if (det != 0.0)
{
Vector3d p = rayOrigin + rayDirection * t;
Vector3d q = p - v0;
Eigen::Vector3d p = rayOrigin + rayDirection * t;
Eigen::Vector3d q = p - v0;
double q0 = e0.dot(q);
double q1 = e1.dot(q);
double d = 1.0 / det;
@ -521,7 +495,7 @@ Mesh::pick(const Vector3d& rayOrigin, const Vector3d& rayDirection, PickResult*
}
// Get the indices for the next triangle
if (primType == TriList)
if (primType == PrimitiveGroupType::TriList)
{
index += 3;
if (index < nIndices)
@ -531,7 +505,7 @@ Mesh::pick(const Vector3d& rayOrigin, const Vector3d& rayDirection, PickResult*
i2 = group->indices[index + 2];
}
}
else if (primType == TriStrip)
else if (primType == PrimitiveGroupType::TriStrip)
{
index += 1;
if (index < nIndices)
@ -564,7 +538,7 @@ Mesh::pick(const Vector3d& rayOrigin, const Vector3d& rayDirection, PickResult*
bool
Mesh::pick(const Vector3d& rayOrigin, const Vector3d& rayDirection, double& distance) const
Mesh::pick(const Eigen::Vector3d& rayOrigin, const Eigen::Vector3d& rayDirection, double& distance) const
{
PickResult result;
bool hit = pick(rayOrigin, rayDirection, &result);
@ -577,38 +551,38 @@ Mesh::pick(const Vector3d& rayOrigin, const Vector3d& rayDirection, double& dist
}
AlignedBox<float, 3>
Eigen::AlignedBox<float, 3>
Mesh::getBoundingBox() const
{
AlignedBox<float, 3> bbox;
Eigen::AlignedBox<float, 3> bbox;
// Return an empty box if there's no position info
if (vertexDesc.getAttribute(Position).format != Float3)
if (vertexDesc.getAttribute(VertexAttributeSemantic::Position).format != VertexAttributeFormat::Float3)
return bbox;
char* vdata = reinterpret_cast<char*>(vertices) + vertexDesc.getAttribute(Position).offset;
char* vdata = reinterpret_cast<char*>(vertices) + vertexDesc.getAttribute(VertexAttributeSemantic::Position).offset;
if (vertexDesc.getAttribute(PointSize).format == Float1)
if (vertexDesc.getAttribute(VertexAttributeSemantic::PointSize).format == VertexAttributeFormat::Float1)
{
// Handle bounding box calculation for point sprites. Unlike other
// primitives, point sprite vertices have a non-zero size.
int pointSizeOffset = (int) vertexDesc.getAttribute(PointSize).offset -
(int) vertexDesc.getAttribute(Position).offset;
int pointSizeOffset = (int) vertexDesc.getAttribute(VertexAttributeSemantic::PointSize).offset -
(int) vertexDesc.getAttribute(VertexAttributeSemantic::Position).offset;
for (unsigned int i = 0; i < nVertices; i++, vdata += vertexDesc.stride)
{
Vector3f center = Map<Vector3f>(reinterpret_cast<float*>(vdata));
Eigen::Vector3f center = Eigen::Map<Eigen::Vector3f>(reinterpret_cast<float*>(vdata));
float pointSize = (reinterpret_cast<float*>(vdata + pointSizeOffset))[0];
Vector3f offsetVec = Vector3f::Constant(pointSize);
Eigen::Vector3f offsetVec = Eigen::Vector3f::Constant(pointSize);
AlignedBox<float, 3> pointbox(center - offsetVec, center + offsetVec);
Eigen::AlignedBox<float, 3> pointbox(center - offsetVec, center + offsetVec);
bbox.extend(pointbox);
}
}
else
{
for (unsigned int i = 0; i < nVertices; i++, vdata += vertexDesc.stride)
bbox.extend(Map<Vector3f>(reinterpret_cast<float*>(vdata)));
bbox.extend(Eigen::Map<Eigen::Vector3f>(reinterpret_cast<float*>(vdata)));
}
return bbox;
@ -616,19 +590,19 @@ Mesh::getBoundingBox() const
void
Mesh::transform(const Vector3f& translation, float scale)
Mesh::transform(const Eigen::Vector3f& translation, float scale)
{
if (vertexDesc.getAttribute(Position).format != Float3)
if (vertexDesc.getAttribute(VertexAttributeSemantic::Position).format != VertexAttributeFormat::Float3)
return;
char* vdata = reinterpret_cast<char*>(vertices) + vertexDesc.getAttribute(Position).offset;
char* vdata = reinterpret_cast<char*>(vertices) + vertexDesc.getAttribute(VertexAttributeSemantic::Position).offset;
unsigned int i;
// Scale and translate the vertex positions
for (i = 0; i < nVertices; i++, vdata += vertexDesc.stride)
{
const Vector3f tv = (Map<Vector3f>(reinterpret_cast<float*>(vdata)) + translation) * scale;
Map<Vector3f>(reinterpret_cast<float*>(vdata)) = tv;
const Eigen::Vector3f tv = (Eigen::Map<Eigen::Vector3f>(reinterpret_cast<float*>(vdata)) + translation) * scale;
Eigen::Map<Eigen::Vector3f>(reinterpret_cast<float*>(vdata)) = tv;
}
// Scale and translate the overriden vertex values
@ -640,22 +614,22 @@ Mesh::transform(const Vector3f& translation, float scale)
continue;
auto vertexDesc = group->vertexDescriptionOverride;
int positionOffset = vertexDesc.getAttribute(Position).offset;
int nextPositionOffset = vertexDesc.getAttribute(NextPosition).offset;
int positionOffset = vertexDesc.getAttribute(VertexAttributeSemantic::Position).offset;
int nextPositionOffset = vertexDesc.getAttribute(VertexAttributeSemantic::NextPosition).offset;
for (unsigned int j = 0; j < group->vertexCountOverride; j++, vdata += vertexDesc.stride)
{
Vector3f tv = (Map<Vector3f>(reinterpret_cast<float*>(vdata + positionOffset)) + translation) * scale;
Map<Vector3f>(reinterpret_cast<float*>(vdata + positionOffset)) = tv;
Eigen::Vector3f tv = (Eigen::Map<Eigen::Vector3f>(reinterpret_cast<float*>(vdata + positionOffset)) + translation) * scale;
Eigen::Map<Eigen::Vector3f>(reinterpret_cast<float*>(vdata + positionOffset)) = tv;
tv = (Map<Vector3f>(reinterpret_cast<float*>(vdata + nextPositionOffset)) + translation) * scale;
Map<Vector3f>(reinterpret_cast<float*>(vdata + nextPositionOffset)) = tv;
tv = (Eigen::Map<Eigen::Vector3f>(reinterpret_cast<float*>(vdata + nextPositionOffset)) + translation) * scale;
Eigen::Map<Eigen::Vector3f>(reinterpret_cast<float*>(vdata + nextPositionOffset)) = tv;
}
}
// Point sizes need to be scaled as well
if (vertexDesc.getAttribute(PointSize).format == Float1)
if (vertexDesc.getAttribute(VertexAttributeSemantic::PointSize).format == VertexAttributeFormat::Float1)
{
vdata = reinterpret_cast<char*>(vertices) + vertexDesc.getAttribute(PointSize).offset;
vdata = reinterpret_cast<char*>(vertices) + vertexDesc.getAttribute(VertexAttributeSemantic::PointSize).offset;
for (i = 0; i < nVertices; i++, vdata += vertexDesc.stride)
reinterpret_cast<float*>(vdata)[0] *= scale;
}
@ -673,104 +647,4 @@ Mesh::getPrimitiveCount() const
return count;
}
Mesh::PrimitiveGroupType
Mesh::parsePrimitiveGroupType(const string& name)
{
if (name == "trilist")
return TriList;
if (name == "tristrip")
return TriStrip;
if (name == "trifan")
return TriFan;
if (name == "linelist")
return LineList;
if (name == "linestrip")
return LineStrip;
if (name == "points")
return PointList;
if (name == "sprites")
return SpriteList;
else
return InvalidPrimitiveGroupType;
}
Mesh::VertexAttributeSemantic
Mesh::parseVertexAttributeSemantic(const string& name)
{
if (name == "position")
return Position;
if (name == "normal")
return Normal;
if (name == "color0")
return Color0;
if (name == "color1")
return Color1;
if (name == "tangent")
return Tangent;
if (name == "texcoord0")
return Texture0;
if (name == "texcoord1")
return Texture1;
if (name == "texcoord2")
return Texture2;
if (name == "texcoord3")
return Texture3;
if (name == "pointsize")
return PointSize;
return InvalidSemantic;
}
Mesh::VertexAttributeFormat
Mesh::parseVertexAttributeFormat(const string& name)
{
if (name == "f1")
return Float1;
if (name == "f2")
return Float2;
if (name == "f3")
return Float3;
if (name == "f4")
return Float4;
if (name == "ub4")
return UByte4;
return InvalidFormat;
}
Material::TextureSemantic
Mesh::parseTextureSemantic(const string& name)
{
if (name == "texture0")
return Material::DiffuseMap;
if (name == "normalmap")
return Material::NormalMap;
if (name == "specularmap")
return Material::SpecularMap;
if (name == "emissivemap")
return Material::EmissiveMap;
return Material::InvalidTextureSemantic;
}
unsigned int
Mesh::getVertexAttributeSize(VertexAttributeFormat fmt)
{
switch (fmt)
{
case Float1:
case UByte4:
return 4;
case Float2:
return 8;
case Float3:
return 12;
case Float4:
return 16;
default:
return 0;
}
}
} // end namespace cmod

View File

@ -8,144 +8,169 @@
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#ifndef _CELMODEL_MESH_H_
#define _CELMODEL_MESH_H_
#pragma once
#include <array>
#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>
#include "material.h"
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <vector>
#include <string>
#include "material.h"
namespace cmod
{
// 32-bit index type
using index32 = std::uint32_t;
enum class VertexAttributeSemantic : std::int16_t
{
Position = 0,
Color0 = 1,
Color1 = 2,
Normal = 3,
Tangent = 4,
Texture0 = 5,
Texture1 = 6,
Texture2 = 7,
Texture3 = 8,
PointSize = 9,
NextPosition = 10,
ScaleFactor = 11,
SemanticMax = 12,
InvalidSemantic = -1,
};
enum class VertexAttributeFormat : std::int16_t
{
Float1 = 0,
Float2 = 1,
Float3 = 2,
Float4 = 3,
UByte4 = 4,
FormatMax = 5,
InvalidFormat = -1,
};
enum class PrimitiveGroupType : std::int16_t
{
TriList = 0,
TriStrip = 1,
TriFan = 2,
LineList = 3,
LineStrip = 4,
PointList = 5,
SpriteList = 6,
PrimitiveTypeMax = 7,
InvalidPrimitiveGroupType = -1
};
struct VertexAttribute
{
VertexAttribute() :
semantic(VertexAttributeSemantic::InvalidSemantic),
format(VertexAttributeFormat::InvalidFormat),
offset(0)
{
}
VertexAttribute(VertexAttributeSemantic _semantic,
VertexAttributeFormat _format,
unsigned int _offset) :
semantic(_semantic),
format(_format),
offset(_offset)
{
}
static constexpr unsigned int getFormatSize(VertexAttributeFormat fmt)
{
switch (fmt)
{
case VertexAttributeFormat::Float1:
case VertexAttributeFormat::UByte4:
return 4;
case VertexAttributeFormat::Float2:
return 8;
case VertexAttributeFormat::Float3:
return 12;
case VertexAttributeFormat::Float4:
return 16;
default:
return 0;
}
}
VertexAttributeSemantic semantic;
VertexAttributeFormat format;
unsigned int offset;
};
struct VertexDescription
{
VertexDescription(unsigned int _stride,
unsigned int _nAttributes,
VertexAttribute* _attributes);
VertexDescription(const VertexDescription& desc);
~VertexDescription();
inline const VertexAttribute& getAttribute(VertexAttributeSemantic semantic) const
{
return semanticMap[static_cast<std::size_t>(semantic)];
}
VertexDescription appendingAttributes(const VertexAttribute* newAttributes, int count) const;
bool validate() const;
VertexDescription& operator=(const VertexDescription&);
unsigned int stride;
unsigned int nAttributes;
VertexAttribute* attributes;
private:
void clearSemanticMap();
void buildSemanticMap();
// Vertex attributes indexed by semantic
std::array<VertexAttribute, static_cast<std::size_t>(VertexAttributeSemantic::SemanticMax)> semanticMap;
};
class PrimitiveGroup
{
public:
PrimitiveGroup() = default;
~PrimitiveGroup() = default;
unsigned int getPrimitiveCount() const;
PrimitiveGroupType prim;
unsigned int materialIndex;
index32* indices;
unsigned int nIndices;
PrimitiveGroupType primOverride;
void* vertexOverride;
unsigned int vertexCountOverride;
index32* indicesOverride;
unsigned int nIndicesOverride;
VertexDescription vertexDescriptionOverride { 0, 0, nullptr };
};
class Mesh
{
public:
// 32-bit index type
typedef unsigned int index32;
class BufferResource
{
};
enum VertexAttributeSemantic
{
Position = 0,
Color0 = 1,
Color1 = 2,
Normal = 3,
Tangent = 4,
Texture0 = 5,
Texture1 = 6,
Texture2 = 7,
Texture3 = 8,
PointSize = 9,
NextPosition = 10,
ScaleFactor = 11,
SemanticMax = 12,
InvalidSemantic = -1,
};
enum VertexAttributeFormat
{
Float1 = 0,
Float2 = 1,
Float3 = 2,
Float4 = 3,
UByte4 = 4,
FormatMax = 5,
InvalidFormat = -1,
};
struct VertexAttribute
{
VertexAttribute() :
semantic(InvalidSemantic),
format(InvalidFormat),
offset(0)
{
}
VertexAttribute(VertexAttributeSemantic _semantic,
VertexAttributeFormat _format,
unsigned int _offset) :
semantic(_semantic),
format(_format),
offset(_offset)
{
}
VertexAttributeSemantic semantic;
VertexAttributeFormat format;
unsigned int offset;
};
struct VertexDescription
{
VertexDescription(unsigned int _stride,
unsigned int _nAttributes,
VertexAttribute* _attributes);
VertexDescription(const VertexDescription& desc);
~VertexDescription();
const VertexAttribute& getAttribute(VertexAttributeSemantic semantic) const
{
return semanticMap[semantic];
}
VertexDescription appendingAttributes(const VertexAttribute* newAttributes, int count) const;
bool validate() const;
VertexDescription& operator=(const VertexDescription&);
unsigned int stride;
unsigned int nAttributes;
VertexAttribute* attributes;
private:
void clearSemanticMap();
void buildSemanticMap();
// Vertex attributes indexed by semantic
VertexAttribute semanticMap[SemanticMax];
};
enum PrimitiveGroupType
{
TriList = 0,
TriStrip = 1,
TriFan = 2,
LineList = 3,
LineStrip = 4,
PointList = 5,
SpriteList = 6,
PrimitiveTypeMax = 7,
InvalidPrimitiveGroupType = -1
};
class PrimitiveGroup
{
public:
PrimitiveGroup() = default;
~PrimitiveGroup() = default;
unsigned int getPrimitiveCount() const;
PrimitiveGroupType prim;
unsigned int materialIndex;
index32* indices;
unsigned int nIndices;
PrimitiveGroupType primOverride;
void* vertexOverride;
unsigned int vertexCountOverride;
index32* indicesOverride;
unsigned int nIndicesOverride;
VertexDescription vertexDescriptionOverride { 0, 0, nullptr };
};
class PickResult
{
public:
@ -164,7 +189,7 @@ class Mesh
bool setVertexDescription(const VertexDescription& desc);
const VertexDescription& getVertexDescription() const;
PrimitiveGroup* createLinePrimitiveGroup(bool lineStrip, unsigned int nIndices, Mesh::index32* indices);
PrimitiveGroup* createLinePrimitiveGroup(bool lineStrip, unsigned int nIndices, index32* indices);
const PrimitiveGroup* getGroup(unsigned int index) const;
PrimitiveGroup* getGroup(unsigned int index);
unsigned int addGroup(PrimitiveGroup* group);
@ -198,21 +223,13 @@ class Mesh
unsigned int getVertexStride() const { return vertexDesc.stride; }
unsigned int getPrimitiveCount() const;
static PrimitiveGroupType parsePrimitiveGroupType(const std::string&);
static VertexAttributeSemantic parseVertexAttributeSemantic(const std::string&);
static VertexAttributeFormat parseVertexAttributeFormat(const std::string&);
static Material::TextureSemantic parseTextureSemantic(const std::string&);
static unsigned int getVertexAttributeSize(VertexAttributeFormat);
private:
void recomputeBoundingBox();
private:
VertexDescription vertexDesc{ 0, 0, nullptr };
unsigned int nVertices{ 0 };
void* vertices{ nullptr };
mutable BufferResource* vbResource{ nullptr };
std::vector<PrimitiveGroup*> groups;
@ -220,6 +237,3 @@ class Mesh
};
} // namespace cmod
#endif // !_CELMESH_MESH_H_

View File

@ -95,7 +95,7 @@ Model::addMaterial(const Material* m)
// the model, we could potentially end up with false positives--this
// won't cause any rendering troubles, but could hurt performance
// if it forces multipass rendering when it's not required.
for (int i = 0; i < Material::TextureSemanticMax; i++)
for (int i = 0; i < static_cast<int>(TextureSemantic::TextureSemanticMax); i++)
{
if (m->maps[i] != InvalidResource)
{
@ -306,7 +306,7 @@ Model::determineOpacity()
for (unsigned int i = 0; i < materials.size(); i++)
{
if ((materials[i]->opacity > 0.01f && materials[i]->opacity < 1.0f) ||
materials[i]->blend == Material::AdditiveBlend)
materials[i]->blend == BlendMode::AdditiveBlend)
{
opaque = false;
return;
@ -318,9 +318,9 @@ Model::determineOpacity()
bool
Model::usesTextureType(Material::TextureSemantic t) const
Model::usesTextureType(TextureSemantic t) const
{
return textureUsage[static_cast<int>(t)];
return textureUsage[static_cast<std::size_t>(t)];
}

View File

@ -11,6 +11,7 @@
#pragma once
#include <array>
#include <cstddef>
#include <vector>
#include <Eigen/Core>
@ -99,15 +100,15 @@ class Model
* all within a mesh. This information is used to decide
* if multiple rendering passes are required.
*/
virtual bool usesTextureType(Material::TextureSemantic) const;
bool usesTextureType(TextureSemantic) const;
/** Return true if the model has no translucent components. */
virtual bool isOpaque() const
bool isOpaque() const
{
return opaque;
}
virtual bool isNormalized() const
bool isNormalized() const
{
return normalized;
}
@ -118,7 +119,7 @@ class Model
class MeshComparator
{
public:
public:
virtual ~MeshComparator() = default;
virtual bool operator()(const Mesh&, const Mesh&) const = 0;
@ -145,7 +146,7 @@ class Model
*/
class OpacityComparator : public MeshComparator
{
public:
public:
OpacityComparator() = default;
virtual ~OpacityComparator() = default;
@ -156,7 +157,7 @@ class Model
std::vector<const Material*> materials;
std::vector<Mesh*> meshes;
std::array<bool, Material::TextureSemanticMax> textureUsage;
std::array<bool, static_cast<std::size_t>(TextureSemantic::TextureSemanticMax)> textureUsage;
bool opaque{ true };
bool normalized{ false };
};

View File

@ -35,12 +35,12 @@ constexpr const char CEL_MODEL_HEADER_ASCII[] = "#celmodel__ascii";
constexpr const char CEL_MODEL_HEADER_BINARY[] = "#celmodel_binary";
// Material default values
constexpr Material::Color DefaultDiffuse(0.0f, 0.0f, 0.0f);
constexpr Material::Color DefaultSpecular(0.0f, 0.0f, 0.0f);
constexpr Material::Color DefaultEmissive(0.0f, 0.0f, 0.0f);
constexpr Color DefaultDiffuse(0.0f, 0.0f, 0.0f);
constexpr Color DefaultSpecular(0.0f, 0.0f, 0.0f);
constexpr Color DefaultEmissive(0.0f, 0.0f, 0.0f);
constexpr float DefaultSpecularPower = 1.0f;
constexpr float DefaultOpacity = 1.0f;
constexpr Material::BlendMode DefaultBlend = Material::NormalBlend;
constexpr BlendMode DefaultBlend = BlendMode::NormalBlend;
// Standard tokens for ASCII model loader
constexpr const char MeshToken[] = "mesh";
@ -188,6 +188,88 @@ defined here--they have the obvious definitions.
<material_index> :: <unsigned_int> | -1
\endcode
*/
PrimitiveGroupType
parsePrimitiveGroupType(const std::string& name)
{
if (name == "trilist")
return PrimitiveGroupType::TriList;
if (name == "tristrip")
return PrimitiveGroupType::TriStrip;
if (name == "trifan")
return PrimitiveGroupType::TriFan;
if (name == "linelist")
return PrimitiveGroupType::LineList;
if (name == "linestrip")
return PrimitiveGroupType::LineStrip;
if (name == "points")
return PrimitiveGroupType::PointList;
if (name == "sprites")
return PrimitiveGroupType::SpriteList;
else
return PrimitiveGroupType::InvalidPrimitiveGroupType;
}
VertexAttributeSemantic
parseVertexAttributeSemantic(const std::string& name)
{
if (name == "position")
return VertexAttributeSemantic::Position;
if (name == "normal")
return VertexAttributeSemantic::Normal;
if (name == "color0")
return VertexAttributeSemantic::Color0;
if (name == "color1")
return VertexAttributeSemantic::Color1;
if (name == "tangent")
return VertexAttributeSemantic::Tangent;
if (name == "texcoord0")
return VertexAttributeSemantic::Texture0;
if (name == "texcoord1")
return VertexAttributeSemantic::Texture1;
if (name == "texcoord2")
return VertexAttributeSemantic::Texture2;
if (name == "texcoord3")
return VertexAttributeSemantic::Texture3;
if (name == "pointsize")
return VertexAttributeSemantic::PointSize;
return VertexAttributeSemantic::InvalidSemantic;
}
VertexAttributeFormat
parseVertexAttributeFormat(const std::string& name)
{
if (name == "f1")
return VertexAttributeFormat::Float1;
if (name == "f2")
return VertexAttributeFormat::Float2;
if (name == "f3")
return VertexAttributeFormat::Float3;
if (name == "f4")
return VertexAttributeFormat::Float4;
if (name == "ub4")
return VertexAttributeFormat::UByte4;
return VertexAttributeFormat::InvalidFormat;
}
TextureSemantic
parseTextureSemantic(const std::string& name)
{
if (name == "texture0")
return TextureSemantic::DiffuseMap;
if (name == "normalmap")
return TextureSemantic::NormalMap;
if (name == "specularmap")
return TextureSemantic::SpecularMap;
if (name == "emissivemap")
return TextureSemantic::EmissiveMap;
return TextureSemantic::InvalidTextureSemantic;
}
class AsciiModelLoader : public ModelLoader
{
public:
@ -201,9 +283,9 @@ public:
void reportError(const std::string& /*msg*/) override;
Material* loadMaterial();
Mesh::VertexDescription* loadVertexDescription();
VertexDescription* loadVertexDescription();
Mesh* loadMesh();
char* loadVertices(const Mesh::VertexDescription& vertexDesc,
char* loadVertices(const VertexDescription& vertexDesc,
unsigned int& vertexCount);
private:
@ -239,9 +321,9 @@ AsciiModelLoader::loadMaterial()
while (tok.nextToken() == Tokenizer::TokenName && tok.getNameValue() != EndMaterialToken)
{
std::string property = tok.getStringValue();
Material::TextureSemantic texType = Mesh::parseTextureSemantic(property);
TextureSemantic texType = parseTextureSemantic(property);
if (texType != Material::InvalidTextureSemantic)
if (texType != TextureSemantic::InvalidTextureSemantic)
{
if (tok.nextToken() != Tokenizer::TokenString)
{
@ -253,24 +335,24 @@ AsciiModelLoader::loadMaterial()
std::string textureName = tok.getStringValue();
ResourceHandle tex = getHandle(textureName);
material->maps[texType] = tex;
material->setMap(texType, tex);
}
else if (property == "blend")
{
Material::BlendMode blendMode = Material::InvalidBlend;
BlendMode blendMode = BlendMode::InvalidBlend;
if (tok.nextToken() == Tokenizer::TokenName)
{
std::string blendModeName = tok.getStringValue();
if (blendModeName == "normal")
blendMode = Material::NormalBlend;
blendMode = BlendMode::NormalBlend;
else if (blendModeName == "add")
blendMode = Material::AdditiveBlend;
blendMode = BlendMode::AdditiveBlend;
else if (blendModeName == "premultiplied")
blendMode = Material::PremultipliedAlphaBlend;
blendMode = BlendMode::PremultipliedAlphaBlend;
}
if (blendMode == Material::InvalidBlend)
if (blendMode == BlendMode::InvalidBlend)
{
reportError("Bad blend mode in material");
delete material;
@ -301,10 +383,12 @@ AsciiModelLoader::loadMaterial()
data[i] = tok.getNumberValue();
}
Material::Color colorVal;
Color colorVal;
if (nValues == 3)
{
colorVal = Material::Color((float) data[0], (float) data[1], (float) data[2]);
colorVal = Color(static_cast<float>(data[0]),
static_cast<float>(data[1]),
static_cast<float>(data[2]));
}
if (property == "diffuse")
@ -340,7 +424,7 @@ AsciiModelLoader::loadMaterial()
}
Mesh::VertexDescription*
VertexDescription*
AsciiModelLoader::loadVertexDescription()
{
if (tok.nextToken() != Tokenizer::TokenName || tok.getNameValue() != VertexDescToken)
@ -352,7 +436,7 @@ AsciiModelLoader::loadVertexDescription()
int maxAttributes = 16;
int nAttributes = 0;
unsigned int offset = 0;
auto* attributes = new Mesh::VertexAttribute[maxAttributes];
auto* attributes = new VertexAttribute[maxAttributes];
while (tok.nextToken() == Tokenizer::TokenName && tok.getNameValue() != EndVertexDescToken)
{
@ -384,18 +468,16 @@ AsciiModelLoader::loadVertexDescription()
return nullptr;
}
Mesh::VertexAttributeSemantic semantic =
Mesh::parseVertexAttributeSemantic(semanticName);
if (semantic == Mesh::InvalidSemantic)
VertexAttributeSemantic semantic = parseVertexAttributeSemantic(semanticName);
if (semantic == VertexAttributeSemantic::InvalidSemantic)
{
reportError(fmt::format("Invalid vertex attribute semantic '{}'", semanticName));
delete[] attributes;
return nullptr;
}
Mesh::VertexAttributeFormat format =
Mesh::parseVertexAttributeFormat(formatName);
if (format == Mesh::InvalidFormat)
VertexAttributeFormat format = parseVertexAttributeFormat(formatName);
if (format == VertexAttributeFormat::InvalidFormat)
{
reportError(fmt::format("Invalid vertex attribute format '{}'", formatName));
delete[] attributes;
@ -406,7 +488,7 @@ AsciiModelLoader::loadVertexDescription()
attributes[nAttributes].format = format;
attributes[nAttributes].offset = offset;
offset += Mesh::getVertexAttributeSize(format);
offset += VertexAttribute::getFormatSize(format);
nAttributes++;
}
@ -424,15 +506,14 @@ AsciiModelLoader::loadVertexDescription()
return nullptr;
}
auto *vertexDesc =
new Mesh::VertexDescription(offset, nAttributes, attributes);
auto *vertexDesc = new VertexDescription(offset, nAttributes, attributes);
delete[] attributes;
return vertexDesc;
}
char*
AsciiModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
AsciiModelLoader::loadVertices(const VertexDescription& vertexDesc,
unsigned int& vertexCount)
{
if (tok.nextToken() != Tokenizer::TokenName && tok.getNameValue() != VerticesToken)
@ -465,22 +546,22 @@ AsciiModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
assert(offset < vertexDataSize);
for (unsigned int attr = 0; attr < vertexDesc.nAttributes; attr++)
{
Mesh::VertexAttributeFormat fmt = vertexDesc.attributes[attr].format;
VertexAttributeFormat vfmt = vertexDesc.attributes[attr].format;
/*unsigned int nBytes = Mesh::getVertexAttributeSize(fmt); Unused*/
int readCount = 0;
switch (fmt)
switch (vfmt)
{
case Mesh::Float1:
case VertexAttributeFormat::Float1:
readCount = 1;
break;
case Mesh::Float2:
case VertexAttributeFormat::Float2:
readCount = 2;
break;
case Mesh::Float3:
case VertexAttributeFormat::Float3:
readCount = 3;
break;
case Mesh::Float4:
case Mesh::UByte4:
case VertexAttributeFormat::Float4:
case VertexAttributeFormat::UByte4:
readCount = 4;
break;
default:
@ -504,7 +585,7 @@ AsciiModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
}
unsigned int base = offset + vertexDesc.attributes[attr].offset;
if (fmt == Mesh::UByte4)
if (vfmt == VertexAttributeFormat::UByte4)
{
for (int k = 0; k < readCount; k++)
{
@ -535,7 +616,7 @@ AsciiModelLoader::loadMesh()
return nullptr;
}
Mesh::VertexDescription* vertexDesc = loadVertexDescription();
VertexDescription* vertexDesc = loadVertexDescription();
if (vertexDesc == nullptr)
return nullptr;
@ -554,9 +635,8 @@ AsciiModelLoader::loadMesh()
while (tok.nextToken() == Tokenizer::TokenName && tok.getNameValue() != EndMeshToken)
{
Mesh::PrimitiveGroupType type =
Mesh::parsePrimitiveGroupType(tok.getStringValue());
if (type == Mesh::InvalidPrimitiveGroupType)
PrimitiveGroupType type = parsePrimitiveGroupType(tok.getStringValue());
if (type == PrimitiveGroupType::InvalidPrimitiveGroupType)
{
reportError("Bad primitive group type: " + tok.getStringValue());
delete mesh;
@ -589,7 +669,7 @@ AsciiModelLoader::loadMesh()
unsigned int indexCount = (unsigned int) tok.getIntegerValue();
auto* indices = new Mesh::index32[indexCount];
auto* indices = new index32[indexCount];
for (unsigned int i = 0; i < indexCount; i++)
{
@ -700,12 +780,12 @@ public:
private:
bool writeMesh(const Mesh& /*mesh*/);
bool writeMaterial(const Material& /*material*/);
bool writeGroup(const Mesh::PrimitiveGroup& /*group*/);
bool writeVertexDescription(const Mesh::VertexDescription& /*desc*/);
bool writeGroup(const PrimitiveGroup& /*group*/);
bool writeVertexDescription(const VertexDescription& /*desc*/);
bool writeVertices(const void* vertexData,
unsigned int nVertices,
unsigned int stride,
const Mesh::VertexDescription& desc);
const VertexDescription& desc);
std::ostream& out;
};
@ -734,23 +814,23 @@ AsciiModelWriter::write(const Model& model)
bool
AsciiModelWriter::writeGroup(const Mesh::PrimitiveGroup& group)
AsciiModelWriter::writeGroup(const PrimitiveGroup& group)
{
switch (group.prim)
{
case Mesh::TriList:
case PrimitiveGroupType::TriList:
fmt::print(out, "trilist"); break;
case Mesh::TriStrip:
case PrimitiveGroupType::TriStrip:
fmt::print(out, "tristrip"); break;
case Mesh::TriFan:
case PrimitiveGroupType::TriFan:
fmt::print(out, "trifan"); break;
case Mesh::LineList:
case PrimitiveGroupType::LineList:
fmt::print(out, "linelist"); break;
case Mesh::LineStrip:
case PrimitiveGroupType::LineStrip:
fmt::print(out, "linestrip"); break;
case Mesh::PointList:
case PrimitiveGroupType::PointList:
fmt::print(out, "points"); break;
case Mesh::SpriteList:
case PrimitiveGroupType::SpriteList:
fmt::print(out, "sprites"); break;
default:
return false;
@ -820,7 +900,7 @@ bool
AsciiModelWriter::writeVertices(const void* vertexData,
unsigned int nVertices,
unsigned int stride,
const Mesh::VertexDescription& desc)
const VertexDescription& desc)
{
const auto* vertex = reinterpret_cast<const unsigned char*>(vertexData);
@ -837,23 +917,23 @@ AsciiModelWriter::writeVertices(const void* vertexData,
switch (desc.attributes[attr].format)
{
case Mesh::Float1:
case VertexAttributeFormat::Float1:
std::memcpy(fdata, ubdata, sizeof(float));
fmt::print(out, "{}", fdata[0]);
break;
case Mesh::Float2:
case VertexAttributeFormat::Float2:
std::memcpy(fdata, ubdata, sizeof(float) * 2);
fmt::print(out, "{} {}", fdata[0], fdata[1]);
break;
case Mesh::Float3:
case VertexAttributeFormat::Float3:
std::memcpy(fdata, ubdata, sizeof(float) * 3);
fmt::print(out, "{} {} {}", fdata[0], fdata[1], fdata[2]);
break;
case Mesh::Float4:
case VertexAttributeFormat::Float4:
std::memcpy(fdata, ubdata, sizeof(float) * 4);
fmt::print(out, "{} {} {} {}", fdata[0], fdata[1], fdata[2], fdata[3]);
break;
case Mesh::UByte4:
case VertexAttributeFormat::UByte4:
fmt::print(out, "{} {} {} {}", +ubdata[0], +ubdata[1], +ubdata[2], +ubdata[3]);
break;
default:
@ -871,7 +951,7 @@ AsciiModelWriter::writeVertices(const void* vertexData,
bool
AsciiModelWriter::writeVertexDescription(const Mesh::VertexDescription& desc)
AsciiModelWriter::writeVertexDescription(const VertexDescription& desc)
{
if (!(out << "vertexdesc\n").good()) { return false; }
for (unsigned int attr = 0; attr < desc.nAttributes; attr++)
@ -881,34 +961,34 @@ AsciiModelWriter::writeVertexDescription(const Mesh::VertexDescription& desc)
switch (desc.attributes[attr].semantic)
{
case Mesh::Position:
case VertexAttributeSemantic::Position:
out << "position";
break;
case Mesh::Color0:
case VertexAttributeSemantic::Color0:
out << "color0";
break;
case Mesh::Color1:
case VertexAttributeSemantic::Color1:
out << "color1";
break;
case Mesh::Normal:
case VertexAttributeSemantic::Normal:
out << "normal";
break;
case Mesh::Tangent:
case VertexAttributeSemantic::Tangent:
out << "tangent";
break;
case Mesh::Texture0:
case VertexAttributeSemantic::Texture0:
out << "texcoord0";
break;
case Mesh::Texture1:
case VertexAttributeSemantic::Texture1:
out << "texcoord1";
break;
case Mesh::Texture2:
case VertexAttributeSemantic::Texture2:
out << "texcoord2";
break;
case Mesh::Texture3:
case VertexAttributeSemantic::Texture3:
out << "texcoord3";
break;
case Mesh::PointSize:
case VertexAttributeSemantic::PointSize:
out << "pointsize";
break;
default:
@ -920,19 +1000,19 @@ AsciiModelWriter::writeVertexDescription(const Mesh::VertexDescription& desc)
switch (desc.attributes[attr].format)
{
case Mesh::Float1:
case VertexAttributeFormat::Float1:
out << "f1";
break;
case Mesh::Float2:
case VertexAttributeFormat::Float2:
out << "f2";
break;
case Mesh::Float3:
case VertexAttributeFormat::Float3:
out << "f3";
break;
case Mesh::Float4:
case VertexAttributeFormat::Float4:
out << "f4";
break;
case Mesh::UByte4:
case VertexAttributeFormat::UByte4:
out << "ub4";
break;
default:
@ -994,13 +1074,13 @@ AsciiModelWriter::writeMaterial(const Material& material)
if (!(out << "blend ").good()) { return false; }
switch (material.blend)
{
case Material::NormalBlend:
case BlendMode::NormalBlend:
out << "normal";
break;
case Material::AdditiveBlend:
case BlendMode::AdditiveBlend:
out << "add";
break;
case Material::PremultipliedAlphaBlend:
case BlendMode::PremultipliedAlphaBlend:
out << "premultiplied";
break;
default:
@ -1011,7 +1091,7 @@ AsciiModelWriter::writeMaterial(const Material& material)
if (!out.good() || !(out << '\n').good()) { return false; }
}
for (int i = 0; i < Material::TextureSemanticMax; i++)
for (int i = 0; i < static_cast<int>(TextureSemantic::TextureSemanticMax); i++)
{
fs::path texSource;
if (material.maps[i] != InvalidResource)
@ -1021,18 +1101,18 @@ AsciiModelWriter::writeMaterial(const Material& material)
if (!texSource.empty())
{
switch (Material::TextureSemantic(i))
switch (static_cast<TextureSemantic>(i))
{
case Material::DiffuseMap:
case TextureSemantic::DiffuseMap:
out << "texture0";
break;
case Material::NormalMap:
case TextureSemantic::NormalMap:
out << "normalmap";
break;
case Material::SpecularMap:
case TextureSemantic::SpecularMap:
out << "specularmap";
break;
case Material::EmissiveMap:
case TextureSemantic::EmissiveMap:
out << "emissivemap";
break;
default:
@ -1079,7 +1159,7 @@ bool readTypeFloat1(std::istream& in, float& f)
}
bool readTypeColor(std::istream& in, Material::Color& c)
bool readTypeColor(std::istream& in, Color& c)
{
ModelFileType cmodType;
float r, g, b;
@ -1092,7 +1172,7 @@ bool readTypeColor(std::istream& in, Material::Color& c)
return false;
}
c = Material::Color(r, g, b);
c = Color(r, g, b);
return true;
}
@ -1178,9 +1258,9 @@ public:
void reportError(const std::string& /*msg*/) override;
Material* loadMaterial();
Mesh::VertexDescription* loadVertexDescription();
VertexDescription* loadVertexDescription();
Mesh* loadMesh();
char* loadVertices(const Mesh::VertexDescription& vertexDesc,
char* loadVertices(const VertexDescription& vertexDesc,
unsigned int& vertexCount);
private:
@ -1329,13 +1409,13 @@ BinaryModelLoader::loadMaterial()
{
std::int16_t blendMode;
if (!celutil::readLE<std::int16_t>(in, blendMode)
|| blendMode < 0 || blendMode >= Material::BlendMax)
|| blendMode < 0 || blendMode >= static_cast<std::int16_t>(BlendMode::BlendMax))
{
reportError("Bad blend mode");
delete material;
return nullptr;
}
material->blend = (Material::BlendMode) blendMode;
material->blend = static_cast<BlendMode>(blendMode);
}
break;
@ -1343,7 +1423,7 @@ BinaryModelLoader::loadMaterial()
{
std::int16_t texType;
if (!celutil::readLE<std::int16_t>(in, texType)
|| texType < 0 || texType >= Material::TextureSemanticMax)
|| texType < 0 || texType >= static_cast<std::int16_t>(TextureSemantic::TextureSemanticMax))
{
reportError("Bad texture type");
delete material;
@ -1385,7 +1465,7 @@ BinaryModelLoader::loadMaterial()
}
Mesh::VertexDescription*
VertexDescription*
BinaryModelLoader::loadVertexDescription()
{
ModelFileToken tok;
@ -1398,7 +1478,7 @@ BinaryModelLoader::loadVertexDescription()
int maxAttributes = 16;
int nAttributes = 0;
unsigned int offset = 0;
auto* attributes = new Mesh::VertexAttribute[maxAttributes];
auto* attributes = new VertexAttribute[maxAttributes];
for (;;)
{
@ -1414,11 +1494,11 @@ BinaryModelLoader::loadVertexDescription()
{
break;
}
if (tok >= 0 && tok < Mesh::SemanticMax)
if (tok >= 0 && tok < static_cast<std::int16_t>(VertexAttributeSemantic::SemanticMax))
{
std::int16_t fmt;
if (!celutil::readLE<std::int16_t>(in, fmt)
|| fmt < 0 || fmt >= Mesh::FormatMax)
std::int16_t vfmt;
if (!celutil::readLE<std::int16_t>(in, vfmt)
|| vfmt < 0 || vfmt >= static_cast<std::int16_t>(VertexAttributeFormat::FormatMax))
{
reportError("Invalid vertex attribute type");
delete[] attributes;
@ -1433,12 +1513,12 @@ BinaryModelLoader::loadVertexDescription()
}
attributes[nAttributes].semantic =
static_cast<Mesh::VertexAttributeSemantic>(tok);
static_cast<VertexAttributeSemantic>(tok);
attributes[nAttributes].format =
static_cast<Mesh::VertexAttributeFormat>(fmt);
static_cast<VertexAttributeFormat>(vfmt);
attributes[nAttributes].offset = offset;
offset += Mesh::getVertexAttributeSize(attributes[nAttributes].format);
offset += VertexAttribute::getFormatSize(attributes[nAttributes].format);
nAttributes++;
}
else
@ -1457,7 +1537,7 @@ BinaryModelLoader::loadVertexDescription()
}
auto *vertexDesc =
new Mesh::VertexDescription(offset, nAttributes, attributes);
new VertexDescription(offset, nAttributes, attributes);
delete[] attributes;
return vertexDesc;
}
@ -1466,7 +1546,7 @@ BinaryModelLoader::loadVertexDescription()
Mesh*
BinaryModelLoader::loadMesh()
{
Mesh::VertexDescription* vertexDesc = loadVertexDescription();
VertexDescription* vertexDesc = loadVertexDescription();
if (vertexDesc == nullptr)
return nullptr;
@ -1497,15 +1577,14 @@ BinaryModelLoader::loadMesh()
{
break;
}
if (tok < 0 || tok >= Mesh::PrimitiveTypeMax)
if (tok < 0 || tok >= static_cast<std::int16_t>(PrimitiveGroupType::PrimitiveTypeMax))
{
reportError("Bad primitive group type");
delete mesh;
return nullptr;
}
Mesh::PrimitiveGroupType type =
static_cast<Mesh::PrimitiveGroupType>(tok);
PrimitiveGroupType type = static_cast<PrimitiveGroupType>(tok);
std::uint32_t materialIndex, indexCount;
if (!celutil::readLE<std::uint32_t>(in, materialIndex)
|| !celutil::readLE<std::uint32_t>(in, indexCount))
@ -1539,7 +1618,7 @@ BinaryModelLoader::loadMesh()
char*
BinaryModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
BinaryModelLoader::loadVertices(const VertexDescription& vertexDesc,
unsigned int& vertexCount)
{
ModelFileToken tok;
@ -1565,12 +1644,12 @@ BinaryModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
for (unsigned int attr = 0; attr < vertexDesc.nAttributes; attr++)
{
unsigned int base = offset + vertexDesc.attributes[attr].offset;
Mesh::VertexAttributeFormat fmt = vertexDesc.attributes[attr].format;
VertexAttributeFormat fmt = vertexDesc.attributes[attr].format;
float f[4];
/*int readCount = 0; Unused*/
switch (fmt)
{
case Mesh::Float1:
case VertexAttributeFormat::Float1:
if (!celutil::readLE<float>(in, f[0]))
{
reportError("Failed to read Float1");
@ -1579,7 +1658,7 @@ BinaryModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
}
std::memcpy(vertexData + base, f, sizeof(float));
break;
case Mesh::Float2:
case VertexAttributeFormat::Float2:
if (!celutil::readLE<float>(in, f[0])
|| !celutil::readLE<float>(in, f[1]))
{
@ -1589,7 +1668,7 @@ BinaryModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
}
std::memcpy(vertexData + base, f, sizeof(float) * 2);
break;
case Mesh::Float3:
case VertexAttributeFormat::Float3:
if (!celutil::readLE<float>(in, f[0])
|| !celutil::readLE<float>(in, f[1])
|| !celutil::readLE<float>(in, f[2]))
@ -1600,7 +1679,7 @@ BinaryModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
}
std::memcpy(vertexData + base, f, sizeof(float) * 3);
break;
case Mesh::Float4:
case VertexAttributeFormat::Float4:
if (!celutil::readLE<float>(in, f[0])
|| !celutil::readLE<float>(in, f[1])
|| !celutil::readLE<float>(in, f[2])
@ -1612,7 +1691,7 @@ BinaryModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
}
std::memcpy(vertexData + base, f, sizeof(float) * 4);
break;
case Mesh::UByte4:
case VertexAttributeFormat::UByte4:
if (!in.get(reinterpret_cast<char*>(vertexData + base), 4).good())
{
reportError("failed to read UByte4");
@ -1652,7 +1731,7 @@ bool writeTypeFloat1(std::ostream& out, float f)
}
bool writeTypeColor(std::ostream& out, const Material::Color& c)
bool writeTypeColor(std::ostream& out, const Color& c)
{
return writeType(out, CMOD_Color)
&& celutil::writeLE<float>(out, c.red())
@ -1684,12 +1763,12 @@ public:
private:
bool writeMesh(const Mesh& /*mesh*/);
bool writeMaterial(const Material& /*material*/);
bool writeGroup(const Mesh::PrimitiveGroup& /*group*/);
bool writeVertexDescription(const Mesh::VertexDescription& /*desc*/);
bool writeGroup(const PrimitiveGroup& /*group*/);
bool writeVertexDescription(const VertexDescription& /*desc*/);
bool writeVertices(const void* vertexData,
unsigned int nVertices,
unsigned int stride,
const Mesh::VertexDescription& desc);
const VertexDescription& desc);
std::ostream& out;
};
@ -1715,9 +1794,9 @@ BinaryModelWriter::write(const Model& model)
bool
BinaryModelWriter::writeGroup(const Mesh::PrimitiveGroup& group)
BinaryModelWriter::writeGroup(const PrimitiveGroup& group)
{
if (!celutil::writeLE<std::int16_t>(out, group.prim)
if (!celutil::writeLE<std::int16_t>(out, static_cast<std::int16_t>(group.prim))
|| !celutil::writeLE<std::uint32_t>(out, group.materialIndex)
|| !celutil::writeLE<std::uint32_t>(out, group.nIndices))
{
@ -1759,7 +1838,7 @@ bool
BinaryModelWriter::writeVertices(const void* vertexData,
unsigned int nVertices,
unsigned int stride,
const Mesh::VertexDescription& desc)
const VertexDescription& desc)
{
const auto* vertex = reinterpret_cast<const char*>(vertexData);
@ -1778,29 +1857,29 @@ BinaryModelWriter::writeVertices(const void* vertexData,
bool result;
switch (desc.attributes[attr].format)
{
case Mesh::Float1:
case VertexAttributeFormat::Float1:
std::memcpy(fdata, cdata, sizeof(float));
result = celutil::writeLE<float>(out, fdata[0]);
break;
case Mesh::Float2:
case VertexAttributeFormat::Float2:
std::memcpy(fdata, cdata, sizeof(float) * 2);
result = celutil::writeLE<float>(out, fdata[0])
&& celutil::writeLE<float>(out, fdata[1]);
break;
case Mesh::Float3:
case VertexAttributeFormat::Float3:
std::memcpy(fdata, cdata, sizeof(float) * 3);
result = celutil::writeLE<float>(out, fdata[0])
&& celutil::writeLE<float>(out, fdata[1])
&& celutil::writeLE<float>(out, fdata[2]);
break;
case Mesh::Float4:
case VertexAttributeFormat::Float4:
std::memcpy(fdata, cdata, sizeof(float) * 4);
result = celutil::writeLE<float>(out, fdata[0])
&& celutil::writeLE<float>(out, fdata[1])
&& celutil::writeLE<float>(out, fdata[2])
&& celutil::writeLE<float>(out, fdata[3]);
break;
case Mesh::UByte4:
case VertexAttributeFormat::UByte4:
result = out.write(cdata, 4).good();
break;
default:
@ -1817,14 +1896,14 @@ BinaryModelWriter::writeVertices(const void* vertexData,
bool
BinaryModelWriter::writeVertexDescription(const Mesh::VertexDescription& desc)
BinaryModelWriter::writeVertexDescription(const VertexDescription& desc)
{
if (!writeToken(out, CMOD_VertexDesc)) { return false; }
for (unsigned int attr = 0; attr < desc.nAttributes; attr++)
{
if (!celutil::writeLE<std::int16_t>(out, desc.attributes[attr].semantic)
|| !celutil::writeLE<std::int16_t>(out, desc.attributes[attr].format))
if (!celutil::writeLE<std::int16_t>(out, static_cast<std::int16_t>(desc.attributes[attr].semantic))
|| !celutil::writeLE<std::int16_t>(out, static_cast<std::int16_t>(desc.attributes[attr].format)))
{
return false;
}
@ -1870,12 +1949,13 @@ BinaryModelWriter::writeMaterial(const Material& material)
}
if (material.blend != DefaultBlend
&& (!writeToken(out, CMOD_Blend) || !celutil::writeLE<std::int16_t>(out, material.blend)))
&& (!writeToken(out, CMOD_Blend)
|| !celutil::writeLE<std::int16_t>(out, static_cast<std::int16_t>(material.blend))))
{
return false;
}
for (int i = 0; i < Material::TextureSemanticMax; i++)
for (int i = 0; i < static_cast<int>(TextureSemantic::TextureSemanticMax); i++)
{
if (material.maps[i] != InvalidResource)
{

View File

@ -47,7 +47,7 @@ template<class T> class ResourceManager
public:
ResourceManager();
ResourceManager(const fs::path& _baseDir) : baseDir(_baseDir) {};
~ResourceManager();
~ResourceManager() = default;
typedef typename T::ResourceType ResourceType;

View File

@ -9,28 +9,21 @@
//
// Convert a 3DS file to a Celestia mesh (.cmod) file
#include "convert3ds.h"
#include "cmodops.h"
#include <celmodel/modelfile.h>
#include <cel3ds/3dsread.h>
#include <celmath/mathlib.h>
#include <cstring>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <memory>
#include <string>
#include <cel3ds/3dsread.h>
#include <celmath/mathlib.h>
#include "cmodops.h"
#include "convert3ds.h"
#include "pathmanager.h"
using namespace cmod;
using namespace std;
using namespace celmath;
void usage()
{
cerr << "Usage: 3dstocmod <input 3ds file>\n";
std::cerr << "Usage: 3dstocmod <input 3ds file>\n";
}
@ -42,60 +35,48 @@ int main(int argc, char* argv[])
return 1;
}
string inputFileName = argv[1];
std::string inputFileName = argv[1];
cerr << "Reading...\n";
std::cerr << "Reading...\n";
std::unique_ptr<M3DScene> scene = Read3DSFile(inputFileName);
if (scene == nullptr)
{
cerr << "Error reading 3DS file '" << inputFileName << "'\n";
std::cerr << "Error reading 3DS file '" << inputFileName << "'\n";
return 1;
}
cerr << "Converting...\n";
Model* model = Convert3DSModel(*scene, GetPathManager()->getHandle);
std::cerr << "Converting...\n";
cmod::Model* model = Convert3DSModel(*scene, GetPathManager()->getHandle);
if (!model)
{
cerr << "Error converting 3DS file to Celestia model\n";
std::cerr << "Error converting 3DS file to Celestia model\n";
return 1;
}
// Generate normals for the model
double smoothAngle = 45.0; // degrees
float smoothAngle = 45.0; // degrees
double weldTolerance = 1.0e-6;
bool weldVertices = true;
Model* newModel = GenerateModelNormals(*model, (float)degToRad(smoothAngle), weldVertices, weldTolerance);
cmod::Model* newModel = GenerateModelNormals(*model, celmath::degToRad(smoothAngle), weldVertices, weldTolerance);
delete model;
if (!newModel)
{
cerr << "Ran out of memory while generating surface normals.\n";
std::cerr << "Ran out of memory while generating surface normals.\n";
return 1;
}
// Automatically uniquify vertices
for (unsigned int i = 0; newModel->getMesh(i) != nullptr; i++)
{
Mesh* mesh = newModel->getMesh(i);
cmod::Mesh* mesh = newModel->getMesh(i);
UniquifyVertices(*mesh);
}
model = newModel;
#if 0
// Print information about primitive groups
for (uint32_t i = 0; model->getMesh(i); i++)
{
const Mesh* mesh = model->getMesh(i);
for (uint32_t j = 0; mesh->getGroup(j); j++)
{
const Mesh::PrimitiveGroup* group = mesh->getGroup(j);
}
}
#endif
SaveModelAscii(model, cout, GetPathManager()->getSource);
SaveModelAscii(model, std::cout, GetPathManager()->getSource);
return 0;
}

View File

@ -9,8 +9,7 @@
//
// C++ wrapper for OpenGL framebuffer objects.
#ifndef _GLFRAMEBUFFER_H_
#define _GLFRAMEBUFFER_H_
#pragma once
#include "glsupport.h"
@ -57,5 +56,3 @@ private:
GLuint m_fboId;
GLenum m_status;
};
#endif // _GLFRAMEBUFFER_H_

View File

@ -9,10 +9,13 @@
//
// C++ wrapper for OpenGL shaders and shader programs
#include "glsupport.h"
#include <Eigen/Core>
#pragma once
#include <string>
#include <Eigen/Core>
#include "glsupport.h"
class GLVertexShader;
class GLFragmentShader;

View File

@ -9,38 +9,74 @@
// of the License, or (at your option) any later version.
#include <fstream>
#include <iostream>
#include <memory>
#include "mainwindow.h"
#include "materialwidget.h"
#include <string>
#include <QActionGroup>
#include <QColor>
#include <QColorDialog>
#include <QDialog>
#include <QDialogButtonBox>
#include <QDir>
#include <QDockWidget>
#include <QDoubleValidator>
#include <QFileDialog>
#include <QFileInfo>
#include <QFileOpenEvent>
#include <QFormLayout>
#include <QKeySequence>
#include <QLineEdit>
#include <QMenu>
#include <QMenuBar>
#include <QMessageBox>
#include <QSetIterator>
#include <QSettings>
#include <QStatusBar>
#include <QVBoxLayout>
#include <cel3ds/3dsmodel.h>
#include <cel3ds/3dsread.h>
#include <celmodel/material.h>
#include <celmodel/mesh.h>
#include <celmodel/model.h>
#include <celmodel/modelfile.h>
#include "cmodops.h"
#include "convert3ds.h"
#include "convertobj.h"
#include "cmodops.h"
#include "pathmanager.h"
#include <cel3ds/3dsread.h>
#include <celmodel/modelfile.h>
#include <QStatusBar>
#include <QMenuBar>
#include <QSettings>
#include <QDockWidget>
#include <QEvent>
#include <QMessageBox>
#include <QCloseEvent>
#include <QFileOpenEvent>
#include <QFileInfo>
#include <QVBoxLayout>
#include <QDialogButtonBox>
#include <QColorDialog>
#include <QDir>
#include <QFileDialog>
#include <QFormLayout>
using namespace cmod;
using namespace std;
#include "glshader.h"
#include "glsupport.h"
#include "materialwidget.h"
#include "mainwindow.h"
#include "modelviewwidget.h"
namespace
{
// Version number for saving/restoring widget layout state. Increment this
// value whenever new tool widgets are added or removed.
static const 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
MainWindow::MainWindow() :
@ -214,20 +250,7 @@ void MainWindow::initializeGL()
}
}
static Material*
cloneMaterial(const Material* other)
{
Material* material = new 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;
}
bool
@ -254,7 +277,7 @@ MainWindow::eventFilter(QObject* obj, QEvent* e)
void
MainWindow::setModel(const QString& fileName, Model* model)
MainWindow::setModel(const QString& fileName, cmod::Model* model)
{
QFileInfo info(fileName);
QString modelDir = info.absoluteDir().path();
@ -277,7 +300,7 @@ MainWindow::setModel(const QString& fileName, Model* model)
void
MainWindow::showModelStatistics()
{
Model* model = m_modelView->model();
cmod::Model* model = m_modelView->model();
if (model)
{
// Count triangles and vertices in the mesh
@ -285,18 +308,18 @@ MainWindow::showModelStatistics()
unsigned int triangleCount = 0;
for (unsigned int meshIndex = 0; meshIndex < model->getMeshCount(); ++meshIndex)
{
const Mesh* mesh = model->getMesh(meshIndex);
const cmod::Mesh* mesh = model->getMesh(meshIndex);
vertexCount += mesh->getVertexCount();
for (unsigned int groupIndex = 0; groupIndex < mesh->getGroupCount(); ++groupIndex)
{
const Mesh::PrimitiveGroup* group = mesh->getGroup(groupIndex);
const cmod::PrimitiveGroup* group = mesh->getGroup(groupIndex);
switch (group->prim)
{
case Mesh::TriList:
case cmod::PrimitiveGroupType::TriList:
triangleCount += group->nIndices / 3;
break;
case Mesh::TriFan:
case Mesh::TriStrip:
case cmod::PrimitiveGroupType::TriFan:
case cmod::PrimitiveGroupType::TriStrip:
triangleCount += group->nIndices - 2;
break;
default:
@ -373,7 +396,7 @@ MainWindow::openModel(const QString& fileName)
{
if (!fileName.isEmpty())
{
string fileNameStd = string(fileName.toUtf8().data());
std::string fileNameStd = std::string(fileName.toUtf8().data());
QFileInfo info(fileName);
GetPathManager()->reset();
@ -387,7 +410,7 @@ MainWindow::openModel(const QString& fileName)
return;
}
Model* model = Convert3DSModel(*scene, GetPathManager()->getHandle);
cmod::Model* model = Convert3DSModel(*scene, GetPathManager()->getHandle);
if (model == nullptr)
{
QMessageBox::warning(this, "Load error", tr("Internal error converting 3DS file %1").arg(fileName));
@ -395,11 +418,11 @@ MainWindow::openModel(const QString& fileName)
}
// Generate normals for the model
double smoothAngle = 45.0; // degrees
float smoothAngle = 45.0; // degrees
double weldTolerance = 1.0e-6;
bool weldVertices = true;
Model* newModel = GenerateModelNormals(*model, float(smoothAngle * 3.14159265 / 180.0), weldVertices, weldTolerance);
cmod::Model* newModel = GenerateModelNormals(*model, celmath::degToRad(smoothAngle), weldVertices, weldTolerance);
delete model;
if (!newModel)
@ -411,7 +434,7 @@ MainWindow::openModel(const QString& fileName)
// Automatically uniquify vertices
for (unsigned int i = 0; newModel->getMesh(i) != nullptr; i++)
{
Mesh* mesh = newModel->getMesh(i);
cmod::Mesh* mesh = newModel->getMesh(i);
UniquifyVertices(*mesh);
}
@ -420,8 +443,8 @@ MainWindow::openModel(const QString& fileName)
}
else if (info.suffix().toLower() == "obj")
{
Model* model = nullptr;
ifstream in(fileNameStd, ios::in | ios::binary);
cmod::Model* model = nullptr;
std::ifstream in(fileNameStd, std::ios::in | std::ios::binary);
if (!in.good())
{
QMessageBox::warning(this, "Load error", tr("Error opening obj file %1").arg(fileName));
@ -440,7 +463,7 @@ MainWindow::openModel(const QString& fileName)
// Automatically uniquify vertices
for (unsigned int i = 0; model->getMesh(i) != nullptr; i++)
{
Mesh* mesh = model->getMesh(i);
cmod::Mesh* mesh = model->getMesh(i);
UniquifyVertices(*mesh);
}
@ -448,15 +471,15 @@ MainWindow::openModel(const QString& fileName)
}
else if (info.suffix().toLower() == "cmod")
{
Model* model = nullptr;
ifstream in(fileNameStd, ios::in | ios::binary);
cmod::Model* model = nullptr;
std::ifstream in(fileNameStd, std::ios::in | std::ios::binary);
if (!in.good())
{
QMessageBox::warning(this, "Load error", tr("Error opening CMOD file %1").arg(fileName));
return;
}
model = LoadModel(in, GetPathManager()->getHandle);
model = cmod::LoadModel(in, GetPathManager()->getHandle);
if (model == nullptr)
{
QMessageBox::warning(this, "Load error", tr("Error reading CMOD file %1").arg(fileName));
@ -498,9 +521,9 @@ MainWindow::saveModelAs()
void
MainWindow::saveModel(const QString& saveFileName)
{
string fileNameStd = string(saveFileName.toUtf8().data());
std::string fileNameStd = std::string(saveFileName.toUtf8().data());
ofstream out(fileNameStd, ios::out | ios::binary);
std::ofstream out(fileNameStd, std::ios::out | std::ios::binary);
bool ok = false;
if (out.good())
{
@ -557,7 +580,7 @@ MainWindow::setRenderPath(QAction* action)
void
MainWindow::generateNormals()
{
Model* model = m_modelView->model();
cmod::Model* model = m_modelView->model();
if (!model)
{
return;
@ -597,11 +620,14 @@ MainWindow::generateNormals()
if (dialog.exec() == QDialog::Accepted)
{
double smoothAngle = smoothAngleEdit->text().toDouble();
float smoothAngle = smoothAngleEdit->text().toFloat();
double weldTolerance = toleranceEdit->text().toDouble();
bool weldVertices = true;
Model* newModel = GenerateModelNormals(*model, float(smoothAngle * 3.14159265 / 180.0), weldVertices, weldTolerance);
cmod::Model* newModel = GenerateModelNormals(*model,
celmath::degToRad(smoothAngle),
weldVertices,
weldTolerance);
if (!newModel)
{
QMessageBox::warning(this, tr("Internal Error"), tr("Out of memory error during normal generation"));
@ -620,7 +646,7 @@ MainWindow::generateNormals()
void
MainWindow::generateTangents()
{
Model* model = m_modelView->model();
cmod::Model* model = m_modelView->model();
if (!model)
{
return;
@ -652,7 +678,7 @@ MainWindow::generateTangents()
double weldTolerance = toleranceEdit->text().toDouble();
bool weldVertices = true;
Model* newModel = new Model();
cmod::Model* newModel = new cmod::Model();
// Copy materials
for (unsigned int i = 0; model->getMaterial(i) != nullptr; i++)
@ -662,13 +688,13 @@ MainWindow::generateTangents()
for (unsigned int i = 0; model->getMesh(i) != nullptr; i++)
{
Mesh* mesh = model->getMesh(i);
Mesh* newMesh = nullptr;
cmod::Mesh* mesh = model->getMesh(i);
cmod::Mesh* newMesh = nullptr;
newMesh = GenerateTangents(*mesh, weldVertices);
if (newMesh == nullptr)
{
cerr << "Error generating normals!\n";
std::cerr << "Error generating normals!\n";
// TODO: Clone the mesh and add it to the model
}
else
@ -687,7 +713,7 @@ MainWindow::generateTangents()
void
MainWindow::uniquifyVertices()
{
Model* model = m_modelView->model();
cmod::Model* model = m_modelView->model();
if (!model)
{
return;
@ -695,7 +721,7 @@ MainWindow::uniquifyVertices()
for (unsigned int i = 0; model->getMesh(i) != nullptr; i++)
{
Mesh* mesh = model->getMesh(i);
cmod::Mesh* mesh = model->getMesh(i);
UniquifyVertices(*mesh);
}
@ -707,13 +733,13 @@ MainWindow::uniquifyVertices()
void
MainWindow::mergeMeshes()
{
Model* model = m_modelView->model();
cmod::Model* model = m_modelView->model();
if (!model)
{
return;
}
Model* newModel = MergeModelMeshes(*model);
cmod::Model* newModel = MergeModelMeshes(*model);
setModel(modelFileName(), newModel);
}
@ -728,9 +754,9 @@ MainWindow::updateSelectionInfo()
else
{
m_materialWidget->setEnabled(true);
QSetIterator<Mesh::PrimitiveGroup*> iter(m_modelView->selection());
Mesh::PrimitiveGroup* selectedGroup = iter.next();
const Material* material = m_modelView->model()->getMaterial(selectedGroup->materialIndex);
QSetIterator<cmod::PrimitiveGroup*> iter(m_modelView->selection());
cmod::PrimitiveGroup* selectedGroup = iter.next();
const cmod::Material* material = m_modelView->model()->getMaterial(selectedGroup->materialIndex);
if (material)
{
m_materialWidget->setMaterial(*material);
@ -740,12 +766,12 @@ MainWindow::updateSelectionInfo()
void
MainWindow::changeCurrentMaterial(const Material& material)
MainWindow::changeCurrentMaterial(const cmod::Material& material)
{
if (!m_modelView->selection().isEmpty())
{
QSetIterator<Mesh::PrimitiveGroup*> iter(m_modelView->selection());
Mesh::PrimitiveGroup* selectedGroup = iter.next();
QSetIterator<cmod::PrimitiveGroup*> iter(m_modelView->selection());
cmod::PrimitiveGroup* selectedGroup = iter.next();
m_modelView->setMaterial(selectedGroup->materialIndex, material);
}
}

View File

@ -8,17 +8,26 @@
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#ifndef _CMODVIEW_MAINWINDOW_H_
#define _CMODVIEW_MAINWINDOW_H_
#pragma once
#include "modelviewwidget.h"
#include "materialwidget.h"
#include <QMainWindow>
#include <QString>
#include <QLabel>
#include <QAction>
#include <QCloseEvent>
#include <QEvent>
#include <QLabel>
#include <QMainWindow>
#include <QObject>
#include <QString>
class MaterialWidget;
class ModelViewWidget;
namespace cmod
{
class Material;
class Model;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
@ -73,6 +82,3 @@ private:
QAction* m_saveAsAction;
QAction* m_gl2Action;
};
#endif // _CMODVIEW_MAINWINDOW_H_

View File

@ -7,31 +7,36 @@
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#include "glsupport.h"
#include "materialwidget.h"
#include "pathmanager.h"
#include <celmodel/material.h>
#include <QGridLayout>
#include <QPushButton>
#include <QColorDialog>
#include <QDir>
#include <QGridLayout>
#include <QPushButton>
#include <QSet>
#include <QStringList>
using namespace cmod;
#include "pathmanager.h"
#include "materialwidget.h"
static QColor toQtColor(const Material::Color& color)
namespace
{
return QColor((int) (color.red() * 255.99f), (int) (color.green() * 255.99f), (int) (color.blue() * 255.99f));
QColor toQtColor(const cmod::Color& color)
{
return QColor(static_cast<int>(color.red() * 255.99f),
static_cast<int>(color.green() * 255.99f),
static_cast<int>(color.blue() * 255.99f));
}
static Material::Color fromQtColor(const QColor& color)
cmod::Color fromQtColor(const QColor& color)
{
return Material::Color(color.redF(), color.greenF(), color.blueF());
return cmod::Color(color.redF(), color.greenF(), color.blueF());
}
// TODO: implement a copy constructor and assignment operator for materials
static void copyMaterial(Material& dest, const Material& src)
void copyMaterial(cmod::Material& dest, const cmod::Material& src)
{
dest.diffuse = src.diffuse;
dest.specular = src.specular;
@ -43,7 +48,7 @@ static void copyMaterial(Material& dest, const Material& src)
}
static void setWidgetColor(QLabel* widget, const Material::Color& color)
static void setWidgetColor(QLabel* widget, const cmod::Color& color)
{
widget->setPalette(QPalette(toQtColor(color)));
widget->setAutoFillBackground(true);
@ -51,6 +56,54 @@ static void setWidgetColor(QLabel* widget, const Material::Color& color)
}
inline QString toQString(const wchar_t *s)
{
return QString::fromWCharArray(s);
}
inline QString toQString(const char *s)
{
return QString::fromLocal8Bit(s);
}
void selectComboBoxItem(QComboBox* combo, const QString &text)
{
int itemIndex = combo->findText(text);
if (itemIndex < 0)
{
combo->addItem(text, text);
itemIndex = combo->count() - 1;
}
combo->setCurrentIndex(itemIndex);
}
void selectComboBoxItem(QComboBox* combo, const fs::path &path)
{
selectComboBoxItem(combo, toQString(path.c_str()));
}
// Return a list of all texture filenames in the specified folder
QSet<QString> listTextures(QDir& dir)
{
QStringList filters;
filters << "*.png" << "*.jpg" << "*.dds" << "*.dxt5nm";
QStringList textureFileNames = dir.entryList(filters, QDir::Files);
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
return QSet<QString>(textureFileNames.begin(), textureFileNames.end());
#else
return QSet<QString>::fromList(textureFileNames);
#endif
}
} // end unnamed namespace
MaterialWidget::MaterialWidget(QWidget* parent) :
QWidget(parent)
@ -131,40 +184,14 @@ MaterialWidget::MaterialWidget(QWidget* parent) :
connect(m_normalMap, SIGNAL(activated(int)), this, SLOT(changeMaterialParameters()));
connect(m_emissiveMap, SIGNAL(activated(int)), this, SLOT(changeMaterialParameters()));
setMaterial(Material());
setMaterial(cmod::Material());
this->setLayout(layout);
}
inline QString toQString(const wchar_t *s)
{
return QString::fromWCharArray(s);
}
inline QString toQString(const char *s)
{
return QString::fromLocal8Bit(s);
}
static void selectComboBoxItem(QComboBox* combo, const QString &text)
{
int itemIndex = combo->findText(text);
if (itemIndex < 0)
{
combo->addItem(text, text);
itemIndex = combo->count() - 1;
}
combo->setCurrentIndex(itemIndex);
}
static void selectComboBoxItem(QComboBox* combo, const fs::path &path)
{
selectComboBoxItem(combo, toQString(path.c_str()));
}
void
MaterialWidget::setMaterial(const Material& material)
MaterialWidget::setMaterial(const cmod::Material& material)
{
copyMaterial(m_material, material);
@ -174,20 +201,20 @@ MaterialWidget::setMaterial(const Material& material)
m_opacity->setText(QString::number(m_material.opacity));
m_specularPower->setText(QString::number(m_material.specularPower));
if (m_material.maps[Material::DiffuseMap] != InvalidResource)
selectComboBoxItem(m_baseTexture, GetPathManager()->getSource(m_material.maps[Material::DiffuseMap]));
if (m_material.getMap(cmod::TextureSemantic::DiffuseMap) != InvalidResource)
selectComboBoxItem(m_baseTexture, GetPathManager()->getSource(m_material.getMap(cmod::TextureSemantic::DiffuseMap)));
else
m_baseTexture->setCurrentIndex(0);
if (m_material.maps[Material::SpecularMap] != InvalidResource)
selectComboBoxItem(m_specularMap, GetPathManager()->getSource(m_material.maps[Material::SpecularMap]));
if (m_material.getMap(cmod::TextureSemantic::SpecularMap) != InvalidResource)
selectComboBoxItem(m_specularMap, GetPathManager()->getSource(m_material.getMap(cmod::TextureSemantic::SpecularMap)));
else
m_specularMap->setCurrentIndex(0);
if (m_material.maps[Material::EmissiveMap] != InvalidResource)
selectComboBoxItem(m_emissiveMap, GetPathManager()->getSource(m_material.maps[Material::EmissiveMap]));
if (m_material.getMap(cmod::TextureSemantic::EmissiveMap) != InvalidResource)
selectComboBoxItem(m_emissiveMap, GetPathManager()->getSource(m_material.getMap(cmod::TextureSemantic::EmissiveMap)));
else
m_emissiveMap->setCurrentIndex(0);
if (m_material.maps[Material::NormalMap] != InvalidResource)
selectComboBoxItem(m_normalMap, GetPathManager()->getSource(m_material.maps[Material::NormalMap]));
if (m_material.getMap(cmod::TextureSemantic::NormalMap) != InvalidResource)
selectComboBoxItem(m_normalMap, GetPathManager()->getSource(m_material.getMap(cmod::TextureSemantic::NormalMap)));
else
m_normalMap->setCurrentIndex(0);
@ -279,48 +306,34 @@ MaterialWidget::changeMaterialParameters()
m_material.opacity = m_opacity->text().toFloat();
m_material.specularPower = m_specularPower->text().toFloat();
m_material.maps[Material::DiffuseMap] = InvalidResource;
m_material.setMap(cmod::TextureSemantic::DiffuseMap, InvalidResource);
if (!m_baseTexture->itemData(m_baseTexture->currentIndex()).isNull())
{
m_material.maps[Material::DiffuseMap] = GetPathManager()->getHandle(m_baseTexture->currentText().toStdString());
m_material.setMap(cmod::TextureSemantic::DiffuseMap, GetPathManager()->getHandle(m_baseTexture->currentText().toStdString()));
}
m_material.maps[Material::SpecularMap] = InvalidResource;
m_material.setMap(cmod::TextureSemantic::SpecularMap, InvalidResource);
if (!m_specularMap->itemData(m_specularMap->currentIndex()).isNull())
{
m_material.maps[Material::SpecularMap] = GetPathManager()->getHandle(m_specularMap->currentText().toStdString());
m_material.setMap(cmod::TextureSemantic::SpecularMap, GetPathManager()->getHandle(m_specularMap->currentText().toStdString()));
}
m_material.maps[Material::NormalMap] = InvalidResource;
m_material.setMap(cmod::TextureSemantic::NormalMap, InvalidResource);
if (!m_normalMap->itemData(m_normalMap->currentIndex()).isNull())
{
m_material.maps[Material::NormalMap] = GetPathManager()->getHandle(m_normalMap->currentText().toStdString());
m_material.setMap(cmod::TextureSemantic::NormalMap, GetPathManager()->getHandle(m_normalMap->currentText().toStdString()));
}
m_material.maps[Material::EmissiveMap] = InvalidResource;
m_material.setMap(cmod::TextureSemantic::EmissiveMap, InvalidResource);
if (!m_emissiveMap->itemData(m_emissiveMap->currentIndex()).isNull())
{
m_material.maps[Material::EmissiveMap] = GetPathManager()->getHandle(m_emissiveMap->currentText().toStdString());
m_material.setMap(cmod::TextureSemantic::EmissiveMap, GetPathManager()->getHandle(m_emissiveMap->currentText().toStdString()));
}
emit materialEdited(m_material);
}
// Return a list of all texture filenames in the specified folder
static QSet<QString> listTextures(QDir& dir)
{
QStringList filters;
filters << "*.png" << "*.jpg" << "*.dds" << "*.dxt5nm";
QStringList textureFileNames = dir.entryList(filters, QDir::Files);
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
return QSet<QString>(textureFileNames.begin(), textureFileNames.end());
#else
return QSet<QString>::fromList(textureFileNames);
#endif
}
void
MaterialWidget::setTextureSearchPath(const QString& path)
{

View File

@ -7,14 +7,17 @@
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#ifndef _CMODVIEW_MATERIAL_WIDGET_H_
#define _CMODVIEW_MATERIAL_WIDGET_H_
#pragma once
#include <celmodel/material.h>
#include <QWidget>
#include <QColor>
#include <QComboBox>
#include <QLabel>
#include <QLineEdit>
#include <QComboBox>
#include <QObject>
#include <QString>
#include <QWidget>
#include <celmodel/material.h>
class MaterialWidget : public QWidget
@ -66,5 +69,3 @@ private:
cmod::Material m_material;
};
#endif // _CMODVIEW_MATERIAL_WIDGET_H_

View File

@ -8,30 +8,37 @@
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#include "glsupport.h"
#include "modelviewwidget.h"
#include "glframebuffer.h"
#include "pathmanager.h"
#include <QFileInfo>
#include <QGLWidget>
#include <QMouseEvent>
#include <QTextStream>
#include <Eigen/LU>
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <iostream>
using namespace celestia;
using namespace cmod;
using namespace Eigen;
#include <QFileInfo>
#include <QIODevice>
#include <QMap>
#include <QPixmap>
#include <QTextStream>
#include <celmath/mathlib.h>
#include <celmodel/model.h>
#include "pathmanager.h"
#include "glframebuffer.h"
#include "glshader.h"
#include "glsupport.h"
#include "modelviewwidget.h"
#define DEBUG_SHADOWS 0
static const float VIEWPORT_FOV = 45.0;
//static const double PI = 3.1415926535897932;
namespace
{
static const int ShadowBufferSize = 1024;
static const int ShadowSampleKernelWidth = 2;
constexpr float VIEWPORT_FOV = 45.0;
constexpr int ShadowBufferSize = 1024;
constexpr int ShadowSampleKernelWidth = 2;
enum {
@ -45,11 +52,59 @@ inline QString toQString(const wchar_t *s)
return QString::fromWCharArray(s);
}
inline QString toQString(const char *s)
{
return QString::fromLocal8Bit(s);
}
// Calculate the matrix used to render the model from the
// perspective of the light.
Eigen::Matrix4f
directionalLightMatrix(const Eigen::Vector3f& lightDirection)
{
Eigen::Vector3f viewDir = lightDirection;
Eigen::Vector3f upDir = viewDir.unitOrthogonal();
Eigen::Vector3f rightDir = upDir.cross(viewDir);
Eigen::Matrix4f m = Eigen::Matrix4f::Identity();
m.row(0).head(3) = rightDir;
m.row(1).head(3) = upDir;
m.row(2).head(3) = viewDir;
return m;
}
Eigen::Matrix4f
parallelProjectionMatrix(float left, float right, float bottom, float top, float zNear, float zFar)
{
// Duplicates OpenGL's glOrtho() function
Eigen::Matrix4f m = Eigen::Matrix4f::Identity();
m.diagonal() = Eigen::Vector4f(2.0f / (right - left),
2.0f / (top - bottom),
-2.0f / (zFar - zNear),
1.0f);
m.col(3) = Eigen::Vector4f(-(right + left) / (right - left),
-(top + bottom) / (top - bottom),
-(zFar + zNear) / (zFar - zNear),
1.0f);
return m;
}
Eigen::Matrix4f
shadowProjectionMatrix(float objectRadius)
{
return parallelProjectionMatrix(-objectRadius, objectRadius,
-objectRadius, objectRadius,
-objectRadius, objectRadius);
}
} // end unnamed namespace
class MaterialLibrary
{
public:
@ -141,7 +196,7 @@ private:
ShaderKey
ShaderKey::Create(const Material* material, const LightingEnvironment* lighting, const Mesh::VertexDescription* vertexDesc)
ShaderKey::Create(const cmod::Material* material, const LightingEnvironment* lighting, const cmod::VertexDescription* vertexDesc)
{
// Compute the shader key for a particular material and lighting setup
unsigned int info = 0;
@ -150,8 +205,8 @@ ShaderKey::Create(const Material* material, const LightingEnvironment* lighting,
bool hasTexCoords = false;
if (vertexDesc)
{
hasTangents = vertexDesc->getAttribute(Mesh::Tangent).format == Mesh::Float3;
hasTexCoords = vertexDesc->getAttribute(Mesh::Texture0).format == Mesh::Float2;
hasTangents = vertexDesc->getAttribute(cmod::VertexAttributeSemantic::Tangent).format == cmod::VertexAttributeFormat::Float3;
hasTexCoords = vertexDesc->getAttribute(cmod::VertexAttributeSemantic::Texture0).format == cmod::VertexAttributeFormat::Float2;
}
// Bits 0-3 are the number of light sources
@ -172,30 +227,30 @@ ShaderKey::Create(const Material* material, const LightingEnvironment* lighting,
// Bits 8-15 are texture map info
if (hasTexCoords)
{
if (material->maps[Material::DiffuseMap] != InvalidResource)
if (material->getMap(cmod::TextureSemantic::DiffuseMap) != InvalidResource)
{
info |= DiffuseMapMask;
}
if (material->maps[Material::SpecularMap] != InvalidResource)
if (material->getMap(cmod::TextureSemantic::SpecularMap) != InvalidResource)
{
info |= SpecularMapMask;
}
if (material->maps[Material::NormalMap] != InvalidResource)
if (material->getMap(cmod::TextureSemantic::NormalMap) != InvalidResource)
{
info |= NormalMapMask;
}
if (material->maps[Material::EmissiveMap] != InvalidResource)
if (material->getMap(cmod::TextureSemantic::EmissiveMap) != InvalidResource)
{
info |= EmissiveMapMask;
}
// Bit 16 is set if the normal map is compressed
if (material->maps[Material::NormalMap] != InvalidResource && hasTangents)
if (material->getMap(cmod::TextureSemantic::NormalMap) != InvalidResource && hasTangents)
{
if (GetPathManager()->getSource(material->maps[Material::NormalMap]).extension() == ".dxt5nm")
if (GetPathManager()->getSource(material->getMap(cmod::TextureSemantic::NormalMap)).extension() == ".dxt5nm")
{
info |= CompressedNormalMapMask;
}
@ -206,60 +261,16 @@ ShaderKey::Create(const Material* material, const LightingEnvironment* lighting,
}
// Calculate the matrix used to render the model from the
// perspective of the light.
static
Matrix4f directionalLightMatrix(const Vector3f& lightDirection)
{
Vector3f viewDir = lightDirection;
Vector3f upDir = viewDir.unitOrthogonal();
Vector3f rightDir = upDir.cross(viewDir);
Matrix4f m = Matrix4f::Identity();
m.row(0).head(3) = rightDir;
m.row(1).head(3) = upDir;
m.row(2).head(3) = viewDir;
return m;
}
static
Matrix4f parallelProjectionMatrix(float left, float right, float bottom, float top, float zNear, float zFar)
{
// Duplicates OpenGL's glOrtho() function
Matrix4f m = Matrix4f::Identity();
m.diagonal() = Vector4f(2.0f / (right - left),
2.0f / (top - bottom),
-2.0f / (zFar - zNear),
1.0f);
m.col(3) = Vector4f(-(right + left) / (right - left),
-(top + bottom) / (top - bottom),
-(zFar + zNear) / (zFar - zNear),
1.0f);
return m;
}
static
Matrix4f shadowProjectionMatrix(float objectRadius)
{
return parallelProjectionMatrix(-objectRadius, objectRadius,
-objectRadius, objectRadius,
-objectRadius, objectRadius);
}
ModelViewWidget::ModelViewWidget(QWidget *parent) :
QGLWidget(parent),
m_model(nullptr),
m_modelBoundingRadius(1.0),
m_cameraPosition(Vector3d::Zero()),
m_cameraOrientation(Quaterniond::Identity()),
m_cameraPosition(Eigen::Vector3d::Zero()),
m_cameraOrientation(Eigen::Quaterniond::Identity()),
m_renderStyle(NormalStyle),
m_renderPath(FixedFunctionPath),
m_materialLibrary(nullptr),
m_lightOrientation(Quaterniond::Identity()),
m_lightOrientation(Eigen::Quaterniond::Identity()),
m_lightingEnabled(true),
m_ambientLightEnabled(true),
m_shadowsEnabled(false)
@ -294,26 +305,26 @@ ModelViewWidget::setModel(cmod::Model* model, const QString& modelDirPath)
{
for (unsigned int i = 0; i < m_model->getMaterialCount(); ++i)
{
const Material* material = m_model->getMaterial(i);
if (material->maps[Material::DiffuseMap] != InvalidResource)
const cmod::Material* material = m_model->getMaterial(i);
if (material->getMap(cmod::TextureSemantic::DiffuseMap) != InvalidResource)
{
m_materialLibrary->getTexture(
toQString(GetPathManager()->getSource(material->maps[Material::DiffuseMap]).c_str()));
toQString(GetPathManager()->getSource(material->getMap(cmod::TextureSemantic::DiffuseMap)).c_str()));
}
if (material->maps[Material::NormalMap] != InvalidResource)
if (material->getMap(cmod::TextureSemantic::NormalMap) != InvalidResource)
{
m_materialLibrary->getTexture(
toQString(GetPathManager()->getSource(material->maps[Material::NormalMap]).c_str()));
toQString(GetPathManager()->getSource(material->getMap(cmod::TextureSemantic::NormalMap)).c_str()));
}
if (material->maps[Material::SpecularMap] != InvalidResource)
if (material->getMap(cmod::TextureSemantic::SpecularMap) != InvalidResource)
{
m_materialLibrary->getTexture(
toQString(GetPathManager()->getSource(material->maps[Material::SpecularMap]).c_str()));
toQString(GetPathManager()->getSource(material->getMap(cmod::TextureSemantic::SpecularMap)).c_str()));
}
if (material->maps[Material::EmissiveMap] != InvalidResource)
if (material->getMap(cmod::TextureSemantic::EmissiveMap) != InvalidResource)
{
m_materialLibrary->getTexture(
toQString(GetPathManager()->getSource(material->maps[Material::EmissiveMap]).c_str()));
toQString(GetPathManager()->getSource(material->getMap(cmod::TextureSemantic::EmissiveMap)).c_str()));
}
}
}
@ -327,7 +338,7 @@ ModelViewWidget::setModel(cmod::Model* model, const QString& modelDirPath)
void
ModelViewWidget::resetCamera()
{
AlignedBox<float, 3> bbox;
Eigen::AlignedBox<float, 3> bbox;
if (m_model != nullptr)
{
for (unsigned int i = 0; i < m_model->getMeshCount(); ++i)
@ -337,8 +348,8 @@ ModelViewWidget::resetCamera()
}
m_modelBoundingRadius = std::max(bbox.max().norm(), bbox.min().norm());
m_cameraPosition = m_modelBoundingRadius * Vector3d::UnitZ() * 2.0;
m_cameraOrientation = Quaterniond::Identity();
m_cameraPosition = m_modelBoundingRadius * Eigen::Vector3d::UnitZ() * 2.0;
m_cameraOrientation = Eigen::Quaterniond::Identity();
}
@ -378,9 +389,9 @@ ModelViewWidget::mouseReleaseEvent(QMouseEvent* event)
int moveDistance = (event->pos() - m_mouseDownPosition).manhattanLength();
if (moveDistance < 3)
{
float x = (float) event->pos().x() / (float) size().width() * 2.0f - 1.0f;
float y = (float) event->pos().y() / (float) size().height() * -2.0f + 1.0f;
select(Vector2f(x, y));
float x = static_cast<float>(event->pos().x()) / static_cast<float>(size().width()) * 2.0f - 1.0f;
float y = static_cast<float>(event->pos().y()) / static_cast<float>(size().height()) * -2.0f + 1.0f;
select(Eigen::Vector2f(x, y));
}
}
@ -412,20 +423,20 @@ ModelViewWidget::mouseMoveEvent(QMouseEvent *event)
int dx = event->x() - m_lastMousePosition.x();
int dy = event->y() - m_lastMousePosition.y();
double xrotation = (double) dy / 100.0;
double yrotation = (double) dx / 100.0;
Quaterniond q = AngleAxis<double>(-xrotation, Vector3d::UnitX()) *
AngleAxis<double>(-yrotation, Vector3d::UnitY());
double xrotation = static_cast<double>(dy) / 100.0;
double yrotation = static_cast<double>(dx) / 100.0;
Eigen::Quaterniond q = Eigen::AngleAxis<double>(-xrotation, Eigen::Vector3d::UnitX()) *
Eigen::AngleAxis<double>(-yrotation, Eigen::Vector3d::UnitY());
if (rotateLights)
{
Quaterniond r = m_lightOrientation * q * m_lightOrientation.conjugate();
Eigen::Quaterniond r = m_lightOrientation * q * m_lightOrientation.conjugate();
r.normalize();
m_lightOrientation = r * m_lightOrientation;
}
else if (rotateCamera)
{
Quaterniond r = m_cameraOrientation * q * m_cameraOrientation.conjugate();
Eigen::Quaterniond r = m_cameraOrientation * q * m_cameraOrientation.conjugate();
r.normalize(); // guard against accumulating rounding errors
m_cameraPosition = r * m_cameraPosition;
@ -461,22 +472,22 @@ ModelViewWidget::wheelEvent(QWheelEvent* event)
void
ModelViewWidget::select(const Vector2f& viewportPoint)
ModelViewWidget::select(const Eigen::Vector2f& viewportPoint)
{
if (!m_model)
{
return;
}
float aspectRatio = (float) size().width() / (float) size().height();
auto fovRad = float(VIEWPORT_FOV * PI / 180.0f);
float h = (float) tan(fovRad / 2.0f);
Vector3d direction(h * aspectRatio * viewportPoint.x(), h * viewportPoint.y(), -1.0f);
float aspectRatio = static_cast<float>(size().width()) / static_cast<float>(size().height());
auto fovRad = celmath::degToRad(VIEWPORT_FOV);
float h = std::tan(fovRad / 2.0f);
Eigen::Vector3d direction(h * aspectRatio * viewportPoint.x(), h * viewportPoint.y(), -1.0f);
direction.normalize();
Vector3d origin = Vector3d::Zero();
Affine3d camera(cameraTransform().inverse());
Eigen::Vector3d origin = Eigen::Vector3d::Zero();
Eigen::Affine3d camera(cameraTransform().inverse());
Mesh::PickResult pickResult;
cmod::Mesh::PickResult pickResult;
bool hit = m_model->pick(camera * origin, camera.linear() * direction, &pickResult);
if (hit)
{
@ -494,10 +505,10 @@ ModelViewWidget::select(const Vector2f& viewportPoint)
}
Affine3d
Eigen::Affine3d
ModelViewWidget::cameraTransform() const
{
Affine3d t(m_cameraOrientation.conjugate());
Eigen::Affine3d t(m_cameraOrientation.conjugate());
t.translate(-m_cameraPosition);
return t;
}
@ -513,17 +524,17 @@ ModelViewWidget::setMaterial(unsigned int index, const cmod::Material& material)
// Copy material parameters
// TODO: eliminate const cast when Model::setMaterial() is implemented
Material* modelMaterial = const_cast<Material*>(m_model->getMaterial(index));
cmod::Material* modelMaterial = const_cast<cmod::Material*>(m_model->getMaterial(index));
modelMaterial->diffuse = material.diffuse;
modelMaterial->specular = material.specular;
modelMaterial->emissive = material.emissive;
modelMaterial->opacity = material.opacity;
modelMaterial->specularPower = material.specularPower;
modelMaterial->maps[Material::DiffuseMap] = material.maps[Material::DiffuseMap];
modelMaterial->maps[Material::SpecularMap] = material.maps[Material::SpecularMap];
modelMaterial->maps[Material::NormalMap] = material.maps[Material::NormalMap];
modelMaterial->maps[Material::EmissiveMap] = material.maps[Material::EmissiveMap];
modelMaterial->setMap(cmod::TextureSemantic::DiffuseMap, material.getMap(cmod::TextureSemantic::DiffuseMap));
modelMaterial->setMap(cmod::TextureSemantic::SpecularMap, material.getMap(cmod::TextureSemantic::SpecularMap));
modelMaterial->setMap(cmod::TextureSemantic::NormalMap, material.getMap(cmod::TextureSemantic::NormalMap));
modelMaterial->setMap(cmod::TextureSemantic::EmissiveMap, material.getMap(cmod::TextureSemantic::EmissiveMap));
update();
}
@ -539,7 +550,7 @@ ModelViewWidget::setBackgroundColor(const QColor& color)
void
ModelViewWidget::initializeGL()
{
gl::init();
celestia::gl::init();
emit contextCreated();
}
@ -550,8 +561,8 @@ ModelViewWidget::paintGL()
// Generate the shadow buffers for each light source
if (m_shadowsEnabled && m_shadowBuffers.size() > 0)
{
Material defaultMaterial;
defaultMaterial.diffuse = Material::Color(1.0f, 1.0f, 1.0f);
cmod::Material defaultMaterial;
defaultMaterial.diffuse = cmod::Color(1.0f, 1.0f, 1.0f);
LightingEnvironment lightingOff;
bindMaterial(&defaultMaterial, &lightingOff, nullptr);
glEnable(GL_CULL_FACE);
@ -588,7 +599,7 @@ ModelViewWidget::paintGL()
{
ambientLightLevel = 0.2f;
}
Vector4f ambientLight = Vector4f::Constant(ambientLightLevel);
Eigen::Vector4f ambientLight = Eigen::Vector4f::Constant(ambientLightLevel);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight.data());
glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL_EXT, GL_SEPARATE_SPECULAR_COLOR_EXT);
@ -603,10 +614,10 @@ ModelViewWidget::paintGL()
GLenum glLight = GL_LIGHT0 + lightIndex;
lightIndex++;
Vector3d direction = m_lightOrientation * lightSource.direction;
Vector4f lightColor = Vector4f::Zero();
Eigen::Vector3d direction = m_lightOrientation * lightSource.direction;
Eigen::Vector4f lightColor = Eigen::Vector4f::Zero();
lightColor.head(3) = lightSource.color * lightSource.intensity;
Vector4f lightPosition = Vector4f::Zero();
Eigen::Vector4f lightPosition = Eigen::Vector4f::Zero();
lightPosition.head(3) = direction.cast<float>();
glEnable(glLight);
@ -690,7 +701,7 @@ ModelViewWidget::resizeGL(int width, int height)
}
static GLenum GLComponentTypes[Mesh::FormatMax] =
static GLenum GLComponentTypes[static_cast<std::size_t>(cmod::VertexAttributeFormat::FormatMax)] =
{
GL_FLOAT, // Float1
GL_FLOAT, // Float2
@ -699,7 +710,7 @@ static GLenum GLComponentTypes[Mesh::FormatMax] =
GL_UNSIGNED_BYTE, // UByte4
};
static int GLComponentCounts[Mesh::FormatMax] =
static int GLComponentCounts[static_cast<std::size_t>(cmod::VertexAttributeFormat::FormatMax)] =
{
1, // Float1
2, // Float2
@ -710,16 +721,16 @@ static int GLComponentCounts[Mesh::FormatMax] =
static void
setVertexArrays(const Mesh::VertexDescription& desc, const void* vertexData)
setVertexArrays(const cmod::VertexDescription& desc, const void* vertexData)
{
const Mesh::VertexAttribute& position = desc.getAttribute(Mesh::Position);
const Mesh::VertexAttribute& normal = desc.getAttribute(Mesh::Normal);
const Mesh::VertexAttribute& color0 = desc.getAttribute(Mesh::Color0);
const Mesh::VertexAttribute& texCoord0 = desc.getAttribute(Mesh::Texture0);
const Mesh::VertexAttribute& tangent = desc.getAttribute(Mesh::Tangent);
const cmod::VertexAttribute& position = desc.getAttribute(cmod::VertexAttributeSemantic::Position);
const cmod::VertexAttribute& normal = desc.getAttribute(cmod::VertexAttributeSemantic::Normal);
const cmod::VertexAttribute& color0 = desc.getAttribute(cmod::VertexAttributeSemantic::Color0);
const cmod::VertexAttribute& texCoord0 = desc.getAttribute(cmod::VertexAttributeSemantic::Texture0);
const cmod::VertexAttribute& tangent = desc.getAttribute(cmod::VertexAttributeSemantic::Tangent);
// Can't render anything unless we have positions
if (position.format != Mesh::Float3)
if (position.format != cmod::VertexAttributeFormat::Float3)
return;
// Set up the vertex arrays
@ -730,9 +741,9 @@ setVertexArrays(const Mesh::VertexDescription& desc, const void* vertexData)
// Set up the normal array
switch (normal.format)
{
case Mesh::Float3:
case cmod::VertexAttributeFormat::Float3:
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GLComponentTypes[(int) normal.format],
glNormalPointer(GLComponentTypes[static_cast<std::size_t>(normal.format)],
desc.stride,
reinterpret_cast<const char*>(vertexData) + normal.offset);
break;
@ -744,12 +755,12 @@ setVertexArrays(const Mesh::VertexDescription& desc, const void* vertexData)
// Set up the color array
switch (color0.format)
{
case Mesh::Float3:
case Mesh::Float4:
case Mesh::UByte4:
case cmod::VertexAttributeFormat::Float3:
case cmod::VertexAttributeFormat::Float4:
case cmod::VertexAttributeFormat::UByte4:
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(GLComponentCounts[color0.format],
GLComponentTypes[color0.format],
glColorPointer(GLComponentCounts[static_cast<std::size_t>(color0.format)],
GLComponentTypes[static_cast<std::size_t>(color0.format)],
desc.stride,
reinterpret_cast<const char*>(vertexData) + color0.offset);
break;
@ -761,13 +772,13 @@ setVertexArrays(const Mesh::VertexDescription& desc, const void* vertexData)
// Set up the texture coordinate array
switch (texCoord0.format)
{
case Mesh::Float1:
case Mesh::Float2:
case Mesh::Float3:
case Mesh::Float4:
case cmod::VertexAttributeFormat::Float1:
case cmod::VertexAttributeFormat::Float2:
case cmod::VertexAttributeFormat::Float3:
case cmod::VertexAttributeFormat::Float4:
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(GLComponentCounts[(int) texCoord0.format],
GLComponentTypes[(int) texCoord0.format],
glTexCoordPointer(GLComponentCounts[static_cast<std::size_t>(texCoord0.format)],
GLComponentTypes[static_cast<std::size_t>(texCoord0.format)],
desc.stride,
reinterpret_cast<const char*>(vertexData) + texCoord0.offset);
break;
@ -778,11 +789,11 @@ setVertexArrays(const Mesh::VertexDescription& desc, const void* vertexData)
switch (tangent.format)
{
case Mesh::Float3:
case cmod::VertexAttributeFormat::Float3:
glEnableVertexAttribArrayARB(TangentAttributeIndex);
glVertexAttribPointerARB(TangentAttributeIndex,
GLComponentCounts[(int) tangent.format],
GLComponentTypes[(int) tangent.format],
GLComponentCounts[static_cast<std::size_t>(tangent.format)],
GLComponentTypes[static_cast<std::size_t>(tangent.format)],
GL_FALSE,
desc.stride,
reinterpret_cast<const char*>(vertexData) + tangent.offset);
@ -797,12 +808,12 @@ setVertexArrays(const Mesh::VertexDescription& desc, const void* vertexData)
// Set just the vertex pointer
void
setVertexPointer(const Mesh::VertexDescription& desc, const void* vertexData)
setVertexPointer(const cmod::VertexDescription& desc, const void* vertexData)
{
const Mesh::VertexAttribute& position = desc.getAttribute(Mesh::Position);
const cmod::VertexAttribute& position = desc.getAttribute(cmod::VertexAttributeSemantic::Position);
// Can't render anything unless we have positions
if (position.format != Mesh::Float3)
if (position.format != cmod::VertexAttributeFormat::Float3)
return;
// Set up the vertex arrays
@ -818,21 +829,21 @@ setVertexPointer(const Mesh::VertexDescription& desc, const void* vertexData)
static GLenum
getGLMode(Mesh::PrimitiveGroupType primitive)
getGLMode(cmod::PrimitiveGroupType primitive)
{
switch (primitive)
{
case Mesh::TriList:
case cmod::PrimitiveGroupType::TriList:
return GL_TRIANGLES;
case Mesh::TriStrip:
case cmod::PrimitiveGroupType::TriStrip:
return GL_TRIANGLE_STRIP;
case Mesh::TriFan:
case cmod::PrimitiveGroupType::TriFan:
return GL_TRIANGLE_FAN;
case Mesh::LineList:
case cmod::PrimitiveGroupType::LineList:
return GL_LINES;
case Mesh::LineStrip:
case cmod::PrimitiveGroupType::LineStrip:
return GL_LINE_STRIP;
case Mesh::PointList:
case cmod::PrimitiveGroupType::PointList:
return GL_POINTS;
default:
return GL_POINTS;
@ -872,7 +883,7 @@ ModelViewWidget::setAmbientLight(bool enable)
void
ModelViewWidget::setShadows(bool enable)
{
if (!gl::EXT_framebuffer_object)
if (!celestia::gl::EXT_framebuffer_object)
{
return;
}
@ -897,9 +908,9 @@ ModelViewWidget::setShadows(bool enable)
void
ModelViewWidget::bindMaterial(const Material* material,
ModelViewWidget::bindMaterial(const cmod::Material* material,
const LightingEnvironment* lighting,
const Mesh::VertexDescription* vertexDesc)
const cmod::VertexDescription* vertexDesc)
{
GLShaderProgram* shader = nullptr;
@ -930,15 +941,15 @@ ModelViewWidget::bindMaterial(const Material* material,
shader->setUniformValue("modelView", cameraTransform().matrix().cast<float>());
shader->setUniformValue("diffuseColor", Vector3f(material->diffuse.red(), material->diffuse.green(), material->diffuse.blue()));
shader->setUniformValue("specularColor", Vector3f(material->specular.red(), material->specular.green(), material->specular.blue()));
shader->setUniformValue("diffuseColor", Eigen::Vector3f(material->diffuse.red(), material->diffuse.green(), material->diffuse.blue()));
shader->setUniformValue("specularColor", Eigen::Vector3f(material->specular.red(), material->specular.green(), material->specular.blue()));
shader->setUniformValue("opacity", material->opacity);
shader->setUniformValue("specularPower", material->specularPower);
if (shaderKey.hasDiffuseMap())
{
GLuint diffuseMapId = m_materialLibrary->getTexture(
toQString(GetPathManager()->getSource(material->maps[Material::DiffuseMap]).c_str()));
toQString(GetPathManager()->getSource(material->getMap(cmod::TextureSemantic::DiffuseMap)).c_str()));
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, diffuseMapId);
shader->setSampler("diffuseMap", 0);
@ -947,7 +958,7 @@ ModelViewWidget::bindMaterial(const Material* material,
if (shaderKey.hasNormalMap())
{
GLuint normalMapId = m_materialLibrary->getTexture(
toQString(GetPathManager()->getSource(material->maps[Material::NormalMap]).c_str()));
toQString(GetPathManager()->getSource(material->getMap(cmod::TextureSemantic::NormalMap)).c_str()));
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, normalMapId);
@ -958,7 +969,7 @@ ModelViewWidget::bindMaterial(const Material* material,
if (shaderKey.hasSpecularMap())
{
GLuint specularMapId = m_materialLibrary->getTexture(
toQString(GetPathManager()->getSource(material->maps[Material::SpecularMap]).c_str()));
toQString(GetPathManager()->getSource(material->getMap(cmod::TextureSemantic::SpecularMap)).c_str()));
glActiveTexture(GL_TEXTURE2);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, specularMapId);
@ -969,7 +980,7 @@ ModelViewWidget::bindMaterial(const Material* material,
if (shaderKey.hasEmissiveMap())
{
GLuint emissiveMapId = m_materialLibrary->getTexture(
toQString(GetPathManager()->getSource(material->maps[Material::EmissiveMap]).c_str()));
toQString(GetPathManager()->getSource(material->getMap(cmod::TextureSemantic::EmissiveMap)).c_str()));
glActiveTexture(GL_TEXTURE3);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, emissiveMapId);
@ -978,15 +989,15 @@ ModelViewWidget::bindMaterial(const Material* material,
}
unsigned int lightIndex = 0;
Matrix3d lightMatrix = m_lightOrientation.toRotationMatrix();
Eigen::Matrix3d lightMatrix = m_lightOrientation.toRotationMatrix();
Vector3f lightDirections[8];
Vector3f lightColors[8];
Eigen::Vector3f lightDirections[8];
Eigen::Vector3f lightColors[8];
foreach (LightSource lightSource, m_lightSources)
{
Vector3d direction = lightMatrix * lightSource.direction;
Vector3f color = lightSource.color * lightSource.intensity;
Eigen::Vector3d direction = lightMatrix * lightSource.direction;
Eigen::Vector3f color = lightSource.color * lightSource.intensity;
lightDirections[lightIndex] = direction.cast<float>();
lightColors[lightIndex] = color;
@ -1005,10 +1016,10 @@ ModelViewWidget::bindMaterial(const Material* material,
{
ambientLightLevel = 0.2f;
}
shader->setUniformValue("ambientLightColor", Vector3f::Constant(ambientLightLevel));
shader->setUniformValue("ambientLightColor", Eigen::Vector3f::Constant(ambientLightLevel));
// Get the eye position in model space
Vector4f eyePosition = cameraTransform().inverse().cast<float>() * Vector4f::UnitW();
Eigen::Vector4f eyePosition = cameraTransform().inverse().cast<float>() * Eigen::Vector4f::UnitW();
shader->setUniformValue("eyePosition", eyePosition.head(3));
// Set all shadow related values
@ -1030,15 +1041,15 @@ ModelViewWidget::bindMaterial(const Material* material,
glActiveTexture(GL_TEXTURE0);
}
Matrix4f shadowMatrixes[MaxShadows];
Matrix4f bias = Matrix4f::Zero();
bias.diagonal() = Vector4f(0.5f, 0.5f, 0.5f, 1.0f);
bias.col(3) = Vector4f(0.5f, 0.5f, 0.5f, 1.0f);
Eigen::Matrix4f shadowMatrixes[MaxShadows];
Eigen::Matrix4f bias = Eigen::Matrix4f::Zero();
bias.diagonal() = Eigen::Vector4f(0.5f, 0.5f, 0.5f, 1.0f);
bias.col(3) = Eigen::Vector4f(0.5f, 0.5f, 0.5f, 1.0f);
for (unsigned int i = 0; i < shaderKey.shadowCount(); ++i)
{
Matrix4f modelView = directionalLightMatrix(lightDirections[i]);
Matrix4f projection = shadowProjectionMatrix(m_modelBoundingRadius);
Eigen::Matrix4f modelView = directionalLightMatrix(lightDirections[i]);
Eigen::Matrix4f projection = shadowProjectionMatrix(m_modelBoundingRadius);
shadowMatrixes[i] = bias * projection * modelView;
// TESTING ONLY:
@ -1056,9 +1067,9 @@ ModelViewWidget::bindMaterial(const Material* material,
glUseProgram(0);
}
Vector4f diffuse(material->diffuse.red(), material->diffuse.green(), material->diffuse.blue(), material->opacity);
Vector4f specular(material->specular.red(), material->specular.green(), material->specular.blue(), 1.0f);
Vector4f emissive(material->emissive.red(), material->emissive.green(), material->emissive.blue(), 1.0f);
Eigen::Vector4f diffuse(material->diffuse.red(), material->diffuse.green(), material->diffuse.blue(), material->opacity);
Eigen::Vector4f specular(material->specular.red(), material->specular.green(), material->specular.blue(), 1.0f);
Eigen::Vector4f emissive(material->emissive.red(), material->emissive.green(), material->emissive.blue(), 1.0f);
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse.data());
glMaterialfv(GL_FRONT, GL_AMBIENT, diffuse.data());
glColor4fv(diffuse.data());
@ -1068,10 +1079,10 @@ ModelViewWidget::bindMaterial(const Material* material,
// Set up the diffuse (base) texture
GLuint baseTexId = 0;
if (material->maps[Material::DiffuseMap] != InvalidResource)
if (material->getMap(cmod::TextureSemantic::DiffuseMap) != InvalidResource)
{
baseTexId = m_materialLibrary->getTexture(
toQString(GetPathManager()->getSource(material->maps[Material::DiffuseMap]).c_str()));
toQString(GetPathManager()->getSource(material->getMap(cmod::TextureSemantic::DiffuseMap)).c_str()));
}
if (baseTexId != 0)
@ -1100,10 +1111,10 @@ ModelViewWidget::bindMaterial(const Material* material,
void
ModelViewWidget::renderModel(Model* model)
ModelViewWidget::renderModel(cmod::Model* model)
{
Material defaultMaterial;
defaultMaterial.diffuse = Material::Color(1.0f, 1.0f, 1.0f);
cmod::Material defaultMaterial;
defaultMaterial.diffuse = cmod::Color(1.0f, 1.0f, 1.0f);
glEnable(GL_CULL_FACE);
if (m_renderStyle == WireFrameStyle)
@ -1138,10 +1149,10 @@ ModelViewWidget::renderModel(Model* model)
// Render all meshes
for (unsigned int meshIndex = 0; meshIndex < model->getMeshCount(); ++meshIndex)
{
const Mesh* mesh = model->getMesh(meshIndex);
const cmod::Mesh* mesh = model->getMesh(meshIndex);
setVertexArrays(mesh->getVertexDescription(), mesh->getVertexData());
if (mesh->getVertexDescription().getAttribute(Mesh::Normal).format == Mesh::Float3)
if (mesh->getVertexDescription().getAttribute(cmod::VertexAttributeSemantic::Normal).format == cmod::VertexAttributeFormat::Float3)
{
setLighting(true);
}
@ -1152,8 +1163,8 @@ ModelViewWidget::renderModel(Model* model)
for (unsigned int groupIndex = 0; groupIndex < mesh->getGroupCount(); ++groupIndex)
{
const Mesh::PrimitiveGroup* group = mesh->getGroup(groupIndex);
const Material* material = &defaultMaterial;
const cmod::PrimitiveGroup* group = mesh->getGroup(groupIndex);
const cmod::Material* material = &defaultMaterial;
if (group->materialIndex < model->getMaterialCount())
{
material = model->getMaterial(group->materialIndex);
@ -1178,7 +1189,7 @@ ModelViewWidget::renderModel(Model* model)
void
ModelViewWidget::renderSelection(Model* model)
ModelViewWidget::renderSelection(cmod::Model* model)
{
glEnable(GL_CULL_FACE);
glPolygonMode(GL_FRONT, GL_LINE);
@ -1191,8 +1202,8 @@ ModelViewWidget::renderSelection(Model* model)
if (renderPath() == OpenGL2Path)
{
Material selectionMaterial;
selectionMaterial.diffuse = Material::Color(0.0f, 1.0f, 0.0f);
cmod::Material selectionMaterial;
selectionMaterial.diffuse = cmod::Color(0.0f, 1.0f, 0.0f);
selectionMaterial.opacity = 0.5f;
LightingEnvironment lightsOff;
@ -1201,12 +1212,12 @@ ModelViewWidget::renderSelection(Model* model)
for (unsigned int meshIndex = 0; meshIndex < model->getMeshCount(); ++meshIndex)
{
Mesh* mesh = model->getMesh(meshIndex);
cmod::Mesh* mesh = model->getMesh(meshIndex);
setVertexPointer(mesh->getVertexDescription(), mesh->getVertexData());
for (unsigned int groupIndex = 0; groupIndex < mesh->getGroupCount(); ++groupIndex)
{
Mesh::PrimitiveGroup* group = mesh->getGroup(groupIndex);
cmod::PrimitiveGroup* group = mesh->getGroup(groupIndex);
if (m_selection.contains(group))
{
GLenum primitiveMode = getGLMode(group->prim);
@ -1223,18 +1234,18 @@ ModelViewWidget::renderSelection(Model* model)
void
ModelViewWidget::renderDepthOnly(Model* model)
ModelViewWidget::renderDepthOnly(cmod::Model* model)
{
glDepthMask(GL_TRUE);
for (unsigned int meshIndex = 0; meshIndex < model->getMeshCount(); ++meshIndex)
{
Mesh* mesh = model->getMesh(meshIndex);
cmod::Mesh* mesh = model->getMesh(meshIndex);
setVertexPointer(mesh->getVertexDescription(), mesh->getVertexData());
for (unsigned int groupIndex = 0; groupIndex < mesh->getGroupCount(); ++groupIndex)
{
Mesh::PrimitiveGroup* group = mesh->getGroup(groupIndex);
cmod::PrimitiveGroup* group = mesh->getGroup(groupIndex);
GLenum primitiveMode = getGLMode(group->prim);
glDrawElements(primitiveMode, group->nIndices, GL_UNSIGNED_INT, group->indices);
}
@ -1248,14 +1259,14 @@ ModelViewWidget::setupDefaultLightSources()
m_lightSources.clear();
LightSource light1;
light1.color = Vector3f(1.0f, 1.0f, 1.0f);
light1.color = Eigen::Vector3f(1.0f, 1.0f, 1.0f);
light1.intensity = 1.0f;
light1.direction = Vector3d(1.0, 1.0, 5.0).normalized();
light1.direction = Eigen::Vector3d(1.0, 1.0, 5.0).normalized();
LightSource light2;
light2.color = Vector3f(1.0f, 1.0f, 1.0f);
light2.color = Eigen::Vector3f(1.0f, 1.0f, 1.0f);
light2.intensity = 1.0f;
light2.direction = Vector3d(3.0, -3.0, -1.0).normalized();
light2.direction = Eigen::Vector3d(3.0, -3.0, -1.0).normalized();
m_lightSources << light1;// << light2;
}
@ -1559,7 +1570,7 @@ ModelViewWidget::renderShadow(unsigned int lightIndex)
}
GLFrameBufferObject* shadowBuffer = m_shadowBuffers[lightIndex];
Vector3f lightDirection = (m_lightOrientation * m_lightSources[lightIndex].direction).cast<float>();
Eigen::Vector3f lightDirection = (m_lightOrientation * m_lightSources[lightIndex].direction).cast<float>();
shadowBuffer->bind();
glViewport(0, 0, shadowBuffer->width(), shadowBuffer->height());

View File

@ -8,20 +8,35 @@
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#ifndef _CMODVIEW_MODEL_VIEW_WIDGET_H_
#define _CMODVIEW_MODEL_VIEW_WIDGET_H_
#pragma once
#include "glshader.h"
#include <QColor>
#include <QGLWidget>
#include <QSet>
#include <QHash>
#include <celmodel/model.h>
#include <QList>
#include <QMouseEvent>
#include <QObject>
#include <QPoint>
#include <QSet>
#include <QString>
#include <QWheelEvent>
#include <QWidget>
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <celmodel/material.h>
#include <celmodel/mesh.h>
namespace cmod
{
class Model;
}
class MaterialLibrary;
class GLFrameBufferObject;
class GLShaderProgram;
class LightingEnvironment
{
@ -51,7 +66,7 @@ public:
static ShaderKey Create(const cmod::Material* material,
const LightingEnvironment* lighting,
const cmod::Mesh::VertexDescription* vertexDesc);
const cmod::VertexDescription* vertexDesc);
unsigned int hash() const
{
@ -157,7 +172,7 @@ public:
void wheelEvent(QWheelEvent* event);
void select(const Eigen::Vector2f& point);
QSet<cmod::Mesh::PrimitiveGroup*> selection()
QSet<cmod::PrimitiveGroup*> selection()
{
return m_selection;
}
@ -217,7 +232,7 @@ private:
void renderShadow(unsigned int lightIndex);
void bindMaterial(const cmod::Material* material,
const LightingEnvironment* lighting,
const cmod::Mesh::VertexDescription* vertexDesc);
const cmod::VertexDescription* vertexDesc);
void setupDefaultLightSources();
GLShaderProgram* createShader(const ShaderKey& shaderKey);
@ -234,7 +249,7 @@ private:
MaterialLibrary* m_materialLibrary;
QSet<cmod::Mesh::PrimitiveGroup*> m_selection;
QSet<cmod::PrimitiveGroup*> m_selection;
QHash<ShaderKey, GLShaderProgram*> m_shaderCache;
QColor m_backgroundColor;
@ -247,5 +262,3 @@ private:
bool m_ambientLightEnabled;
bool m_shadowsEnabled;
};
#endif // _CMODVIEW_MODEL_VIEW_WIDGET_H_

File diff suppressed because it is too large Load Diff

View File

@ -9,23 +9,32 @@
//
// Perform various adjustments to a Celestia mesh.
#ifndef _CMODOPS_H_
#define _CMODOPS_H_
#pragma once
#include <celmodel/model.h>
#include <Eigen/Core>
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <vector>
#include <Eigen/Core>
#include <celmodel/mesh.h>
namespace cmod
{
class Model;
}
struct Vertex
{
Vertex() :
index(0), attributes(nullptr) {};
Vertex(uint32_t _index, const void* _attributes) :
Vertex(std::uint32_t _index, const void* _attributes) :
index(_index), attributes(_attributes) {};
uint32_t index;
std::uint32_t index;
const void* attributes;
};
@ -33,8 +42,8 @@ struct Vertex
struct Face
{
Eigen::Vector3f normal;
uint32_t i[3]; // vertex attribute indices
uint32_t vi[3]; // vertex point indices -- same as above unless welding
std::uint32_t i[3]; // vertex attribute indices
std::uint32_t vi[3]; // vertex point indices -- same as above unless welding
};
@ -53,7 +62,7 @@ extern bool ConvertToStrips(cmod::Mesh& mesh);
template<typename T, typename U> void
JoinVertices(std::vector<Face>& faces,
const void* vertexData,
const cmod::Mesh::VertexDescription& desc,
const cmod::VertexDescription& desc,
const T& orderingPredicate,
const U& equivalencePredicate)
{
@ -64,19 +73,18 @@ JoinVertices(std::vector<Face>& faces,
// Must have a position
assert(desc.getAttribute(cmod::Mesh::Position).format == cmod::Mesh::Float3);
uint32_t posOffset = desc.getAttribute(cmod::Mesh::Position).offset;
const char* vertexPoints = reinterpret_cast<const char*>(vertexData) +
posOffset;
uint32_t nVertices = faces.size() * 3;
std::uint32_t posOffset = desc.getAttribute(cmod::VertexAttributeSemantic::Position).offset;
const char* vertexPoints = reinterpret_cast<const char*>(vertexData) + posOffset;
std::uint32_t nVertices = faces.size() * 3;
// Initialize the array of vertices
std::vector<Vertex> vertices(nVertices);
uint32_t f;
std::uint32_t f;
for (f = 0; f < faces.size(); f++)
{
for (uint32_t j = 0; j < 3; j++)
for (std::uint32_t j = 0; j < 3; j++)
{
uint32_t index = faces[f].i[j];
std::uint32_t index = faces[f].i[j];
vertices[f * 3 + j] = Vertex(index,
vertexPoints + desc.stride * index);
@ -84,13 +92,13 @@ JoinVertices(std::vector<Face>& faces,
}
// Sort the vertices so that identical ones will be ordered consecutively
sort(vertices.begin(), vertices.end(), orderingPredicate);
std::sort(vertices.begin(), vertices.end(), orderingPredicate);
// Build the vertex merge map
std::vector<uint32_t> mergeMap(nVertices);
uint32_t lastUnique = 0;
uint32_t uniqueCount = 0;
for (uint32_t i = 0; i < nVertices; i++)
std::vector<std::uint32_t> mergeMap(nVertices);
std::uint32_t lastUnique = 0;
std::uint32_t uniqueCount = 0;
for (std::uint32_t i = 0; i < nVertices; i++)
{
if (i == 0 || !equivalencePredicate(vertices[i - 1], vertices[i]))
{
@ -104,11 +112,9 @@ JoinVertices(std::vector<Face>& faces,
// Remap the vertex indices
for (f = 0; f < faces.size(); f++)
{
for (uint32_t k= 0; k < 3; k++)
for (std::uint32_t k= 0; k < 3; k++)
{
faces[f].vi[k] = mergeMap[faces[f].i[k]];
}
}
}
#endif // _CMODOPS_H_

View File

@ -9,28 +9,29 @@
//
// Functions for converting a 3DS scene into a Celestia model (cmod)
#include <cmath>
#include <cstdint>
#include <Eigen/Core>
#include <celmodel/material.h>
#include <celmodel/mesh.h>
#include "convert3ds.h"
#include "pathmanager.h"
using namespace cmod;
using namespace Eigen;
using namespace std;
static Material*
namespace
{
cmod::Material*
convert3dsMaterial(const M3DMaterial* material3ds, cmod::HandleGetter& handleGetter)
{
Material* newMaterial = new Material();
cmod::Material* newMaterial = new cmod::Material();
M3DColor diffuse = material3ds->getDiffuseColor();
newMaterial->diffuse = Material::Color(diffuse.red, diffuse.green, diffuse.blue);
newMaterial->diffuse = cmod::Color(diffuse.red, diffuse.green, diffuse.blue);
newMaterial->opacity = material3ds->getOpacity();
M3DColor specular = material3ds->getSpecularColor();
newMaterial->specular = Material::Color(specular.red, specular.green, specular.blue);
newMaterial->specular = cmod::Color(specular.red, specular.green, specular.blue);
float shininess = material3ds->getShininess();
@ -38,25 +39,29 @@ convert3dsMaterial(const M3DMaterial* material3ds, cmod::HandleGetter& handleGet
// range that OpenGL uses for the specular exponent. The
// current equation is just a guess at the mapping that
// 3DS actually uses.
newMaterial->specularPower = (float) pow(2.0, 1.0 + 0.1 * shininess);
newMaterial->specularPower = std::pow(2.0f, 1.0f + 0.1f * shininess);
if (newMaterial->specularPower > 128.0f)
newMaterial->specularPower = 128.0f;
if (!material3ds->getTextureMap().empty())
{
newMaterial->maps[Material::DiffuseMap] = handleGetter(material3ds->getTextureMap());
newMaterial->setMap(cmod::TextureSemantic::DiffuseMap, handleGetter(material3ds->getTextureMap()));
}
return newMaterial;
}
} // end unnamed namespace
void
Convert3DSMesh(Model& model,
Convert3DSMesh(cmod::Model& model,
const M3DTriangleMesh& mesh3ds,
const M3DScene& scene,
const string& meshName)
const std::string& meshName)
{
int nVertices = mesh3ds.getVertexCount();
int nTexCoords = mesh3ds.getTexCoordCount();
@ -73,38 +78,42 @@ Convert3DSMesh(Model& model,
for (int i = 0; i < mesh3ds.getVertexCount(); ++i)
{
int k = i * vertexSize;
Vector3f pos = mesh3ds.getVertex(i);
Eigen::Vector3f pos = mesh3ds.getVertex(i);
vertices[k + 0] = pos.x();
vertices[k + 1] = pos.y();
vertices[k + 2] = pos.z();
if (hasTexCoords)
{
Vector2f texCoord = mesh3ds.getTexCoord(i);
Eigen::Vector2f texCoord = mesh3ds.getTexCoord(i);
vertices[k + 3] = texCoord.x();
vertices[k + 4] = texCoord.y();
}
}
Mesh::VertexAttribute attributes[8];
uint32_t nAttributes = 0;
uint32_t offset = 0;
cmod::VertexAttribute attributes[8];
std::uint32_t nAttributes = 0;
std::uint32_t offset = 0;
// Position attribute is always present
attributes[nAttributes] = Mesh::VertexAttribute(Mesh::Position, Mesh::Float3, 0);
attributes[nAttributes] = cmod::VertexAttribute(cmod::VertexAttributeSemantic::Position,
cmod::VertexAttributeFormat::Float3,
0);
nAttributes++;
offset += 12;
if (hasTexCoords)
{
attributes[nAttributes] = Mesh::VertexAttribute(Mesh::Texture0, Mesh::Float2, offset);
attributes[nAttributes] = cmod::VertexAttribute(cmod::VertexAttributeSemantic::Texture0,
cmod::VertexAttributeFormat::Float2,
offset);
nAttributes++;
offset += 8;
}
// Create the Celestia mesh
Mesh* mesh = new Mesh();
mesh->setVertexDescription(Mesh::VertexDescription(offset, nAttributes, attributes));
cmod::Mesh* mesh = new cmod::Mesh();
mesh->setVertexDescription(cmod::VertexDescription(offset, nAttributes, attributes));
mesh->setVertices(nVertices, vertices);
mesh->setName(meshName);
@ -114,34 +123,34 @@ Convert3DSMesh(Model& model,
// No material groups in the 3DS file. This is allowed. We'll create a single
// primitive group with the default material.
unsigned int faceCount = mesh3ds.getFaceCount();
auto* indices = new uint32_t[faceCount * 3];
auto* indices = new std::uint32_t[faceCount * 3];
for (unsigned int i = 0; i < faceCount; i++)
{
uint16_t v0 = 0, v1 = 0, v2 = 0;
std::uint16_t v0 = 0, v1 = 0, v2 = 0;
mesh3ds.getFace(i, v0, v1, v2);
indices[i * 3 + 0] = v0;
indices[i * 3 + 1] = v1;
indices[i * 3 + 2] = v2;
}
mesh->addGroup(Mesh::TriList, ~0, faceCount * 3, indices);
mesh->addGroup(cmod::PrimitiveGroupType::TriList, ~0, faceCount * 3, indices);
}
else
{
// We have at least one material group. Create a cmod primitive group for
// each material group in th 3ds mesh.
for (uint32_t groupIndex = 0; groupIndex < mesh3ds.getMeshMaterialGroupCount(); ++groupIndex)
for (std::uint32_t groupIndex = 0; groupIndex < mesh3ds.getMeshMaterialGroupCount(); ++groupIndex)
{
const M3DMeshMaterialGroup* matGroup = mesh3ds.getMeshMaterialGroup(groupIndex);
uint32_t nMatGroupFaces = matGroup->faces.size();
auto* indices = new uint32_t[nMatGroupFaces * 3];
std::uint32_t nMatGroupFaces = matGroup->faces.size();
auto* indices = new std::uint32_t[nMatGroupFaces * 3];
for (unsigned int i = 0; i < nMatGroupFaces; i++)
{
uint16_t v0 = 0, v1 = 0, v2 = 0;
uint16_t faceIndex = matGroup->faces[i];
std::uint16_t v0 = 0, v1 = 0, v2 = 0;
std::uint16_t faceIndex = matGroup->faces[i];
mesh3ds.getFace(faceIndex, v0, v1, v2);
indices[i * 3 + 0] = v0;
indices[i * 3 + 1] = v1;
@ -150,7 +159,7 @@ Convert3DSMesh(Model& model,
// Get the material index
unsigned int materialIndex = ~0u;
string material3dsName = matGroup->materialName;
std::string material3dsName = matGroup->materialName;
if (!material3dsName.empty())
{
for (unsigned int i = 0; i < scene.getMaterialCount(); i++)
@ -163,7 +172,7 @@ Convert3DSMesh(Model& model,
}
}
mesh->addGroup(Mesh::TriList, materialIndex, nMatGroupFaces * 3, indices);
mesh->addGroup(cmod::PrimitiveGroupType::TriList, materialIndex, nMatGroupFaces * 3, indices);
}
}
@ -171,10 +180,10 @@ Convert3DSMesh(Model& model,
}
Model*
cmod::Model*
Convert3DSModel(const M3DScene& scene, cmod::HandleGetter handleGetter)
{
Model* model = new Model();
cmod::Model* model = new cmod::Model();
// Convert materials
for (unsigned int i = 0; i < scene.getMaterialCount(); i++)

View File

@ -9,12 +9,14 @@
//
// Functions for converting a 3DS scene into a Celestia model (cmod)
#ifndef _CONVERT3DS_H_
#define _CONVERT3DS_H_
#pragma once
#include <string>
#include <cel3ds/3dsmodel.h>
#include <celmodel/model.h>
#include <celmodel/modelfile.h>
#include <cel3ds/3dsmodel.h>
extern void Convert3DSMesh(cmod::Model& model,
M3DTriangleMesh& mesh3ds,
@ -22,5 +24,3 @@ extern void Convert3DSMesh(cmod::Model& model,
const std::string& meshName);
extern cmod::Model* Convert3DSModel(const M3DScene& scene,
cmod::HandleGetter handleGetter);
#endif // _CONVERT3DS_H_

View File

@ -10,28 +10,22 @@
// Functions for converting a Wavefront .obj file into a
// Celestia model (cmod)
#include "convertobj.h"
#include <algorithm>
#include <sstream>
#include <cstdio>
#include <sstream>
using namespace cmod;
using namespace Eigen;
using namespace std;
#include <celmodel/material.h>
#include <celmodel/mesh.h>
#include <celmodel/model.h>
#include "convertobj.h"
WavefrontLoader::WavefrontLoader(istream& in) :
m_in(in),
m_lineNumber(0),
m_model(nullptr)
namespace
{
}
string::size_type getToken(const string& s, string::size_type start, string& token)
std::string::size_type getToken(const std::string& s, std::string::size_type start, std::string& token)
{
string::size_type pos = start;
std::string::size_type pos = start;
token.clear();
while (pos < s.size() && isspace(s[pos]))
@ -48,7 +42,6 @@ string::size_type getToken(const string& s, string::size_type start, string& tok
return pos;
}
// Convert a 1-based array index to a zero based index. Negative
// indices are relative to the top of the end of the array. Return
// -1 if the index is invalid.
@ -56,51 +49,65 @@ int convertIndex(int index, unsigned int maxValue)
{
if (index > 0)
{
if (index <= (int) maxValue)
if (index <= static_cast<int>(maxValue))
return index - 1;
return -1;
}
if (index < 0)
{
if (-index <= (int) maxValue)
return (int) maxValue + index;
if (-index <= static_cast<int>(maxValue))
return static_cast<int>(maxValue) + index;
return -1;
}
return -1;
}
} // end unnamed namespace
WavefrontLoader::WavefrontLoader(std::istream& in) :
m_in(in),
m_lineNumber(0),
m_model(nullptr)
{
}
cmod::Model*
WavefrontLoader::load()
{
string line;
string keyword;
std::string line;
std::string keyword;
unsigned int vertexCount = 0;
ObjVertex::VertexType lastVertexType = ObjVertex::Point;
int currentMaterialIndex = -1;
m_model = new Model();
m_model = new cmod::Model();
while (getline(m_in, line))
{
m_lineNumber++;
// strip comments
string::size_type commentPos = line.find('#');
if (commentPos != string::npos)
std::string::size_type commentPos = line.find('#');
if (commentPos != std::string::npos)
{
line = line.substr(0, commentPos);
}
string::size_type pos = getToken(line, 0, keyword);
std::string::size_type pos = getToken(line, 0, keyword);
if (!keyword.empty())
{
if (keyword == "v")
{
Vector3f v(Vector3f::Zero());
if (sscanf(line.c_str() + pos, "%f %f %f", &v.x(), &v.y(), &v.z()) != 3)
Eigen::Vector3f v(Eigen::Vector3f::Zero());
if (std::sscanf(line.c_str() + pos, "%f %f %f", &v.x(), &v.y(), &v.z()) != 3)
{
reportError("Bad vertex");
return nullptr;
@ -109,8 +116,8 @@ WavefrontLoader::load()
}
else if (keyword == "vn")
{
Vector3f v(Vector3f::Zero());
if (sscanf(line.c_str() + pos, "%f %f %f", &v.x(), &v.y(), &v.z()) != 3)
Eigen::Vector3f v(Eigen::Vector3f::Zero());
if (std::sscanf(line.c_str() + pos, "%f %f %f", &v.x(), &v.y(), &v.z()) != 3)
{
reportError("Bad normal");
return nullptr;
@ -119,8 +126,8 @@ WavefrontLoader::load()
}
else if (keyword == "vt")
{
Vector2f v(Vector2f::Zero());
if (sscanf(line.c_str() + pos, "%f %f", &v.x(), &v.y()) != 2)
Eigen::Vector2f v(Eigen::Vector2f::Zero());
if (std::sscanf(line.c_str() + pos, "%f %f", &v.x(), &v.y()) != 2)
{
reportError("Bad texture coordinate");
return nullptr;
@ -129,8 +136,8 @@ WavefrontLoader::load()
}
else if (keyword == "usemtl")
{
Material* material = new Material();
material->diffuse = Material::Color(1.0f, 1.0f, 1.0f);
cmod::Material* material = new cmod::Material();
material->diffuse = cmod::Color(1.0f, 1.0f, 1.0f);
currentMaterialIndex = m_model->addMaterial(material) - 1;
if (!m_materialGroups.empty())
{
@ -149,27 +156,27 @@ WavefrontLoader::load()
}
else if (keyword == "f")
{
vector<ObjVertex> faceVertices;
std::vector<ObjVertex> faceVertices;
while (pos < line.size())
{
string vertexString;
std::string vertexString;
pos = getToken(line, pos, vertexString);
if (!vertexString.empty())
{
ObjVertex vertex;
if (sscanf(vertexString.c_str(), "%d/%d/%d", &vertex.vertexIndex, &vertex.texCoordIndex, &vertex.normalIndex) == 3)
if (std::sscanf(vertexString.c_str(), "%d/%d/%d", &vertex.vertexIndex, &vertex.texCoordIndex, &vertex.normalIndex) == 3)
{
// Vertex, texture coordinate, and normal
}
else if (sscanf(vertexString.c_str(), "%d//%d", &vertex.vertexIndex, &vertex.normalIndex) == 2)
else if (std::sscanf(vertexString.c_str(), "%d//%d", &vertex.vertexIndex, &vertex.normalIndex) == 2)
{
// Vertex + normal
}
else if (sscanf(vertexString.c_str(), "%d/%d", &vertex.vertexIndex, &vertex.texCoordIndex) == 2)
else if (std::sscanf(vertexString.c_str(), "%d/%d", &vertex.vertexIndex, &vertex.texCoordIndex) == 2)
{
// Vertex + texture coordinate
}
else if (sscanf(vertexString.c_str(), "%d", &vertex.vertexIndex) == 1)
else if (std::sscanf(vertexString.c_str(), "%d", &vertex.vertexIndex) == 1)
{
// Vertex only
}
@ -292,10 +299,10 @@ WavefrontLoader::load()
void
WavefrontLoader::reportError(const string& message)
WavefrontLoader::reportError(const std::string& message)
{
//cerr << message << endl;
ostringstream os;
std::ostringstream os;
os << "Line " << m_lineNumber << ": " << message;
m_errorMessage = os.str();
@ -324,25 +331,31 @@ WavefrontLoader::addVertexData(const Eigen::Vector3f& v)
void
WavefrontLoader::createMesh(ObjVertex::VertexType vertexType, unsigned int vertexCount)
{
Mesh::VertexAttribute attributes[8];
cmod::VertexAttribute attributes[8];
unsigned int nAttributes = 0;
unsigned int offset = 0;
// Position attribute is always present
attributes[nAttributes] = Mesh::VertexAttribute(Mesh::Position, Mesh::Float3, 0);
attributes[nAttributes] = cmod::VertexAttribute(cmod::VertexAttributeSemantic::Position,
cmod::VertexAttributeFormat::Float3,
0);
nAttributes++;
offset += 12;
if (vertexType == ObjVertex::PointNormal || vertexType == ObjVertex::PointTexNormal)
{
attributes[nAttributes] = Mesh::VertexAttribute(Mesh::Normal, Mesh::Float3, offset);
attributes[nAttributes] = cmod::VertexAttribute(cmod::VertexAttributeSemantic::Normal,
cmod::VertexAttributeFormat::Float3,
offset);
nAttributes++;
offset += 12;
}
if (vertexType == ObjVertex::PointTex || vertexType == ObjVertex::PointTexNormal)
{
attributes[nAttributes] = Mesh::VertexAttribute(Mesh::Texture0, Mesh::Float2, offset);
attributes[nAttributes] = cmod::VertexAttribute(cmod::VertexAttributeSemantic::Texture0,
cmod::VertexAttributeFormat::Float2,
offset);
nAttributes++;
offset += 8;
}
@ -351,8 +364,8 @@ WavefrontLoader::createMesh(ObjVertex::VertexType vertexType, unsigned int verte
copy(m_vertexData.begin(), m_vertexData.end(), vertexDataCopy);
// Create the Celestia mesh
Mesh* mesh = new Mesh();
mesh->setVertexDescription(Mesh::VertexDescription(offset, nAttributes, attributes));
cmod::Mesh* mesh = new cmod::Mesh();
mesh->setVertexDescription(cmod::VertexDescription(offset, nAttributes, attributes));
mesh->setVertices(vertexCount, vertexDataCopy);
// Add primitive groups
@ -371,9 +384,9 @@ WavefrontLoader::createMesh(ObjVertex::VertexType vertexType, unsigned int verte
if (indexCount > 0)
{
Mesh::index32* indexDataCopy = new Mesh::index32[indexCount];
cmod::index32* indexDataCopy = new cmod::index32[indexCount];
copy(m_indexData.begin() + firstIndex, m_indexData.begin() + firstIndex + indexCount, indexDataCopy);
mesh->addGroup(Mesh::TriList, m_materialGroups[i].materialIndex, indexCount, indexDataCopy);
mesh->addGroup(cmod::PrimitiveGroupType::TriList, m_materialGroups[i].materialIndex, indexCount, indexDataCopy);
}
}

View File

@ -10,14 +10,18 @@
// Functions for converting a Wavefront .obj file into a
// Celestia model (cmod)
#ifndef _CMOD_CONVERTOBJ_H_
#define _CMOD_CONVERTOBJ_H_
#pragma once
#include <celmodel/model.h>
#include <Eigen/Core>
#include <iostream>
#include <vector>
#include <iosfwd>
#include <string>
#include <vector>
#include <Eigen/Core>
namespace cmod
{
class Model;
}
class WavefrontLoader
@ -93,12 +97,10 @@ private:
std::vector<Eigen::Vector2f> m_texCoords;
std::vector<float> m_vertexData;
std::vector<cmod::Mesh::index32> m_indexData;
std::vector<cmod::index32> m_indexData;
std::vector<MaterialGroup> m_materialGroups;
cmod::Model* m_model;
std::string m_errorMessage;
};
#endif // _CMOD_CONVERTOBJ_H_