Extract inner types from Material and Mesh
- Remove using namspace cmod - Convert enums to enum classespull/1196/head
parent
474057221b
commit
b79959979a
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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*) ¶ms);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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_
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -95,7 +95,6 @@ std::ofstream hdrlog;
|
|||
#endif
|
||||
#endif
|
||||
|
||||
using namespace cmod;
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
using namespace celestia;
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_
|
||||
|
||||
|
|
|
@ -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)];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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_
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
@ -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_
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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_
|
||||
|
|
Loading…
Reference in New Issue