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
|
* all within this geometry object. This information is used
|
||||||
* to decide whether multiple rendering passes are required.
|
* to decide whether multiple rendering passes are required.
|
||||||
*/
|
*/
|
||||||
virtual bool usesTextureType(cmod::Material::TextureSemantic) const
|
virtual bool usesTextureType(cmod::TextureSemantic) const
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,196 +11,44 @@
|
||||||
// Experimental particle system support
|
// Experimental particle system support
|
||||||
#define PARTICLE_SYSTEM 0
|
#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
|
#if PARTICLE_SYSTEM
|
||||||
#include "particlesystem.h"
|
#include "particlesystem.h"
|
||||||
#include "particlesystemfile.h"
|
#include "particlesystemfile.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "parser.h"
|
namespace
|
||||||
#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()
|
|
||||||
{
|
{
|
||||||
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
|
struct NoiseMeshParameters
|
||||||
{
|
{
|
||||||
Vector3f size;
|
Eigen::Vector3f size;
|
||||||
Vector3f offset;
|
Eigen::Vector3f offset;
|
||||||
float featureHeight;
|
float featureHeight;
|
||||||
float octaves;
|
float octaves;
|
||||||
float slices;
|
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 theta = u * static_cast<float>(PI) * 2;
|
||||||
float phi = (v - 0.5f) * (float) PI;
|
float phi = (v - 0.5f) * static_cast<float>(PI);
|
||||||
float x = (float) (cos(phi) * cos(theta));
|
|
||||||
float y = (float) sin(phi);
|
|
||||||
float z = (float) (cos(phi) * sin(theta));
|
|
||||||
|
|
||||||
// assert(info != nullptr);
|
// 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;
|
return celmath::fractalsum(p, params->octaves) * params->featureHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: The Celestia mesh format is deprecated
|
// 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())
|
if (!meshFile.good())
|
||||||
{
|
{
|
||||||
DPRINTF(LOG_LEVEL_ERROR, "Error opening mesh file: %s\n", filename);
|
DPRINTF(LOG_LEVEL_ERROR, "Error opening mesh file: %s\n", filename);
|
||||||
|
@ -268,8 +118,8 @@ Model* LoadCelestiaMesh(const fs::path& filename)
|
||||||
|
|
||||||
NoiseMeshParameters params{};
|
NoiseMeshParameters params{};
|
||||||
|
|
||||||
params.size = Vector3f::Ones();
|
params.size = Eigen::Vector3f::Ones();
|
||||||
params.offset = Vector3f::Constant(10.0f);
|
params.offset = Eigen::Vector3f::Constant(10.0f);
|
||||||
params.featureHeight = 0.0f;
|
params.featureHeight = 0.0f;
|
||||||
params.octaves = 1;
|
params.octaves = 1;
|
||||||
params.slices = 20;
|
params.slices = 20;
|
||||||
|
@ -284,12 +134,13 @@ Model* LoadCelestiaMesh(const fs::path& filename)
|
||||||
|
|
||||||
delete meshDefValue;
|
delete meshDefValue;
|
||||||
|
|
||||||
Model* model = new Model();
|
cmod::Model* model = new cmod::Model();
|
||||||
SphereMesh* sphereMesh = new SphereMesh(params.size,
|
SphereMesh* sphereMesh = new SphereMesh(params.size,
|
||||||
(int) params.rings, (int) params.slices,
|
static_cast<int>(params.rings),
|
||||||
|
static_cast<int>(params.slices),
|
||||||
NoiseDisplacementFunc,
|
NoiseDisplacementFunc,
|
||||||
(void*) ¶ms);
|
(void*) ¶ms);
|
||||||
Mesh* mesh = sphereMesh->convertToMesh();
|
cmod::Mesh* mesh = sphereMesh->convertToMesh();
|
||||||
model->addMesh(mesh);
|
model->addMesh(mesh);
|
||||||
delete sphereMesh;
|
delete sphereMesh;
|
||||||
|
|
||||||
|
@ -297,7 +148,7 @@ Model* LoadCelestiaMesh(const fs::path& filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Mesh*
|
cmod::Mesh*
|
||||||
ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
const M3DScene& scene)
|
const M3DScene& scene)
|
||||||
{
|
{
|
||||||
|
@ -311,33 +162,39 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
|
|
||||||
// Create the attribute set. Always include positions and normals, texture coords
|
// Create the attribute set. Always include positions and normals, texture coords
|
||||||
// are optional.
|
// are optional.
|
||||||
Mesh::VertexAttribute attributes[8];
|
cmod::VertexAttribute attributes[8];
|
||||||
uint32_t nAttributes = 0;
|
std::uint32_t nAttributes = 0;
|
||||||
uint32_t offset = 0;
|
std::uint32_t offset = 0;
|
||||||
|
|
||||||
// Position attribute are required
|
// 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++;
|
nAttributes++;
|
||||||
offset += 12;
|
offset += 12;
|
||||||
|
|
||||||
// Normals are always generated
|
// 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++;
|
nAttributes++;
|
||||||
offset += 12;
|
offset += 12;
|
||||||
|
|
||||||
if (hasTextureCoords)
|
if (hasTextureCoords)
|
||||||
{
|
{
|
||||||
attributes[nAttributes] = Mesh::VertexAttribute(Mesh::Texture0, Mesh::Float2, offset);
|
attributes[nAttributes] = cmod::VertexAttribute(cmod::VertexAttributeSemantic::Texture0,
|
||||||
|
cmod::VertexAttributeFormat::Float2,
|
||||||
|
offset);
|
||||||
nAttributes++;
|
nAttributes++;
|
||||||
offset += 8;
|
offset += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t vertexSize = offset;
|
std::uint32_t vertexSize = offset;
|
||||||
|
|
||||||
// bool smooth = (mesh.getSmoothingGroupCount() == nFaces);
|
// bool smooth = (mesh.getSmoothingGroupCount() == nFaces);
|
||||||
|
|
||||||
Vector3f* faceNormals = new Vector3f[nFaces];
|
Eigen::Vector3f* faceNormals = new Eigen::Vector3f[nFaces];
|
||||||
Vector3f* vertexNormals = new Vector3f[nFaces * 3];
|
Eigen::Vector3f* vertexNormals = new Eigen::Vector3f[nFaces * 3];
|
||||||
auto* faceCounts = new int[nVertices];
|
auto* faceCounts = new int[nVertices];
|
||||||
auto** vertexFaces = new int*[nVertices];
|
auto** vertexFaces = new int*[nVertices];
|
||||||
|
|
||||||
|
@ -350,16 +207,16 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
// generate face normals
|
// generate face normals
|
||||||
for (int i = 0; i < nFaces; i++)
|
for (int i = 0; i < nFaces; i++)
|
||||||
{
|
{
|
||||||
uint16_t v0, v1, v2;
|
std::uint16_t v0, v1, v2;
|
||||||
mesh.getFace(i, v0, v1, v2);
|
mesh.getFace(i, v0, v1, v2);
|
||||||
|
|
||||||
faceCounts[v0]++;
|
faceCounts[v0]++;
|
||||||
faceCounts[v1]++;
|
faceCounts[v1]++;
|
||||||
faceCounts[v2]++;
|
faceCounts[v2]++;
|
||||||
|
|
||||||
Vector3f p0 = mesh.getVertex(v0);
|
Eigen::Vector3f p0 = mesh.getVertex(v0);
|
||||||
Vector3f p1 = mesh.getVertex(v1);
|
Eigen::Vector3f p1 = mesh.getVertex(v1);
|
||||||
Vector3f p2 = mesh.getVertex(v2);
|
Eigen::Vector3f p2 = mesh.getVertex(v2);
|
||||||
faceNormals[i] = (p1 - p0).cross(p2 - p1).normalized();
|
faceNormals[i] = (p1 - p0).cross(p2 - p1).normalized();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,7 +242,7 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
|
|
||||||
for (int i = 0; i < nFaces; i++)
|
for (int i = 0; i < nFaces; i++)
|
||||||
{
|
{
|
||||||
uint16_t v0, v1, v2;
|
std::uint16_t v0, v1, v2;
|
||||||
mesh.getFace(i, v0, v1, v2);
|
mesh.getFace(i, v0, v1, v2);
|
||||||
vertexFaces[v0][faceCounts[v0]--] = i;
|
vertexFaces[v0][faceCounts[v0]--] = i;
|
||||||
vertexFaces[v1][faceCounts[v1]--] = i;
|
vertexFaces[v1][faceCounts[v1]--] = i;
|
||||||
|
@ -395,11 +252,11 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
// average face normals to compute the vertex normals
|
// average face normals to compute the vertex normals
|
||||||
for (int i = 0; i < nFaces; i++)
|
for (int i = 0; i < nFaces; i++)
|
||||||
{
|
{
|
||||||
uint16_t v0, v1, v2;
|
std::uint16_t v0, v1, v2;
|
||||||
mesh.getFace(i, v0, v1, v2);
|
mesh.getFace(i, v0, v1, v2);
|
||||||
// uint32_t smoothingGroups = mesh.getSmoothingGroups(i);
|
// 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++)
|
for (int j = 1; j <= vertexFaces[v0][0]; j++)
|
||||||
{
|
{
|
||||||
int k = vertexFaces[v0][j];
|
int k = vertexFaces[v0][j];
|
||||||
|
@ -409,7 +266,7 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
}
|
}
|
||||||
vertexNormals[i * 3] = v.normalized();
|
vertexNormals[i * 3] = v.normalized();
|
||||||
|
|
||||||
v = Vector3f::Zero();
|
v = Eigen::Vector3f::Zero();
|
||||||
for (int j = 1; j <= vertexFaces[v1][0]; j++)
|
for (int j = 1; j <= vertexFaces[v1][0]; j++)
|
||||||
{
|
{
|
||||||
int k = vertexFaces[v1][j];
|
int k = vertexFaces[v1][j];
|
||||||
|
@ -419,7 +276,7 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
}
|
}
|
||||||
vertexNormals[i * 3 + 1] = v.normalized();
|
vertexNormals[i * 3 + 1] = v.normalized();
|
||||||
|
|
||||||
v = Vector3f::Zero();
|
v = Eigen::Vector3f::Zero();
|
||||||
for (int j = 1; j <= vertexFaces[v2][0]; j++)
|
for (int j = 1; j <= vertexFaces[v2][0]; j++)
|
||||||
{
|
{
|
||||||
int k = vertexFaces[v2][j];
|
int k = vertexFaces[v2][j];
|
||||||
|
@ -437,13 +294,13 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
|
|
||||||
for (int i = 0; i < nFaces; i++)
|
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]);
|
mesh.getFace(i, triVert[0], triVert[1], triVert[2]);
|
||||||
|
|
||||||
for (unsigned int j = 0; j < 3; j++)
|
for (unsigned int j = 0; j < 3; j++)
|
||||||
{
|
{
|
||||||
Vector3f position = mesh.getVertex(triVert[j]);
|
Eigen::Vector3f position = mesh.getVertex(triVert[j]);
|
||||||
Vector3f normal = vertexNormals[i * 3 + j];
|
Eigen::Vector3f normal = vertexNormals[i * 3 + j];
|
||||||
|
|
||||||
int dataOffset = (i * 3 + j) * floatsPerVertex;
|
int dataOffset = (i * 3 + j) * floatsPerVertex;
|
||||||
vertexData[dataOffset + 0] = position.x();
|
vertexData[dataOffset + 0] = position.x();
|
||||||
|
@ -454,7 +311,7 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
vertexData[dataOffset + 5] = normal.z();
|
vertexData[dataOffset + 5] = normal.z();
|
||||||
if (hasTextureCoords)
|
if (hasTextureCoords)
|
||||||
{
|
{
|
||||||
Vector2f texCoord = mesh.getTexCoord(triVert[j]);
|
Eigen::Vector2f texCoord = mesh.getTexCoord(triVert[j]);
|
||||||
vertexData[dataOffset + 6] = texCoord.x();
|
vertexData[dataOffset + 6] = texCoord.x();
|
||||||
vertexData[dataOffset + 7] = texCoord.y();
|
vertexData[dataOffset + 7] = texCoord.y();
|
||||||
}
|
}
|
||||||
|
@ -462,8 +319,8 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the mesh
|
// Create the mesh
|
||||||
Mesh* newMesh = new Mesh();
|
cmod::Mesh* newMesh = new cmod::Mesh();
|
||||||
newMesh->setVertexDescription(Mesh::VertexDescription(vertexSize, nAttributes, attributes));
|
newMesh->setVertexDescription(cmod::VertexDescription(vertexSize, nAttributes, attributes));
|
||||||
newMesh->setVertices(nFaces * 3, vertexData);
|
newMesh->setVertices(nFaces * 3, vertexData);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mesh.getMeshMaterialGroupCount(); ++i)
|
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
|
// Vertex lists are not indexed, so the conversion to an indexed format is
|
||||||
// trivial (although much space is wasted storing unnecessary indices.)
|
// 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];
|
auto indices = new std::uint32_t[nMatGroupFaces * 3];
|
||||||
for (uint32_t j = 0; j < nMatGroupFaces; ++j)
|
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 + 0] = faceIndex * 3 + 0;
|
||||||
indices[j * 3 + 1] = faceIndex * 3 + 1;
|
indices[j * 3 + 1] = faceIndex * 3 + 1;
|
||||||
indices[j * 3 + 2] = faceIndex * 3 + 2;
|
indices[j * 3 + 2] = faceIndex * 3 + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup the material index
|
// Lookup the material index
|
||||||
uint32_t materialIndex = 0;
|
std::uint32_t materialIndex = 0;
|
||||||
for (uint32_t j = 0; j < scene.getMaterialCount(); ++j)
|
for (std::uint32_t j = 0; j < scene.getMaterialCount(); ++j)
|
||||||
{
|
{
|
||||||
if (matGroup->materialName == scene.getMaterial(j)->getName())
|
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
|
// clean up
|
||||||
|
@ -511,32 +368,23 @@ ConvertTriangleMesh(const M3DTriangleMesh& mesh,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
cmod::Model*
|
||||||
static Material::Color
|
|
||||||
toMaterialColor(Color c)
|
|
||||||
{
|
|
||||||
return {c.red(), c.green(), c.blue()};
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static Model*
|
|
||||||
Convert3DSModel(const M3DScene& scene, const fs::path& texPath)
|
Convert3DSModel(const M3DScene& scene, const fs::path& texPath)
|
||||||
{
|
{
|
||||||
Model* model = new Model();
|
cmod::Model* model = new cmod::Model();
|
||||||
|
|
||||||
// Convert the materials
|
// 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);
|
const M3DMaterial* material = scene.getMaterial(i);
|
||||||
Material* newMaterial = new Material();
|
cmod::Material* newMaterial = new cmod::Material();
|
||||||
|
|
||||||
M3DColor diffuse = material->getDiffuseColor();
|
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();
|
newMaterial->opacity = material->getOpacity();
|
||||||
|
|
||||||
M3DColor specular = material->getSpecularColor();
|
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();
|
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
|
// range that OpenGL uses for the specular exponent. The
|
||||||
// current equation is just a guess at the mapping that
|
// current equation is just a guess at the mapping that
|
||||||
// 3DS actually uses.
|
// 3DS actually uses.
|
||||||
newMaterial->specularPower = (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)
|
if (newMaterial->specularPower > 128.0f)
|
||||||
newMaterial->specularPower = 128.0f;
|
newMaterial->specularPower = 128.0f;
|
||||||
|
|
||||||
if (!material->getTextureMap().empty())
|
if (!material->getTextureMap().empty())
|
||||||
{
|
{
|
||||||
ResourceHandle tex = GetTextureManager()->getHandle(TextureInfo(material->getTextureMap(), texPath, TextureInfo::WrapTexture));
|
ResourceHandle tex = GetTextureManager()->getHandle(TextureInfo(material->getTextureMap(), texPath, TextureInfo::WrapTexture));
|
||||||
newMaterial->maps[Material::DiffuseMap] = tex;
|
newMaterial->setMap(cmod::TextureSemantic::DiffuseMap, tex);
|
||||||
}
|
}
|
||||||
|
|
||||||
model->addMaterial(newMaterial);
|
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
|
// 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.
|
// 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);
|
const M3DModel* model3ds = scene.getModel(i);
|
||||||
if (model3ds)
|
if (model3ds)
|
||||||
|
@ -569,7 +417,7 @@ Convert3DSModel(const M3DScene& scene, const fs::path& texPath)
|
||||||
const M3DTriangleMesh* mesh = model3ds->getTriMesh(j);
|
const M3DTriangleMesh* mesh = model3ds->getTriMesh(j);
|
||||||
if (mesh)
|
if (mesh)
|
||||||
{
|
{
|
||||||
Mesh* newMesh = ConvertTriangleMesh(*mesh, scene);
|
cmod::Mesh* newMesh = ConvertTriangleMesh(*mesh, scene);
|
||||||
model->addMesh(newMesh);
|
model->addMesh(newMesh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -578,3 +426,152 @@ Convert3DSModel(const M3DScene& scene, const fs::path& texPath)
|
||||||
|
|
||||||
return model;
|
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
|
// as published by the Free Software Foundation; either version 2
|
||||||
// of the License, or (at your option) any later version.
|
// of the License, or (at your option) any later version.
|
||||||
|
|
||||||
#ifndef _CELENGINE_MESHMANAGER_H_
|
#pragma once
|
||||||
#define _CELENGINE_MESHMANAGER_H_
|
|
||||||
|
#include <Eigen/Core>
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
#include <celutil/resmanager.h>
|
|
||||||
#include <celengine/geometry.h>
|
|
||||||
#include <celcompat/filesystem.h>
|
#include <celcompat/filesystem.h>
|
||||||
|
#include <celutil/resmanager.h>
|
||||||
|
#include "geometry.h"
|
||||||
|
|
||||||
|
|
||||||
class GeometryInfo : public ResourceInfo<Geometry>
|
class GeometryInfo : public ResourceInfo<Geometry>
|
||||||
|
@ -75,6 +74,3 @@ inline bool operator<(const GeometryInfo& g0, const GeometryInfo& g1)
|
||||||
typedef ResourceManager<GeometryInfo> GeometryManager;
|
typedef ResourceManager<GeometryInfo> GeometryManager;
|
||||||
|
|
||||||
extern GeometryManager* GetGeometryManager();
|
extern GeometryManager* GetGeometryManager();
|
||||||
|
|
||||||
#endif // _CELENGINE_MESHMANAGER_H_
|
|
||||||
|
|
||||||
|
|
|
@ -8,18 +8,12 @@
|
||||||
// as published by the Free Software Foundation; either version 2
|
// as published by the Free Software Foundation; either version 2
|
||||||
// of the License, or (at your option) any later version.
|
// of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "glsupport.h"
|
||||||
#include "modelgeometry.h"
|
#include "modelgeometry.h"
|
||||||
#include "rendcontext.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
|
// Vertex buffer object support
|
||||||
|
@ -51,9 +45,9 @@ public:
|
||||||
/** Create a new ModelGeometry wrapping the specified model.
|
/** Create a new ModelGeometry wrapping the specified model.
|
||||||
* The ModelGeoemtry takes ownership of the model.
|
* The ModelGeoemtry takes ownership of the model.
|
||||||
*/
|
*/
|
||||||
ModelGeometry::ModelGeometry(unique_ptr<cmod::Model>&& model) :
|
ModelGeometry::ModelGeometry(std::unique_ptr<cmod::Model>&& model) :
|
||||||
m_model(move(model)),
|
m_model(std::move(model)),
|
||||||
m_glData(unique_ptr<ModelOpenGLData>(new ModelOpenGLData()))
|
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)
|
for (unsigned int i = 0; i < m_model->getMeshCount(); ++i)
|
||||||
{
|
{
|
||||||
Mesh* mesh = m_model->getMesh(i);
|
cmod::Mesh* mesh = m_model->getMesh(i);
|
||||||
const Mesh::VertexDescription& vertexDesc = mesh->getVertexDescription();
|
const cmod::VertexDescription& vertexDesc = mesh->getVertexDescription();
|
||||||
|
|
||||||
GLuint vboId = 0;
|
GLuint vboId = 0;
|
||||||
if (mesh->getVertexCount() * vertexDesc.stride > MinVBOSize)
|
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)
|
for (unsigned int groupIndex = 0; groupIndex < mesh->getGroupCount(); ++groupIndex)
|
||||||
{
|
{
|
||||||
const Mesh::PrimitiveGroup* group = mesh->getGroup(groupIndex);
|
const cmod::PrimitiveGroup* group = mesh->getGroup(groupIndex);
|
||||||
if (group->vertexOverride != nullptr && group->vertexCountOverride * group->vertexDescriptionOverride.stride > MinVBOSize)
|
if (group->vertexOverride != nullptr
|
||||||
|
&& group->vertexCountOverride * group->vertexDescriptionOverride.stride > MinVBOSize)
|
||||||
{
|
{
|
||||||
glGenBuffers(1, &vboId);
|
glGenBuffers(1, &vboId);
|
||||||
if (vboId != 0)
|
if (vboId != 0)
|
||||||
|
@ -129,7 +124,7 @@ ModelGeometry::render(RenderContext& rc, double /* t */)
|
||||||
// Iterate over all meshes in the model
|
// Iterate over all meshes in the model
|
||||||
for (unsigned int meshIndex = 0; meshIndex < m_model->getMeshCount(); ++meshIndex)
|
for (unsigned int meshIndex = 0; meshIndex < m_model->getMeshCount(); ++meshIndex)
|
||||||
{
|
{
|
||||||
Mesh* mesh = m_model->getMesh(meshIndex);
|
cmod::Mesh* mesh = m_model->getMesh(meshIndex);
|
||||||
|
|
||||||
const void* currentData = nullptr;
|
const void* currentData = nullptr;
|
||||||
GLuint currentVboId = 0;
|
GLuint currentVboId = 0;
|
||||||
|
@ -137,7 +132,7 @@ ModelGeometry::render(RenderContext& rc, double /* t */)
|
||||||
// Iterate over all primitive groups in the mesh
|
// Iterate over all primitive groups in the mesh
|
||||||
for (unsigned int groupIndex = 0; groupIndex < mesh->getGroupCount(); ++groupIndex)
|
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();
|
bool useOverrideValue = group->vertexOverride != nullptr && rc.shouldDrawLineAsTriangles();
|
||||||
|
|
||||||
const void* data = useOverrideValue ? group->vertexOverride : mesh->getVertexData();
|
const void* data = useOverrideValue ? group->vertexOverride : mesh->getVertexData();
|
||||||
|
@ -168,7 +163,7 @@ ModelGeometry::render(RenderContext& rc, double /* t */)
|
||||||
rc.updateShader(vertexDescription, group->prim);
|
rc.updateShader(vertexDescription, group->prim);
|
||||||
|
|
||||||
// Set up the material
|
// Set up the material
|
||||||
const Material* material = nullptr;
|
const cmod::Material* material = nullptr;
|
||||||
unsigned int materialIndex = group->materialIndex;
|
unsigned int materialIndex = group->materialIndex;
|
||||||
if (materialIndex != lastMaterial && materialIndex < materialCount)
|
if (materialIndex != lastMaterial && materialIndex < materialCount)
|
||||||
{
|
{
|
||||||
|
@ -203,7 +198,7 @@ ModelGeometry::isNormalized() const
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ModelGeometry::usesTextureType(Material::TextureSemantic t) const
|
ModelGeometry::usesTextureType(cmod::TextureSemantic t) const
|
||||||
{
|
{
|
||||||
return m_model->usesTextureType(t);
|
return m_model->usesTextureType(t);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,11 @@
|
||||||
#include <Eigen/Geometry>
|
#include <Eigen/Geometry>
|
||||||
|
|
||||||
#include <celmodel/model.h>
|
#include <celmodel/model.h>
|
||||||
#include <celutil/resmanager.h>
|
|
||||||
#include "geometry.h"
|
#include "geometry.h"
|
||||||
|
|
||||||
|
|
||||||
class ModelOpenGLData;
|
class ModelOpenGLData;
|
||||||
|
class RenderContext;
|
||||||
|
|
||||||
class ModelGeometry : public Geometry
|
class ModelGeometry : public Geometry
|
||||||
{
|
{
|
||||||
|
@ -32,14 +32,14 @@ class ModelGeometry : public Geometry
|
||||||
* and set distance; otherwise return false and leave
|
* and set distance; otherwise return false and leave
|
||||||
* distance unmodified.
|
* 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
|
//! 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;
|
bool usesTextureType(cmod::TextureSemantic) const override;
|
||||||
virtual bool isOpaque() const;
|
bool isOpaque() const override;
|
||||||
virtual bool isNormalized() const;
|
bool isNormalized() const override;
|
||||||
|
|
||||||
void loadTextures();
|
void loadTextures();
|
||||||
|
|
||||||
|
|
|
@ -8,22 +8,24 @@
|
||||||
// as published by the Free Software Foundation; either version 2
|
// as published by the Free Software Foundation; either version 2
|
||||||
// of the License, or (at your option) any later version.
|
// of the License, or (at your option) any later version.
|
||||||
|
|
||||||
#include <vector>
|
#include <algorithm>
|
||||||
#include <celmath/geomutil.h>
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include <celutil/color.h>
|
||||||
#include "body.h"
|
#include "body.h"
|
||||||
#include "modelgeometry.h"
|
#include "lightenv.h"
|
||||||
#include "rendcontext.h"
|
#include "rendcontext.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "shadowmap.h"
|
|
||||||
#include "texmanager.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_TRIANGLES,
|
||||||
GL_TRIANGLE_STRIP,
|
GL_TRIANGLE_STRIP,
|
||||||
|
@ -34,7 +36,7 @@ static GLenum GLPrimitiveModes[Mesh::PrimitiveTypeMax] =
|
||||||
GL_POINTS,
|
GL_POINTS,
|
||||||
};
|
};
|
||||||
|
|
||||||
static GLenum GLComponentTypes[Mesh::FormatMax] =
|
constexpr GLenum GLComponentTypes[static_cast<std::size_t>(cmod::VertexAttributeFormat::FormatMax)] =
|
||||||
{
|
{
|
||||||
GL_FLOAT, // Float1
|
GL_FLOAT, // Float1
|
||||||
GL_FLOAT, // Float2
|
GL_FLOAT, // Float2
|
||||||
|
@ -43,7 +45,7 @@ static GLenum GLComponentTypes[Mesh::FormatMax] =
|
||||||
GL_UNSIGNED_BYTE, // UByte4
|
GL_UNSIGNED_BYTE, // UByte4
|
||||||
};
|
};
|
||||||
|
|
||||||
static int GLComponentCounts[Mesh::FormatMax] =
|
constexpr int GLComponentCounts[static_cast<std::size_t>(cmod::VertexAttributeFormat::FormatMax)] =
|
||||||
{
|
{
|
||||||
1, // Float1
|
1, // Float1
|
||||||
2, // Float2
|
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) :
|
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)
|
if (_material == nullptr)
|
||||||
material = &defaultMaterial;
|
material = &defaultMaterial;
|
||||||
|
@ -78,7 +227,7 @@ RenderContext::RenderContext(const Material* _material)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const Material*
|
const cmod::Material*
|
||||||
RenderContext::getMaterial() const
|
RenderContext::getMaterial() const
|
||||||
{
|
{
|
||||||
return material;
|
return material;
|
||||||
|
@ -86,7 +235,7 @@ RenderContext::getMaterial() const
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
RenderContext::setMaterial(const Material* newMaterial)
|
RenderContext::setMaterial(const cmod::Material* newMaterial)
|
||||||
{
|
{
|
||||||
if (!locked)
|
if (!locked)
|
||||||
{
|
{
|
||||||
|
@ -103,8 +252,8 @@ RenderContext::setMaterial(const Material* newMaterial)
|
||||||
}
|
}
|
||||||
else if (renderPass == EmissivePass)
|
else if (renderPass == EmissivePass)
|
||||||
{
|
{
|
||||||
if (material->maps[Material::EmissiveMap] !=
|
if (material->getMap(cmod::TextureSemantic::EmissiveMap) !=
|
||||||
newMaterial->maps[Material::EmissiveMap])
|
newMaterial->getMap(cmod::TextureSemantic::EmissiveMap))
|
||||||
{
|
{
|
||||||
material = newMaterial;
|
material = newMaterial;
|
||||||
makeCurrent(*material);
|
makeCurrent(*material);
|
||||||
|
@ -136,13 +285,13 @@ RenderContext::getPointScale() const
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
RenderContext::setCameraOrientation(const Quaternionf& q)
|
RenderContext::setCameraOrientation(const Eigen::Quaternionf& q)
|
||||||
{
|
{
|
||||||
cameraOrientation = q;
|
cameraOrientation = q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Quaternionf
|
Eigen::Quaternionf
|
||||||
RenderContext::getCameraOrientation() const
|
RenderContext::getCameraOrientation() const
|
||||||
{
|
{
|
||||||
return cameraOrientation;
|
return cameraOrientation;
|
||||||
|
@ -150,11 +299,11 @@ RenderContext::getCameraOrientation() const
|
||||||
|
|
||||||
|
|
||||||
void
|
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
|
// Skip rendering if this is the emissive pass but there's no
|
||||||
// emissive texture.
|
// emissive texture.
|
||||||
ResourceHandle emissiveMap = material->maps[Material::EmissiveMap];
|
ResourceHandle emissiveMap = material->getMap(cmod::TextureSemantic::EmissiveMap);
|
||||||
|
|
||||||
if (renderPass == EmissivePass && emissiveMap == InvalidResource)
|
if (renderPass == EmissivePass && emissiveMap == InvalidResource)
|
||||||
{
|
{
|
||||||
|
@ -162,10 +311,10 @@ RenderContext::drawGroup(const Mesh::PrimitiveGroup& group, bool useOverride)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool drawPoints = false;
|
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;
|
drawPoints = true;
|
||||||
if (group.prim == Mesh::PointList)
|
if (group.prim == cmod::PrimitiveGroupType::PointList)
|
||||||
glVertexAttrib1f(CelestiaGLProgram::PointSizeAttributeIndex, 1.0f);
|
glVertexAttrib1f(CelestiaGLProgram::PointSizeAttributeIndex, 1.0f);
|
||||||
#ifndef GL_ES
|
#ifndef GL_ES
|
||||||
glEnable(GL_POINT_SPRITE);
|
glEnable(GL_POINT_SPRITE);
|
||||||
|
@ -189,7 +338,7 @@ RenderContext::drawGroup(const Mesh::PrimitiveGroup& group, bool useOverride)
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
RenderContext::setVertexArrays(const Mesh::VertexDescription& desc,
|
RenderContext::setVertexArrays(const cmod::VertexDescription& desc,
|
||||||
const void* vertexData)
|
const void* vertexData)
|
||||||
{
|
{
|
||||||
setStandardVertexArrays(desc, vertexData);
|
setStandardVertexArrays(desc, vertexData);
|
||||||
|
@ -197,18 +346,23 @@ RenderContext::setVertexArrays(const Mesh::VertexDescription& desc,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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.
|
// Normally, the shader that will be used depends only on the material.
|
||||||
// But the presence of point size and normals can also affect the
|
// But the presence of point size and normals can also affect the
|
||||||
// shader, so force an update of the material if those attributes appear
|
// shader, so force an update of the material if those attributes appear
|
||||||
// or disappear in the new set of vertex arrays.
|
// or disappear in the new set of vertex arrays.
|
||||||
bool usePointSizeNow = (desc.getAttribute(Mesh::PointSize).format == Mesh::Float1);
|
bool usePointSizeNow = (desc.getAttribute(cmod::VertexAttributeSemantic::PointSize).format
|
||||||
bool useNormalsNow = (desc.getAttribute(Mesh::Normal).format == Mesh::Float3);
|
== cmod::VertexAttributeFormat::Float1);
|
||||||
bool useColorsNow = (desc.getAttribute(Mesh::Color0).format != Mesh::InvalidFormat);
|
bool useNormalsNow = (desc.getAttribute(cmod::VertexAttributeSemantic::Normal).format
|
||||||
bool useTexCoordsNow = (desc.getAttribute(Mesh::Texture0).format != Mesh::InvalidFormat);
|
== cmod::VertexAttributeFormat::Float3);
|
||||||
bool drawLineNow = (desc.getAttribute(Mesh::NextPosition).format == Mesh::Float3);
|
bool useColorsNow = (desc.getAttribute(cmod::VertexAttributeSemantic::Color0).format
|
||||||
bool useStaticPointSizeNow = primType == Mesh::PointList;
|
!= 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 ||
|
if (usePointSizeNow != usePointSize ||
|
||||||
useStaticPointSizeNow != useStaticPointSize ||
|
useStaticPointSizeNow != useStaticPointSize ||
|
||||||
|
@ -240,168 +394,17 @@ RenderContext::setModelViewMatrix(const Eigen::Matrix4f *m)
|
||||||
modelViewMatrix = 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 render context ******/
|
||||||
|
|
||||||
GLSL_RenderContext::GLSL_RenderContext(Renderer* renderer,
|
GLSL_RenderContext::GLSL_RenderContext(Renderer* renderer,
|
||||||
const LightingState& ls,
|
const LightingState& ls,
|
||||||
float _objRadius,
|
float _objRadius,
|
||||||
const Quaternionf& orientation) :
|
const Eigen::Quaternionf& orientation) :
|
||||||
RenderContext(renderer),
|
RenderContext(renderer),
|
||||||
lightingState(ls),
|
lightingState(ls),
|
||||||
objRadius(_objRadius),
|
objRadius(_objRadius),
|
||||||
objScale(Vector3f::Constant(_objRadius)),
|
objScale(Eigen::Vector3f::Constant(_objRadius)),
|
||||||
objOrientation(orientation)
|
objOrientation(orientation)
|
||||||
{
|
{
|
||||||
initLightingEnvironment();
|
initLightingEnvironment();
|
||||||
|
@ -411,7 +414,7 @@ GLSL_RenderContext::GLSL_RenderContext(Renderer* renderer,
|
||||||
GLSL_RenderContext::GLSL_RenderContext(Renderer* renderer,
|
GLSL_RenderContext::GLSL_RenderContext(Renderer* renderer,
|
||||||
const LightingState& ls,
|
const LightingState& ls,
|
||||||
const Eigen::Vector3f& _objScale,
|
const Eigen::Vector3f& _objScale,
|
||||||
const Quaternionf& orientation) :
|
const Eigen::Quaternionf& orientation) :
|
||||||
RenderContext(renderer),
|
RenderContext(renderer),
|
||||||
lightingState(ls),
|
lightingState(ls),
|
||||||
objRadius(_objScale.maxCoeff()),
|
objRadius(_objScale.maxCoeff()),
|
||||||
|
@ -438,7 +441,7 @@ GLSL_RenderContext::initLightingEnvironment()
|
||||||
{
|
{
|
||||||
// Set the light and shadow environment, which is constant for the entire model.
|
// Set the light and shadow environment, which is constant for the entire model.
|
||||||
// The material properties will be set per mesh.
|
// 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.
|
// Set the shadow information.
|
||||||
// Track the total number of shadows; if there are too many, we'll have
|
// 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())
|
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);
|
shaderProps.setEclipseShadowCountForLight(li, nShadows);
|
||||||
totalShadows += nShadows;
|
totalShadows += nShadows;
|
||||||
}
|
}
|
||||||
|
@ -457,7 +461,7 @@ GLSL_RenderContext::initLightingEnvironment()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GLSL_RenderContext::makeCurrent(const Material& m)
|
GLSL_RenderContext::makeCurrent(const cmod::Material& m)
|
||||||
{
|
{
|
||||||
Texture* textures[4] = { nullptr, nullptr, nullptr, nullptr };
|
Texture* textures[4] = { nullptr, nullptr, nullptr, nullptr };
|
||||||
unsigned int nTextures = 0;
|
unsigned int nTextures = 0;
|
||||||
|
@ -490,10 +494,10 @@ GLSL_RenderContext::makeCurrent(const Material& m)
|
||||||
shaderProps.lightModel = ShaderProperties::ParticleDiffuseModel;
|
shaderProps.lightModel = ShaderProperties::ParticleDiffuseModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceHandle diffuseMap = m.maps[Material::DiffuseMap];
|
ResourceHandle diffuseMap = m.getMap(cmod::TextureSemantic::DiffuseMap);
|
||||||
ResourceHandle normalMap = m.maps[Material::NormalMap];
|
ResourceHandle normalMap = m.getMap(cmod::TextureSemantic::NormalMap);
|
||||||
ResourceHandle specularMap = m.maps[Material::SpecularMap];
|
ResourceHandle specularMap = m.getMap(cmod::TextureSemantic::SpecularMap);
|
||||||
ResourceHandle emissiveMap = m.maps[Material::EmissiveMap];
|
ResourceHandle emissiveMap = m.getMap(cmod::TextureSemantic::EmissiveMap);
|
||||||
|
|
||||||
if (diffuseMap != InvalidResource && (useTexCoords || usePointSize))
|
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;
|
shaderProps.lightModel = ShaderProperties::PerPixelSpecularModel;
|
||||||
specTex = GetTextureManager()->find(specularMap);
|
specTex = GetTextureManager()->find(specularMap);
|
||||||
|
@ -634,9 +638,9 @@ GLSL_RenderContext::makeCurrent(const Material& m)
|
||||||
#if GL_ONLY_SHADOWS
|
#if GL_ONLY_SHADOWS
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
|
||||||
#endif
|
#endif
|
||||||
Matrix4f shadowBias(Matrix4f::Zero());
|
Eigen::Matrix4f shadowBias(Eigen::Matrix4f::Zero());
|
||||||
shadowBias.diagonal() = Vector4f(0.5f, 0.5f, 0.5f, 1.0f);
|
shadowBias.diagonal() = Eigen::Vector4f(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
shadowBias.col(3) = 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->ShadowMatrix0 = shadowBias * (*lightMatrix);
|
||||||
prog->floatParam("shadowMapSize") = static_cast<float>(shadowMapWidth);
|
prog->floatParam("shadowMapSize") = static_cast<float>(shadowMapWidth);
|
||||||
}
|
}
|
||||||
|
@ -698,7 +702,7 @@ GLSL_RenderContext::makeCurrent(const Material& m)
|
||||||
float ringWidth = rings->outerRadius - rings->innerRadius;
|
float ringWidth = rings->outerRadius - rings->innerRadius;
|
||||||
prog->ringRadius = rings->innerRadius / objRadius;
|
prog->ringRadius = rings->innerRadius / objRadius;
|
||||||
prog->ringWidth = objRadius / ringWidth;
|
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;
|
prog->ringCenter = lightingState.ringCenter / objRadius;
|
||||||
|
|
||||||
for (unsigned int lightIndex = 0; lightIndex < lightingState.nLights; ++lightIndex)
|
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 ||
|
if (m.opacity != 1.0f ||
|
||||||
m.blend == Material::AdditiveBlend ||
|
m.blend == cmod::BlendMode::AdditiveBlend ||
|
||||||
(baseTex != nullptr && baseTex->hasAlpha()))
|
(baseTex != nullptr && baseTex->hasAlpha()))
|
||||||
{
|
{
|
||||||
newBlendMode = m.blend;
|
newBlendMode = m.blend;
|
||||||
|
@ -723,7 +727,7 @@ GLSL_RenderContext::makeCurrent(const Material& m)
|
||||||
blendMode = newBlendMode;
|
blendMode = newBlendMode;
|
||||||
switch (blendMode)
|
switch (blendMode)
|
||||||
{
|
{
|
||||||
case Material::NormalBlend:
|
case cmod::BlendMode::NormalBlend:
|
||||||
renderer->enableBlending();
|
renderer->enableBlending();
|
||||||
renderer->setBlendingFactors(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
renderer->setBlendingFactors(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
if (disableDepthWriteOnBlend)
|
if (disableDepthWriteOnBlend)
|
||||||
|
@ -731,7 +735,7 @@ GLSL_RenderContext::makeCurrent(const Material& m)
|
||||||
else
|
else
|
||||||
renderer->enableDepthMask();
|
renderer->enableDepthMask();
|
||||||
break;
|
break;
|
||||||
case Material::AdditiveBlend:
|
case cmod::BlendMode::AdditiveBlend:
|
||||||
renderer->enableBlending();
|
renderer->enableBlending();
|
||||||
renderer->setBlendingFactors(GL_SRC_ALPHA, GL_ONE);
|
renderer->setBlendingFactors(GL_SRC_ALPHA, GL_ONE);
|
||||||
if (disableDepthWriteOnBlend)
|
if (disableDepthWriteOnBlend)
|
||||||
|
@ -739,7 +743,7 @@ GLSL_RenderContext::makeCurrent(const Material& m)
|
||||||
else
|
else
|
||||||
renderer->enableDepthMask();
|
renderer->enableDepthMask();
|
||||||
break;
|
break;
|
||||||
case Material::PremultipliedAlphaBlend:
|
case cmod::BlendMode::PremultipliedAlphaBlend:
|
||||||
renderer->enableBlending();
|
renderer->enableBlending();
|
||||||
renderer->setBlendingFactors(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
renderer->setBlendingFactors(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
if (disableDepthWriteOnBlend)
|
if (disableDepthWriteOnBlend)
|
||||||
|
@ -781,7 +785,7 @@ GLSL_RenderContext::setShadowMap(GLuint _shadowMap, GLuint _width, const Eigen::
|
||||||
|
|
||||||
GLSLUnlit_RenderContext::GLSLUnlit_RenderContext(Renderer* renderer, float _objRadius) :
|
GLSLUnlit_RenderContext::GLSLUnlit_RenderContext(Renderer* renderer, float _objRadius) :
|
||||||
RenderContext(renderer),
|
RenderContext(renderer),
|
||||||
blendMode(Material::InvalidBlend),
|
blendMode(cmod::BlendMode::InvalidBlend),
|
||||||
objRadius(_objRadius)
|
objRadius(_objRadius)
|
||||||
{
|
{
|
||||||
initLightingEnvironment();
|
initLightingEnvironment();
|
||||||
|
@ -809,7 +813,7 @@ GLSLUnlit_RenderContext::initLightingEnvironment()
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
GLSLUnlit_RenderContext::makeCurrent(const Material& m)
|
GLSLUnlit_RenderContext::makeCurrent(const cmod::Material& m)
|
||||||
{
|
{
|
||||||
Texture* textures[4] = { nullptr, nullptr, nullptr, nullptr };
|
Texture* textures[4] = { nullptr, nullptr, nullptr, nullptr };
|
||||||
unsigned int nTextures = 0;
|
unsigned int nTextures = 0;
|
||||||
|
@ -820,7 +824,7 @@ GLSLUnlit_RenderContext::makeCurrent(const Material& m)
|
||||||
shaderProps.lightModel = ShaderProperties::EmissiveModel;
|
shaderProps.lightModel = ShaderProperties::EmissiveModel;
|
||||||
shaderProps.texUsage = ShaderProperties::SharedTextureCoords;
|
shaderProps.texUsage = ShaderProperties::SharedTextureCoords;
|
||||||
|
|
||||||
ResourceHandle diffuseMap = m.maps[Material::DiffuseMap];
|
ResourceHandle diffuseMap = m.getMap(cmod::TextureSemantic::DiffuseMap);
|
||||||
if (diffuseMap != InvalidResource && (useTexCoords || usePointSize))
|
if (diffuseMap != InvalidResource && (useTexCoords || usePointSize))
|
||||||
{
|
{
|
||||||
baseTex = GetTextureManager()->find(diffuseMap);
|
baseTex = GetTextureManager()->find(diffuseMap);
|
||||||
|
@ -879,9 +883,9 @@ GLSLUnlit_RenderContext::makeCurrent(const Material& m)
|
||||||
prog->lineWidthY = renderer->getLineWidthY();
|
prog->lineWidthY = renderer->getLineWidthY();
|
||||||
}
|
}
|
||||||
|
|
||||||
Material::BlendMode newBlendMode = Material::InvalidBlend;
|
cmod::BlendMode newBlendMode = cmod::BlendMode::InvalidBlend;
|
||||||
if (m.opacity != 1.0f ||
|
if (m.opacity != 1.0f ||
|
||||||
m.blend == Material::AdditiveBlend ||
|
m.blend == cmod::BlendMode::AdditiveBlend ||
|
||||||
(baseTex != nullptr && baseTex->hasAlpha()))
|
(baseTex != nullptr && baseTex->hasAlpha()))
|
||||||
{
|
{
|
||||||
newBlendMode = m.blend;
|
newBlendMode = m.blend;
|
||||||
|
@ -892,17 +896,17 @@ GLSLUnlit_RenderContext::makeCurrent(const Material& m)
|
||||||
blendMode = newBlendMode;
|
blendMode = newBlendMode;
|
||||||
switch (blendMode)
|
switch (blendMode)
|
||||||
{
|
{
|
||||||
case Material::NormalBlend:
|
case cmod::BlendMode::NormalBlend:
|
||||||
renderer->enableBlending();
|
renderer->enableBlending();
|
||||||
renderer->setBlendingFactors(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
renderer->setBlendingFactors(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
renderer->disableDepthMask();
|
renderer->disableDepthMask();
|
||||||
break;
|
break;
|
||||||
case Material::AdditiveBlend:
|
case cmod::BlendMode::AdditiveBlend:
|
||||||
renderer->enableBlending();
|
renderer->enableBlending();
|
||||||
renderer->setBlendingFactors(GL_SRC_ALPHA, GL_ONE);
|
renderer->setBlendingFactors(GL_SRC_ALPHA, GL_ONE);
|
||||||
renderer->disableDepthMask();
|
renderer->disableDepthMask();
|
||||||
break;
|
break;
|
||||||
case Material::PremultipliedAlphaBlend:
|
case cmod::BlendMode::PremultipliedAlphaBlend:
|
||||||
renderer->enableBlending();
|
renderer->enableBlending();
|
||||||
renderer->setBlendingFactors(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
renderer->setBlendingFactors(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
renderer->disableDepthMask();
|
renderer->disableDepthMask();
|
||||||
|
|
|
@ -8,13 +8,21 @@
|
||||||
// as published by the Free Software Foundation; either version 2
|
// as published by the Free Software Foundation; either version 2
|
||||||
// of the License, or (at your option) any later version.
|
// of the License, or (at your option) any later version.
|
||||||
|
|
||||||
#ifndef _CELENGINE_RENDCONTEXT_H_
|
#pragma once
|
||||||
#define _CELENGINE_RENDCONTEXT_H_
|
|
||||||
|
|
||||||
#include "shadermanager.h"
|
#include <Eigen/Core>
|
||||||
#include <celmodel/mesh.h>
|
|
||||||
#include <Eigen/Geometry>
|
#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 Renderer;
|
||||||
|
|
||||||
class RenderContext
|
class RenderContext
|
||||||
|
@ -27,10 +35,10 @@ class RenderContext
|
||||||
virtual ~RenderContext() = default;
|
virtual ~RenderContext() = default;
|
||||||
|
|
||||||
virtual void makeCurrent(const cmod::Material&) = 0;
|
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);
|
const void* vertexData);
|
||||||
virtual void updateShader(const cmod::Mesh::VertexDescription& desc, cmod::Mesh::PrimitiveGroupType primType);
|
virtual void updateShader(const cmod::VertexDescription& desc, cmod::PrimitiveGroupType primType);
|
||||||
virtual void drawGroup(const cmod::Mesh::PrimitiveGroup& group, bool useOverride);
|
virtual void drawGroup(const cmod::PrimitiveGroup& group, bool useOverride);
|
||||||
|
|
||||||
const cmod::Material* getMaterial() const;
|
const cmod::Material* getMaterial() const;
|
||||||
void setMaterial(const cmod::Material*);
|
void setMaterial(const cmod::Material*);
|
||||||
|
@ -57,13 +65,6 @@ class RenderContext
|
||||||
void setModelViewMatrix(const Eigen::Matrix4f *m);
|
void setModelViewMatrix(const Eigen::Matrix4f *m);
|
||||||
void setProjectionMatrix(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:
|
protected:
|
||||||
Renderer* renderer { nullptr };
|
Renderer* renderer { nullptr };
|
||||||
bool usePointSize{ false };
|
bool usePointSize{ false };
|
||||||
|
@ -74,6 +75,13 @@ class RenderContext
|
||||||
bool drawLine { false };
|
bool drawLine { false };
|
||||||
const Eigen::Matrix4f *modelViewMatrix;
|
const Eigen::Matrix4f *modelViewMatrix;
|
||||||
const Eigen::Matrix4f *projectionMatrix;
|
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*);
|
void setShadowMap(GLuint, GLuint, const Eigen::Matrix4f*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initLightingEnvironment();
|
void initLightingEnvironment();
|
||||||
void setLightingParameters(CelestiaGLProgram& prog, Color diffuseColor, Color specularColor);
|
void setLightingParameters(CelestiaGLProgram& prog, Color diffuseColor, Color specularColor);
|
||||||
void setShadowParameters(CelestiaGLProgram& prog);
|
void setShadowParameters(CelestiaGLProgram& prog);
|
||||||
|
|
||||||
private:
|
|
||||||
const LightingState& lightingState;
|
const LightingState& lightingState;
|
||||||
const Atmosphere* atmosphere{ nullptr };
|
const Atmosphere* atmosphere{ nullptr };
|
||||||
cmod::Material::BlendMode blendMode{ cmod::Material::InvalidBlend };
|
cmod::BlendMode blendMode{ cmod::BlendMode::InvalidBlend };
|
||||||
float objRadius;
|
float objRadius;
|
||||||
Eigen::Vector3f objScale;
|
Eigen::Vector3f objScale;
|
||||||
Eigen::Quaternionf objOrientation;
|
Eigen::Quaternionf objOrientation;
|
||||||
|
@ -139,12 +146,8 @@ class GLSLUnlit_RenderContext : public RenderContext
|
||||||
void initLightingEnvironment();
|
void initLightingEnvironment();
|
||||||
void setLightingParameters(CelestiaGLProgram& prog, Color diffuseColor, Color specularColor);
|
void setLightingParameters(CelestiaGLProgram& prog, Color diffuseColor, Color specularColor);
|
||||||
|
|
||||||
private:
|
cmod::BlendMode blendMode;
|
||||||
cmod::Material::BlendMode blendMode;
|
|
||||||
float objRadius;
|
float objRadius;
|
||||||
|
|
||||||
ShaderProperties shaderProps;
|
ShaderProperties shaderProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // _CELENGINE_RENDCONTEXT_H_
|
|
||||||
|
|
|
@ -95,7 +95,6 @@ std::ofstream hdrlog;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace cmod;
|
|
||||||
using namespace Eigen;
|
using namespace Eigen;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace celestia;
|
using namespace celestia;
|
||||||
|
|
|
@ -8,14 +8,15 @@
|
||||||
// as published by the Free Software Foundation; either version 2
|
// as published by the Free Software Foundation; either version 2
|
||||||
// of the License, or (at your option) any later version.
|
// of the License, or (at your option) any later version.
|
||||||
|
|
||||||
#ifndef _CELENGINE_RENDER_H_
|
#pragma once
|
||||||
#define _CELENGINE_RENDER_H_
|
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <Eigen/Core>
|
#include <Eigen/Core>
|
||||||
|
|
||||||
#include <celengine/universe.h>
|
#include <celengine/universe.h>
|
||||||
#include <celengine/selection.h>
|
#include <celengine/selection.h>
|
||||||
#include <celengine/starcolors.h>
|
#include <celengine/starcolors.h>
|
||||||
|
@ -965,6 +966,3 @@ class RendererWatcher
|
||||||
|
|
||||||
virtual void notifyRenderSettingsChanged(const Renderer*) = 0;
|
virtual void notifyRenderSettingsChanged(const Renderer*) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // _CELENGINE_RENDER_H_
|
|
||||||
|
|
|
@ -10,59 +10,117 @@
|
||||||
// as published by the Free Software Foundation; either version 2
|
// as published by the Free Software Foundation; either version 2
|
||||||
// of the License, or (at your option) any later version.
|
// of the License, or (at your option) any later version.
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstddef>
|
||||||
#include <memory>
|
#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 "framebuffer.h"
|
||||||
#include "geometry.h"
|
#include "geometry.h"
|
||||||
|
#include "glsupport.h"
|
||||||
#include "lodspheremesh.h"
|
#include "lodspheremesh.h"
|
||||||
#include "meshmanager.h"
|
#include "rendcontext.h"
|
||||||
#include "modelgeometry.h"
|
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "renderinfo.h"
|
|
||||||
#include "renderglsl.h"
|
#include "renderglsl.h"
|
||||||
|
#include "renderinfo.h"
|
||||||
#include "shadermanager.h"
|
#include "shadermanager.h"
|
||||||
#include "texmanager.h"
|
#include "texture.h"
|
||||||
#include "vecgl.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;
|
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,
|
void renderGeometryShadow_GLSL(Geometry* geometry,
|
||||||
FramebufferObject* shadowFbo,
|
FramebufferObject* shadowFbo,
|
||||||
const LightingState& ls,
|
const LightingState& ls,
|
||||||
int lightIndex,
|
int lightIndex,
|
||||||
double tsec,
|
double tsec,
|
||||||
Renderer* renderer,
|
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
|
// Render a planet sphere with GLSL shaders
|
||||||
void renderEllipsoid_GLSL(const RenderInfo& ri,
|
void renderEllipsoid_GLSL(const RenderInfo& ri,
|
||||||
const LightingState& ls,
|
const LightingState& ls,
|
||||||
Atmosphere* atmosphere,
|
Atmosphere* atmosphere,
|
||||||
float cloudTexOffset,
|
float cloudTexOffset,
|
||||||
const Vector3f& semiAxes,
|
const Eigen::Vector3f& semiAxes,
|
||||||
unsigned int textureRes,
|
unsigned int textureRes,
|
||||||
uint64_t renderFlags,
|
std::uint64_t renderFlags,
|
||||||
const Quaternionf& planetOrientation,
|
const Eigen::Quaternionf& planetOrientation,
|
||||||
const Frustum& frustum,
|
const celmath::Frustum& frustum,
|
||||||
const Matrices &m,
|
const Matrices &m,
|
||||||
Renderer* renderer)
|
Renderer* renderer)
|
||||||
{
|
{
|
||||||
float radius = semiAxes.maxCoeff();
|
float radius = semiAxes.maxCoeff();
|
||||||
|
|
||||||
|
@ -71,7 +129,7 @@ void renderEllipsoid_GLSL(const RenderInfo& ri,
|
||||||
unsigned int nTextures = 0;
|
unsigned int nTextures = 0;
|
||||||
|
|
||||||
ShaderProperties shadprop;
|
ShaderProperties shadprop;
|
||||||
shadprop.nLights = min(ls.nLights, MaxShaderLights);
|
shadprop.nLights = std::min(ls.nLights, MaxShaderLights);
|
||||||
|
|
||||||
// Set up the textures used by this object
|
// Set up the textures used by this object
|
||||||
if (ri.baseTex != nullptr)
|
if (ri.baseTex != nullptr)
|
||||||
|
@ -189,7 +247,8 @@ void renderEllipsoid_GLSL(const RenderInfo& ri,
|
||||||
{
|
{
|
||||||
if (ls.shadows[li] && !ls.shadows[li]->empty())
|
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);
|
shadprop.setEclipseShadowCountForLight(li, nShadows);
|
||||||
totalShadows += nShadows;
|
totalShadows += nShadows;
|
||||||
}
|
}
|
||||||
|
@ -262,7 +321,7 @@ void renderEllipsoid_GLSL(const RenderInfo& ri,
|
||||||
float ringWidth = ls.shadowingRingSystem->outerRadius - ls.shadowingRingSystem->innerRadius;
|
float ringWidth = ls.shadowingRingSystem->outerRadius - ls.shadowingRingSystem->innerRadius;
|
||||||
prog->ringRadius = ls.shadowingRingSystem->innerRadius / radius;
|
prog->ringRadius = ls.shadowingRingSystem->innerRadius / radius;
|
||||||
prog->ringWidth = radius / ringWidth;
|
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;
|
prog->ringCenter = ls.ringCenter / radius;
|
||||||
for (unsigned int lightIndex = 0; lightIndex < ls.nLights; ++lightIndex)
|
for (unsigned int lightIndex = 0; lightIndex < ls.nLights; ++lightIndex)
|
||||||
{
|
{
|
||||||
|
@ -311,14 +370,14 @@ void renderGeometry_GLSL(Geometry* geometry,
|
||||||
const LightingState& ls,
|
const LightingState& ls,
|
||||||
const Atmosphere* atmosphere,
|
const Atmosphere* atmosphere,
|
||||||
float geometryScale,
|
float geometryScale,
|
||||||
uint64_t renderFlags,
|
std::uint64_t renderFlags,
|
||||||
const Quaternionf& planetOrientation,
|
const Eigen::Quaternionf& planetOrientation,
|
||||||
double tsec,
|
double tsec,
|
||||||
const Matrices &m,
|
const Matrices &m,
|
||||||
Renderer* renderer)
|
Renderer* renderer)
|
||||||
{
|
{
|
||||||
auto *shadowBuffer = renderer->getShadowFBO(0);
|
auto *shadowBuffer = renderer->getShadowFBO(0);
|
||||||
Matrix4f lightMatrix(Matrix4f::Identity());
|
Eigen::Matrix4f lightMatrix(Eigen::Matrix4f::Identity());
|
||||||
|
|
||||||
if (shadowBuffer != nullptr && shadowBuffer->isValid())
|
if (shadowBuffer != nullptr && shadowBuffer->isValid())
|
||||||
{
|
{
|
||||||
|
@ -407,12 +466,12 @@ void renderGeometry_GLSL(Geometry* geometry,
|
||||||
// override all materials specified in the geometry file.
|
// override all materials specified in the geometry file.
|
||||||
if (texOverride != InvalidResource)
|
if (texOverride != InvalidResource)
|
||||||
{
|
{
|
||||||
Material m;
|
cmod::Material m;
|
||||||
m.diffuse = Material::Color(ri.color);
|
m.diffuse = cmod::Color(ri.color);
|
||||||
m.specular = Material::Color(ri.specularColor);
|
m.specular = cmod::Color(ri.specularColor);
|
||||||
m.specularPower = ri.specularPower;
|
m.specularPower = ri.specularPower;
|
||||||
|
|
||||||
m.maps[Material::DiffuseMap] = texOverride;
|
m.setMap(cmod::TextureSemantic::DiffuseMap, texOverride);
|
||||||
rc.setMaterial(&m);
|
rc.setMaterial(&m);
|
||||||
rc.lock();
|
rc.lock();
|
||||||
geometry->render(rc, tsec);
|
geometry->render(rc, tsec);
|
||||||
|
@ -432,8 +491,8 @@ void renderGeometry_GLSL_Unlit(Geometry* geometry,
|
||||||
const RenderInfo& ri,
|
const RenderInfo& ri,
|
||||||
ResourceHandle texOverride,
|
ResourceHandle texOverride,
|
||||||
float geometryScale,
|
float geometryScale,
|
||||||
uint64_t /* renderFlags */,
|
std::uint64_t /* renderFlags */,
|
||||||
const Quaternionf& /* planetOrientation */,
|
const Eigen::Quaternionf& /* planetOrientation */,
|
||||||
double tsec,
|
double tsec,
|
||||||
const Matrices &m,
|
const Matrices &m,
|
||||||
Renderer* renderer)
|
Renderer* renderer)
|
||||||
|
@ -448,12 +507,12 @@ void renderGeometry_GLSL_Unlit(Geometry* geometry,
|
||||||
// override all materials specified in the model file.
|
// override all materials specified in the model file.
|
||||||
if (texOverride != InvalidResource)
|
if (texOverride != InvalidResource)
|
||||||
{
|
{
|
||||||
Material m;
|
cmod::Material m;
|
||||||
m.diffuse = Material::Color(ri.color);
|
m.diffuse = cmod::Color(ri.color);
|
||||||
m.specular = Material::Color(ri.specularColor);
|
m.specular = cmod::Color(ri.specularColor);
|
||||||
m.specularPower = ri.specularPower;
|
m.specularPower = ri.specularPower;
|
||||||
|
|
||||||
m.maps[Material::DiffuseMap] = texOverride;
|
m.setMap(cmod::TextureSemantic::DiffuseMap, texOverride);
|
||||||
rc.setMaterial(&m);
|
rc.setMaterial(&m);
|
||||||
rc.lock();
|
rc.lock();
|
||||||
geometry->render(rc, tsec);
|
geometry->render(rc, tsec);
|
||||||
|
@ -472,11 +531,11 @@ void renderClouds_GLSL(const RenderInfo& ri,
|
||||||
Texture* cloudTex,
|
Texture* cloudTex,
|
||||||
Texture* cloudNormalMap,
|
Texture* cloudNormalMap,
|
||||||
float texOffset,
|
float texOffset,
|
||||||
const Vector3f& semiAxes,
|
const Eigen::Vector3f& semiAxes,
|
||||||
unsigned int /*textureRes*/,
|
unsigned int /*textureRes*/,
|
||||||
uint64_t renderFlags,
|
std::uint64_t renderFlags,
|
||||||
const Quaternionf& planetOrientation,
|
const Eigen::Quaternionf& planetOrientation,
|
||||||
const Frustum& frustum,
|
const celmath::Frustum& frustum,
|
||||||
const Matrices &m,
|
const Matrices &m,
|
||||||
Renderer* renderer)
|
Renderer* renderer)
|
||||||
{
|
{
|
||||||
|
@ -546,7 +605,8 @@ void renderClouds_GLSL(const RenderInfo& ri,
|
||||||
{
|
{
|
||||||
if (ls.shadows[li] && !ls.shadows[li]->empty())
|
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);
|
shadprop.setEclipseShadowCountForLight(li, nShadows);
|
||||||
totalShadows += nShadows;
|
totalShadows += nShadows;
|
||||||
}
|
}
|
||||||
|
@ -604,8 +664,8 @@ renderAtmosphere_GLSL(const RenderInfo& ri,
|
||||||
const LightingState& ls,
|
const LightingState& ls,
|
||||||
Atmosphere* atmosphere,
|
Atmosphere* atmosphere,
|
||||||
float radius,
|
float radius,
|
||||||
const Quaternionf& /*planetOrientation*/,
|
const Eigen::Quaternionf& /*planetOrientation*/,
|
||||||
const Frustum& frustum,
|
const celmath::Frustum& frustum,
|
||||||
const Matrices &m,
|
const Matrices &m,
|
||||||
Renderer* renderer)
|
Renderer* renderer)
|
||||||
{
|
{
|
||||||
|
@ -629,9 +689,9 @@ renderAtmosphere_GLSL(const RenderInfo& ri,
|
||||||
prog->use();
|
prog->use();
|
||||||
|
|
||||||
prog->setLightParameters(ls, ri.color, ri.specularColor, Color::Black);
|
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;
|
float atmScale = atmosphereRadius / radius;
|
||||||
|
|
||||||
prog->eyePosition = ls.eyePos_obj / atmScale;
|
prog->eyePosition = ls.eyePos_obj / atmScale;
|
||||||
|
@ -671,19 +731,19 @@ static void renderRingSystem(GLuint *vboId,
|
||||||
GLshort tex[2];
|
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)
|
if (*vboId == 0)
|
||||||
{
|
{
|
||||||
struct RingVertex vertex;
|
struct RingVertex vertex;
|
||||||
vector<struct RingVertex> ringCoord;
|
std::vector<struct RingVertex> ringCoord;
|
||||||
ringCoord.reserve(2 * nSections);
|
ringCoord.reserve(2 * nSections);
|
||||||
for (unsigned i = 0; i <= nSections; i++)
|
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 theta = t * angle;
|
||||||
float s = (float) sin(theta);
|
float s = std::sin(theta);
|
||||||
float c = (float) cos(theta);
|
float c = std::cos(theta);
|
||||||
|
|
||||||
// inner point
|
// inner point
|
||||||
vertex.pos[0] = c * innerRadius;
|
vertex.pos[0] = c * innerRadius;
|
||||||
|
@ -717,7 +777,7 @@ static void renderRingSystem(GLuint *vboId,
|
||||||
glVertexAttribPointer(CelestiaGLProgram::TextureCoord0AttributeIndex,
|
glVertexAttribPointer(CelestiaGLProgram::TextureCoord0AttributeIndex,
|
||||||
2, GL_SHORT, GL_FALSE,
|
2, GL_SHORT, GL_FALSE,
|
||||||
sizeof(struct RingVertex),
|
sizeof(struct RingVertex),
|
||||||
(GLvoid*) offsetof(struct RingVertex, tex));
|
reinterpret_cast<GLvoid*>(offsetof(struct RingVertex, tex)));
|
||||||
|
|
||||||
glEnableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex);
|
glEnableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex);
|
||||||
glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex,
|
glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex,
|
||||||
|
@ -768,7 +828,7 @@ void renderRings_GLSL(RingSystem& rings,
|
||||||
// Set up the shader properties for ring rendering
|
// Set up the shader properties for ring rendering
|
||||||
{
|
{
|
||||||
shadprop.lightModel = ShaderProperties::RingIllumModel;
|
shadprop.lightModel = ShaderProperties::RingIllumModel;
|
||||||
shadprop.nLights = min(ls.nLights, MaxShaderLights);
|
shadprop.nLights = std::min(ls.nLights, MaxShaderLights);
|
||||||
|
|
||||||
if (renderShadow)
|
if (renderShadow)
|
||||||
{
|
{
|
||||||
|
@ -804,8 +864,8 @@ void renderRings_GLSL(RingSystem& rings,
|
||||||
// planet would ever orbit underneath its sun (an orbital
|
// planet would ever orbit underneath its sun (an orbital
|
||||||
// inclination of 90 degrees), but this should be made
|
// inclination of 90 degrees), but this should be made
|
||||||
// more robust anyway.
|
// more robust anyway.
|
||||||
Vector3f axis = Vector3f::UnitY().cross(light.direction_obj);
|
Eigen::Vector3f axis = Eigen::Vector3f::UnitY().cross(light.direction_obj);
|
||||||
float cosAngle = Vector3f::UnitY().dot(light.direction_obj);
|
float cosAngle = Eigen::Vector3f::UnitY().dot(light.direction_obj);
|
||||||
axis.normalize();
|
axis.normalize();
|
||||||
|
|
||||||
float tScale = 1.0f;
|
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
|
// Calculate the radius of the ellipse at the incident angle of the
|
||||||
// light on the ring plane + 90 degrees.
|
// light on the ring plane + 90 degrees.
|
||||||
float r = a * (float) sqrt((1.0f - ecc2) /
|
float r = a * std::sqrt((1.0f - ecc2) /
|
||||||
(1.0f - ecc2 * square(cosAngle)));
|
(1.0f - ecc2 * celmath::square(cosAngle)));
|
||||||
|
|
||||||
tScale *= a / r;
|
tScale *= a / r;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The s axis is perpendicular to the shadow axis in the plane of the
|
// 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.
|
// of the rings, and the t axis completes the orthonormal basis.
|
||||||
Vector3f sAxis = axis * 0.5f;
|
Eigen::Vector3f sAxis = axis * 0.5f;
|
||||||
Vector3f tAxis = (axis.cross(light.direction_obj)) * 0.5f * tScale;
|
Eigen::Vector3f tAxis = (axis.cross(light.direction_obj)) * 0.5f * tScale;
|
||||||
Vector4f texGenS;
|
Eigen::Vector4f texGenS;
|
||||||
texGenS.head(3) = sAxis;
|
texGenS.head(3) = sAxis;
|
||||||
texGenS[3] = 0.5f;
|
texGenS[3] = 0.5f;
|
||||||
Vector4f texGenT;
|
Eigen::Vector4f texGenT;
|
||||||
texGenT.head(3) = tAxis;
|
texGenT.head(3) = tAxis;
|
||||||
texGenT[3] = 0.5f;
|
texGenT[3] = 0.5f;
|
||||||
|
|
||||||
|
@ -862,11 +922,11 @@ void renderRings_GLSL(RingSystem& rings,
|
||||||
ringsTex->bind();
|
ringsTex->bind();
|
||||||
|
|
||||||
if (rings.renderData == nullptr)
|
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());
|
auto data = reinterpret_cast<GLRingRenderData*>(rings.renderData.get());
|
||||||
|
|
||||||
unsigned nSections = 180;
|
unsigned nSections = 180;
|
||||||
size_t i = 0;
|
std::size_t i = 0;
|
||||||
for (i = 0; i < data->vboId.size() - 1; i++)
|
for (i = 0; i < data->vboId.size() - 1; i++)
|
||||||
{
|
{
|
||||||
float s = segmentSizeInPixels * tan(PI / nSections);
|
float s = segmentSizeInPixels * tan(PI / nSections);
|
||||||
|
@ -878,71 +938,3 @@ void renderRings_GLSL(RingSystem& rings,
|
||||||
|
|
||||||
renderer->setBlendingFactors(GL_SRC_ALPHA, GL_ONE);
|
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
|
// as published by the Free Software Foundation; either version 2
|
||||||
// of the License, or (at your option) any later version.
|
// of the License, or (at your option) any later version.
|
||||||
|
|
||||||
#ifndef _CELENGINE_RENDERGLSL_H_
|
#pragma once
|
||||||
#define _CELENGINE_RENDERGLSL_H_
|
|
||||||
|
|
||||||
#include <celengine/lightenv.h>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <Eigen/Core>
|
||||||
#include <Eigen/Geometry>
|
#include <Eigen/Geometry>
|
||||||
|
|
||||||
|
#include <celutil/reshandle.h>
|
||||||
|
|
||||||
|
|
||||||
|
class Atmosphere;
|
||||||
|
class Geometry;
|
||||||
|
class LightingState;
|
||||||
|
struct Matrices;
|
||||||
class Renderer;
|
class Renderer;
|
||||||
|
struct RenderInfo;
|
||||||
|
class RingSystem;
|
||||||
|
class Texture;
|
||||||
|
|
||||||
|
namespace celmath
|
||||||
|
{
|
||||||
|
class Frustum;
|
||||||
|
}
|
||||||
|
|
||||||
void renderEllipsoid_GLSL(const RenderInfo& ri,
|
void renderEllipsoid_GLSL(const RenderInfo& ri,
|
||||||
const LightingState& ls,
|
const LightingState& ls,
|
||||||
Atmosphere* atmosphere,
|
Atmosphere* atmosphere,
|
||||||
float cloudTexOffset,
|
float cloudTexOffset,
|
||||||
const Eigen::Vector3f& semiAxes,
|
const Eigen::Vector3f& semiAxes,
|
||||||
unsigned int textureRes,
|
unsigned int textureRes,
|
||||||
uint64_t renderFlags,
|
std::uint64_t renderFlags,
|
||||||
const Eigen::Quaternionf& planetOrientation,
|
const Eigen::Quaternionf& planetOrientation,
|
||||||
const celmath::Frustum& frustum,
|
const celmath::Frustum& frustum,
|
||||||
const Matrices &m,
|
const Matrices &m,
|
||||||
Renderer* renderer);
|
Renderer* renderer);
|
||||||
|
|
||||||
void renderGeometry_GLSL(Geometry* geometry,
|
void renderGeometry_GLSL(Geometry* geometry,
|
||||||
const RenderInfo& ri,
|
const RenderInfo& ri,
|
||||||
|
@ -36,7 +52,7 @@ void renderGeometry_GLSL(Geometry* geometry,
|
||||||
const LightingState& ls,
|
const LightingState& ls,
|
||||||
const Atmosphere* atmosphere,
|
const Atmosphere* atmosphere,
|
||||||
float geometryScale,
|
float geometryScale,
|
||||||
uint64_t renderFlags,
|
std::uint64_t renderFlags,
|
||||||
const Eigen::Quaternionf& planetOrientation,
|
const Eigen::Quaternionf& planetOrientation,
|
||||||
double tsec,
|
double tsec,
|
||||||
const Matrices &m,
|
const Matrices &m,
|
||||||
|
@ -50,7 +66,7 @@ void renderClouds_GLSL(const RenderInfo& ri,
|
||||||
float texOffset,
|
float texOffset,
|
||||||
const Eigen::Vector3f& semiAxes,
|
const Eigen::Vector3f& semiAxes,
|
||||||
unsigned int textureRes,
|
unsigned int textureRes,
|
||||||
uint64_t renderFlags,
|
std::uint64_t renderFlags,
|
||||||
const Eigen::Quaternionf& planetOrientation,
|
const Eigen::Quaternionf& planetOrientation,
|
||||||
const celmath::Frustum& frustum,
|
const celmath::Frustum& frustum,
|
||||||
const Matrices &m,
|
const Matrices &m,
|
||||||
|
@ -80,10 +96,8 @@ void renderGeometry_GLSL_Unlit(Geometry* geometry,
|
||||||
const RenderInfo& ri,
|
const RenderInfo& ri,
|
||||||
ResourceHandle texOverride,
|
ResourceHandle texOverride,
|
||||||
float geometryScale,
|
float geometryScale,
|
||||||
uint64_t renderFlags,
|
std::uint64_t renderFlags,
|
||||||
const Eigen::Quaternionf& planetOrientation,
|
const Eigen::Quaternionf& planetOrientation,
|
||||||
double tsec,
|
double tsec,
|
||||||
const Matrices &m,
|
const Matrices &m,
|
||||||
Renderer* renderer);
|
Renderer* renderer);
|
||||||
|
|
||||||
#endif // _CELENGINE_RENDERGLSL_H_
|
|
||||||
|
|
|
@ -7,6 +7,18 @@
|
||||||
// as published by the Free Software Foundation; either version 2
|
// as published by the Free Software Foundation; either version 2
|
||||||
// of the License, or (at your option) any later version.
|
// 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
|
struct RenderInfo
|
||||||
{
|
{
|
||||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||||
|
|
|
@ -12,12 +12,11 @@
|
||||||
// It's sole function now is to handle the now-deprecated .cms mesh files;
|
// It's sole function now is to handle the now-deprecated .cms mesh files;
|
||||||
// it will eventually be removed from Celestia.
|
// it will eventually be removed from Celestia.
|
||||||
|
|
||||||
#include "spheremesh.h"
|
|
||||||
#include <celmath/mathlib.h>
|
|
||||||
#include "glsupport.h"
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
using namespace Eigen;
|
#include <celmodel/mesh.h>
|
||||||
|
#include "spheremesh.h"
|
||||||
|
|
||||||
|
|
||||||
SphereMesh::SphereMesh(float radius, int _nRings, int _nSlices)
|
SphereMesh::SphereMesh(float radius, int _nRings, int _nSlices)
|
||||||
|
@ -25,13 +24,13 @@ SphereMesh::SphereMesh(float radius, int _nRings, int _nSlices)
|
||||||
createSphere(radius, _nRings, _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);
|
createSphere(1.0f, _nRings, _nSlices);
|
||||||
scale(size);
|
scale(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
SphereMesh::SphereMesh(const Vector3f& size,
|
SphereMesh::SphereMesh(const Eigen::Vector3f& size,
|
||||||
const DisplacementMap& dispmap,
|
const DisplacementMap& dispmap,
|
||||||
float height)
|
float height)
|
||||||
{
|
{
|
||||||
|
@ -42,7 +41,7 @@ SphereMesh::SphereMesh(const Vector3f& size,
|
||||||
fixNormals();
|
fixNormals();
|
||||||
}
|
}
|
||||||
|
|
||||||
SphereMesh::SphereMesh(const Vector3f& size,
|
SphereMesh::SphereMesh(const Eigen::Vector3f& size,
|
||||||
int _nRings, int _nSlices,
|
int _nRings, int _nSlices,
|
||||||
DisplacementMapFunc func,
|
DisplacementMapFunc func,
|
||||||
void* info)
|
void* info)
|
||||||
|
@ -79,27 +78,27 @@ void SphereMesh::createSphere(float radius, int _nRings, int _nSlices)
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < nRings; 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++)
|
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;
|
int n = i * (nSlices + 1) + j;
|
||||||
auto x = (float) (std::cos(phi) * std::cos(theta));
|
auto x = std::cos(phi) * std::cos(theta);
|
||||||
auto y = (float) std::sin(phi);
|
auto y = std::sin(phi);
|
||||||
auto z = (float) (std::cos(phi) * std::sin(theta));
|
auto z = std::cos(phi) * std::sin(theta);
|
||||||
vertices[n * 3] = x * radius;
|
vertices[n * 3] = x * radius;
|
||||||
vertices[n * 3 + 1] = y * radius;
|
vertices[n * 3 + 1] = y * radius;
|
||||||
vertices[n * 3 + 2] = z * radius;
|
vertices[n * 3 + 2] = z * radius;
|
||||||
normals[n * 3] = x;
|
normals[n * 3] = x;
|
||||||
normals[n * 3 + 1] = y;
|
normals[n * 3 + 1] = y;
|
||||||
normals[n * 3 + 2] = z;
|
normals[n * 3 + 2] = z;
|
||||||
texCoords[n * 2] = 1.0f - (float) j / (float) nSlices;
|
texCoords[n * 2] = 1.0f - static_cast<float>(j) / static_cast<float>(nSlices);
|
||||||
texCoords[n * 2 + 1] = 1.0f - (float) i / (float) (nRings - 1);
|
texCoords[n * 2 + 1] = 1.0f - static_cast<float>(i) / static_cast<float>(nRings - 1);
|
||||||
|
|
||||||
// Compute the tangent--required for bump mapping
|
// Compute the tangent--required for bump mapping
|
||||||
auto tx = (float) (std::sin(phi) * std::sin(theta));
|
auto tx = std::sin(phi) * std::sin(theta);
|
||||||
auto ty = (float) -std::cos(phi);
|
auto ty = -std::cos(phi);
|
||||||
auto tz = (float) (std::sin(phi) * std::cos(theta));
|
auto tz = std::sin(phi) * std::cos(theta);
|
||||||
tangents[n * 3] = tx;
|
tangents[n * 3] = tx;
|
||||||
tangents[n * 3 + 1] = ty;
|
tangents[n * 3 + 1] = ty;
|
||||||
tangents[n * 3 + 2] = tz;
|
tangents[n * 3 + 2] = tz;
|
||||||
|
@ -122,7 +121,7 @@ void SphereMesh::createSphere(float radius, int _nRings, int _nSlices)
|
||||||
void SphereMesh::generateNormals()
|
void SphereMesh::generateNormals()
|
||||||
{
|
{
|
||||||
int nQuads = nSlices * (nRings - 1);
|
int nQuads = nSlices * (nRings - 1);
|
||||||
Vector3f* faceNormals = new Vector3f[nQuads];
|
Eigen::Vector3f* faceNormals = new Eigen::Vector3f[nQuads];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
// Compute face normals for the mesh
|
// Compute face normals for the mesh
|
||||||
|
@ -138,20 +137,20 @@ void SphereMesh::generateNormals()
|
||||||
// Compute the face normal. Watch out for degenerate (zero-length)
|
// Compute the face normal. Watch out for degenerate (zero-length)
|
||||||
// edges. If there are two degenerate edges, the entire face must
|
// edges. If there are two degenerate edges, the entire face must
|
||||||
// be degenerate and we'll handle that later
|
// be degenerate and we'll handle that later
|
||||||
Vector3f v0(p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]);
|
Eigen::Vector3f v0 = Eigen::Map<Eigen::Vector3f>(p1) - Eigen::Map<Eigen::Vector3f>(p0);
|
||||||
Vector3f v1(p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]);
|
Eigen::Vector3f v1 = Eigen::Map<Eigen::Vector3f>(p2) - Eigen::Map<Eigen::Vector3f>(p1);
|
||||||
if (v0.norm() < 1e-6f)
|
if (v0.norm() < 1e-6f)
|
||||||
{
|
{
|
||||||
v0 = Vector3f(p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]);
|
v0 = Eigen::Map<Eigen::Vector3f>(p2) - Eigen::Map<Eigen::Vector3f>(p1);
|
||||||
v1 = Vector3f(p3[0] - p2[0], p3[1] - p2[1], p3[2] - p2[2]);
|
v1 = Eigen::Map<Eigen::Vector3f>(p3) - Eigen::Map<Eigen::Vector3f>(p2);
|
||||||
}
|
}
|
||||||
else if (v1.norm() < 1e-6f)
|
else if (v1.norm() < 1e-6f)
|
||||||
{
|
{
|
||||||
v0 = Vector3f(p3[0] - p2[0], p3[1] - p2[1], p3[2] - p2[2]);
|
v0 = Eigen::Map<Eigen::Vector3f>(p3) - Eigen::Map<Eigen::Vector3f>(p2);
|
||||||
v1 = Vector3f(p0[0] - p3[0], p0[1] - p3[1], p0[2] - p3[2]);
|
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();
|
float length = faceNormal.norm();
|
||||||
if (length != 0)
|
if (length != 0)
|
||||||
faceNormal *= (1 / length);
|
faceNormal *= (1 / length);
|
||||||
|
@ -224,11 +223,11 @@ void SphereMesh::generateNormals()
|
||||||
{
|
{
|
||||||
if (faceCounts[i] > 0)
|
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 nx = normals[i * 3] * s;
|
||||||
float ny = normals[i * 3 + 1] * s;
|
float ny = normals[i * 3 + 1] * s;
|
||||||
float nz = normals[i * 3 + 2] * 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)
|
if (length > 0)
|
||||||
{
|
{
|
||||||
length = 1 / length;
|
length = 1 / length;
|
||||||
|
@ -251,9 +250,9 @@ void SphereMesh::fixNormals()
|
||||||
{
|
{
|
||||||
float* v0 = normals + (i * (nSlices + 1)) * 3;
|
float* v0 = normals + (i * (nSlices + 1)) * 3;
|
||||||
float* v1 = normals + ((i + 1) * (nSlices + 1) - 1) * 3;
|
float* v1 = normals + ((i + 1) * (nSlices + 1) - 1) * 3;
|
||||||
Vector3f n0(v0[0], v0[1], v0[2]);
|
Eigen::Map<Eigen::Vector3f> n0(v0);
|
||||||
Vector3f n1(v0[0], v0[1], v0[2]);
|
Eigen::Map<Eigen::Vector3f> n1(v1);
|
||||||
Vector3f normal = n0 + n1;
|
Eigen::Vector3f normal = n0 + n1;
|
||||||
normal.normalize();
|
normal.normalize();
|
||||||
v0[0] = normal.x();
|
v0[0] = normal.x();
|
||||||
v0[1] = normal.y();
|
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;
|
int i;
|
||||||
for (i = 0; i < nVertices; 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
|
// TODO: Make a fast special case for uniform scale factors, where
|
||||||
// renormalization is not required.
|
// renormalization is not required.
|
||||||
Vector3f is = s.cwiseInverse();
|
Eigen::Vector3f is = s.cwiseInverse();
|
||||||
for (i = 0; i < nVertices; i++)
|
for (i = 0; i < nVertices; i++)
|
||||||
{
|
{
|
||||||
int n = i * 3;
|
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();
|
normal.normalize();
|
||||||
normals[n] = normal.x();
|
normals[n] = normal.x();
|
||||||
normals[n + 1] = normal.y();
|
normals[n + 1] = normal.y();
|
||||||
|
@ -297,24 +296,16 @@ void SphereMesh::scale(const Vector3f& s)
|
||||||
void SphereMesh::displace(const DisplacementMap& dispmap,
|
void SphereMesh::displace(const DisplacementMap& dispmap,
|
||||||
float height)
|
float height)
|
||||||
{
|
{
|
||||||
// assert(dispMap.getWidth() == nSlices);
|
|
||||||
// assert(dispMap.getHeight() == nRings);
|
|
||||||
|
|
||||||
for (int i = 0; i < nRings; i++)
|
for (int i = 0; i < nRings; i++)
|
||||||
{
|
{
|
||||||
for (int j = 0; j <= nSlices; j++)
|
for (int j = 0; j <= nSlices; j++)
|
||||||
{
|
{
|
||||||
int n = (i * (nSlices + 1) + j) * 3;
|
int n = (i * (nSlices + 1) + j) * 3;
|
||||||
/*
|
|
||||||
float theta = (float) j / (float) nSlices * (float) PI * 2;
|
Eigen::Map<Eigen::Vector3f> normal(normals);
|
||||||
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]);
|
|
||||||
|
|
||||||
int k = (j == nSlices) ? 0 : j;
|
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] += v.x();
|
||||||
vertices[n + 1] += v.y();
|
vertices[n + 1] += v.y();
|
||||||
vertices[n + 2] += v.z();
|
vertices[n + 2] += v.z();
|
||||||
|
@ -332,8 +323,8 @@ void SphereMesh::displace(DisplacementMapFunc func, void* info)
|
||||||
{
|
{
|
||||||
float u = (float) j / (float) nSlices;
|
float u = (float) j / (float) nSlices;
|
||||||
int n = (i * (nSlices + 1) + j) * 3;
|
int n = (i * (nSlices + 1) + j) * 3;
|
||||||
Vector3f normal(normals[n], normals[n + 1], normals[n + 2]);
|
Eigen::Map<Eigen::Vector3f> normal(normals);
|
||||||
Vector3f vert = normal * func(u, v, info);
|
Eigen::Vector3f vert = normal * func(u, v, info);
|
||||||
vertices[n] += vert.x();
|
vertices[n] += vert.x();
|
||||||
vertices[n + 1] += vert.y();
|
vertices[n + 1] += vert.y();
|
||||||
vertices[n + 2] += vert.z();
|
vertices[n + 2] += vert.z();
|
||||||
|
@ -344,15 +335,21 @@ void SphereMesh::displace(DisplacementMapFunc func, void* info)
|
||||||
|
|
||||||
cmod::Mesh* SphereMesh::convertToMesh() const
|
cmod::Mesh* SphereMesh::convertToMesh() const
|
||||||
{
|
{
|
||||||
uint32_t stride = 32;
|
std::uint32_t stride = 32;
|
||||||
cmod::Mesh::VertexAttribute attributes[3];
|
cmod::VertexAttribute attributes[3];
|
||||||
attributes[0] = cmod::Mesh::VertexAttribute(cmod::Mesh::Position, cmod::Mesh::Float3, 0);
|
attributes[0] = cmod::VertexAttribute(cmod::VertexAttributeSemantic::Position,
|
||||||
attributes[1] = cmod::Mesh::VertexAttribute(cmod::Mesh::Normal, cmod::Mesh::Float3, 12);
|
cmod::VertexAttributeFormat::Float3,
|
||||||
attributes[2] = cmod::Mesh::VertexAttribute(cmod::Mesh::Texture0, cmod::Mesh::Float2, 24);
|
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();
|
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
|
// Copy the vertex data from the separate position, normal, and texture coordinate
|
||||||
// arrays into a single array.
|
// arrays into a single array.
|
||||||
|
@ -375,14 +372,14 @@ cmod::Mesh* SphereMesh::convertToMesh() const
|
||||||
|
|
||||||
for (int i = 0; i < nRings - 1; i++)
|
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++)
|
for (int j = 0; j <= nSlices; j++)
|
||||||
{
|
{
|
||||||
indexData[j * 2 + 0] = i * (nSlices + 1) + j;
|
indexData[j * 2 + 0] = i * (nSlices + 1) + j;
|
||||||
indexData[j * 2 + 1] = (i + 1) * (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;
|
return mesh;
|
||||||
|
|
|
@ -8,16 +8,20 @@
|
||||||
// as published by the Free Software Foundation; either version 2
|
// as published by the Free Software Foundation; either version 2
|
||||||
// of the License, or (at your option) any later version.
|
// of the License, or (at your option) any later version.
|
||||||
|
|
||||||
#ifndef _CELENGINE_SPHEREMESH_H_
|
#pragma once
|
||||||
#define _CELENGINE_SPHEREMESH_H_
|
|
||||||
|
|
||||||
// IMPORTANT: This file is a relic from the early days of Celestia.
|
// 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;
|
// Its sole function now is to handle the now-deprecated .cms mesh files;
|
||||||
// it will eventually be removed from Celestia.
|
// it will eventually be removed from Celestia.
|
||||||
|
|
||||||
#include <celengine/dispmap.h>
|
#include <Eigen/Core>
|
||||||
#include <celmodel/mesh.h>
|
|
||||||
|
|
||||||
|
#include <celengine/dispmap.h>
|
||||||
|
|
||||||
|
namespace cmod
|
||||||
|
{
|
||||||
|
class Mesh;
|
||||||
|
}
|
||||||
|
|
||||||
/*! The SphereMesh class is used to generate displacement mapped
|
/*! The SphereMesh class is used to generate displacement mapped
|
||||||
* spheres when loading the now-deprecated .cms geometry files.
|
* spheres when loading the now-deprecated .cms geometry files.
|
||||||
|
@ -59,5 +63,3 @@ public:
|
||||||
int nIndices;
|
int nIndices;
|
||||||
unsigned short* indices{ nullptr };
|
unsigned short* indices{ nullptr };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _CELENGINE_SPHEREMESH_H_
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
namespace cmod
|
namespace cmod
|
||||||
{
|
{
|
||||||
|
|
||||||
Material::Material()
|
Material::Material()
|
||||||
{
|
{
|
||||||
maps.fill(InvalidResource);
|
maps.fill(InvalidResource);
|
||||||
|
@ -21,7 +22,7 @@ Material::Material()
|
||||||
|
|
||||||
|
|
||||||
bool
|
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)
|
return std::tie(c0.m_red, c0.m_green, c0.m_blue)
|
||||||
< std::tie(c1.m_red, c1.m_green, c1.m_blue);
|
< std::tie(c1.m_red, c1.m_green, c1.m_blue);
|
||||||
|
|
|
@ -10,114 +10,131 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Eigen/Core>
|
|
||||||
#include <string>
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include <Eigen/Core>
|
||||||
|
|
||||||
#include <celutil/color.h>
|
#include <celutil/color.h>
|
||||||
#include <celutil/reshandle.h>
|
#include <celutil/reshandle.h>
|
||||||
#include <celcompat/filesystem.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace cmod
|
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
|
class Material
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Material();
|
Material();
|
||||||
~Material() = default;
|
~Material() = default;
|
||||||
|
|
||||||
class Color
|
inline ResourceHandle getMap(TextureSemantic semantic) const
|
||||||
{
|
{
|
||||||
public:
|
return maps[static_cast<std::size_t>(semantic)];
|
||||||
constexpr Color() :
|
}
|
||||||
m_red(0.0f),
|
|
||||||
m_green(0.0f),
|
|
||||||
m_blue(0.0f)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Color(float r, float g, float b) :
|
inline void setMap(TextureSemantic semantic, ResourceHandle handle)
|
||||||
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
|
|
||||||
{
|
{
|
||||||
NormalBlend = 0,
|
maps[static_cast<std::size_t>(semantic)] = handle;
|
||||||
AdditiveBlend = 1,
|
}
|
||||||
PremultipliedAlphaBlend = 2,
|
|
||||||
BlendMax = 3,
|
|
||||||
InvalidBlend = -1,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum TextureSemantic
|
|
||||||
{
|
|
||||||
DiffuseMap = 0,
|
|
||||||
NormalMap = 1,
|
|
||||||
SpecularMap = 2,
|
|
||||||
EmissiveMap = 3,
|
|
||||||
TextureSemanticMax = 4,
|
|
||||||
InvalidTextureSemantic = -1,
|
|
||||||
};
|
|
||||||
|
|
||||||
Color diffuse{ 0.0f, 0.0f, 0.0f };
|
Color diffuse{ 0.0f, 0.0f, 0.0f };
|
||||||
Color emissive{ 0.0f, 0.0f, 0.0f };
|
Color emissive{ 0.0f, 0.0f, 0.0f };
|
||||||
Color specular{ 0.0f, 0.0f, 0.0f };
|
Color specular{ 0.0f, 0.0f, 0.0f };
|
||||||
float specularPower{ 1.0f };
|
float specularPower{ 1.0f };
|
||||||
float opacity{ 1.0f };
|
float opacity{ 1.0f };
|
||||||
BlendMode blend{ NormalBlend };
|
BlendMode blend{ BlendMode::NormalBlend };
|
||||||
std::array<ResourceHandle, TextureSemanticMax> maps;
|
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
|
// Define an ordering for materials; required for elimination of duplicate
|
||||||
// materials.
|
// materials.
|
||||||
|
|
|
@ -8,34 +8,22 @@
|
||||||
// as published by the Free Software Foundation; either version 2
|
// as published by the Free Software Foundation; either version 2
|
||||||
// of the License, or (at your option) any later version.
|
// of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
#include "mesh.h"
|
#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
|
|
||||||
};
|
|
||||||
|
|
||||||
|
VertexDescription::VertexDescription(unsigned int _stride,
|
||||||
Mesh::VertexDescription::VertexDescription(unsigned int _stride,
|
unsigned int _nAttributes,
|
||||||
unsigned int _nAttributes,
|
VertexAttribute* _attributes) :
|
||||||
VertexAttribute* _attributes) :
|
stride(_stride),
|
||||||
stride(_stride),
|
nAttributes(_nAttributes),
|
||||||
nAttributes(_nAttributes),
|
attributes(nullptr)
|
||||||
attributes(nullptr)
|
|
||||||
{
|
{
|
||||||
if (nAttributes != 0)
|
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),
|
stride(desc.stride),
|
||||||
nAttributes(desc.nAttributes),
|
nAttributes(desc.nAttributes),
|
||||||
attributes(nullptr)
|
attributes(nullptr)
|
||||||
|
@ -62,8 +50,8 @@ Mesh::VertexDescription::VertexDescription(const VertexDescription& desc) :
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Mesh::VertexDescription&
|
VertexDescription&
|
||||||
Mesh::VertexDescription::operator=(const Mesh::VertexDescription& desc)
|
VertexDescription::operator=(const VertexDescription& desc)
|
||||||
{
|
{
|
||||||
if (this == &desc)
|
if (this == &desc)
|
||||||
return *this;
|
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
|
// TODO: This should be called in the constructor; we should start using
|
||||||
// exceptions in Celestia.
|
// exceptions in Celestia.
|
||||||
bool
|
bool
|
||||||
Mesh::VertexDescription::validate() const
|
VertexDescription::validate() const
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < nAttributes; i++)
|
for (unsigned int i = 0; i < nAttributes; i++)
|
||||||
{
|
{
|
||||||
VertexAttribute& attr = attributes[i];
|
VertexAttribute& attr = attributes[i];
|
||||||
|
|
||||||
// Validate the attribute
|
// Validate the attribute
|
||||||
if (attr.semantic >= SemanticMax || attr.format >= FormatMax)
|
if (attr.offset % 4 != 0 || attr.offset + VertexAttribute::getFormatSize(attr.format) > stride)
|
||||||
return false;
|
|
||||||
if (attr.offset % 4 != 0)
|
|
||||||
return false;
|
|
||||||
if (attr.offset + VertexAttributeFormatSizes[attr.format] > stride)
|
|
||||||
return false;
|
return false;
|
||||||
// TODO: check for repetition of attributes
|
// TODO: check for repetition of attributes
|
||||||
// if (vertexAttributeMap[attr->semantic].format != InvalidFormat)
|
// if (vertexAttributeMap[attr->semantic].format != InvalidFormat)
|
||||||
|
@ -109,69 +93,62 @@ Mesh::VertexDescription::validate() const
|
||||||
return true;
|
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;
|
unsigned int totalAttributeCount = nAttributes + count;
|
||||||
VertexAttribute* allAttributes = new VertexAttribute[totalAttributeCount];
|
VertexAttribute* allAttributes = new VertexAttribute[totalAttributeCount];
|
||||||
memcpy(allAttributes, attributes, sizeof(VertexAttribute) * nAttributes);
|
std::memcpy(allAttributes, attributes, sizeof(VertexAttribute) * nAttributes);
|
||||||
unsigned int newStride = stride;
|
unsigned int newStride = stride;
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
VertexAttribute attribute = newAttributes[i];
|
VertexAttribute attribute = newAttributes[i];
|
||||||
allAttributes[nAttributes + i] = attribute;
|
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);
|
VertexDescription desc = VertexDescription(newStride, totalAttributeCount, allAttributes);
|
||||||
delete[] allAttributes;
|
delete[] allAttributes;
|
||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh::VertexDescription::~VertexDescription()
|
VertexDescription::~VertexDescription()
|
||||||
{
|
{
|
||||||
delete[] attributes;
|
delete[] attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Mesh::VertexDescription::buildSemanticMap()
|
VertexDescription::buildSemanticMap()
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < nAttributes; i++)
|
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
|
void
|
||||||
Mesh::VertexDescription::clearSemanticMap()
|
VertexDescription::clearSemanticMap()
|
||||||
{
|
{
|
||||||
for (auto& i : semanticMap)
|
for (auto& i : semanticMap)
|
||||||
i = VertexAttribute();
|
i = VertexAttribute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Mesh::PrimitiveGroup::~PrimitiveGroup()
|
|
||||||
//{
|
|
||||||
// TODO: probably should free index list; need to sort out
|
|
||||||
// ownership issues.
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
Mesh::PrimitiveGroup::getPrimitiveCount() const
|
PrimitiveGroup::getPrimitiveCount() const
|
||||||
{
|
{
|
||||||
switch (prim)
|
switch (prim)
|
||||||
{
|
{
|
||||||
case TriList:
|
case PrimitiveGroupType::TriList:
|
||||||
return nIndices / 3;
|
return nIndices / 3;
|
||||||
case TriStrip:
|
case PrimitiveGroupType::TriStrip:
|
||||||
case TriFan:
|
case PrimitiveGroupType::TriFan:
|
||||||
return nIndices - 2;
|
return nIndices - 2;
|
||||||
case LineList:
|
case PrimitiveGroupType::LineList:
|
||||||
return nIndices / 2;
|
return nIndices / 2;
|
||||||
case LineStrip:
|
case PrimitiveGroupType::LineStrip:
|
||||||
return nIndices - 2;
|
return nIndices - 2;
|
||||||
case PointList:
|
case PrimitiveGroupType::PointList:
|
||||||
case SpriteList:
|
case PrimitiveGroupType::SpriteList:
|
||||||
return nIndices;
|
return nIndices;
|
||||||
default:
|
default:
|
||||||
// Invalid value
|
// Invalid value
|
||||||
|
@ -188,7 +165,6 @@ Mesh::~Mesh()
|
||||||
// TODO: this is just to cast away void* and shut up GCC warnings;
|
// TODO: this is just to cast away void* and shut up GCC warnings;
|
||||||
// should probably be static_cast<VertexList::VertexPart*>
|
// should probably be static_cast<VertexList::VertexPart*>
|
||||||
delete[] static_cast<char*>(vertices);
|
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;
|
return vertexDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const Mesh::PrimitiveGroup*
|
const PrimitiveGroup*
|
||||||
Mesh::getGroup(unsigned int index) const
|
Mesh::getGroup(unsigned int index) const
|
||||||
{
|
{
|
||||||
if (index >= groups.size())
|
if (index >= groups.size())
|
||||||
|
@ -235,7 +211,7 @@ Mesh::getGroup(unsigned int index) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Mesh::PrimitiveGroup*
|
PrimitiveGroup*
|
||||||
Mesh::getGroup(unsigned int index)
|
Mesh::getGroup(unsigned int index)
|
||||||
{
|
{
|
||||||
if (index >= groups.size())
|
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
|
// Transform LINE_STRIP/LINES to triangle vertices
|
||||||
int transformedVertCount = lineStrip ? (nIndices - 1) * 4 : nIndices * 2;
|
int transformedVertCount = lineStrip ? (nIndices - 1) * 4 : nIndices * 2;
|
||||||
// Get information of the position attributes
|
// Get information of the position attributes
|
||||||
auto positionAttributes = vertexDesc.getAttribute(Position);
|
auto positionAttributes = vertexDesc.getAttribute(VertexAttributeSemantic::Position);
|
||||||
int positionSize = getVertexAttributeSize(positionAttributes.format);
|
int positionSize = VertexAttribute::getFormatSize(positionAttributes.format);
|
||||||
int positionOffset = positionAttributes.offset;
|
int positionOffset = positionAttributes.offset;
|
||||||
|
|
||||||
int originalStride = vertexDesc.stride;
|
int originalStride = vertexDesc.stride;
|
||||||
|
@ -289,23 +266,23 @@ Mesh::PrimitiveGroup* Mesh::createLinePrimitiveGroup(bool lineStrip, unsigned in
|
||||||
float *ffn = (float *)origNextVertLoc;
|
float *ffn = (float *)origNextVertLoc;
|
||||||
|
|
||||||
// Fill the info for the 4 vertices
|
// Fill the info for the 4 vertices
|
||||||
memcpy(ptr, origThisVertLoc, originalStride);
|
std::memcpy(ptr, origThisVertLoc, originalStride);
|
||||||
memcpy(ptr + originalStride, origNextVertLoc + positionOffset, positionSize);
|
std::memcpy(ptr + originalStride, origNextVertLoc + positionOffset, positionSize);
|
||||||
*(float *)&ptr[originalStride + positionSize] = -0.5f;
|
*(float *)&ptr[originalStride + positionSize] = -0.5f;
|
||||||
ptr += stride;
|
ptr += stride;
|
||||||
|
|
||||||
memcpy(ptr, origThisVertLoc, originalStride);
|
std::memcpy(ptr, origThisVertLoc, originalStride);
|
||||||
memcpy(ptr + originalStride, origNextVertLoc + positionOffset, positionSize);
|
std::memcpy(ptr + originalStride, origNextVertLoc + positionOffset, positionSize);
|
||||||
*(float *)&ptr[originalStride + positionSize] = 0.5f;
|
*(float *)&ptr[originalStride + positionSize] = 0.5f;
|
||||||
ptr += stride;
|
ptr += stride;
|
||||||
|
|
||||||
memcpy(ptr, origNextVertLoc, originalStride);
|
std::memcpy(ptr, origNextVertLoc, originalStride);
|
||||||
memcpy(ptr + originalStride, origThisVertLoc + positionOffset, positionSize);
|
std::memcpy(ptr + originalStride, origThisVertLoc + positionOffset, positionSize);
|
||||||
*(float *)&ptr[originalStride + positionSize] = -0.5f;
|
*(float *)&ptr[originalStride + positionSize] = -0.5f;
|
||||||
ptr += stride;
|
ptr += stride;
|
||||||
|
|
||||||
memcpy(ptr, origNextVertLoc, originalStride);
|
std::memcpy(ptr, origNextVertLoc, originalStride);
|
||||||
memcpy(ptr + originalStride, origThisVertLoc + positionOffset, positionSize);
|
std::memcpy(ptr + originalStride, origThisVertLoc + positionOffset, positionSize);
|
||||||
*(float *)&ptr[originalStride + positionSize] = 0.5f;
|
*(float *)&ptr[originalStride + positionSize] = 0.5f;
|
||||||
ptr += stride;
|
ptr += stride;
|
||||||
|
|
||||||
|
@ -321,9 +298,9 @@ Mesh::PrimitiveGroup* Mesh::createLinePrimitiveGroup(bool lineStrip, unsigned in
|
||||||
newIndices[lineIndex + 5] = newIndex;
|
newIndices[lineIndex + 5] = newIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
array<VertexAttribute, 2> newAttributes = {
|
std::array<VertexAttribute, 2> newAttributes = {
|
||||||
VertexAttribute(NextPosition, positionAttributes.format, originalStride),
|
VertexAttribute(VertexAttributeSemantic::NextPosition, positionAttributes.format, originalStride),
|
||||||
VertexAttribute(ScaleFactor, Float1, originalStride + positionSize),
|
VertexAttribute(VertexAttributeSemantic::ScaleFactor, VertexAttributeFormat::Float1, originalStride + positionSize),
|
||||||
};
|
};
|
||||||
auto* g = new PrimitiveGroup();
|
auto* g = new PrimitiveGroup();
|
||||||
g->vertexOverride = data;
|
g->vertexOverride = data;
|
||||||
|
@ -343,9 +320,9 @@ Mesh::addGroup(PrimitiveGroupType prim,
|
||||||
index32* indices)
|
index32* indices)
|
||||||
{
|
{
|
||||||
PrimitiveGroup* g;
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -382,7 +359,7 @@ Mesh::clearGroups()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const string&
|
const std::string&
|
||||||
Mesh::getName() const
|
Mesh::getName() const
|
||||||
{
|
{
|
||||||
return name;
|
return name;
|
||||||
|
@ -390,14 +367,14 @@ Mesh::getName() const
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Mesh::setName(const string& _name)
|
Mesh::setName(const std::string& _name)
|
||||||
{
|
{
|
||||||
name = _name;
|
name = _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Mesh::remapIndices(const vector<index32>& indexMap)
|
Mesh::remapIndices(const std::vector<index32>& indexMap)
|
||||||
{
|
{
|
||||||
for (auto group : groups)
|
for (auto group : groups)
|
||||||
{
|
{
|
||||||
|
@ -410,57 +387,54 @@ Mesh::remapIndices(const vector<index32>& indexMap)
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Mesh::remapMaterials(const vector<unsigned int>& materialMap)
|
Mesh::remapMaterials(const std::vector<unsigned int>& materialMap)
|
||||||
{
|
{
|
||||||
for (auto group : groups)
|
for (auto group : groups)
|
||||||
group->materialIndex = materialMap[group->materialIndex];
|
group->materialIndex = materialMap[group->materialIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct PrimitiveGroupComparator
|
|
||||||
{
|
|
||||||
bool operator()(const Mesh::PrimitiveGroup* g0, const Mesh::PrimitiveGroup* g1) const
|
|
||||||
{
|
|
||||||
return g0->materialIndex < g1->materialIndex;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Mesh::aggregateByMaterial()
|
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
|
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 maxDistance = 1.0e30;
|
||||||
double closest = maxDistance;
|
double closest = maxDistance;
|
||||||
|
|
||||||
// Pick will automatically fail without vertex positions--no reasonable
|
// Pick will automatically fail without vertex positions--no reasonable
|
||||||
// mesh should lack these.
|
// mesh should lack these.
|
||||||
if (vertexDesc.getAttribute(Position).semantic != Position ||
|
if (vertexDesc.getAttribute(VertexAttributeSemantic::Position).semantic != VertexAttributeSemantic::Position ||
|
||||||
vertexDesc.getAttribute(Position).format != Float3)
|
vertexDesc.getAttribute(VertexAttributeSemantic::Position).format != VertexAttributeFormat::Float3)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int posOffset = vertexDesc.getAttribute(Position).offset;
|
unsigned int posOffset = vertexDesc.getAttribute(VertexAttributeSemantic::Position).offset;
|
||||||
auto* vdata = reinterpret_cast<char*>(vertices);
|
auto* vdata = reinterpret_cast<char*>(vertices);
|
||||||
|
|
||||||
// Iterate over all primitive groups in the mesh
|
// Iterate over all primitive groups in the mesh
|
||||||
for (const auto group : groups)
|
for (const auto group : groups)
|
||||||
{
|
{
|
||||||
Mesh::PrimitiveGroupType primType = group->prim;
|
PrimitiveGroupType primType = group->prim;
|
||||||
index32 nIndices = group->nIndices;
|
index32 nIndices = group->nIndices;
|
||||||
|
|
||||||
// Only attempt to compute the intersection of the ray with triangle
|
// Only attempt to compute the intersection of the ray with triangle
|
||||||
// groups.
|
// groups.
|
||||||
if ((primType == TriList || primType == TriStrip || primType == TriFan) &&
|
if ((primType == PrimitiveGroupType::TriList
|
||||||
|
|| primType == PrimitiveGroupType::TriStrip
|
||||||
|
|| primType == PrimitiveGroupType::TriFan) &&
|
||||||
(nIndices >= 3) &&
|
(nIndices >= 3) &&
|
||||||
!(primType == TriList && nIndices % 3 != 0))
|
!(primType == PrimitiveGroupType::TriList && nIndices % 3 != 0))
|
||||||
{
|
{
|
||||||
unsigned int primitiveIndex = 0;
|
unsigned int primitiveIndex = 0;
|
||||||
index32 index = 0;
|
index32 index = 0;
|
||||||
|
@ -472,14 +446,14 @@ Mesh::pick(const Vector3d& rayOrigin, const Vector3d& rayDirection, PickResult*
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// Get the triangle vertices v0, v1, and v2
|
// Get the triangle vertices v0, v1, and v2
|
||||||
Vector3d v0 = Map<Vector3f>(reinterpret_cast<float*>(vdata + i0 * vertexDesc.stride + posOffset)).cast<double>();
|
Eigen::Vector3d v0 = Eigen::Map<Eigen::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>();
|
Eigen::Vector3d v1 = Eigen::Map<Eigen::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 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
|
// Compute the edge vectors e0 and e1, and the normal n
|
||||||
Vector3d e0 = v1 - v0;
|
Eigen::Vector3d e0 = v1 - v0;
|
||||||
Vector3d e1 = v2 - v0;
|
Eigen::Vector3d e1 = v2 - v0;
|
||||||
Vector3d n = e0.cross(e1);
|
Eigen::Vector3d n = e0.cross(e1);
|
||||||
|
|
||||||
// c is the cosine of the angle between the ray and triangle normal
|
// c is the cosine of the angle between the ray and triangle normal
|
||||||
double c = n.dot(rayDirection);
|
double c = n.dot(rayDirection);
|
||||||
|
@ -499,8 +473,8 @@ Mesh::pick(const Vector3d& rayOrigin, const Vector3d& rayDirection, PickResult*
|
||||||
double det = m00 * m11 - m01 * m10;
|
double det = m00 * m11 - m01 * m10;
|
||||||
if (det != 0.0)
|
if (det != 0.0)
|
||||||
{
|
{
|
||||||
Vector3d p = rayOrigin + rayDirection * t;
|
Eigen::Vector3d p = rayOrigin + rayDirection * t;
|
||||||
Vector3d q = p - v0;
|
Eigen::Vector3d q = p - v0;
|
||||||
double q0 = e0.dot(q);
|
double q0 = e0.dot(q);
|
||||||
double q1 = e1.dot(q);
|
double q1 = e1.dot(q);
|
||||||
double d = 1.0 / det;
|
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
|
// Get the indices for the next triangle
|
||||||
if (primType == TriList)
|
if (primType == PrimitiveGroupType::TriList)
|
||||||
{
|
{
|
||||||
index += 3;
|
index += 3;
|
||||||
if (index < nIndices)
|
if (index < nIndices)
|
||||||
|
@ -531,7 +505,7 @@ Mesh::pick(const Vector3d& rayOrigin, const Vector3d& rayDirection, PickResult*
|
||||||
i2 = group->indices[index + 2];
|
i2 = group->indices[index + 2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (primType == TriStrip)
|
else if (primType == PrimitiveGroupType::TriStrip)
|
||||||
{
|
{
|
||||||
index += 1;
|
index += 1;
|
||||||
if (index < nIndices)
|
if (index < nIndices)
|
||||||
|
@ -564,7 +538,7 @@ Mesh::pick(const Vector3d& rayOrigin, const Vector3d& rayDirection, PickResult*
|
||||||
|
|
||||||
|
|
||||||
bool
|
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;
|
PickResult result;
|
||||||
bool hit = pick(rayOrigin, rayDirection, &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
|
Mesh::getBoundingBox() const
|
||||||
{
|
{
|
||||||
AlignedBox<float, 3> bbox;
|
Eigen::AlignedBox<float, 3> bbox;
|
||||||
|
|
||||||
// Return an empty box if there's no position info
|
// 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;
|
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
|
// Handle bounding box calculation for point sprites. Unlike other
|
||||||
// primitives, point sprite vertices have a non-zero size.
|
// primitives, point sprite vertices have a non-zero size.
|
||||||
int pointSizeOffset = (int) vertexDesc.getAttribute(PointSize).offset -
|
int pointSizeOffset = (int) vertexDesc.getAttribute(VertexAttributeSemantic::PointSize).offset -
|
||||||
(int) vertexDesc.getAttribute(Position).offset;
|
(int) vertexDesc.getAttribute(VertexAttributeSemantic::Position).offset;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < nVertices; i++, vdata += vertexDesc.stride)
|
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];
|
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);
|
bbox.extend(pointbox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < nVertices; i++, vdata += vertexDesc.stride)
|
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;
|
return bbox;
|
||||||
|
@ -616,19 +590,19 @@ Mesh::getBoundingBox() const
|
||||||
|
|
||||||
|
|
||||||
void
|
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;
|
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;
|
unsigned int i;
|
||||||
|
|
||||||
// Scale and translate the vertex positions
|
// Scale and translate the vertex positions
|
||||||
for (i = 0; i < nVertices; i++, vdata += vertexDesc.stride)
|
for (i = 0; i < nVertices; i++, vdata += vertexDesc.stride)
|
||||||
{
|
{
|
||||||
const Vector3f tv = (Map<Vector3f>(reinterpret_cast<float*>(vdata)) + translation) * scale;
|
const Eigen::Vector3f tv = (Eigen::Map<Eigen::Vector3f>(reinterpret_cast<float*>(vdata)) + translation) * scale;
|
||||||
Map<Vector3f>(reinterpret_cast<float*>(vdata)) = tv;
|
Eigen::Map<Eigen::Vector3f>(reinterpret_cast<float*>(vdata)) = tv;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scale and translate the overriden vertex values
|
// Scale and translate the overriden vertex values
|
||||||
|
@ -640,22 +614,22 @@ Mesh::transform(const Vector3f& translation, float scale)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto vertexDesc = group->vertexDescriptionOverride;
|
auto vertexDesc = group->vertexDescriptionOverride;
|
||||||
int positionOffset = vertexDesc.getAttribute(Position).offset;
|
int positionOffset = vertexDesc.getAttribute(VertexAttributeSemantic::Position).offset;
|
||||||
int nextPositionOffset = vertexDesc.getAttribute(NextPosition).offset;
|
int nextPositionOffset = vertexDesc.getAttribute(VertexAttributeSemantic::NextPosition).offset;
|
||||||
for (unsigned int j = 0; j < group->vertexCountOverride; j++, vdata += vertexDesc.stride)
|
for (unsigned int j = 0; j < group->vertexCountOverride; j++, vdata += vertexDesc.stride)
|
||||||
{
|
{
|
||||||
Vector3f tv = (Map<Vector3f>(reinterpret_cast<float*>(vdata + positionOffset)) + translation) * scale;
|
Eigen::Vector3f tv = (Eigen::Map<Eigen::Vector3f>(reinterpret_cast<float*>(vdata + positionOffset)) + translation) * scale;
|
||||||
Map<Vector3f>(reinterpret_cast<float*>(vdata + positionOffset)) = tv;
|
Eigen::Map<Eigen::Vector3f>(reinterpret_cast<float*>(vdata + positionOffset)) = tv;
|
||||||
|
|
||||||
tv = (Map<Vector3f>(reinterpret_cast<float*>(vdata + nextPositionOffset)) + translation) * scale;
|
tv = (Eigen::Map<Eigen::Vector3f>(reinterpret_cast<float*>(vdata + nextPositionOffset)) + translation) * scale;
|
||||||
Map<Vector3f>(reinterpret_cast<float*>(vdata + nextPositionOffset)) = tv;
|
Eigen::Map<Eigen::Vector3f>(reinterpret_cast<float*>(vdata + nextPositionOffset)) = tv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Point sizes need to be scaled as well
|
// 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)
|
for (i = 0; i < nVertices; i++, vdata += vertexDesc.stride)
|
||||||
reinterpret_cast<float*>(vdata)[0] *= scale;
|
reinterpret_cast<float*>(vdata)[0] *= scale;
|
||||||
}
|
}
|
||||||
|
@ -673,104 +647,4 @@ Mesh::getPrimitiveCount() const
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // end namespace cmod
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -8,144 +8,169 @@
|
||||||
// as published by the Free Software Foundation; either version 2
|
// as published by the Free Software Foundation; either version 2
|
||||||
// of the License, or (at your option) any later version.
|
// of the License, or (at your option) any later version.
|
||||||
|
|
||||||
#ifndef _CELMODEL_MESH_H_
|
#pragma once
|
||||||
#define _CELMODEL_MESH_H_
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "material.h"
|
|
||||||
#include <Eigen/Core>
|
#include <Eigen/Core>
|
||||||
#include <Eigen/Geometry>
|
#include <Eigen/Geometry>
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
#include "material.h"
|
||||||
|
|
||||||
|
|
||||||
namespace cmod
|
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
|
class Mesh
|
||||||
{
|
{
|
||||||
public:
|
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
|
class PickResult
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -164,7 +189,7 @@ class Mesh
|
||||||
bool setVertexDescription(const VertexDescription& desc);
|
bool setVertexDescription(const VertexDescription& desc);
|
||||||
const VertexDescription& getVertexDescription() const;
|
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;
|
const PrimitiveGroup* getGroup(unsigned int index) const;
|
||||||
PrimitiveGroup* getGroup(unsigned int index);
|
PrimitiveGroup* getGroup(unsigned int index);
|
||||||
unsigned int addGroup(PrimitiveGroup* group);
|
unsigned int addGroup(PrimitiveGroup* group);
|
||||||
|
@ -198,21 +223,13 @@ class Mesh
|
||||||
unsigned int getVertexStride() const { return vertexDesc.stride; }
|
unsigned int getVertexStride() const { return vertexDesc.stride; }
|
||||||
unsigned int getPrimitiveCount() const;
|
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:
|
private:
|
||||||
void recomputeBoundingBox();
|
void recomputeBoundingBox();
|
||||||
|
|
||||||
private:
|
|
||||||
VertexDescription vertexDesc{ 0, 0, nullptr };
|
VertexDescription vertexDesc{ 0, 0, nullptr };
|
||||||
|
|
||||||
unsigned int nVertices{ 0 };
|
unsigned int nVertices{ 0 };
|
||||||
void* vertices{ nullptr };
|
void* vertices{ nullptr };
|
||||||
mutable BufferResource* vbResource{ nullptr };
|
|
||||||
|
|
||||||
std::vector<PrimitiveGroup*> groups;
|
std::vector<PrimitiveGroup*> groups;
|
||||||
|
|
||||||
|
@ -220,6 +237,3 @@ class Mesh
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cmod
|
} // 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
|
// the model, we could potentially end up with false positives--this
|
||||||
// won't cause any rendering troubles, but could hurt performance
|
// won't cause any rendering troubles, but could hurt performance
|
||||||
// if it forces multipass rendering when it's not required.
|
// if it forces multipass rendering when it's not required.
|
||||||
for (int i = 0; i < Material::TextureSemanticMax; i++)
|
for (int i = 0; i < static_cast<int>(TextureSemantic::TextureSemanticMax); i++)
|
||||||
{
|
{
|
||||||
if (m->maps[i] != InvalidResource)
|
if (m->maps[i] != InvalidResource)
|
||||||
{
|
{
|
||||||
|
@ -306,7 +306,7 @@ Model::determineOpacity()
|
||||||
for (unsigned int i = 0; i < materials.size(); i++)
|
for (unsigned int i = 0; i < materials.size(); i++)
|
||||||
{
|
{
|
||||||
if ((materials[i]->opacity > 0.01f && materials[i]->opacity < 1.0f) ||
|
if ((materials[i]->opacity > 0.01f && materials[i]->opacity < 1.0f) ||
|
||||||
materials[i]->blend == Material::AdditiveBlend)
|
materials[i]->blend == BlendMode::AdditiveBlend)
|
||||||
{
|
{
|
||||||
opaque = false;
|
opaque = false;
|
||||||
return;
|
return;
|
||||||
|
@ -318,9 +318,9 @@ Model::determineOpacity()
|
||||||
|
|
||||||
|
|
||||||
bool
|
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
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <Eigen/Core>
|
#include <Eigen/Core>
|
||||||
|
@ -99,15 +100,15 @@ class Model
|
||||||
* all within a mesh. This information is used to decide
|
* all within a mesh. This information is used to decide
|
||||||
* if multiple rendering passes are required.
|
* 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. */
|
/** Return true if the model has no translucent components. */
|
||||||
virtual bool isOpaque() const
|
bool isOpaque() const
|
||||||
{
|
{
|
||||||
return opaque;
|
return opaque;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool isNormalized() const
|
bool isNormalized() const
|
||||||
{
|
{
|
||||||
return normalized;
|
return normalized;
|
||||||
}
|
}
|
||||||
|
@ -118,7 +119,7 @@ class Model
|
||||||
|
|
||||||
class MeshComparator
|
class MeshComparator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~MeshComparator() = default;
|
virtual ~MeshComparator() = default;
|
||||||
|
|
||||||
virtual bool operator()(const Mesh&, const Mesh&) const = 0;
|
virtual bool operator()(const Mesh&, const Mesh&) const = 0;
|
||||||
|
@ -145,7 +146,7 @@ class Model
|
||||||
*/
|
*/
|
||||||
class OpacityComparator : public MeshComparator
|
class OpacityComparator : public MeshComparator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OpacityComparator() = default;
|
OpacityComparator() = default;
|
||||||
virtual ~OpacityComparator() = default;
|
virtual ~OpacityComparator() = default;
|
||||||
|
|
||||||
|
@ -156,7 +157,7 @@ class Model
|
||||||
std::vector<const Material*> materials;
|
std::vector<const Material*> materials;
|
||||||
std::vector<Mesh*> meshes;
|
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 opaque{ true };
|
||||||
bool normalized{ false };
|
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";
|
constexpr const char CEL_MODEL_HEADER_BINARY[] = "#celmodel_binary";
|
||||||
|
|
||||||
// Material default values
|
// Material default values
|
||||||
constexpr Material::Color DefaultDiffuse(0.0f, 0.0f, 0.0f);
|
constexpr Color DefaultDiffuse(0.0f, 0.0f, 0.0f);
|
||||||
constexpr Material::Color DefaultSpecular(0.0f, 0.0f, 0.0f);
|
constexpr Color DefaultSpecular(0.0f, 0.0f, 0.0f);
|
||||||
constexpr Material::Color DefaultEmissive(0.0f, 0.0f, 0.0f);
|
constexpr Color DefaultEmissive(0.0f, 0.0f, 0.0f);
|
||||||
constexpr float DefaultSpecularPower = 1.0f;
|
constexpr float DefaultSpecularPower = 1.0f;
|
||||||
constexpr float DefaultOpacity = 1.0f;
|
constexpr float DefaultOpacity = 1.0f;
|
||||||
constexpr Material::BlendMode DefaultBlend = Material::NormalBlend;
|
constexpr BlendMode DefaultBlend = BlendMode::NormalBlend;
|
||||||
|
|
||||||
// Standard tokens for ASCII model loader
|
// Standard tokens for ASCII model loader
|
||||||
constexpr const char MeshToken[] = "mesh";
|
constexpr const char MeshToken[] = "mesh";
|
||||||
|
@ -188,6 +188,88 @@ defined here--they have the obvious definitions.
|
||||||
<material_index> :: <unsigned_int> | -1
|
<material_index> :: <unsigned_int> | -1
|
||||||
\endcode
|
\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
|
class AsciiModelLoader : public ModelLoader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -201,9 +283,9 @@ public:
|
||||||
void reportError(const std::string& /*msg*/) override;
|
void reportError(const std::string& /*msg*/) override;
|
||||||
|
|
||||||
Material* loadMaterial();
|
Material* loadMaterial();
|
||||||
Mesh::VertexDescription* loadVertexDescription();
|
VertexDescription* loadVertexDescription();
|
||||||
Mesh* loadMesh();
|
Mesh* loadMesh();
|
||||||
char* loadVertices(const Mesh::VertexDescription& vertexDesc,
|
char* loadVertices(const VertexDescription& vertexDesc,
|
||||||
unsigned int& vertexCount);
|
unsigned int& vertexCount);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -239,9 +321,9 @@ AsciiModelLoader::loadMaterial()
|
||||||
while (tok.nextToken() == Tokenizer::TokenName && tok.getNameValue() != EndMaterialToken)
|
while (tok.nextToken() == Tokenizer::TokenName && tok.getNameValue() != EndMaterialToken)
|
||||||
{
|
{
|
||||||
std::string property = tok.getStringValue();
|
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)
|
if (tok.nextToken() != Tokenizer::TokenString)
|
||||||
{
|
{
|
||||||
|
@ -253,24 +335,24 @@ AsciiModelLoader::loadMaterial()
|
||||||
std::string textureName = tok.getStringValue();
|
std::string textureName = tok.getStringValue();
|
||||||
|
|
||||||
ResourceHandle tex = getHandle(textureName);
|
ResourceHandle tex = getHandle(textureName);
|
||||||
material->maps[texType] = tex;
|
material->setMap(texType, tex);
|
||||||
}
|
}
|
||||||
else if (property == "blend")
|
else if (property == "blend")
|
||||||
{
|
{
|
||||||
Material::BlendMode blendMode = Material::InvalidBlend;
|
BlendMode blendMode = BlendMode::InvalidBlend;
|
||||||
|
|
||||||
if (tok.nextToken() == Tokenizer::TokenName)
|
if (tok.nextToken() == Tokenizer::TokenName)
|
||||||
{
|
{
|
||||||
std::string blendModeName = tok.getStringValue();
|
std::string blendModeName = tok.getStringValue();
|
||||||
if (blendModeName == "normal")
|
if (blendModeName == "normal")
|
||||||
blendMode = Material::NormalBlend;
|
blendMode = BlendMode::NormalBlend;
|
||||||
else if (blendModeName == "add")
|
else if (blendModeName == "add")
|
||||||
blendMode = Material::AdditiveBlend;
|
blendMode = BlendMode::AdditiveBlend;
|
||||||
else if (blendModeName == "premultiplied")
|
else if (blendModeName == "premultiplied")
|
||||||
blendMode = Material::PremultipliedAlphaBlend;
|
blendMode = BlendMode::PremultipliedAlphaBlend;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blendMode == Material::InvalidBlend)
|
if (blendMode == BlendMode::InvalidBlend)
|
||||||
{
|
{
|
||||||
reportError("Bad blend mode in material");
|
reportError("Bad blend mode in material");
|
||||||
delete material;
|
delete material;
|
||||||
|
@ -301,10 +383,12 @@ AsciiModelLoader::loadMaterial()
|
||||||
data[i] = tok.getNumberValue();
|
data[i] = tok.getNumberValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
Material::Color colorVal;
|
Color colorVal;
|
||||||
if (nValues == 3)
|
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")
|
if (property == "diffuse")
|
||||||
|
@ -340,7 +424,7 @@ AsciiModelLoader::loadMaterial()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Mesh::VertexDescription*
|
VertexDescription*
|
||||||
AsciiModelLoader::loadVertexDescription()
|
AsciiModelLoader::loadVertexDescription()
|
||||||
{
|
{
|
||||||
if (tok.nextToken() != Tokenizer::TokenName || tok.getNameValue() != VertexDescToken)
|
if (tok.nextToken() != Tokenizer::TokenName || tok.getNameValue() != VertexDescToken)
|
||||||
|
@ -352,7 +436,7 @@ AsciiModelLoader::loadVertexDescription()
|
||||||
int maxAttributes = 16;
|
int maxAttributes = 16;
|
||||||
int nAttributes = 0;
|
int nAttributes = 0;
|
||||||
unsigned int offset = 0;
|
unsigned int offset = 0;
|
||||||
auto* attributes = new Mesh::VertexAttribute[maxAttributes];
|
auto* attributes = new VertexAttribute[maxAttributes];
|
||||||
|
|
||||||
while (tok.nextToken() == Tokenizer::TokenName && tok.getNameValue() != EndVertexDescToken)
|
while (tok.nextToken() == Tokenizer::TokenName && tok.getNameValue() != EndVertexDescToken)
|
||||||
{
|
{
|
||||||
|
@ -384,18 +468,16 @@ AsciiModelLoader::loadVertexDescription()
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh::VertexAttributeSemantic semantic =
|
VertexAttributeSemantic semantic = parseVertexAttributeSemantic(semanticName);
|
||||||
Mesh::parseVertexAttributeSemantic(semanticName);
|
if (semantic == VertexAttributeSemantic::InvalidSemantic)
|
||||||
if (semantic == Mesh::InvalidSemantic)
|
|
||||||
{
|
{
|
||||||
reportError(fmt::format("Invalid vertex attribute semantic '{}'", semanticName));
|
reportError(fmt::format("Invalid vertex attribute semantic '{}'", semanticName));
|
||||||
delete[] attributes;
|
delete[] attributes;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh::VertexAttributeFormat format =
|
VertexAttributeFormat format = parseVertexAttributeFormat(formatName);
|
||||||
Mesh::parseVertexAttributeFormat(formatName);
|
if (format == VertexAttributeFormat::InvalidFormat)
|
||||||
if (format == Mesh::InvalidFormat)
|
|
||||||
{
|
{
|
||||||
reportError(fmt::format("Invalid vertex attribute format '{}'", formatName));
|
reportError(fmt::format("Invalid vertex attribute format '{}'", formatName));
|
||||||
delete[] attributes;
|
delete[] attributes;
|
||||||
|
@ -406,7 +488,7 @@ AsciiModelLoader::loadVertexDescription()
|
||||||
attributes[nAttributes].format = format;
|
attributes[nAttributes].format = format;
|
||||||
attributes[nAttributes].offset = offset;
|
attributes[nAttributes].offset = offset;
|
||||||
|
|
||||||
offset += Mesh::getVertexAttributeSize(format);
|
offset += VertexAttribute::getFormatSize(format);
|
||||||
nAttributes++;
|
nAttributes++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,15 +506,14 @@ AsciiModelLoader::loadVertexDescription()
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *vertexDesc =
|
auto *vertexDesc = new VertexDescription(offset, nAttributes, attributes);
|
||||||
new Mesh::VertexDescription(offset, nAttributes, attributes);
|
|
||||||
delete[] attributes;
|
delete[] attributes;
|
||||||
return vertexDesc;
|
return vertexDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char*
|
char*
|
||||||
AsciiModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
|
AsciiModelLoader::loadVertices(const VertexDescription& vertexDesc,
|
||||||
unsigned int& vertexCount)
|
unsigned int& vertexCount)
|
||||||
{
|
{
|
||||||
if (tok.nextToken() != Tokenizer::TokenName && tok.getNameValue() != VerticesToken)
|
if (tok.nextToken() != Tokenizer::TokenName && tok.getNameValue() != VerticesToken)
|
||||||
|
@ -465,22 +546,22 @@ AsciiModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
|
||||||
assert(offset < vertexDataSize);
|
assert(offset < vertexDataSize);
|
||||||
for (unsigned int attr = 0; attr < vertexDesc.nAttributes; attr++)
|
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*/
|
/*unsigned int nBytes = Mesh::getVertexAttributeSize(fmt); Unused*/
|
||||||
int readCount = 0;
|
int readCount = 0;
|
||||||
switch (fmt)
|
switch (vfmt)
|
||||||
{
|
{
|
||||||
case Mesh::Float1:
|
case VertexAttributeFormat::Float1:
|
||||||
readCount = 1;
|
readCount = 1;
|
||||||
break;
|
break;
|
||||||
case Mesh::Float2:
|
case VertexAttributeFormat::Float2:
|
||||||
readCount = 2;
|
readCount = 2;
|
||||||
break;
|
break;
|
||||||
case Mesh::Float3:
|
case VertexAttributeFormat::Float3:
|
||||||
readCount = 3;
|
readCount = 3;
|
||||||
break;
|
break;
|
||||||
case Mesh::Float4:
|
case VertexAttributeFormat::Float4:
|
||||||
case Mesh::UByte4:
|
case VertexAttributeFormat::UByte4:
|
||||||
readCount = 4;
|
readCount = 4;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -504,7 +585,7 @@ AsciiModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int base = offset + vertexDesc.attributes[attr].offset;
|
unsigned int base = offset + vertexDesc.attributes[attr].offset;
|
||||||
if (fmt == Mesh::UByte4)
|
if (vfmt == VertexAttributeFormat::UByte4)
|
||||||
{
|
{
|
||||||
for (int k = 0; k < readCount; k++)
|
for (int k = 0; k < readCount; k++)
|
||||||
{
|
{
|
||||||
|
@ -535,7 +616,7 @@ AsciiModelLoader::loadMesh()
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh::VertexDescription* vertexDesc = loadVertexDescription();
|
VertexDescription* vertexDesc = loadVertexDescription();
|
||||||
if (vertexDesc == nullptr)
|
if (vertexDesc == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
@ -554,9 +635,8 @@ AsciiModelLoader::loadMesh()
|
||||||
|
|
||||||
while (tok.nextToken() == Tokenizer::TokenName && tok.getNameValue() != EndMeshToken)
|
while (tok.nextToken() == Tokenizer::TokenName && tok.getNameValue() != EndMeshToken)
|
||||||
{
|
{
|
||||||
Mesh::PrimitiveGroupType type =
|
PrimitiveGroupType type = parsePrimitiveGroupType(tok.getStringValue());
|
||||||
Mesh::parsePrimitiveGroupType(tok.getStringValue());
|
if (type == PrimitiveGroupType::InvalidPrimitiveGroupType)
|
||||||
if (type == Mesh::InvalidPrimitiveGroupType)
|
|
||||||
{
|
{
|
||||||
reportError("Bad primitive group type: " + tok.getStringValue());
|
reportError("Bad primitive group type: " + tok.getStringValue());
|
||||||
delete mesh;
|
delete mesh;
|
||||||
|
@ -589,7 +669,7 @@ AsciiModelLoader::loadMesh()
|
||||||
|
|
||||||
unsigned int indexCount = (unsigned int) tok.getIntegerValue();
|
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++)
|
for (unsigned int i = 0; i < indexCount; i++)
|
||||||
{
|
{
|
||||||
|
@ -700,12 +780,12 @@ public:
|
||||||
private:
|
private:
|
||||||
bool writeMesh(const Mesh& /*mesh*/);
|
bool writeMesh(const Mesh& /*mesh*/);
|
||||||
bool writeMaterial(const Material& /*material*/);
|
bool writeMaterial(const Material& /*material*/);
|
||||||
bool writeGroup(const Mesh::PrimitiveGroup& /*group*/);
|
bool writeGroup(const PrimitiveGroup& /*group*/);
|
||||||
bool writeVertexDescription(const Mesh::VertexDescription& /*desc*/);
|
bool writeVertexDescription(const VertexDescription& /*desc*/);
|
||||||
bool writeVertices(const void* vertexData,
|
bool writeVertices(const void* vertexData,
|
||||||
unsigned int nVertices,
|
unsigned int nVertices,
|
||||||
unsigned int stride,
|
unsigned int stride,
|
||||||
const Mesh::VertexDescription& desc);
|
const VertexDescription& desc);
|
||||||
|
|
||||||
std::ostream& out;
|
std::ostream& out;
|
||||||
};
|
};
|
||||||
|
@ -734,23 +814,23 @@ AsciiModelWriter::write(const Model& model)
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
AsciiModelWriter::writeGroup(const Mesh::PrimitiveGroup& group)
|
AsciiModelWriter::writeGroup(const PrimitiveGroup& group)
|
||||||
{
|
{
|
||||||
switch (group.prim)
|
switch (group.prim)
|
||||||
{
|
{
|
||||||
case Mesh::TriList:
|
case PrimitiveGroupType::TriList:
|
||||||
fmt::print(out, "trilist"); break;
|
fmt::print(out, "trilist"); break;
|
||||||
case Mesh::TriStrip:
|
case PrimitiveGroupType::TriStrip:
|
||||||
fmt::print(out, "tristrip"); break;
|
fmt::print(out, "tristrip"); break;
|
||||||
case Mesh::TriFan:
|
case PrimitiveGroupType::TriFan:
|
||||||
fmt::print(out, "trifan"); break;
|
fmt::print(out, "trifan"); break;
|
||||||
case Mesh::LineList:
|
case PrimitiveGroupType::LineList:
|
||||||
fmt::print(out, "linelist"); break;
|
fmt::print(out, "linelist"); break;
|
||||||
case Mesh::LineStrip:
|
case PrimitiveGroupType::LineStrip:
|
||||||
fmt::print(out, "linestrip"); break;
|
fmt::print(out, "linestrip"); break;
|
||||||
case Mesh::PointList:
|
case PrimitiveGroupType::PointList:
|
||||||
fmt::print(out, "points"); break;
|
fmt::print(out, "points"); break;
|
||||||
case Mesh::SpriteList:
|
case PrimitiveGroupType::SpriteList:
|
||||||
fmt::print(out, "sprites"); break;
|
fmt::print(out, "sprites"); break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -820,7 +900,7 @@ bool
|
||||||
AsciiModelWriter::writeVertices(const void* vertexData,
|
AsciiModelWriter::writeVertices(const void* vertexData,
|
||||||
unsigned int nVertices,
|
unsigned int nVertices,
|
||||||
unsigned int stride,
|
unsigned int stride,
|
||||||
const Mesh::VertexDescription& desc)
|
const VertexDescription& desc)
|
||||||
{
|
{
|
||||||
const auto* vertex = reinterpret_cast<const unsigned char*>(vertexData);
|
const auto* vertex = reinterpret_cast<const unsigned char*>(vertexData);
|
||||||
|
|
||||||
|
@ -837,23 +917,23 @@ AsciiModelWriter::writeVertices(const void* vertexData,
|
||||||
|
|
||||||
switch (desc.attributes[attr].format)
|
switch (desc.attributes[attr].format)
|
||||||
{
|
{
|
||||||
case Mesh::Float1:
|
case VertexAttributeFormat::Float1:
|
||||||
std::memcpy(fdata, ubdata, sizeof(float));
|
std::memcpy(fdata, ubdata, sizeof(float));
|
||||||
fmt::print(out, "{}", fdata[0]);
|
fmt::print(out, "{}", fdata[0]);
|
||||||
break;
|
break;
|
||||||
case Mesh::Float2:
|
case VertexAttributeFormat::Float2:
|
||||||
std::memcpy(fdata, ubdata, sizeof(float) * 2);
|
std::memcpy(fdata, ubdata, sizeof(float) * 2);
|
||||||
fmt::print(out, "{} {}", fdata[0], fdata[1]);
|
fmt::print(out, "{} {}", fdata[0], fdata[1]);
|
||||||
break;
|
break;
|
||||||
case Mesh::Float3:
|
case VertexAttributeFormat::Float3:
|
||||||
std::memcpy(fdata, ubdata, sizeof(float) * 3);
|
std::memcpy(fdata, ubdata, sizeof(float) * 3);
|
||||||
fmt::print(out, "{} {} {}", fdata[0], fdata[1], fdata[2]);
|
fmt::print(out, "{} {} {}", fdata[0], fdata[1], fdata[2]);
|
||||||
break;
|
break;
|
||||||
case Mesh::Float4:
|
case VertexAttributeFormat::Float4:
|
||||||
std::memcpy(fdata, ubdata, sizeof(float) * 4);
|
std::memcpy(fdata, ubdata, sizeof(float) * 4);
|
||||||
fmt::print(out, "{} {} {} {}", fdata[0], fdata[1], fdata[2], fdata[3]);
|
fmt::print(out, "{} {} {} {}", fdata[0], fdata[1], fdata[2], fdata[3]);
|
||||||
break;
|
break;
|
||||||
case Mesh::UByte4:
|
case VertexAttributeFormat::UByte4:
|
||||||
fmt::print(out, "{} {} {} {}", +ubdata[0], +ubdata[1], +ubdata[2], +ubdata[3]);
|
fmt::print(out, "{} {} {} {}", +ubdata[0], +ubdata[1], +ubdata[2], +ubdata[3]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -871,7 +951,7 @@ AsciiModelWriter::writeVertices(const void* vertexData,
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
AsciiModelWriter::writeVertexDescription(const Mesh::VertexDescription& desc)
|
AsciiModelWriter::writeVertexDescription(const VertexDescription& desc)
|
||||||
{
|
{
|
||||||
if (!(out << "vertexdesc\n").good()) { return false; }
|
if (!(out << "vertexdesc\n").good()) { return false; }
|
||||||
for (unsigned int attr = 0; attr < desc.nAttributes; attr++)
|
for (unsigned int attr = 0; attr < desc.nAttributes; attr++)
|
||||||
|
@ -881,34 +961,34 @@ AsciiModelWriter::writeVertexDescription(const Mesh::VertexDescription& desc)
|
||||||
|
|
||||||
switch (desc.attributes[attr].semantic)
|
switch (desc.attributes[attr].semantic)
|
||||||
{
|
{
|
||||||
case Mesh::Position:
|
case VertexAttributeSemantic::Position:
|
||||||
out << "position";
|
out << "position";
|
||||||
break;
|
break;
|
||||||
case Mesh::Color0:
|
case VertexAttributeSemantic::Color0:
|
||||||
out << "color0";
|
out << "color0";
|
||||||
break;
|
break;
|
||||||
case Mesh::Color1:
|
case VertexAttributeSemantic::Color1:
|
||||||
out << "color1";
|
out << "color1";
|
||||||
break;
|
break;
|
||||||
case Mesh::Normal:
|
case VertexAttributeSemantic::Normal:
|
||||||
out << "normal";
|
out << "normal";
|
||||||
break;
|
break;
|
||||||
case Mesh::Tangent:
|
case VertexAttributeSemantic::Tangent:
|
||||||
out << "tangent";
|
out << "tangent";
|
||||||
break;
|
break;
|
||||||
case Mesh::Texture0:
|
case VertexAttributeSemantic::Texture0:
|
||||||
out << "texcoord0";
|
out << "texcoord0";
|
||||||
break;
|
break;
|
||||||
case Mesh::Texture1:
|
case VertexAttributeSemantic::Texture1:
|
||||||
out << "texcoord1";
|
out << "texcoord1";
|
||||||
break;
|
break;
|
||||||
case Mesh::Texture2:
|
case VertexAttributeSemantic::Texture2:
|
||||||
out << "texcoord2";
|
out << "texcoord2";
|
||||||
break;
|
break;
|
||||||
case Mesh::Texture3:
|
case VertexAttributeSemantic::Texture3:
|
||||||
out << "texcoord3";
|
out << "texcoord3";
|
||||||
break;
|
break;
|
||||||
case Mesh::PointSize:
|
case VertexAttributeSemantic::PointSize:
|
||||||
out << "pointsize";
|
out << "pointsize";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -920,19 +1000,19 @@ AsciiModelWriter::writeVertexDescription(const Mesh::VertexDescription& desc)
|
||||||
|
|
||||||
switch (desc.attributes[attr].format)
|
switch (desc.attributes[attr].format)
|
||||||
{
|
{
|
||||||
case Mesh::Float1:
|
case VertexAttributeFormat::Float1:
|
||||||
out << "f1";
|
out << "f1";
|
||||||
break;
|
break;
|
||||||
case Mesh::Float2:
|
case VertexAttributeFormat::Float2:
|
||||||
out << "f2";
|
out << "f2";
|
||||||
break;
|
break;
|
||||||
case Mesh::Float3:
|
case VertexAttributeFormat::Float3:
|
||||||
out << "f3";
|
out << "f3";
|
||||||
break;
|
break;
|
||||||
case Mesh::Float4:
|
case VertexAttributeFormat::Float4:
|
||||||
out << "f4";
|
out << "f4";
|
||||||
break;
|
break;
|
||||||
case Mesh::UByte4:
|
case VertexAttributeFormat::UByte4:
|
||||||
out << "ub4";
|
out << "ub4";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -994,13 +1074,13 @@ AsciiModelWriter::writeMaterial(const Material& material)
|
||||||
if (!(out << "blend ").good()) { return false; }
|
if (!(out << "blend ").good()) { return false; }
|
||||||
switch (material.blend)
|
switch (material.blend)
|
||||||
{
|
{
|
||||||
case Material::NormalBlend:
|
case BlendMode::NormalBlend:
|
||||||
out << "normal";
|
out << "normal";
|
||||||
break;
|
break;
|
||||||
case Material::AdditiveBlend:
|
case BlendMode::AdditiveBlend:
|
||||||
out << "add";
|
out << "add";
|
||||||
break;
|
break;
|
||||||
case Material::PremultipliedAlphaBlend:
|
case BlendMode::PremultipliedAlphaBlend:
|
||||||
out << "premultiplied";
|
out << "premultiplied";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1011,7 +1091,7 @@ AsciiModelWriter::writeMaterial(const Material& material)
|
||||||
if (!out.good() || !(out << '\n').good()) { return false; }
|
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;
|
fs::path texSource;
|
||||||
if (material.maps[i] != InvalidResource)
|
if (material.maps[i] != InvalidResource)
|
||||||
|
@ -1021,18 +1101,18 @@ AsciiModelWriter::writeMaterial(const Material& material)
|
||||||
|
|
||||||
if (!texSource.empty())
|
if (!texSource.empty())
|
||||||
{
|
{
|
||||||
switch (Material::TextureSemantic(i))
|
switch (static_cast<TextureSemantic>(i))
|
||||||
{
|
{
|
||||||
case Material::DiffuseMap:
|
case TextureSemantic::DiffuseMap:
|
||||||
out << "texture0";
|
out << "texture0";
|
||||||
break;
|
break;
|
||||||
case Material::NormalMap:
|
case TextureSemantic::NormalMap:
|
||||||
out << "normalmap";
|
out << "normalmap";
|
||||||
break;
|
break;
|
||||||
case Material::SpecularMap:
|
case TextureSemantic::SpecularMap:
|
||||||
out << "specularmap";
|
out << "specularmap";
|
||||||
break;
|
break;
|
||||||
case Material::EmissiveMap:
|
case TextureSemantic::EmissiveMap:
|
||||||
out << "emissivemap";
|
out << "emissivemap";
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
ModelFileType cmodType;
|
||||||
float r, g, b;
|
float r, g, b;
|
||||||
|
@ -1092,7 +1172,7 @@ bool readTypeColor(std::istream& in, Material::Color& c)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
c = Material::Color(r, g, b);
|
c = Color(r, g, b);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1178,9 +1258,9 @@ public:
|
||||||
void reportError(const std::string& /*msg*/) override;
|
void reportError(const std::string& /*msg*/) override;
|
||||||
|
|
||||||
Material* loadMaterial();
|
Material* loadMaterial();
|
||||||
Mesh::VertexDescription* loadVertexDescription();
|
VertexDescription* loadVertexDescription();
|
||||||
Mesh* loadMesh();
|
Mesh* loadMesh();
|
||||||
char* loadVertices(const Mesh::VertexDescription& vertexDesc,
|
char* loadVertices(const VertexDescription& vertexDesc,
|
||||||
unsigned int& vertexCount);
|
unsigned int& vertexCount);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1329,13 +1409,13 @@ BinaryModelLoader::loadMaterial()
|
||||||
{
|
{
|
||||||
std::int16_t blendMode;
|
std::int16_t blendMode;
|
||||||
if (!celutil::readLE<std::int16_t>(in, 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");
|
reportError("Bad blend mode");
|
||||||
delete material;
|
delete material;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
material->blend = (Material::BlendMode) blendMode;
|
material->blend = static_cast<BlendMode>(blendMode);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1343,7 +1423,7 @@ BinaryModelLoader::loadMaterial()
|
||||||
{
|
{
|
||||||
std::int16_t texType;
|
std::int16_t texType;
|
||||||
if (!celutil::readLE<std::int16_t>(in, 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");
|
reportError("Bad texture type");
|
||||||
delete material;
|
delete material;
|
||||||
|
@ -1385,7 +1465,7 @@ BinaryModelLoader::loadMaterial()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Mesh::VertexDescription*
|
VertexDescription*
|
||||||
BinaryModelLoader::loadVertexDescription()
|
BinaryModelLoader::loadVertexDescription()
|
||||||
{
|
{
|
||||||
ModelFileToken tok;
|
ModelFileToken tok;
|
||||||
|
@ -1398,7 +1478,7 @@ BinaryModelLoader::loadVertexDescription()
|
||||||
int maxAttributes = 16;
|
int maxAttributes = 16;
|
||||||
int nAttributes = 0;
|
int nAttributes = 0;
|
||||||
unsigned int offset = 0;
|
unsigned int offset = 0;
|
||||||
auto* attributes = new Mesh::VertexAttribute[maxAttributes];
|
auto* attributes = new VertexAttribute[maxAttributes];
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
@ -1414,11 +1494,11 @@ BinaryModelLoader::loadVertexDescription()
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (tok >= 0 && tok < Mesh::SemanticMax)
|
if (tok >= 0 && tok < static_cast<std::int16_t>(VertexAttributeSemantic::SemanticMax))
|
||||||
{
|
{
|
||||||
std::int16_t fmt;
|
std::int16_t vfmt;
|
||||||
if (!celutil::readLE<std::int16_t>(in, fmt)
|
if (!celutil::readLE<std::int16_t>(in, vfmt)
|
||||||
|| fmt < 0 || fmt >= Mesh::FormatMax)
|
|| vfmt < 0 || vfmt >= static_cast<std::int16_t>(VertexAttributeFormat::FormatMax))
|
||||||
{
|
{
|
||||||
reportError("Invalid vertex attribute type");
|
reportError("Invalid vertex attribute type");
|
||||||
delete[] attributes;
|
delete[] attributes;
|
||||||
|
@ -1433,12 +1513,12 @@ BinaryModelLoader::loadVertexDescription()
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes[nAttributes].semantic =
|
attributes[nAttributes].semantic =
|
||||||
static_cast<Mesh::VertexAttributeSemantic>(tok);
|
static_cast<VertexAttributeSemantic>(tok);
|
||||||
attributes[nAttributes].format =
|
attributes[nAttributes].format =
|
||||||
static_cast<Mesh::VertexAttributeFormat>(fmt);
|
static_cast<VertexAttributeFormat>(vfmt);
|
||||||
attributes[nAttributes].offset = offset;
|
attributes[nAttributes].offset = offset;
|
||||||
|
|
||||||
offset += Mesh::getVertexAttributeSize(attributes[nAttributes].format);
|
offset += VertexAttribute::getFormatSize(attributes[nAttributes].format);
|
||||||
nAttributes++;
|
nAttributes++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1457,7 +1537,7 @@ BinaryModelLoader::loadVertexDescription()
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *vertexDesc =
|
auto *vertexDesc =
|
||||||
new Mesh::VertexDescription(offset, nAttributes, attributes);
|
new VertexDescription(offset, nAttributes, attributes);
|
||||||
delete[] attributes;
|
delete[] attributes;
|
||||||
return vertexDesc;
|
return vertexDesc;
|
||||||
}
|
}
|
||||||
|
@ -1466,7 +1546,7 @@ BinaryModelLoader::loadVertexDescription()
|
||||||
Mesh*
|
Mesh*
|
||||||
BinaryModelLoader::loadMesh()
|
BinaryModelLoader::loadMesh()
|
||||||
{
|
{
|
||||||
Mesh::VertexDescription* vertexDesc = loadVertexDescription();
|
VertexDescription* vertexDesc = loadVertexDescription();
|
||||||
if (vertexDesc == nullptr)
|
if (vertexDesc == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
@ -1497,15 +1577,14 @@ BinaryModelLoader::loadMesh()
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (tok < 0 || tok >= Mesh::PrimitiveTypeMax)
|
if (tok < 0 || tok >= static_cast<std::int16_t>(PrimitiveGroupType::PrimitiveTypeMax))
|
||||||
{
|
{
|
||||||
reportError("Bad primitive group type");
|
reportError("Bad primitive group type");
|
||||||
delete mesh;
|
delete mesh;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh::PrimitiveGroupType type =
|
PrimitiveGroupType type = static_cast<PrimitiveGroupType>(tok);
|
||||||
static_cast<Mesh::PrimitiveGroupType>(tok);
|
|
||||||
std::uint32_t materialIndex, indexCount;
|
std::uint32_t materialIndex, indexCount;
|
||||||
if (!celutil::readLE<std::uint32_t>(in, materialIndex)
|
if (!celutil::readLE<std::uint32_t>(in, materialIndex)
|
||||||
|| !celutil::readLE<std::uint32_t>(in, indexCount))
|
|| !celutil::readLE<std::uint32_t>(in, indexCount))
|
||||||
|
@ -1539,7 +1618,7 @@ BinaryModelLoader::loadMesh()
|
||||||
|
|
||||||
|
|
||||||
char*
|
char*
|
||||||
BinaryModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
|
BinaryModelLoader::loadVertices(const VertexDescription& vertexDesc,
|
||||||
unsigned int& vertexCount)
|
unsigned int& vertexCount)
|
||||||
{
|
{
|
||||||
ModelFileToken tok;
|
ModelFileToken tok;
|
||||||
|
@ -1565,12 +1644,12 @@ BinaryModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
|
||||||
for (unsigned int attr = 0; attr < vertexDesc.nAttributes; attr++)
|
for (unsigned int attr = 0; attr < vertexDesc.nAttributes; attr++)
|
||||||
{
|
{
|
||||||
unsigned int base = offset + vertexDesc.attributes[attr].offset;
|
unsigned int base = offset + vertexDesc.attributes[attr].offset;
|
||||||
Mesh::VertexAttributeFormat fmt = vertexDesc.attributes[attr].format;
|
VertexAttributeFormat fmt = vertexDesc.attributes[attr].format;
|
||||||
float f[4];
|
float f[4];
|
||||||
/*int readCount = 0; Unused*/
|
/*int readCount = 0; Unused*/
|
||||||
switch (fmt)
|
switch (fmt)
|
||||||
{
|
{
|
||||||
case Mesh::Float1:
|
case VertexAttributeFormat::Float1:
|
||||||
if (!celutil::readLE<float>(in, f[0]))
|
if (!celutil::readLE<float>(in, f[0]))
|
||||||
{
|
{
|
||||||
reportError("Failed to read Float1");
|
reportError("Failed to read Float1");
|
||||||
|
@ -1579,7 +1658,7 @@ BinaryModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
|
||||||
}
|
}
|
||||||
std::memcpy(vertexData + base, f, sizeof(float));
|
std::memcpy(vertexData + base, f, sizeof(float));
|
||||||
break;
|
break;
|
||||||
case Mesh::Float2:
|
case VertexAttributeFormat::Float2:
|
||||||
if (!celutil::readLE<float>(in, f[0])
|
if (!celutil::readLE<float>(in, f[0])
|
||||||
|| !celutil::readLE<float>(in, f[1]))
|
|| !celutil::readLE<float>(in, f[1]))
|
||||||
{
|
{
|
||||||
|
@ -1589,7 +1668,7 @@ BinaryModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
|
||||||
}
|
}
|
||||||
std::memcpy(vertexData + base, f, sizeof(float) * 2);
|
std::memcpy(vertexData + base, f, sizeof(float) * 2);
|
||||||
break;
|
break;
|
||||||
case Mesh::Float3:
|
case VertexAttributeFormat::Float3:
|
||||||
if (!celutil::readLE<float>(in, f[0])
|
if (!celutil::readLE<float>(in, f[0])
|
||||||
|| !celutil::readLE<float>(in, f[1])
|
|| !celutil::readLE<float>(in, f[1])
|
||||||
|| !celutil::readLE<float>(in, f[2]))
|
|| !celutil::readLE<float>(in, f[2]))
|
||||||
|
@ -1600,7 +1679,7 @@ BinaryModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
|
||||||
}
|
}
|
||||||
std::memcpy(vertexData + base, f, sizeof(float) * 3);
|
std::memcpy(vertexData + base, f, sizeof(float) * 3);
|
||||||
break;
|
break;
|
||||||
case Mesh::Float4:
|
case VertexAttributeFormat::Float4:
|
||||||
if (!celutil::readLE<float>(in, f[0])
|
if (!celutil::readLE<float>(in, f[0])
|
||||||
|| !celutil::readLE<float>(in, f[1])
|
|| !celutil::readLE<float>(in, f[1])
|
||||||
|| !celutil::readLE<float>(in, f[2])
|
|| !celutil::readLE<float>(in, f[2])
|
||||||
|
@ -1612,7 +1691,7 @@ BinaryModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
|
||||||
}
|
}
|
||||||
std::memcpy(vertexData + base, f, sizeof(float) * 4);
|
std::memcpy(vertexData + base, f, sizeof(float) * 4);
|
||||||
break;
|
break;
|
||||||
case Mesh::UByte4:
|
case VertexAttributeFormat::UByte4:
|
||||||
if (!in.get(reinterpret_cast<char*>(vertexData + base), 4).good())
|
if (!in.get(reinterpret_cast<char*>(vertexData + base), 4).good())
|
||||||
{
|
{
|
||||||
reportError("failed to read UByte4");
|
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)
|
return writeType(out, CMOD_Color)
|
||||||
&& celutil::writeLE<float>(out, c.red())
|
&& celutil::writeLE<float>(out, c.red())
|
||||||
|
@ -1684,12 +1763,12 @@ public:
|
||||||
private:
|
private:
|
||||||
bool writeMesh(const Mesh& /*mesh*/);
|
bool writeMesh(const Mesh& /*mesh*/);
|
||||||
bool writeMaterial(const Material& /*material*/);
|
bool writeMaterial(const Material& /*material*/);
|
||||||
bool writeGroup(const Mesh::PrimitiveGroup& /*group*/);
|
bool writeGroup(const PrimitiveGroup& /*group*/);
|
||||||
bool writeVertexDescription(const Mesh::VertexDescription& /*desc*/);
|
bool writeVertexDescription(const VertexDescription& /*desc*/);
|
||||||
bool writeVertices(const void* vertexData,
|
bool writeVertices(const void* vertexData,
|
||||||
unsigned int nVertices,
|
unsigned int nVertices,
|
||||||
unsigned int stride,
|
unsigned int stride,
|
||||||
const Mesh::VertexDescription& desc);
|
const VertexDescription& desc);
|
||||||
|
|
||||||
std::ostream& out;
|
std::ostream& out;
|
||||||
};
|
};
|
||||||
|
@ -1715,9 +1794,9 @@ BinaryModelWriter::write(const Model& model)
|
||||||
|
|
||||||
|
|
||||||
bool
|
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.materialIndex)
|
||||||
|| !celutil::writeLE<std::uint32_t>(out, group.nIndices))
|
|| !celutil::writeLE<std::uint32_t>(out, group.nIndices))
|
||||||
{
|
{
|
||||||
|
@ -1759,7 +1838,7 @@ bool
|
||||||
BinaryModelWriter::writeVertices(const void* vertexData,
|
BinaryModelWriter::writeVertices(const void* vertexData,
|
||||||
unsigned int nVertices,
|
unsigned int nVertices,
|
||||||
unsigned int stride,
|
unsigned int stride,
|
||||||
const Mesh::VertexDescription& desc)
|
const VertexDescription& desc)
|
||||||
{
|
{
|
||||||
const auto* vertex = reinterpret_cast<const char*>(vertexData);
|
const auto* vertex = reinterpret_cast<const char*>(vertexData);
|
||||||
|
|
||||||
|
@ -1778,29 +1857,29 @@ BinaryModelWriter::writeVertices(const void* vertexData,
|
||||||
bool result;
|
bool result;
|
||||||
switch (desc.attributes[attr].format)
|
switch (desc.attributes[attr].format)
|
||||||
{
|
{
|
||||||
case Mesh::Float1:
|
case VertexAttributeFormat::Float1:
|
||||||
std::memcpy(fdata, cdata, sizeof(float));
|
std::memcpy(fdata, cdata, sizeof(float));
|
||||||
result = celutil::writeLE<float>(out, fdata[0]);
|
result = celutil::writeLE<float>(out, fdata[0]);
|
||||||
break;
|
break;
|
||||||
case Mesh::Float2:
|
case VertexAttributeFormat::Float2:
|
||||||
std::memcpy(fdata, cdata, sizeof(float) * 2);
|
std::memcpy(fdata, cdata, sizeof(float) * 2);
|
||||||
result = celutil::writeLE<float>(out, fdata[0])
|
result = celutil::writeLE<float>(out, fdata[0])
|
||||||
&& celutil::writeLE<float>(out, fdata[1]);
|
&& celutil::writeLE<float>(out, fdata[1]);
|
||||||
break;
|
break;
|
||||||
case Mesh::Float3:
|
case VertexAttributeFormat::Float3:
|
||||||
std::memcpy(fdata, cdata, sizeof(float) * 3);
|
std::memcpy(fdata, cdata, sizeof(float) * 3);
|
||||||
result = celutil::writeLE<float>(out, fdata[0])
|
result = celutil::writeLE<float>(out, fdata[0])
|
||||||
&& celutil::writeLE<float>(out, fdata[1])
|
&& celutil::writeLE<float>(out, fdata[1])
|
||||||
&& celutil::writeLE<float>(out, fdata[2]);
|
&& celutil::writeLE<float>(out, fdata[2]);
|
||||||
break;
|
break;
|
||||||
case Mesh::Float4:
|
case VertexAttributeFormat::Float4:
|
||||||
std::memcpy(fdata, cdata, sizeof(float) * 4);
|
std::memcpy(fdata, cdata, sizeof(float) * 4);
|
||||||
result = celutil::writeLE<float>(out, fdata[0])
|
result = celutil::writeLE<float>(out, fdata[0])
|
||||||
&& celutil::writeLE<float>(out, fdata[1])
|
&& celutil::writeLE<float>(out, fdata[1])
|
||||||
&& celutil::writeLE<float>(out, fdata[2])
|
&& celutil::writeLE<float>(out, fdata[2])
|
||||||
&& celutil::writeLE<float>(out, fdata[3]);
|
&& celutil::writeLE<float>(out, fdata[3]);
|
||||||
break;
|
break;
|
||||||
case Mesh::UByte4:
|
case VertexAttributeFormat::UByte4:
|
||||||
result = out.write(cdata, 4).good();
|
result = out.write(cdata, 4).good();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1817,14 +1896,14 @@ BinaryModelWriter::writeVertices(const void* vertexData,
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BinaryModelWriter::writeVertexDescription(const Mesh::VertexDescription& desc)
|
BinaryModelWriter::writeVertexDescription(const VertexDescription& desc)
|
||||||
{
|
{
|
||||||
if (!writeToken(out, CMOD_VertexDesc)) { return false; }
|
if (!writeToken(out, CMOD_VertexDesc)) { return false; }
|
||||||
|
|
||||||
for (unsigned int attr = 0; attr < desc.nAttributes; attr++)
|
for (unsigned int attr = 0; attr < desc.nAttributes; attr++)
|
||||||
{
|
{
|
||||||
if (!celutil::writeLE<std::int16_t>(out, desc.attributes[attr].semantic)
|
if (!celutil::writeLE<std::int16_t>(out, static_cast<std::int16_t>(desc.attributes[attr].semantic))
|
||||||
|| !celutil::writeLE<std::int16_t>(out, desc.attributes[attr].format))
|
|| !celutil::writeLE<std::int16_t>(out, static_cast<std::int16_t>(desc.attributes[attr].format)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1870,12 +1949,13 @@ BinaryModelWriter::writeMaterial(const Material& material)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (material.blend != DefaultBlend
|
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;
|
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)
|
if (material.maps[i] != InvalidResource)
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,7 +47,7 @@ template<class T> class ResourceManager
|
||||||
public:
|
public:
|
||||||
ResourceManager();
|
ResourceManager();
|
||||||
ResourceManager(const fs::path& _baseDir) : baseDir(_baseDir) {};
|
ResourceManager(const fs::path& _baseDir) : baseDir(_baseDir) {};
|
||||||
~ResourceManager();
|
~ResourceManager() = default;
|
||||||
|
|
||||||
typedef typename T::ResourceType ResourceType;
|
typedef typename T::ResourceType ResourceType;
|
||||||
|
|
||||||
|
|
|
@ -9,28 +9,21 @@
|
||||||
//
|
//
|
||||||
// Convert a 3DS file to a Celestia mesh (.cmod) file
|
// 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 <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <cel3ds/3dsread.h>
|
||||||
|
#include <celmath/mathlib.h>
|
||||||
|
|
||||||
|
#include "cmodops.h"
|
||||||
|
#include "convert3ds.h"
|
||||||
#include "pathmanager.h"
|
#include "pathmanager.h"
|
||||||
|
|
||||||
using namespace cmod;
|
|
||||||
using namespace std;
|
|
||||||
using namespace celmath;
|
|
||||||
|
|
||||||
|
|
||||||
void usage()
|
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;
|
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);
|
std::unique_ptr<M3DScene> scene = Read3DSFile(inputFileName);
|
||||||
if (scene == nullptr)
|
if (scene == nullptr)
|
||||||
{
|
{
|
||||||
cerr << "Error reading 3DS file '" << inputFileName << "'\n";
|
std::cerr << "Error reading 3DS file '" << inputFileName << "'\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cerr << "Converting...\n";
|
std::cerr << "Converting...\n";
|
||||||
Model* model = Convert3DSModel(*scene, GetPathManager()->getHandle);
|
cmod::Model* model = Convert3DSModel(*scene, GetPathManager()->getHandle);
|
||||||
if (!model)
|
if (!model)
|
||||||
{
|
{
|
||||||
cerr << "Error converting 3DS file to Celestia model\n";
|
std::cerr << "Error converting 3DS file to Celestia model\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate normals for the model
|
// Generate normals for the model
|
||||||
double smoothAngle = 45.0; // degrees
|
float smoothAngle = 45.0; // degrees
|
||||||
double weldTolerance = 1.0e-6;
|
double weldTolerance = 1.0e-6;
|
||||||
bool weldVertices = true;
|
bool weldVertices = true;
|
||||||
|
|
||||||
Model* newModel = GenerateModelNormals(*model, (float)degToRad(smoothAngle), weldVertices, weldTolerance);
|
cmod::Model* newModel = GenerateModelNormals(*model, celmath::degToRad(smoothAngle), weldVertices, weldTolerance);
|
||||||
delete model;
|
delete model;
|
||||||
|
|
||||||
if (!newModel)
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Automatically uniquify vertices
|
// Automatically uniquify vertices
|
||||||
for (unsigned int i = 0; newModel->getMesh(i) != nullptr; i++)
|
for (unsigned int i = 0; newModel->getMesh(i) != nullptr; i++)
|
||||||
{
|
{
|
||||||
Mesh* mesh = newModel->getMesh(i);
|
cmod::Mesh* mesh = newModel->getMesh(i);
|
||||||
UniquifyVertices(*mesh);
|
UniquifyVertices(*mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
model = newModel;
|
model = newModel;
|
||||||
|
|
||||||
#if 0
|
SaveModelAscii(model, std::cout, GetPathManager()->getSource);
|
||||||
// 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);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,7 @@
|
||||||
//
|
//
|
||||||
// C++ wrapper for OpenGL framebuffer objects.
|
// C++ wrapper for OpenGL framebuffer objects.
|
||||||
|
|
||||||
#ifndef _GLFRAMEBUFFER_H_
|
#pragma once
|
||||||
#define _GLFRAMEBUFFER_H_
|
|
||||||
|
|
||||||
#include "glsupport.h"
|
#include "glsupport.h"
|
||||||
|
|
||||||
|
@ -57,5 +56,3 @@ private:
|
||||||
GLuint m_fboId;
|
GLuint m_fboId;
|
||||||
GLenum m_status;
|
GLenum m_status;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _GLFRAMEBUFFER_H_
|
|
||||||
|
|
|
@ -9,10 +9,13 @@
|
||||||
//
|
//
|
||||||
// C++ wrapper for OpenGL shaders and shader programs
|
// C++ wrapper for OpenGL shaders and shader programs
|
||||||
|
|
||||||
#include "glsupport.h"
|
#pragma once
|
||||||
#include <Eigen/Core>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <Eigen/Core>
|
||||||
|
|
||||||
|
#include "glsupport.h"
|
||||||
|
|
||||||
class GLVertexShader;
|
class GLVertexShader;
|
||||||
class GLFragmentShader;
|
class GLFragmentShader;
|
||||||
|
|
|
@ -9,38 +9,74 @@
|
||||||
// of the License, or (at your option) any later version.
|
// of the License, or (at your option) any later version.
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "mainwindow.h"
|
#include <string>
|
||||||
#include "materialwidget.h"
|
|
||||||
|
#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 "convert3ds.h"
|
||||||
#include "convertobj.h"
|
#include "convertobj.h"
|
||||||
#include "cmodops.h"
|
|
||||||
#include "pathmanager.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;
|
#include "glshader.h"
|
||||||
using namespace std;
|
#include "glsupport.h"
|
||||||
|
#include "materialwidget.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include "modelviewwidget.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
// Version number for saving/restoring widget layout state. Increment this
|
// Version number for saving/restoring widget layout state. Increment this
|
||||||
// value whenever new tool widgets are added or removed.
|
// 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() :
|
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
|
bool
|
||||||
|
@ -254,7 +277,7 @@ MainWindow::eventFilter(QObject* obj, QEvent* e)
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MainWindow::setModel(const QString& fileName, Model* model)
|
MainWindow::setModel(const QString& fileName, cmod::Model* model)
|
||||||
{
|
{
|
||||||
QFileInfo info(fileName);
|
QFileInfo info(fileName);
|
||||||
QString modelDir = info.absoluteDir().path();
|
QString modelDir = info.absoluteDir().path();
|
||||||
|
@ -277,7 +300,7 @@ MainWindow::setModel(const QString& fileName, Model* model)
|
||||||
void
|
void
|
||||||
MainWindow::showModelStatistics()
|
MainWindow::showModelStatistics()
|
||||||
{
|
{
|
||||||
Model* model = m_modelView->model();
|
cmod::Model* model = m_modelView->model();
|
||||||
if (model)
|
if (model)
|
||||||
{
|
{
|
||||||
// Count triangles and vertices in the mesh
|
// Count triangles and vertices in the mesh
|
||||||
|
@ -285,18 +308,18 @@ MainWindow::showModelStatistics()
|
||||||
unsigned int triangleCount = 0;
|
unsigned int triangleCount = 0;
|
||||||
for (unsigned int meshIndex = 0; meshIndex < model->getMeshCount(); ++meshIndex)
|
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();
|
vertexCount += mesh->getVertexCount();
|
||||||
for (unsigned int groupIndex = 0; groupIndex < mesh->getGroupCount(); ++groupIndex)
|
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)
|
switch (group->prim)
|
||||||
{
|
{
|
||||||
case Mesh::TriList:
|
case cmod::PrimitiveGroupType::TriList:
|
||||||
triangleCount += group->nIndices / 3;
|
triangleCount += group->nIndices / 3;
|
||||||
break;
|
break;
|
||||||
case Mesh::TriFan:
|
case cmod::PrimitiveGroupType::TriFan:
|
||||||
case Mesh::TriStrip:
|
case cmod::PrimitiveGroupType::TriStrip:
|
||||||
triangleCount += group->nIndices - 2;
|
triangleCount += group->nIndices - 2;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -373,7 +396,7 @@ MainWindow::openModel(const QString& fileName)
|
||||||
{
|
{
|
||||||
if (!fileName.isEmpty())
|
if (!fileName.isEmpty())
|
||||||
{
|
{
|
||||||
string fileNameStd = string(fileName.toUtf8().data());
|
std::string fileNameStd = std::string(fileName.toUtf8().data());
|
||||||
|
|
||||||
QFileInfo info(fileName);
|
QFileInfo info(fileName);
|
||||||
GetPathManager()->reset();
|
GetPathManager()->reset();
|
||||||
|
@ -387,7 +410,7 @@ MainWindow::openModel(const QString& fileName)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Model* model = Convert3DSModel(*scene, GetPathManager()->getHandle);
|
cmod::Model* model = Convert3DSModel(*scene, GetPathManager()->getHandle);
|
||||||
if (model == nullptr)
|
if (model == nullptr)
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, "Load error", tr("Internal error converting 3DS file %1").arg(fileName));
|
QMessageBox::warning(this, "Load error", tr("Internal error converting 3DS file %1").arg(fileName));
|
||||||
|
@ -395,11 +418,11 @@ MainWindow::openModel(const QString& fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate normals for the model
|
// Generate normals for the model
|
||||||
double smoothAngle = 45.0; // degrees
|
float smoothAngle = 45.0; // degrees
|
||||||
double weldTolerance = 1.0e-6;
|
double weldTolerance = 1.0e-6;
|
||||||
bool weldVertices = true;
|
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;
|
delete model;
|
||||||
|
|
||||||
if (!newModel)
|
if (!newModel)
|
||||||
|
@ -411,7 +434,7 @@ MainWindow::openModel(const QString& fileName)
|
||||||
// Automatically uniquify vertices
|
// Automatically uniquify vertices
|
||||||
for (unsigned int i = 0; newModel->getMesh(i) != nullptr; i++)
|
for (unsigned int i = 0; newModel->getMesh(i) != nullptr; i++)
|
||||||
{
|
{
|
||||||
Mesh* mesh = newModel->getMesh(i);
|
cmod::Mesh* mesh = newModel->getMesh(i);
|
||||||
UniquifyVertices(*mesh);
|
UniquifyVertices(*mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,8 +443,8 @@ MainWindow::openModel(const QString& fileName)
|
||||||
}
|
}
|
||||||
else if (info.suffix().toLower() == "obj")
|
else if (info.suffix().toLower() == "obj")
|
||||||
{
|
{
|
||||||
Model* model = nullptr;
|
cmod::Model* model = nullptr;
|
||||||
ifstream in(fileNameStd, ios::in | ios::binary);
|
std::ifstream in(fileNameStd, std::ios::in | std::ios::binary);
|
||||||
if (!in.good())
|
if (!in.good())
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, "Load error", tr("Error opening obj file %1").arg(fileName));
|
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
|
// Automatically uniquify vertices
|
||||||
for (unsigned int i = 0; model->getMesh(i) != nullptr; i++)
|
for (unsigned int i = 0; model->getMesh(i) != nullptr; i++)
|
||||||
{
|
{
|
||||||
Mesh* mesh = model->getMesh(i);
|
cmod::Mesh* mesh = model->getMesh(i);
|
||||||
UniquifyVertices(*mesh);
|
UniquifyVertices(*mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,15 +471,15 @@ MainWindow::openModel(const QString& fileName)
|
||||||
}
|
}
|
||||||
else if (info.suffix().toLower() == "cmod")
|
else if (info.suffix().toLower() == "cmod")
|
||||||
{
|
{
|
||||||
Model* model = nullptr;
|
cmod::Model* model = nullptr;
|
||||||
ifstream in(fileNameStd, ios::in | ios::binary);
|
std::ifstream in(fileNameStd, std::ios::in | std::ios::binary);
|
||||||
if (!in.good())
|
if (!in.good())
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, "Load error", tr("Error opening CMOD file %1").arg(fileName));
|
QMessageBox::warning(this, "Load error", tr("Error opening CMOD file %1").arg(fileName));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
model = LoadModel(in, GetPathManager()->getHandle);
|
model = cmod::LoadModel(in, GetPathManager()->getHandle);
|
||||||
if (model == nullptr)
|
if (model == nullptr)
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, "Load error", tr("Error reading CMOD file %1").arg(fileName));
|
QMessageBox::warning(this, "Load error", tr("Error reading CMOD file %1").arg(fileName));
|
||||||
|
@ -498,9 +521,9 @@ MainWindow::saveModelAs()
|
||||||
void
|
void
|
||||||
MainWindow::saveModel(const QString& saveFileName)
|
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;
|
bool ok = false;
|
||||||
if (out.good())
|
if (out.good())
|
||||||
{
|
{
|
||||||
|
@ -557,7 +580,7 @@ MainWindow::setRenderPath(QAction* action)
|
||||||
void
|
void
|
||||||
MainWindow::generateNormals()
|
MainWindow::generateNormals()
|
||||||
{
|
{
|
||||||
Model* model = m_modelView->model();
|
cmod::Model* model = m_modelView->model();
|
||||||
if (!model)
|
if (!model)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -597,11 +620,14 @@ MainWindow::generateNormals()
|
||||||
|
|
||||||
if (dialog.exec() == QDialog::Accepted)
|
if (dialog.exec() == QDialog::Accepted)
|
||||||
{
|
{
|
||||||
double smoothAngle = smoothAngleEdit->text().toDouble();
|
float smoothAngle = smoothAngleEdit->text().toFloat();
|
||||||
double weldTolerance = toleranceEdit->text().toDouble();
|
double weldTolerance = toleranceEdit->text().toDouble();
|
||||||
bool weldVertices = true;
|
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)
|
if (!newModel)
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, tr("Internal Error"), tr("Out of memory error during normal generation"));
|
QMessageBox::warning(this, tr("Internal Error"), tr("Out of memory error during normal generation"));
|
||||||
|
@ -620,7 +646,7 @@ MainWindow::generateNormals()
|
||||||
void
|
void
|
||||||
MainWindow::generateTangents()
|
MainWindow::generateTangents()
|
||||||
{
|
{
|
||||||
Model* model = m_modelView->model();
|
cmod::Model* model = m_modelView->model();
|
||||||
if (!model)
|
if (!model)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -652,7 +678,7 @@ MainWindow::generateTangents()
|
||||||
double weldTolerance = toleranceEdit->text().toDouble();
|
double weldTolerance = toleranceEdit->text().toDouble();
|
||||||
bool weldVertices = true;
|
bool weldVertices = true;
|
||||||
|
|
||||||
Model* newModel = new Model();
|
cmod::Model* newModel = new cmod::Model();
|
||||||
|
|
||||||
// Copy materials
|
// Copy materials
|
||||||
for (unsigned int i = 0; model->getMaterial(i) != nullptr; i++)
|
for (unsigned int i = 0; model->getMaterial(i) != nullptr; i++)
|
||||||
|
@ -662,13 +688,13 @@ MainWindow::generateTangents()
|
||||||
|
|
||||||
for (unsigned int i = 0; model->getMesh(i) != nullptr; i++)
|
for (unsigned int i = 0; model->getMesh(i) != nullptr; i++)
|
||||||
{
|
{
|
||||||
Mesh* mesh = model->getMesh(i);
|
cmod::Mesh* mesh = model->getMesh(i);
|
||||||
Mesh* newMesh = nullptr;
|
cmod::Mesh* newMesh = nullptr;
|
||||||
|
|
||||||
newMesh = GenerateTangents(*mesh, weldVertices);
|
newMesh = GenerateTangents(*mesh, weldVertices);
|
||||||
if (newMesh == nullptr)
|
if (newMesh == nullptr)
|
||||||
{
|
{
|
||||||
cerr << "Error generating normals!\n";
|
std::cerr << "Error generating normals!\n";
|
||||||
// TODO: Clone the mesh and add it to the model
|
// TODO: Clone the mesh and add it to the model
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -687,7 +713,7 @@ MainWindow::generateTangents()
|
||||||
void
|
void
|
||||||
MainWindow::uniquifyVertices()
|
MainWindow::uniquifyVertices()
|
||||||
{
|
{
|
||||||
Model* model = m_modelView->model();
|
cmod::Model* model = m_modelView->model();
|
||||||
if (!model)
|
if (!model)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -695,7 +721,7 @@ MainWindow::uniquifyVertices()
|
||||||
|
|
||||||
for (unsigned int i = 0; model->getMesh(i) != nullptr; i++)
|
for (unsigned int i = 0; model->getMesh(i) != nullptr; i++)
|
||||||
{
|
{
|
||||||
Mesh* mesh = model->getMesh(i);
|
cmod::Mesh* mesh = model->getMesh(i);
|
||||||
UniquifyVertices(*mesh);
|
UniquifyVertices(*mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -707,13 +733,13 @@ MainWindow::uniquifyVertices()
|
||||||
void
|
void
|
||||||
MainWindow::mergeMeshes()
|
MainWindow::mergeMeshes()
|
||||||
{
|
{
|
||||||
Model* model = m_modelView->model();
|
cmod::Model* model = m_modelView->model();
|
||||||
if (!model)
|
if (!model)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Model* newModel = MergeModelMeshes(*model);
|
cmod::Model* newModel = MergeModelMeshes(*model);
|
||||||
setModel(modelFileName(), newModel);
|
setModel(modelFileName(), newModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -728,9 +754,9 @@ MainWindow::updateSelectionInfo()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_materialWidget->setEnabled(true);
|
m_materialWidget->setEnabled(true);
|
||||||
QSetIterator<Mesh::PrimitiveGroup*> iter(m_modelView->selection());
|
QSetIterator<cmod::PrimitiveGroup*> iter(m_modelView->selection());
|
||||||
Mesh::PrimitiveGroup* selectedGroup = iter.next();
|
cmod::PrimitiveGroup* selectedGroup = iter.next();
|
||||||
const Material* material = m_modelView->model()->getMaterial(selectedGroup->materialIndex);
|
const cmod::Material* material = m_modelView->model()->getMaterial(selectedGroup->materialIndex);
|
||||||
if (material)
|
if (material)
|
||||||
{
|
{
|
||||||
m_materialWidget->setMaterial(*material);
|
m_materialWidget->setMaterial(*material);
|
||||||
|
@ -740,12 +766,12 @@ MainWindow::updateSelectionInfo()
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MainWindow::changeCurrentMaterial(const Material& material)
|
MainWindow::changeCurrentMaterial(const cmod::Material& material)
|
||||||
{
|
{
|
||||||
if (!m_modelView->selection().isEmpty())
|
if (!m_modelView->selection().isEmpty())
|
||||||
{
|
{
|
||||||
QSetIterator<Mesh::PrimitiveGroup*> iter(m_modelView->selection());
|
QSetIterator<cmod::PrimitiveGroup*> iter(m_modelView->selection());
|
||||||
Mesh::PrimitiveGroup* selectedGroup = iter.next();
|
cmod::PrimitiveGroup* selectedGroup = iter.next();
|
||||||
m_modelView->setMaterial(selectedGroup->materialIndex, material);
|
m_modelView->setMaterial(selectedGroup->materialIndex, material);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,17 +8,26 @@
|
||||||
// as published by the Free Software Foundation; either version 2
|
// as published by the Free Software Foundation; either version 2
|
||||||
// of the License, or (at your option) any later version.
|
// of the License, or (at your option) any later version.
|
||||||
|
|
||||||
#ifndef _CMODVIEW_MAINWINDOW_H_
|
#pragma once
|
||||||
#define _CMODVIEW_MAINWINDOW_H_
|
|
||||||
|
|
||||||
#include "modelviewwidget.h"
|
|
||||||
#include "materialwidget.h"
|
|
||||||
#include <QMainWindow>
|
|
||||||
#include <QString>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QAction>
|
#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
|
class MainWindow : public QMainWindow
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -73,6 +82,3 @@ private:
|
||||||
QAction* m_saveAsAction;
|
QAction* m_saveAsAction;
|
||||||
QAction* m_gl2Action;
|
QAction* m_gl2Action;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _CMODVIEW_MAINWINDOW_H_
|
|
||||||
|
|
||||||
|
|
|
@ -7,31 +7,36 @@
|
||||||
// as published by the Free Software Foundation; either version 2
|
// as published by the Free Software Foundation; either version 2
|
||||||
// of the License, or (at your option) any later version.
|
// 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 <QColorDialog>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QPushButton>
|
||||||
#include <QSet>
|
#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
|
// 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.diffuse = src.diffuse;
|
||||||
dest.specular = src.specular;
|
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->setPalette(QPalette(toQtColor(color)));
|
||||||
widget->setAutoFillBackground(true);
|
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) :
|
MaterialWidget::MaterialWidget(QWidget* parent) :
|
||||||
QWidget(parent)
|
QWidget(parent)
|
||||||
|
|
||||||
|
@ -131,40 +184,14 @@ MaterialWidget::MaterialWidget(QWidget* parent) :
|
||||||
connect(m_normalMap, SIGNAL(activated(int)), this, SLOT(changeMaterialParameters()));
|
connect(m_normalMap, SIGNAL(activated(int)), this, SLOT(changeMaterialParameters()));
|
||||||
connect(m_emissiveMap, SIGNAL(activated(int)), this, SLOT(changeMaterialParameters()));
|
connect(m_emissiveMap, SIGNAL(activated(int)), this, SLOT(changeMaterialParameters()));
|
||||||
|
|
||||||
setMaterial(Material());
|
setMaterial(cmod::Material());
|
||||||
|
|
||||||
this->setLayout(layout);
|
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
|
void
|
||||||
MaterialWidget::setMaterial(const Material& material)
|
MaterialWidget::setMaterial(const cmod::Material& material)
|
||||||
{
|
{
|
||||||
copyMaterial(m_material, material);
|
copyMaterial(m_material, material);
|
||||||
|
|
||||||
|
@ -174,20 +201,20 @@ MaterialWidget::setMaterial(const Material& material)
|
||||||
m_opacity->setText(QString::number(m_material.opacity));
|
m_opacity->setText(QString::number(m_material.opacity));
|
||||||
m_specularPower->setText(QString::number(m_material.specularPower));
|
m_specularPower->setText(QString::number(m_material.specularPower));
|
||||||
|
|
||||||
if (m_material.maps[Material::DiffuseMap] != InvalidResource)
|
if (m_material.getMap(cmod::TextureSemantic::DiffuseMap) != InvalidResource)
|
||||||
selectComboBoxItem(m_baseTexture, GetPathManager()->getSource(m_material.maps[Material::DiffuseMap]));
|
selectComboBoxItem(m_baseTexture, GetPathManager()->getSource(m_material.getMap(cmod::TextureSemantic::DiffuseMap)));
|
||||||
else
|
else
|
||||||
m_baseTexture->setCurrentIndex(0);
|
m_baseTexture->setCurrentIndex(0);
|
||||||
if (m_material.maps[Material::SpecularMap] != InvalidResource)
|
if (m_material.getMap(cmod::TextureSemantic::SpecularMap) != InvalidResource)
|
||||||
selectComboBoxItem(m_specularMap, GetPathManager()->getSource(m_material.maps[Material::SpecularMap]));
|
selectComboBoxItem(m_specularMap, GetPathManager()->getSource(m_material.getMap(cmod::TextureSemantic::SpecularMap)));
|
||||||
else
|
else
|
||||||
m_specularMap->setCurrentIndex(0);
|
m_specularMap->setCurrentIndex(0);
|
||||||
if (m_material.maps[Material::EmissiveMap] != InvalidResource)
|
if (m_material.getMap(cmod::TextureSemantic::EmissiveMap) != InvalidResource)
|
||||||
selectComboBoxItem(m_emissiveMap, GetPathManager()->getSource(m_material.maps[Material::EmissiveMap]));
|
selectComboBoxItem(m_emissiveMap, GetPathManager()->getSource(m_material.getMap(cmod::TextureSemantic::EmissiveMap)));
|
||||||
else
|
else
|
||||||
m_emissiveMap->setCurrentIndex(0);
|
m_emissiveMap->setCurrentIndex(0);
|
||||||
if (m_material.maps[Material::NormalMap] != InvalidResource)
|
if (m_material.getMap(cmod::TextureSemantic::NormalMap) != InvalidResource)
|
||||||
selectComboBoxItem(m_normalMap, GetPathManager()->getSource(m_material.maps[Material::NormalMap]));
|
selectComboBoxItem(m_normalMap, GetPathManager()->getSource(m_material.getMap(cmod::TextureSemantic::NormalMap)));
|
||||||
else
|
else
|
||||||
m_normalMap->setCurrentIndex(0);
|
m_normalMap->setCurrentIndex(0);
|
||||||
|
|
||||||
|
@ -279,48 +306,34 @@ MaterialWidget::changeMaterialParameters()
|
||||||
m_material.opacity = m_opacity->text().toFloat();
|
m_material.opacity = m_opacity->text().toFloat();
|
||||||
m_material.specularPower = m_specularPower->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())
|
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())
|
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())
|
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())
|
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);
|
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
|
void
|
||||||
MaterialWidget::setTextureSearchPath(const QString& path)
|
MaterialWidget::setTextureSearchPath(const QString& path)
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,14 +7,17 @@
|
||||||
// as published by the Free Software Foundation; either version 2
|
// as published by the Free Software Foundation; either version 2
|
||||||
// of the License, or (at your option) any later version.
|
// of the License, or (at your option) any later version.
|
||||||
|
|
||||||
#ifndef _CMODVIEW_MATERIAL_WIDGET_H_
|
#pragma once
|
||||||
#define _CMODVIEW_MATERIAL_WIDGET_H_
|
|
||||||
|
|
||||||
#include <celmodel/material.h>
|
#include <QColor>
|
||||||
#include <QWidget>
|
#include <QComboBox>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QComboBox>
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include <celmodel/material.h>
|
||||||
|
|
||||||
|
|
||||||
class MaterialWidget : public QWidget
|
class MaterialWidget : public QWidget
|
||||||
|
@ -66,5 +69,3 @@ private:
|
||||||
|
|
||||||
cmod::Material m_material;
|
cmod::Material m_material;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _CMODVIEW_MATERIAL_WIDGET_H_
|
|
||||||
|
|
|
@ -8,30 +8,37 @@
|
||||||
// as published by the Free Software Foundation; either version 2
|
// as published by the Free Software Foundation; either version 2
|
||||||
// of the License, or (at your option) any later version.
|
// 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 <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstddef>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace celestia;
|
#include <QFileInfo>
|
||||||
using namespace cmod;
|
#include <QIODevice>
|
||||||
using namespace Eigen;
|
#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
|
#define DEBUG_SHADOWS 0
|
||||||
|
|
||||||
static const float VIEWPORT_FOV = 45.0;
|
namespace
|
||||||
//static const double PI = 3.1415926535897932;
|
{
|
||||||
|
|
||||||
static const int ShadowBufferSize = 1024;
|
constexpr float VIEWPORT_FOV = 45.0;
|
||||||
static const int ShadowSampleKernelWidth = 2;
|
|
||||||
|
constexpr int ShadowBufferSize = 1024;
|
||||||
|
constexpr int ShadowSampleKernelWidth = 2;
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -45,11 +52,59 @@ inline QString toQString(const wchar_t *s)
|
||||||
return QString::fromWCharArray(s);
|
return QString::fromWCharArray(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline QString toQString(const char *s)
|
inline QString toQString(const char *s)
|
||||||
{
|
{
|
||||||
return QString::fromLocal8Bit(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
|
class MaterialLibrary
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -141,7 +196,7 @@ private:
|
||||||
|
|
||||||
|
|
||||||
ShaderKey
|
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
|
// Compute the shader key for a particular material and lighting setup
|
||||||
unsigned int info = 0;
|
unsigned int info = 0;
|
||||||
|
@ -150,8 +205,8 @@ ShaderKey::Create(const Material* material, const LightingEnvironment* lighting,
|
||||||
bool hasTexCoords = false;
|
bool hasTexCoords = false;
|
||||||
if (vertexDesc)
|
if (vertexDesc)
|
||||||
{
|
{
|
||||||
hasTangents = vertexDesc->getAttribute(Mesh::Tangent).format == Mesh::Float3;
|
hasTangents = vertexDesc->getAttribute(cmod::VertexAttributeSemantic::Tangent).format == cmod::VertexAttributeFormat::Float3;
|
||||||
hasTexCoords = vertexDesc->getAttribute(Mesh::Texture0).format == Mesh::Float2;
|
hasTexCoords = vertexDesc->getAttribute(cmod::VertexAttributeSemantic::Texture0).format == cmod::VertexAttributeFormat::Float2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bits 0-3 are the number of light sources
|
// 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
|
// Bits 8-15 are texture map info
|
||||||
if (hasTexCoords)
|
if (hasTexCoords)
|
||||||
{
|
{
|
||||||
if (material->maps[Material::DiffuseMap] != InvalidResource)
|
if (material->getMap(cmod::TextureSemantic::DiffuseMap) != InvalidResource)
|
||||||
{
|
{
|
||||||
info |= DiffuseMapMask;
|
info |= DiffuseMapMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (material->maps[Material::SpecularMap] != InvalidResource)
|
if (material->getMap(cmod::TextureSemantic::SpecularMap) != InvalidResource)
|
||||||
{
|
{
|
||||||
info |= SpecularMapMask;
|
info |= SpecularMapMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (material->maps[Material::NormalMap] != InvalidResource)
|
if (material->getMap(cmod::TextureSemantic::NormalMap) != InvalidResource)
|
||||||
{
|
{
|
||||||
info |= NormalMapMask;
|
info |= NormalMapMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (material->maps[Material::EmissiveMap] != InvalidResource)
|
if (material->getMap(cmod::TextureSemantic::EmissiveMap) != InvalidResource)
|
||||||
{
|
{
|
||||||
info |= EmissiveMapMask;
|
info |= EmissiveMapMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bit 16 is set if the normal map is compressed
|
// 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;
|
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) :
|
ModelViewWidget::ModelViewWidget(QWidget *parent) :
|
||||||
QGLWidget(parent),
|
QGLWidget(parent),
|
||||||
m_model(nullptr),
|
m_model(nullptr),
|
||||||
m_modelBoundingRadius(1.0),
|
m_modelBoundingRadius(1.0),
|
||||||
m_cameraPosition(Vector3d::Zero()),
|
m_cameraPosition(Eigen::Vector3d::Zero()),
|
||||||
m_cameraOrientation(Quaterniond::Identity()),
|
m_cameraOrientation(Eigen::Quaterniond::Identity()),
|
||||||
m_renderStyle(NormalStyle),
|
m_renderStyle(NormalStyle),
|
||||||
m_renderPath(FixedFunctionPath),
|
m_renderPath(FixedFunctionPath),
|
||||||
m_materialLibrary(nullptr),
|
m_materialLibrary(nullptr),
|
||||||
m_lightOrientation(Quaterniond::Identity()),
|
m_lightOrientation(Eigen::Quaterniond::Identity()),
|
||||||
m_lightingEnabled(true),
|
m_lightingEnabled(true),
|
||||||
m_ambientLightEnabled(true),
|
m_ambientLightEnabled(true),
|
||||||
m_shadowsEnabled(false)
|
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)
|
for (unsigned int i = 0; i < m_model->getMaterialCount(); ++i)
|
||||||
{
|
{
|
||||||
const Material* material = m_model->getMaterial(i);
|
const cmod::Material* material = m_model->getMaterial(i);
|
||||||
if (material->maps[Material::DiffuseMap] != InvalidResource)
|
if (material->getMap(cmod::TextureSemantic::DiffuseMap) != InvalidResource)
|
||||||
{
|
{
|
||||||
m_materialLibrary->getTexture(
|
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(
|
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(
|
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(
|
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
|
void
|
||||||
ModelViewWidget::resetCamera()
|
ModelViewWidget::resetCamera()
|
||||||
{
|
{
|
||||||
AlignedBox<float, 3> bbox;
|
Eigen::AlignedBox<float, 3> bbox;
|
||||||
if (m_model != nullptr)
|
if (m_model != nullptr)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < m_model->getMeshCount(); ++i)
|
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_modelBoundingRadius = std::max(bbox.max().norm(), bbox.min().norm());
|
||||||
m_cameraPosition = m_modelBoundingRadius * Vector3d::UnitZ() * 2.0;
|
m_cameraPosition = m_modelBoundingRadius * Eigen::Vector3d::UnitZ() * 2.0;
|
||||||
m_cameraOrientation = Quaterniond::Identity();
|
m_cameraOrientation = Eigen::Quaterniond::Identity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -378,9 +389,9 @@ ModelViewWidget::mouseReleaseEvent(QMouseEvent* event)
|
||||||
int moveDistance = (event->pos() - m_mouseDownPosition).manhattanLength();
|
int moveDistance = (event->pos() - m_mouseDownPosition).manhattanLength();
|
||||||
if (moveDistance < 3)
|
if (moveDistance < 3)
|
||||||
{
|
{
|
||||||
float x = (float) event->pos().x() / (float) size().width() * 2.0f - 1.0f;
|
float x = static_cast<float>(event->pos().x()) / static_cast<float>(size().width()) * 2.0f - 1.0f;
|
||||||
float y = (float) event->pos().y() / (float) size().height() * -2.0f + 1.0f;
|
float y = static_cast<float>(event->pos().y()) / static_cast<float>(size().height()) * -2.0f + 1.0f;
|
||||||
select(Vector2f(x, y));
|
select(Eigen::Vector2f(x, y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,20 +423,20 @@ ModelViewWidget::mouseMoveEvent(QMouseEvent *event)
|
||||||
int dx = event->x() - m_lastMousePosition.x();
|
int dx = event->x() - m_lastMousePosition.x();
|
||||||
int dy = event->y() - m_lastMousePosition.y();
|
int dy = event->y() - m_lastMousePosition.y();
|
||||||
|
|
||||||
double xrotation = (double) dy / 100.0;
|
double xrotation = static_cast<double>(dy) / 100.0;
|
||||||
double yrotation = (double) dx / 100.0;
|
double yrotation = static_cast<double>(dx) / 100.0;
|
||||||
Quaterniond q = AngleAxis<double>(-xrotation, Vector3d::UnitX()) *
|
Eigen::Quaterniond q = Eigen::AngleAxis<double>(-xrotation, Eigen::Vector3d::UnitX()) *
|
||||||
AngleAxis<double>(-yrotation, Vector3d::UnitY());
|
Eigen::AngleAxis<double>(-yrotation, Eigen::Vector3d::UnitY());
|
||||||
|
|
||||||
if (rotateLights)
|
if (rotateLights)
|
||||||
{
|
{
|
||||||
Quaterniond r = m_lightOrientation * q * m_lightOrientation.conjugate();
|
Eigen::Quaterniond r = m_lightOrientation * q * m_lightOrientation.conjugate();
|
||||||
r.normalize();
|
r.normalize();
|
||||||
m_lightOrientation = r * m_lightOrientation;
|
m_lightOrientation = r * m_lightOrientation;
|
||||||
}
|
}
|
||||||
else if (rotateCamera)
|
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
|
r.normalize(); // guard against accumulating rounding errors
|
||||||
|
|
||||||
m_cameraPosition = r * m_cameraPosition;
|
m_cameraPosition = r * m_cameraPosition;
|
||||||
|
@ -461,22 +472,22 @@ ModelViewWidget::wheelEvent(QWheelEvent* event)
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ModelViewWidget::select(const Vector2f& viewportPoint)
|
ModelViewWidget::select(const Eigen::Vector2f& viewportPoint)
|
||||||
{
|
{
|
||||||
if (!m_model)
|
if (!m_model)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float aspectRatio = (float) size().width() / (float) size().height();
|
float aspectRatio = static_cast<float>(size().width()) / static_cast<float>(size().height());
|
||||||
auto fovRad = float(VIEWPORT_FOV * PI / 180.0f);
|
auto fovRad = celmath::degToRad(VIEWPORT_FOV);
|
||||||
float h = (float) tan(fovRad / 2.0f);
|
float h = std::tan(fovRad / 2.0f);
|
||||||
Vector3d direction(h * aspectRatio * viewportPoint.x(), h * viewportPoint.y(), -1.0f);
|
Eigen::Vector3d direction(h * aspectRatio * viewportPoint.x(), h * viewportPoint.y(), -1.0f);
|
||||||
direction.normalize();
|
direction.normalize();
|
||||||
Vector3d origin = Vector3d::Zero();
|
Eigen::Vector3d origin = Eigen::Vector3d::Zero();
|
||||||
Affine3d camera(cameraTransform().inverse());
|
Eigen::Affine3d camera(cameraTransform().inverse());
|
||||||
|
|
||||||
Mesh::PickResult pickResult;
|
cmod::Mesh::PickResult pickResult;
|
||||||
bool hit = m_model->pick(camera * origin, camera.linear() * direction, &pickResult);
|
bool hit = m_model->pick(camera * origin, camera.linear() * direction, &pickResult);
|
||||||
if (hit)
|
if (hit)
|
||||||
{
|
{
|
||||||
|
@ -494,10 +505,10 @@ ModelViewWidget::select(const Vector2f& viewportPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Affine3d
|
Eigen::Affine3d
|
||||||
ModelViewWidget::cameraTransform() const
|
ModelViewWidget::cameraTransform() const
|
||||||
{
|
{
|
||||||
Affine3d t(m_cameraOrientation.conjugate());
|
Eigen::Affine3d t(m_cameraOrientation.conjugate());
|
||||||
t.translate(-m_cameraPosition);
|
t.translate(-m_cameraPosition);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
@ -513,17 +524,17 @@ ModelViewWidget::setMaterial(unsigned int index, const cmod::Material& material)
|
||||||
|
|
||||||
// Copy material parameters
|
// Copy material parameters
|
||||||
// TODO: eliminate const cast when Model::setMaterial() is implemented
|
// 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->diffuse = material.diffuse;
|
||||||
modelMaterial->specular = material.specular;
|
modelMaterial->specular = material.specular;
|
||||||
modelMaterial->emissive = material.emissive;
|
modelMaterial->emissive = material.emissive;
|
||||||
modelMaterial->opacity = material.opacity;
|
modelMaterial->opacity = material.opacity;
|
||||||
modelMaterial->specularPower = material.specularPower;
|
modelMaterial->specularPower = material.specularPower;
|
||||||
|
|
||||||
modelMaterial->maps[Material::DiffuseMap] = material.maps[Material::DiffuseMap];
|
modelMaterial->setMap(cmod::TextureSemantic::DiffuseMap, material.getMap(cmod::TextureSemantic::DiffuseMap));
|
||||||
modelMaterial->maps[Material::SpecularMap] = material.maps[Material::SpecularMap];
|
modelMaterial->setMap(cmod::TextureSemantic::SpecularMap, material.getMap(cmod::TextureSemantic::SpecularMap));
|
||||||
modelMaterial->maps[Material::NormalMap] = material.maps[Material::NormalMap];
|
modelMaterial->setMap(cmod::TextureSemantic::NormalMap, material.getMap(cmod::TextureSemantic::NormalMap));
|
||||||
modelMaterial->maps[Material::EmissiveMap] = material.maps[Material::EmissiveMap];
|
modelMaterial->setMap(cmod::TextureSemantic::EmissiveMap, material.getMap(cmod::TextureSemantic::EmissiveMap));
|
||||||
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
@ -539,7 +550,7 @@ ModelViewWidget::setBackgroundColor(const QColor& color)
|
||||||
void
|
void
|
||||||
ModelViewWidget::initializeGL()
|
ModelViewWidget::initializeGL()
|
||||||
{
|
{
|
||||||
gl::init();
|
celestia::gl::init();
|
||||||
emit contextCreated();
|
emit contextCreated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -550,8 +561,8 @@ ModelViewWidget::paintGL()
|
||||||
// Generate the shadow buffers for each light source
|
// Generate the shadow buffers for each light source
|
||||||
if (m_shadowsEnabled && m_shadowBuffers.size() > 0)
|
if (m_shadowsEnabled && m_shadowBuffers.size() > 0)
|
||||||
{
|
{
|
||||||
Material defaultMaterial;
|
cmod::Material defaultMaterial;
|
||||||
defaultMaterial.diffuse = Material::Color(1.0f, 1.0f, 1.0f);
|
defaultMaterial.diffuse = cmod::Color(1.0f, 1.0f, 1.0f);
|
||||||
LightingEnvironment lightingOff;
|
LightingEnvironment lightingOff;
|
||||||
bindMaterial(&defaultMaterial, &lightingOff, nullptr);
|
bindMaterial(&defaultMaterial, &lightingOff, nullptr);
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
|
@ -588,7 +599,7 @@ ModelViewWidget::paintGL()
|
||||||
{
|
{
|
||||||
ambientLightLevel = 0.2f;
|
ambientLightLevel = 0.2f;
|
||||||
}
|
}
|
||||||
Vector4f ambientLight = Vector4f::Constant(ambientLightLevel);
|
Eigen::Vector4f ambientLight = Eigen::Vector4f::Constant(ambientLightLevel);
|
||||||
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight.data());
|
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight.data());
|
||||||
glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL_EXT, GL_SEPARATE_SPECULAR_COLOR_EXT);
|
glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL_EXT, GL_SEPARATE_SPECULAR_COLOR_EXT);
|
||||||
|
|
||||||
|
@ -603,10 +614,10 @@ ModelViewWidget::paintGL()
|
||||||
GLenum glLight = GL_LIGHT0 + lightIndex;
|
GLenum glLight = GL_LIGHT0 + lightIndex;
|
||||||
lightIndex++;
|
lightIndex++;
|
||||||
|
|
||||||
Vector3d direction = m_lightOrientation * lightSource.direction;
|
Eigen::Vector3d direction = m_lightOrientation * lightSource.direction;
|
||||||
Vector4f lightColor = Vector4f::Zero();
|
Eigen::Vector4f lightColor = Eigen::Vector4f::Zero();
|
||||||
lightColor.head(3) = lightSource.color * lightSource.intensity;
|
lightColor.head(3) = lightSource.color * lightSource.intensity;
|
||||||
Vector4f lightPosition = Vector4f::Zero();
|
Eigen::Vector4f lightPosition = Eigen::Vector4f::Zero();
|
||||||
lightPosition.head(3) = direction.cast<float>();
|
lightPosition.head(3) = direction.cast<float>();
|
||||||
|
|
||||||
glEnable(glLight);
|
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, // Float1
|
||||||
GL_FLOAT, // Float2
|
GL_FLOAT, // Float2
|
||||||
|
@ -699,7 +710,7 @@ static GLenum GLComponentTypes[Mesh::FormatMax] =
|
||||||
GL_UNSIGNED_BYTE, // UByte4
|
GL_UNSIGNED_BYTE, // UByte4
|
||||||
};
|
};
|
||||||
|
|
||||||
static int GLComponentCounts[Mesh::FormatMax] =
|
static int GLComponentCounts[static_cast<std::size_t>(cmod::VertexAttributeFormat::FormatMax)] =
|
||||||
{
|
{
|
||||||
1, // Float1
|
1, // Float1
|
||||||
2, // Float2
|
2, // Float2
|
||||||
|
@ -710,16 +721,16 @@ static int GLComponentCounts[Mesh::FormatMax] =
|
||||||
|
|
||||||
|
|
||||||
static void
|
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 cmod::VertexAttribute& position = desc.getAttribute(cmod::VertexAttributeSemantic::Position);
|
||||||
const Mesh::VertexAttribute& normal = desc.getAttribute(Mesh::Normal);
|
const cmod::VertexAttribute& normal = desc.getAttribute(cmod::VertexAttributeSemantic::Normal);
|
||||||
const Mesh::VertexAttribute& color0 = desc.getAttribute(Mesh::Color0);
|
const cmod::VertexAttribute& color0 = desc.getAttribute(cmod::VertexAttributeSemantic::Color0);
|
||||||
const Mesh::VertexAttribute& texCoord0 = desc.getAttribute(Mesh::Texture0);
|
const cmod::VertexAttribute& texCoord0 = desc.getAttribute(cmod::VertexAttributeSemantic::Texture0);
|
||||||
const Mesh::VertexAttribute& tangent = desc.getAttribute(Mesh::Tangent);
|
const cmod::VertexAttribute& tangent = desc.getAttribute(cmod::VertexAttributeSemantic::Tangent);
|
||||||
|
|
||||||
// Can't render anything unless we have positions
|
// Can't render anything unless we have positions
|
||||||
if (position.format != Mesh::Float3)
|
if (position.format != cmod::VertexAttributeFormat::Float3)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Set up the vertex arrays
|
// Set up the vertex arrays
|
||||||
|
@ -730,9 +741,9 @@ setVertexArrays(const Mesh::VertexDescription& desc, const void* vertexData)
|
||||||
// Set up the normal array
|
// Set up the normal array
|
||||||
switch (normal.format)
|
switch (normal.format)
|
||||||
{
|
{
|
||||||
case Mesh::Float3:
|
case cmod::VertexAttributeFormat::Float3:
|
||||||
glEnableClientState(GL_NORMAL_ARRAY);
|
glEnableClientState(GL_NORMAL_ARRAY);
|
||||||
glNormalPointer(GLComponentTypes[(int) normal.format],
|
glNormalPointer(GLComponentTypes[static_cast<std::size_t>(normal.format)],
|
||||||
desc.stride,
|
desc.stride,
|
||||||
reinterpret_cast<const char*>(vertexData) + normal.offset);
|
reinterpret_cast<const char*>(vertexData) + normal.offset);
|
||||||
break;
|
break;
|
||||||
|
@ -744,12 +755,12 @@ setVertexArrays(const Mesh::VertexDescription& desc, const void* vertexData)
|
||||||
// Set up the color array
|
// Set up the color array
|
||||||
switch (color0.format)
|
switch (color0.format)
|
||||||
{
|
{
|
||||||
case Mesh::Float3:
|
case cmod::VertexAttributeFormat::Float3:
|
||||||
case Mesh::Float4:
|
case cmod::VertexAttributeFormat::Float4:
|
||||||
case Mesh::UByte4:
|
case cmod::VertexAttributeFormat::UByte4:
|
||||||
glEnableClientState(GL_COLOR_ARRAY);
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
glColorPointer(GLComponentCounts[color0.format],
|
glColorPointer(GLComponentCounts[static_cast<std::size_t>(color0.format)],
|
||||||
GLComponentTypes[color0.format],
|
GLComponentTypes[static_cast<std::size_t>(color0.format)],
|
||||||
desc.stride,
|
desc.stride,
|
||||||
reinterpret_cast<const char*>(vertexData) + color0.offset);
|
reinterpret_cast<const char*>(vertexData) + color0.offset);
|
||||||
break;
|
break;
|
||||||
|
@ -761,13 +772,13 @@ setVertexArrays(const Mesh::VertexDescription& desc, const void* vertexData)
|
||||||
// Set up the texture coordinate array
|
// Set up the texture coordinate array
|
||||||
switch (texCoord0.format)
|
switch (texCoord0.format)
|
||||||
{
|
{
|
||||||
case Mesh::Float1:
|
case cmod::VertexAttributeFormat::Float1:
|
||||||
case Mesh::Float2:
|
case cmod::VertexAttributeFormat::Float2:
|
||||||
case Mesh::Float3:
|
case cmod::VertexAttributeFormat::Float3:
|
||||||
case Mesh::Float4:
|
case cmod::VertexAttributeFormat::Float4:
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
glTexCoordPointer(GLComponentCounts[(int) texCoord0.format],
|
glTexCoordPointer(GLComponentCounts[static_cast<std::size_t>(texCoord0.format)],
|
||||||
GLComponentTypes[(int) texCoord0.format],
|
GLComponentTypes[static_cast<std::size_t>(texCoord0.format)],
|
||||||
desc.stride,
|
desc.stride,
|
||||||
reinterpret_cast<const char*>(vertexData) + texCoord0.offset);
|
reinterpret_cast<const char*>(vertexData) + texCoord0.offset);
|
||||||
break;
|
break;
|
||||||
|
@ -778,11 +789,11 @@ setVertexArrays(const Mesh::VertexDescription& desc, const void* vertexData)
|
||||||
|
|
||||||
switch (tangent.format)
|
switch (tangent.format)
|
||||||
{
|
{
|
||||||
case Mesh::Float3:
|
case cmod::VertexAttributeFormat::Float3:
|
||||||
glEnableVertexAttribArrayARB(TangentAttributeIndex);
|
glEnableVertexAttribArrayARB(TangentAttributeIndex);
|
||||||
glVertexAttribPointerARB(TangentAttributeIndex,
|
glVertexAttribPointerARB(TangentAttributeIndex,
|
||||||
GLComponentCounts[(int) tangent.format],
|
GLComponentCounts[static_cast<std::size_t>(tangent.format)],
|
||||||
GLComponentTypes[(int) tangent.format],
|
GLComponentTypes[static_cast<std::size_t>(tangent.format)],
|
||||||
GL_FALSE,
|
GL_FALSE,
|
||||||
desc.stride,
|
desc.stride,
|
||||||
reinterpret_cast<const char*>(vertexData) + tangent.offset);
|
reinterpret_cast<const char*>(vertexData) + tangent.offset);
|
||||||
|
@ -797,12 +808,12 @@ setVertexArrays(const Mesh::VertexDescription& desc, const void* vertexData)
|
||||||
|
|
||||||
// Set just the vertex pointer
|
// Set just the vertex pointer
|
||||||
void
|
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
|
// Can't render anything unless we have positions
|
||||||
if (position.format != Mesh::Float3)
|
if (position.format != cmod::VertexAttributeFormat::Float3)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Set up the vertex arrays
|
// Set up the vertex arrays
|
||||||
|
@ -818,21 +829,21 @@ setVertexPointer(const Mesh::VertexDescription& desc, const void* vertexData)
|
||||||
|
|
||||||
|
|
||||||
static GLenum
|
static GLenum
|
||||||
getGLMode(Mesh::PrimitiveGroupType primitive)
|
getGLMode(cmod::PrimitiveGroupType primitive)
|
||||||
{
|
{
|
||||||
switch (primitive)
|
switch (primitive)
|
||||||
{
|
{
|
||||||
case Mesh::TriList:
|
case cmod::PrimitiveGroupType::TriList:
|
||||||
return GL_TRIANGLES;
|
return GL_TRIANGLES;
|
||||||
case Mesh::TriStrip:
|
case cmod::PrimitiveGroupType::TriStrip:
|
||||||
return GL_TRIANGLE_STRIP;
|
return GL_TRIANGLE_STRIP;
|
||||||
case Mesh::TriFan:
|
case cmod::PrimitiveGroupType::TriFan:
|
||||||
return GL_TRIANGLE_FAN;
|
return GL_TRIANGLE_FAN;
|
||||||
case Mesh::LineList:
|
case cmod::PrimitiveGroupType::LineList:
|
||||||
return GL_LINES;
|
return GL_LINES;
|
||||||
case Mesh::LineStrip:
|
case cmod::PrimitiveGroupType::LineStrip:
|
||||||
return GL_LINE_STRIP;
|
return GL_LINE_STRIP;
|
||||||
case Mesh::PointList:
|
case cmod::PrimitiveGroupType::PointList:
|
||||||
return GL_POINTS;
|
return GL_POINTS;
|
||||||
default:
|
default:
|
||||||
return GL_POINTS;
|
return GL_POINTS;
|
||||||
|
@ -872,7 +883,7 @@ ModelViewWidget::setAmbientLight(bool enable)
|
||||||
void
|
void
|
||||||
ModelViewWidget::setShadows(bool enable)
|
ModelViewWidget::setShadows(bool enable)
|
||||||
{
|
{
|
||||||
if (!gl::EXT_framebuffer_object)
|
if (!celestia::gl::EXT_framebuffer_object)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -897,9 +908,9 @@ ModelViewWidget::setShadows(bool enable)
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ModelViewWidget::bindMaterial(const Material* material,
|
ModelViewWidget::bindMaterial(const cmod::Material* material,
|
||||||
const LightingEnvironment* lighting,
|
const LightingEnvironment* lighting,
|
||||||
const Mesh::VertexDescription* vertexDesc)
|
const cmod::VertexDescription* vertexDesc)
|
||||||
{
|
{
|
||||||
GLShaderProgram* shader = nullptr;
|
GLShaderProgram* shader = nullptr;
|
||||||
|
|
||||||
|
@ -930,15 +941,15 @@ ModelViewWidget::bindMaterial(const Material* material,
|
||||||
|
|
||||||
shader->setUniformValue("modelView", cameraTransform().matrix().cast<float>());
|
shader->setUniformValue("modelView", cameraTransform().matrix().cast<float>());
|
||||||
|
|
||||||
shader->setUniformValue("diffuseColor", Vector3f(material->diffuse.red(), material->diffuse.green(), material->diffuse.blue()));
|
shader->setUniformValue("diffuseColor", Eigen::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("specularColor", Eigen::Vector3f(material->specular.red(), material->specular.green(), material->specular.blue()));
|
||||||
shader->setUniformValue("opacity", material->opacity);
|
shader->setUniformValue("opacity", material->opacity);
|
||||||
shader->setUniformValue("specularPower", material->specularPower);
|
shader->setUniformValue("specularPower", material->specularPower);
|
||||||
|
|
||||||
if (shaderKey.hasDiffuseMap())
|
if (shaderKey.hasDiffuseMap())
|
||||||
{
|
{
|
||||||
GLuint diffuseMapId = m_materialLibrary->getTexture(
|
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);
|
glEnable(GL_TEXTURE_2D);
|
||||||
glBindTexture(GL_TEXTURE_2D, diffuseMapId);
|
glBindTexture(GL_TEXTURE_2D, diffuseMapId);
|
||||||
shader->setSampler("diffuseMap", 0);
|
shader->setSampler("diffuseMap", 0);
|
||||||
|
@ -947,7 +958,7 @@ ModelViewWidget::bindMaterial(const Material* material,
|
||||||
if (shaderKey.hasNormalMap())
|
if (shaderKey.hasNormalMap())
|
||||||
{
|
{
|
||||||
GLuint normalMapId = m_materialLibrary->getTexture(
|
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);
|
glActiveTexture(GL_TEXTURE1);
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
glBindTexture(GL_TEXTURE_2D, normalMapId);
|
glBindTexture(GL_TEXTURE_2D, normalMapId);
|
||||||
|
@ -958,7 +969,7 @@ ModelViewWidget::bindMaterial(const Material* material,
|
||||||
if (shaderKey.hasSpecularMap())
|
if (shaderKey.hasSpecularMap())
|
||||||
{
|
{
|
||||||
GLuint specularMapId = m_materialLibrary->getTexture(
|
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);
|
glActiveTexture(GL_TEXTURE2);
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
glBindTexture(GL_TEXTURE_2D, specularMapId);
|
glBindTexture(GL_TEXTURE_2D, specularMapId);
|
||||||
|
@ -969,7 +980,7 @@ ModelViewWidget::bindMaterial(const Material* material,
|
||||||
if (shaderKey.hasEmissiveMap())
|
if (shaderKey.hasEmissiveMap())
|
||||||
{
|
{
|
||||||
GLuint emissiveMapId = m_materialLibrary->getTexture(
|
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);
|
glActiveTexture(GL_TEXTURE3);
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
glBindTexture(GL_TEXTURE_2D, emissiveMapId);
|
glBindTexture(GL_TEXTURE_2D, emissiveMapId);
|
||||||
|
@ -978,15 +989,15 @@ ModelViewWidget::bindMaterial(const Material* material,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int lightIndex = 0;
|
unsigned int lightIndex = 0;
|
||||||
Matrix3d lightMatrix = m_lightOrientation.toRotationMatrix();
|
Eigen::Matrix3d lightMatrix = m_lightOrientation.toRotationMatrix();
|
||||||
|
|
||||||
Vector3f lightDirections[8];
|
Eigen::Vector3f lightDirections[8];
|
||||||
Vector3f lightColors[8];
|
Eigen::Vector3f lightColors[8];
|
||||||
|
|
||||||
foreach (LightSource lightSource, m_lightSources)
|
foreach (LightSource lightSource, m_lightSources)
|
||||||
{
|
{
|
||||||
Vector3d direction = lightMatrix * lightSource.direction;
|
Eigen::Vector3d direction = lightMatrix * lightSource.direction;
|
||||||
Vector3f color = lightSource.color * lightSource.intensity;
|
Eigen::Vector3f color = lightSource.color * lightSource.intensity;
|
||||||
|
|
||||||
lightDirections[lightIndex] = direction.cast<float>();
|
lightDirections[lightIndex] = direction.cast<float>();
|
||||||
lightColors[lightIndex] = color;
|
lightColors[lightIndex] = color;
|
||||||
|
@ -1005,10 +1016,10 @@ ModelViewWidget::bindMaterial(const Material* material,
|
||||||
{
|
{
|
||||||
ambientLightLevel = 0.2f;
|
ambientLightLevel = 0.2f;
|
||||||
}
|
}
|
||||||
shader->setUniformValue("ambientLightColor", Vector3f::Constant(ambientLightLevel));
|
shader->setUniformValue("ambientLightColor", Eigen::Vector3f::Constant(ambientLightLevel));
|
||||||
|
|
||||||
// Get the eye position in model space
|
// 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));
|
shader->setUniformValue("eyePosition", eyePosition.head(3));
|
||||||
|
|
||||||
// Set all shadow related values
|
// Set all shadow related values
|
||||||
|
@ -1030,15 +1041,15 @@ ModelViewWidget::bindMaterial(const Material* material,
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix4f shadowMatrixes[MaxShadows];
|
Eigen::Matrix4f shadowMatrixes[MaxShadows];
|
||||||
Matrix4f bias = Matrix4f::Zero();
|
Eigen::Matrix4f bias = Eigen::Matrix4f::Zero();
|
||||||
bias.diagonal() = Vector4f(0.5f, 0.5f, 0.5f, 1.0f);
|
bias.diagonal() = Eigen::Vector4f(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
bias.col(3) = 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)
|
for (unsigned int i = 0; i < shaderKey.shadowCount(); ++i)
|
||||||
{
|
{
|
||||||
Matrix4f modelView = directionalLightMatrix(lightDirections[i]);
|
Eigen::Matrix4f modelView = directionalLightMatrix(lightDirections[i]);
|
||||||
Matrix4f projection = shadowProjectionMatrix(m_modelBoundingRadius);
|
Eigen::Matrix4f projection = shadowProjectionMatrix(m_modelBoundingRadius);
|
||||||
shadowMatrixes[i] = bias * projection * modelView;
|
shadowMatrixes[i] = bias * projection * modelView;
|
||||||
|
|
||||||
// TESTING ONLY:
|
// TESTING ONLY:
|
||||||
|
@ -1056,9 +1067,9 @@ ModelViewWidget::bindMaterial(const Material* material,
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector4f diffuse(material->diffuse.red(), material->diffuse.green(), material->diffuse.blue(), material->opacity);
|
Eigen::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);
|
Eigen::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 emissive(material->emissive.red(), material->emissive.green(), material->emissive.blue(), 1.0f);
|
||||||
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse.data());
|
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse.data());
|
||||||
glMaterialfv(GL_FRONT, GL_AMBIENT, diffuse.data());
|
glMaterialfv(GL_FRONT, GL_AMBIENT, diffuse.data());
|
||||||
glColor4fv(diffuse.data());
|
glColor4fv(diffuse.data());
|
||||||
|
@ -1068,10 +1079,10 @@ ModelViewWidget::bindMaterial(const Material* material,
|
||||||
|
|
||||||
// Set up the diffuse (base) texture
|
// Set up the diffuse (base) texture
|
||||||
GLuint baseTexId = 0;
|
GLuint baseTexId = 0;
|
||||||
if (material->maps[Material::DiffuseMap] != InvalidResource)
|
if (material->getMap(cmod::TextureSemantic::DiffuseMap) != InvalidResource)
|
||||||
{
|
{
|
||||||
baseTexId = m_materialLibrary->getTexture(
|
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)
|
if (baseTexId != 0)
|
||||||
|
@ -1100,10 +1111,10 @@ ModelViewWidget::bindMaterial(const Material* material,
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ModelViewWidget::renderModel(Model* model)
|
ModelViewWidget::renderModel(cmod::Model* model)
|
||||||
{
|
{
|
||||||
Material defaultMaterial;
|
cmod::Material defaultMaterial;
|
||||||
defaultMaterial.diffuse = Material::Color(1.0f, 1.0f, 1.0f);
|
defaultMaterial.diffuse = cmod::Color(1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
if (m_renderStyle == WireFrameStyle)
|
if (m_renderStyle == WireFrameStyle)
|
||||||
|
@ -1138,10 +1149,10 @@ ModelViewWidget::renderModel(Model* model)
|
||||||
// Render all meshes
|
// Render all meshes
|
||||||
for (unsigned int meshIndex = 0; meshIndex < model->getMeshCount(); ++meshIndex)
|
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());
|
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);
|
setLighting(true);
|
||||||
}
|
}
|
||||||
|
@ -1152,8 +1163,8 @@ ModelViewWidget::renderModel(Model* model)
|
||||||
|
|
||||||
for (unsigned int groupIndex = 0; groupIndex < mesh->getGroupCount(); ++groupIndex)
|
for (unsigned int groupIndex = 0; groupIndex < mesh->getGroupCount(); ++groupIndex)
|
||||||
{
|
{
|
||||||
const Mesh::PrimitiveGroup* group = mesh->getGroup(groupIndex);
|
const cmod::PrimitiveGroup* group = mesh->getGroup(groupIndex);
|
||||||
const Material* material = &defaultMaterial;
|
const cmod::Material* material = &defaultMaterial;
|
||||||
if (group->materialIndex < model->getMaterialCount())
|
if (group->materialIndex < model->getMaterialCount())
|
||||||
{
|
{
|
||||||
material = model->getMaterial(group->materialIndex);
|
material = model->getMaterial(group->materialIndex);
|
||||||
|
@ -1178,7 +1189,7 @@ ModelViewWidget::renderModel(Model* model)
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ModelViewWidget::renderSelection(Model* model)
|
ModelViewWidget::renderSelection(cmod::Model* model)
|
||||||
{
|
{
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
glPolygonMode(GL_FRONT, GL_LINE);
|
glPolygonMode(GL_FRONT, GL_LINE);
|
||||||
|
@ -1191,8 +1202,8 @@ ModelViewWidget::renderSelection(Model* model)
|
||||||
|
|
||||||
if (renderPath() == OpenGL2Path)
|
if (renderPath() == OpenGL2Path)
|
||||||
{
|
{
|
||||||
Material selectionMaterial;
|
cmod::Material selectionMaterial;
|
||||||
selectionMaterial.diffuse = Material::Color(0.0f, 1.0f, 0.0f);
|
selectionMaterial.diffuse = cmod::Color(0.0f, 1.0f, 0.0f);
|
||||||
selectionMaterial.opacity = 0.5f;
|
selectionMaterial.opacity = 0.5f;
|
||||||
|
|
||||||
LightingEnvironment lightsOff;
|
LightingEnvironment lightsOff;
|
||||||
|
@ -1201,12 +1212,12 @@ ModelViewWidget::renderSelection(Model* model)
|
||||||
|
|
||||||
for (unsigned int meshIndex = 0; meshIndex < model->getMeshCount(); ++meshIndex)
|
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());
|
setVertexPointer(mesh->getVertexDescription(), mesh->getVertexData());
|
||||||
|
|
||||||
for (unsigned int groupIndex = 0; groupIndex < mesh->getGroupCount(); ++groupIndex)
|
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))
|
if (m_selection.contains(group))
|
||||||
{
|
{
|
||||||
GLenum primitiveMode = getGLMode(group->prim);
|
GLenum primitiveMode = getGLMode(group->prim);
|
||||||
|
@ -1223,18 +1234,18 @@ ModelViewWidget::renderSelection(Model* model)
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ModelViewWidget::renderDepthOnly(Model* model)
|
ModelViewWidget::renderDepthOnly(cmod::Model* model)
|
||||||
{
|
{
|
||||||
glDepthMask(GL_TRUE);
|
glDepthMask(GL_TRUE);
|
||||||
|
|
||||||
for (unsigned int meshIndex = 0; meshIndex < model->getMeshCount(); ++meshIndex)
|
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());
|
setVertexPointer(mesh->getVertexDescription(), mesh->getVertexData());
|
||||||
|
|
||||||
for (unsigned int groupIndex = 0; groupIndex < mesh->getGroupCount(); ++groupIndex)
|
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);
|
GLenum primitiveMode = getGLMode(group->prim);
|
||||||
glDrawElements(primitiveMode, group->nIndices, GL_UNSIGNED_INT, group->indices);
|
glDrawElements(primitiveMode, group->nIndices, GL_UNSIGNED_INT, group->indices);
|
||||||
}
|
}
|
||||||
|
@ -1248,14 +1259,14 @@ ModelViewWidget::setupDefaultLightSources()
|
||||||
m_lightSources.clear();
|
m_lightSources.clear();
|
||||||
|
|
||||||
LightSource light1;
|
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.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;
|
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.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;
|
m_lightSources << light1;// << light2;
|
||||||
}
|
}
|
||||||
|
@ -1559,7 +1570,7 @@ ModelViewWidget::renderShadow(unsigned int lightIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFrameBufferObject* shadowBuffer = m_shadowBuffers[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();
|
shadowBuffer->bind();
|
||||||
glViewport(0, 0, shadowBuffer->width(), shadowBuffer->height());
|
glViewport(0, 0, shadowBuffer->width(), shadowBuffer->height());
|
||||||
|
|
|
@ -8,20 +8,35 @@
|
||||||
// as published by the Free Software Foundation; either version 2
|
// as published by the Free Software Foundation; either version 2
|
||||||
// of the License, or (at your option) any later version.
|
// of the License, or (at your option) any later version.
|
||||||
|
|
||||||
#ifndef _CMODVIEW_MODEL_VIEW_WIDGET_H_
|
#pragma once
|
||||||
#define _CMODVIEW_MODEL_VIEW_WIDGET_H_
|
|
||||||
|
|
||||||
#include "glshader.h"
|
#include <QColor>
|
||||||
#include <QGLWidget>
|
#include <QGLWidget>
|
||||||
#include <QSet>
|
|
||||||
#include <QHash>
|
#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/Core>
|
||||||
#include <Eigen/Geometry>
|
#include <Eigen/Geometry>
|
||||||
|
|
||||||
|
#include <celmodel/material.h>
|
||||||
|
#include <celmodel/mesh.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace cmod
|
||||||
|
{
|
||||||
|
class Model;
|
||||||
|
}
|
||||||
|
|
||||||
class MaterialLibrary;
|
class MaterialLibrary;
|
||||||
class GLFrameBufferObject;
|
class GLFrameBufferObject;
|
||||||
|
class GLShaderProgram;
|
||||||
|
|
||||||
class LightingEnvironment
|
class LightingEnvironment
|
||||||
{
|
{
|
||||||
|
@ -51,7 +66,7 @@ public:
|
||||||
|
|
||||||
static ShaderKey Create(const cmod::Material* material,
|
static ShaderKey Create(const cmod::Material* material,
|
||||||
const LightingEnvironment* lighting,
|
const LightingEnvironment* lighting,
|
||||||
const cmod::Mesh::VertexDescription* vertexDesc);
|
const cmod::VertexDescription* vertexDesc);
|
||||||
|
|
||||||
unsigned int hash() const
|
unsigned int hash() const
|
||||||
{
|
{
|
||||||
|
@ -157,7 +172,7 @@ public:
|
||||||
void wheelEvent(QWheelEvent* event);
|
void wheelEvent(QWheelEvent* event);
|
||||||
|
|
||||||
void select(const Eigen::Vector2f& point);
|
void select(const Eigen::Vector2f& point);
|
||||||
QSet<cmod::Mesh::PrimitiveGroup*> selection()
|
QSet<cmod::PrimitiveGroup*> selection()
|
||||||
{
|
{
|
||||||
return m_selection;
|
return m_selection;
|
||||||
}
|
}
|
||||||
|
@ -217,7 +232,7 @@ private:
|
||||||
void renderShadow(unsigned int lightIndex);
|
void renderShadow(unsigned int lightIndex);
|
||||||
void bindMaterial(const cmod::Material* material,
|
void bindMaterial(const cmod::Material* material,
|
||||||
const LightingEnvironment* lighting,
|
const LightingEnvironment* lighting,
|
||||||
const cmod::Mesh::VertexDescription* vertexDesc);
|
const cmod::VertexDescription* vertexDesc);
|
||||||
|
|
||||||
void setupDefaultLightSources();
|
void setupDefaultLightSources();
|
||||||
GLShaderProgram* createShader(const ShaderKey& shaderKey);
|
GLShaderProgram* createShader(const ShaderKey& shaderKey);
|
||||||
|
@ -234,7 +249,7 @@ private:
|
||||||
|
|
||||||
MaterialLibrary* m_materialLibrary;
|
MaterialLibrary* m_materialLibrary;
|
||||||
|
|
||||||
QSet<cmod::Mesh::PrimitiveGroup*> m_selection;
|
QSet<cmod::PrimitiveGroup*> m_selection;
|
||||||
QHash<ShaderKey, GLShaderProgram*> m_shaderCache;
|
QHash<ShaderKey, GLShaderProgram*> m_shaderCache;
|
||||||
|
|
||||||
QColor m_backgroundColor;
|
QColor m_backgroundColor;
|
||||||
|
@ -247,5 +262,3 @@ private:
|
||||||
bool m_ambientLightEnabled;
|
bool m_ambientLightEnabled;
|
||||||
bool m_shadowsEnabled;
|
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.
|
// Perform various adjustments to a Celestia mesh.
|
||||||
|
|
||||||
#ifndef _CMODOPS_H_
|
#pragma once
|
||||||
#define _CMODOPS_H_
|
|
||||||
|
|
||||||
#include <celmodel/model.h>
|
#include <algorithm>
|
||||||
#include <Eigen/Core>
|
#include <cassert>
|
||||||
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <Eigen/Core>
|
||||||
|
|
||||||
|
#include <celmodel/mesh.h>
|
||||||
|
|
||||||
|
namespace cmod
|
||||||
|
{
|
||||||
|
class Model;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct Vertex
|
struct Vertex
|
||||||
{
|
{
|
||||||
Vertex() :
|
Vertex() :
|
||||||
index(0), attributes(nullptr) {};
|
index(0), attributes(nullptr) {};
|
||||||
|
|
||||||
Vertex(uint32_t _index, const void* _attributes) :
|
Vertex(std::uint32_t _index, const void* _attributes) :
|
||||||
index(_index), attributes(_attributes) {};
|
index(_index), attributes(_attributes) {};
|
||||||
|
|
||||||
uint32_t index;
|
std::uint32_t index;
|
||||||
const void* attributes;
|
const void* attributes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -33,8 +42,8 @@ struct Vertex
|
||||||
struct Face
|
struct Face
|
||||||
{
|
{
|
||||||
Eigen::Vector3f normal;
|
Eigen::Vector3f normal;
|
||||||
uint32_t i[3]; // vertex attribute indices
|
std::uint32_t i[3]; // vertex attribute indices
|
||||||
uint32_t vi[3]; // vertex point indices -- same as above unless welding
|
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
|
template<typename T, typename U> void
|
||||||
JoinVertices(std::vector<Face>& faces,
|
JoinVertices(std::vector<Face>& faces,
|
||||||
const void* vertexData,
|
const void* vertexData,
|
||||||
const cmod::Mesh::VertexDescription& desc,
|
const cmod::VertexDescription& desc,
|
||||||
const T& orderingPredicate,
|
const T& orderingPredicate,
|
||||||
const U& equivalencePredicate)
|
const U& equivalencePredicate)
|
||||||
{
|
{
|
||||||
|
@ -64,19 +73,18 @@ JoinVertices(std::vector<Face>& faces,
|
||||||
// Must have a position
|
// Must have a position
|
||||||
assert(desc.getAttribute(cmod::Mesh::Position).format == cmod::Mesh::Float3);
|
assert(desc.getAttribute(cmod::Mesh::Position).format == cmod::Mesh::Float3);
|
||||||
|
|
||||||
uint32_t posOffset = desc.getAttribute(cmod::Mesh::Position).offset;
|
std::uint32_t posOffset = desc.getAttribute(cmod::VertexAttributeSemantic::Position).offset;
|
||||||
const char* vertexPoints = reinterpret_cast<const char*>(vertexData) +
|
const char* vertexPoints = reinterpret_cast<const char*>(vertexData) + posOffset;
|
||||||
posOffset;
|
std::uint32_t nVertices = faces.size() * 3;
|
||||||
uint32_t nVertices = faces.size() * 3;
|
|
||||||
|
|
||||||
// Initialize the array of vertices
|
// Initialize the array of vertices
|
||||||
std::vector<Vertex> vertices(nVertices);
|
std::vector<Vertex> vertices(nVertices);
|
||||||
uint32_t f;
|
std::uint32_t f;
|
||||||
for (f = 0; f < faces.size(); 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,
|
vertices[f * 3 + j] = Vertex(index,
|
||||||
vertexPoints + desc.stride * 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 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
|
// Build the vertex merge map
|
||||||
std::vector<uint32_t> mergeMap(nVertices);
|
std::vector<std::uint32_t> mergeMap(nVertices);
|
||||||
uint32_t lastUnique = 0;
|
std::uint32_t lastUnique = 0;
|
||||||
uint32_t uniqueCount = 0;
|
std::uint32_t uniqueCount = 0;
|
||||||
for (uint32_t i = 0; i < nVertices; i++)
|
for (std::uint32_t i = 0; i < nVertices; i++)
|
||||||
{
|
{
|
||||||
if (i == 0 || !equivalencePredicate(vertices[i - 1], vertices[i]))
|
if (i == 0 || !equivalencePredicate(vertices[i - 1], vertices[i]))
|
||||||
{
|
{
|
||||||
|
@ -104,11 +112,9 @@ JoinVertices(std::vector<Face>& faces,
|
||||||
// Remap the vertex indices
|
// Remap the vertex indices
|
||||||
for (f = 0; f < faces.size(); f++)
|
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]];
|
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)
|
// Functions for converting a 3DS scene into a Celestia model (cmod)
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
#include <Eigen/Core>
|
#include <Eigen/Core>
|
||||||
|
|
||||||
|
#include <celmodel/material.h>
|
||||||
|
#include <celmodel/mesh.h>
|
||||||
|
|
||||||
#include "convert3ds.h"
|
#include "convert3ds.h"
|
||||||
#include "pathmanager.h"
|
|
||||||
|
|
||||||
|
namespace
|
||||||
using namespace cmod;
|
{
|
||||||
using namespace Eigen;
|
cmod::Material*
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
|
|
||||||
static Material*
|
|
||||||
convert3dsMaterial(const M3DMaterial* material3ds, cmod::HandleGetter& handleGetter)
|
convert3dsMaterial(const M3DMaterial* material3ds, cmod::HandleGetter& handleGetter)
|
||||||
{
|
{
|
||||||
Material* newMaterial = new Material();
|
cmod::Material* newMaterial = new cmod::Material();
|
||||||
|
|
||||||
M3DColor diffuse = material3ds->getDiffuseColor();
|
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();
|
newMaterial->opacity = material3ds->getOpacity();
|
||||||
|
|
||||||
M3DColor specular = material3ds->getSpecularColor();
|
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();
|
float shininess = material3ds->getShininess();
|
||||||
|
|
||||||
|
@ -38,25 +39,29 @@ convert3dsMaterial(const M3DMaterial* material3ds, cmod::HandleGetter& handleGet
|
||||||
// range that OpenGL uses for the specular exponent. The
|
// range that OpenGL uses for the specular exponent. The
|
||||||
// current equation is just a guess at the mapping that
|
// current equation is just a guess at the mapping that
|
||||||
// 3DS actually uses.
|
// 3DS actually uses.
|
||||||
newMaterial->specularPower = (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)
|
if (newMaterial->specularPower > 128.0f)
|
||||||
newMaterial->specularPower = 128.0f;
|
newMaterial->specularPower = 128.0f;
|
||||||
|
|
||||||
if (!material3ds->getTextureMap().empty())
|
if (!material3ds->getTextureMap().empty())
|
||||||
{
|
{
|
||||||
newMaterial->maps[Material::DiffuseMap] = handleGetter(material3ds->getTextureMap());
|
newMaterial->setMap(cmod::TextureSemantic::DiffuseMap, handleGetter(material3ds->getTextureMap()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return newMaterial;
|
return newMaterial;
|
||||||
}
|
}
|
||||||
|
} // end unnamed namespace
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Convert3DSMesh(Model& model,
|
Convert3DSMesh(cmod::Model& model,
|
||||||
const M3DTriangleMesh& mesh3ds,
|
const M3DTriangleMesh& mesh3ds,
|
||||||
const M3DScene& scene,
|
const M3DScene& scene,
|
||||||
const string& meshName)
|
const std::string& meshName)
|
||||||
{
|
{
|
||||||
int nVertices = mesh3ds.getVertexCount();
|
int nVertices = mesh3ds.getVertexCount();
|
||||||
int nTexCoords = mesh3ds.getTexCoordCount();
|
int nTexCoords = mesh3ds.getTexCoordCount();
|
||||||
|
@ -73,38 +78,42 @@ Convert3DSMesh(Model& model,
|
||||||
for (int i = 0; i < mesh3ds.getVertexCount(); ++i)
|
for (int i = 0; i < mesh3ds.getVertexCount(); ++i)
|
||||||
{
|
{
|
||||||
int k = i * vertexSize;
|
int k = i * vertexSize;
|
||||||
Vector3f pos = mesh3ds.getVertex(i);
|
Eigen::Vector3f pos = mesh3ds.getVertex(i);
|
||||||
vertices[k + 0] = pos.x();
|
vertices[k + 0] = pos.x();
|
||||||
vertices[k + 1] = pos.y();
|
vertices[k + 1] = pos.y();
|
||||||
vertices[k + 2] = pos.z();
|
vertices[k + 2] = pos.z();
|
||||||
|
|
||||||
if (hasTexCoords)
|
if (hasTexCoords)
|
||||||
{
|
{
|
||||||
Vector2f texCoord = mesh3ds.getTexCoord(i);
|
Eigen::Vector2f texCoord = mesh3ds.getTexCoord(i);
|
||||||
vertices[k + 3] = texCoord.x();
|
vertices[k + 3] = texCoord.x();
|
||||||
vertices[k + 4] = texCoord.y();
|
vertices[k + 4] = texCoord.y();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh::VertexAttribute attributes[8];
|
cmod::VertexAttribute attributes[8];
|
||||||
uint32_t nAttributes = 0;
|
std::uint32_t nAttributes = 0;
|
||||||
uint32_t offset = 0;
|
std::uint32_t offset = 0;
|
||||||
|
|
||||||
// Position attribute is always present
|
// 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++;
|
nAttributes++;
|
||||||
offset += 12;
|
offset += 12;
|
||||||
|
|
||||||
if (hasTexCoords)
|
if (hasTexCoords)
|
||||||
{
|
{
|
||||||
attributes[nAttributes] = Mesh::VertexAttribute(Mesh::Texture0, Mesh::Float2, offset);
|
attributes[nAttributes] = cmod::VertexAttribute(cmod::VertexAttributeSemantic::Texture0,
|
||||||
|
cmod::VertexAttributeFormat::Float2,
|
||||||
|
offset);
|
||||||
nAttributes++;
|
nAttributes++;
|
||||||
offset += 8;
|
offset += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the Celestia mesh
|
// Create the Celestia mesh
|
||||||
Mesh* mesh = new Mesh();
|
cmod::Mesh* mesh = new cmod::Mesh();
|
||||||
mesh->setVertexDescription(Mesh::VertexDescription(offset, nAttributes, attributes));
|
mesh->setVertexDescription(cmod::VertexDescription(offset, nAttributes, attributes));
|
||||||
mesh->setVertices(nVertices, vertices);
|
mesh->setVertices(nVertices, vertices);
|
||||||
|
|
||||||
mesh->setName(meshName);
|
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
|
// No material groups in the 3DS file. This is allowed. We'll create a single
|
||||||
// primitive group with the default material.
|
// primitive group with the default material.
|
||||||
unsigned int faceCount = mesh3ds.getFaceCount();
|
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++)
|
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);
|
mesh3ds.getFace(i, v0, v1, v2);
|
||||||
indices[i * 3 + 0] = v0;
|
indices[i * 3 + 0] = v0;
|
||||||
indices[i * 3 + 1] = v1;
|
indices[i * 3 + 1] = v1;
|
||||||
indices[i * 3 + 2] = v2;
|
indices[i * 3 + 2] = v2;
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh->addGroup(Mesh::TriList, ~0, faceCount * 3, indices);
|
mesh->addGroup(cmod::PrimitiveGroupType::TriList, ~0, faceCount * 3, indices);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We have at least one material group. Create a cmod primitive group for
|
// We have at least one material group. Create a cmod primitive group for
|
||||||
// each material group in th 3ds mesh.
|
// 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);
|
const M3DMeshMaterialGroup* matGroup = mesh3ds.getMeshMaterialGroup(groupIndex);
|
||||||
|
|
||||||
uint32_t nMatGroupFaces = matGroup->faces.size();
|
std::uint32_t nMatGroupFaces = matGroup->faces.size();
|
||||||
auto* indices = new uint32_t[nMatGroupFaces * 3];
|
auto* indices = new std::uint32_t[nMatGroupFaces * 3];
|
||||||
|
|
||||||
for (unsigned int i = 0; i < nMatGroupFaces; i++)
|
for (unsigned int i = 0; i < nMatGroupFaces; i++)
|
||||||
{
|
{
|
||||||
uint16_t v0 = 0, v1 = 0, v2 = 0;
|
std::uint16_t v0 = 0, v1 = 0, v2 = 0;
|
||||||
uint16_t faceIndex = matGroup->faces[i];
|
std::uint16_t faceIndex = matGroup->faces[i];
|
||||||
mesh3ds.getFace(faceIndex, v0, v1, v2);
|
mesh3ds.getFace(faceIndex, v0, v1, v2);
|
||||||
indices[i * 3 + 0] = v0;
|
indices[i * 3 + 0] = v0;
|
||||||
indices[i * 3 + 1] = v1;
|
indices[i * 3 + 1] = v1;
|
||||||
|
@ -150,7 +159,7 @@ Convert3DSMesh(Model& model,
|
||||||
|
|
||||||
// Get the material index
|
// Get the material index
|
||||||
unsigned int materialIndex = ~0u;
|
unsigned int materialIndex = ~0u;
|
||||||
string material3dsName = matGroup->materialName;
|
std::string material3dsName = matGroup->materialName;
|
||||||
if (!material3dsName.empty())
|
if (!material3dsName.empty())
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < scene.getMaterialCount(); i++)
|
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)
|
Convert3DSModel(const M3DScene& scene, cmod::HandleGetter handleGetter)
|
||||||
{
|
{
|
||||||
Model* model = new Model();
|
cmod::Model* model = new cmod::Model();
|
||||||
|
|
||||||
// Convert materials
|
// Convert materials
|
||||||
for (unsigned int i = 0; i < scene.getMaterialCount(); i++)
|
for (unsigned int i = 0; i < scene.getMaterialCount(); i++)
|
||||||
|
|
|
@ -9,12 +9,14 @@
|
||||||
//
|
//
|
||||||
// Functions for converting a 3DS scene into a Celestia model (cmod)
|
// Functions for converting a 3DS scene into a Celestia model (cmod)
|
||||||
|
|
||||||
#ifndef _CONVERT3DS_H_
|
#pragma once
|
||||||
#define _CONVERT3DS_H_
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <cel3ds/3dsmodel.h>
|
||||||
#include <celmodel/model.h>
|
#include <celmodel/model.h>
|
||||||
#include <celmodel/modelfile.h>
|
#include <celmodel/modelfile.h>
|
||||||
#include <cel3ds/3dsmodel.h>
|
|
||||||
|
|
||||||
extern void Convert3DSMesh(cmod::Model& model,
|
extern void Convert3DSMesh(cmod::Model& model,
|
||||||
M3DTriangleMesh& mesh3ds,
|
M3DTriangleMesh& mesh3ds,
|
||||||
|
@ -22,5 +24,3 @@ extern void Convert3DSMesh(cmod::Model& model,
|
||||||
const std::string& meshName);
|
const std::string& meshName);
|
||||||
extern cmod::Model* Convert3DSModel(const M3DScene& scene,
|
extern cmod::Model* Convert3DSModel(const M3DScene& scene,
|
||||||
cmod::HandleGetter handleGetter);
|
cmod::HandleGetter handleGetter);
|
||||||
|
|
||||||
#endif // _CONVERT3DS_H_
|
|
||||||
|
|
|
@ -10,28 +10,22 @@
|
||||||
// Functions for converting a Wavefront .obj file into a
|
// Functions for converting a Wavefront .obj file into a
|
||||||
// Celestia model (cmod)
|
// Celestia model (cmod)
|
||||||
|
|
||||||
#include "convertobj.h"
|
|
||||||
#include <algorithm>
|
|
||||||
#include <sstream>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
using namespace cmod;
|
#include <celmodel/material.h>
|
||||||
using namespace Eigen;
|
#include <celmodel/mesh.h>
|
||||||
using namespace std;
|
#include <celmodel/model.h>
|
||||||
|
|
||||||
|
#include "convertobj.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
WavefrontLoader::WavefrontLoader(istream& in) :
|
|
||||||
m_in(in),
|
|
||||||
m_lineNumber(0),
|
|
||||||
m_model(nullptr)
|
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
|
std::string::size_type getToken(const std::string& s, std::string::size_type start, std::string& token)
|
||||||
string::size_type getToken(const string& s, string::size_type start, string& token)
|
|
||||||
{
|
{
|
||||||
string::size_type pos = start;
|
std::string::size_type pos = start;
|
||||||
token.clear();
|
token.clear();
|
||||||
|
|
||||||
while (pos < s.size() && isspace(s[pos]))
|
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;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Convert a 1-based array index to a zero based index. Negative
|
// 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
|
// indices are relative to the top of the end of the array. Return
|
||||||
// -1 if the index is invalid.
|
// -1 if the index is invalid.
|
||||||
|
@ -56,51 +49,65 @@ int convertIndex(int index, unsigned int maxValue)
|
||||||
{
|
{
|
||||||
if (index > 0)
|
if (index > 0)
|
||||||
{
|
{
|
||||||
if (index <= (int) maxValue)
|
if (index <= static_cast<int>(maxValue))
|
||||||
return index - 1;
|
return index - 1;
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
{
|
{
|
||||||
if (-index <= (int) maxValue)
|
if (-index <= static_cast<int>(maxValue))
|
||||||
return (int) maxValue + index;
|
return static_cast<int>(maxValue) + index;
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // end unnamed namespace
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
WavefrontLoader::WavefrontLoader(std::istream& in) :
|
||||||
|
m_in(in),
|
||||||
|
m_lineNumber(0),
|
||||||
|
m_model(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cmod::Model*
|
cmod::Model*
|
||||||
WavefrontLoader::load()
|
WavefrontLoader::load()
|
||||||
{
|
{
|
||||||
string line;
|
std::string line;
|
||||||
string keyword;
|
std::string keyword;
|
||||||
unsigned int vertexCount = 0;
|
unsigned int vertexCount = 0;
|
||||||
ObjVertex::VertexType lastVertexType = ObjVertex::Point;
|
ObjVertex::VertexType lastVertexType = ObjVertex::Point;
|
||||||
int currentMaterialIndex = -1;
|
int currentMaterialIndex = -1;
|
||||||
|
|
||||||
m_model = new Model();
|
m_model = new cmod::Model();
|
||||||
|
|
||||||
while (getline(m_in, line))
|
while (getline(m_in, line))
|
||||||
{
|
{
|
||||||
m_lineNumber++;
|
m_lineNumber++;
|
||||||
|
|
||||||
// strip comments
|
// strip comments
|
||||||
string::size_type commentPos = line.find('#');
|
std::string::size_type commentPos = line.find('#');
|
||||||
if (commentPos != string::npos)
|
if (commentPos != std::string::npos)
|
||||||
{
|
{
|
||||||
line = line.substr(0, commentPos);
|
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.empty())
|
||||||
{
|
{
|
||||||
if (keyword == "v")
|
if (keyword == "v")
|
||||||
{
|
{
|
||||||
Vector3f v(Vector3f::Zero());
|
Eigen::Vector3f v(Eigen::Vector3f::Zero());
|
||||||
if (sscanf(line.c_str() + pos, "%f %f %f", &v.x(), &v.y(), &v.z()) != 3)
|
if (std::sscanf(line.c_str() + pos, "%f %f %f", &v.x(), &v.y(), &v.z()) != 3)
|
||||||
{
|
{
|
||||||
reportError("Bad vertex");
|
reportError("Bad vertex");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -109,8 +116,8 @@ WavefrontLoader::load()
|
||||||
}
|
}
|
||||||
else if (keyword == "vn")
|
else if (keyword == "vn")
|
||||||
{
|
{
|
||||||
Vector3f v(Vector3f::Zero());
|
Eigen::Vector3f v(Eigen::Vector3f::Zero());
|
||||||
if (sscanf(line.c_str() + pos, "%f %f %f", &v.x(), &v.y(), &v.z()) != 3)
|
if (std::sscanf(line.c_str() + pos, "%f %f %f", &v.x(), &v.y(), &v.z()) != 3)
|
||||||
{
|
{
|
||||||
reportError("Bad normal");
|
reportError("Bad normal");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -119,8 +126,8 @@ WavefrontLoader::load()
|
||||||
}
|
}
|
||||||
else if (keyword == "vt")
|
else if (keyword == "vt")
|
||||||
{
|
{
|
||||||
Vector2f v(Vector2f::Zero());
|
Eigen::Vector2f v(Eigen::Vector2f::Zero());
|
||||||
if (sscanf(line.c_str() + pos, "%f %f", &v.x(), &v.y()) != 2)
|
if (std::sscanf(line.c_str() + pos, "%f %f", &v.x(), &v.y()) != 2)
|
||||||
{
|
{
|
||||||
reportError("Bad texture coordinate");
|
reportError("Bad texture coordinate");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -129,8 +136,8 @@ WavefrontLoader::load()
|
||||||
}
|
}
|
||||||
else if (keyword == "usemtl")
|
else if (keyword == "usemtl")
|
||||||
{
|
{
|
||||||
Material* material = new Material();
|
cmod::Material* material = new cmod::Material();
|
||||||
material->diffuse = Material::Color(1.0f, 1.0f, 1.0f);
|
material->diffuse = cmod::Color(1.0f, 1.0f, 1.0f);
|
||||||
currentMaterialIndex = m_model->addMaterial(material) - 1;
|
currentMaterialIndex = m_model->addMaterial(material) - 1;
|
||||||
if (!m_materialGroups.empty())
|
if (!m_materialGroups.empty())
|
||||||
{
|
{
|
||||||
|
@ -149,27 +156,27 @@ WavefrontLoader::load()
|
||||||
}
|
}
|
||||||
else if (keyword == "f")
|
else if (keyword == "f")
|
||||||
{
|
{
|
||||||
vector<ObjVertex> faceVertices;
|
std::vector<ObjVertex> faceVertices;
|
||||||
while (pos < line.size())
|
while (pos < line.size())
|
||||||
{
|
{
|
||||||
string vertexString;
|
std::string vertexString;
|
||||||
pos = getToken(line, pos, vertexString);
|
pos = getToken(line, pos, vertexString);
|
||||||
if (!vertexString.empty())
|
if (!vertexString.empty())
|
||||||
{
|
{
|
||||||
ObjVertex vertex;
|
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
|
// 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
|
// 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
|
// 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
|
// Vertex only
|
||||||
}
|
}
|
||||||
|
@ -292,10 +299,10 @@ WavefrontLoader::load()
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
WavefrontLoader::reportError(const string& message)
|
WavefrontLoader::reportError(const std::string& message)
|
||||||
{
|
{
|
||||||
//cerr << message << endl;
|
//cerr << message << endl;
|
||||||
ostringstream os;
|
std::ostringstream os;
|
||||||
os << "Line " << m_lineNumber << ": " << message;
|
os << "Line " << m_lineNumber << ": " << message;
|
||||||
m_errorMessage = os.str();
|
m_errorMessage = os.str();
|
||||||
|
|
||||||
|
@ -324,25 +331,31 @@ WavefrontLoader::addVertexData(const Eigen::Vector3f& v)
|
||||||
void
|
void
|
||||||
WavefrontLoader::createMesh(ObjVertex::VertexType vertexType, unsigned int vertexCount)
|
WavefrontLoader::createMesh(ObjVertex::VertexType vertexType, unsigned int vertexCount)
|
||||||
{
|
{
|
||||||
Mesh::VertexAttribute attributes[8];
|
cmod::VertexAttribute attributes[8];
|
||||||
unsigned int nAttributes = 0;
|
unsigned int nAttributes = 0;
|
||||||
unsigned int offset = 0;
|
unsigned int offset = 0;
|
||||||
|
|
||||||
// Position attribute is always present
|
// 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++;
|
nAttributes++;
|
||||||
offset += 12;
|
offset += 12;
|
||||||
|
|
||||||
if (vertexType == ObjVertex::PointNormal || vertexType == ObjVertex::PointTexNormal)
|
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++;
|
nAttributes++;
|
||||||
offset += 12;
|
offset += 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vertexType == ObjVertex::PointTex || vertexType == ObjVertex::PointTexNormal)
|
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++;
|
nAttributes++;
|
||||||
offset += 8;
|
offset += 8;
|
||||||
}
|
}
|
||||||
|
@ -351,8 +364,8 @@ WavefrontLoader::createMesh(ObjVertex::VertexType vertexType, unsigned int verte
|
||||||
copy(m_vertexData.begin(), m_vertexData.end(), vertexDataCopy);
|
copy(m_vertexData.begin(), m_vertexData.end(), vertexDataCopy);
|
||||||
|
|
||||||
// Create the Celestia mesh
|
// Create the Celestia mesh
|
||||||
Mesh* mesh = new Mesh();
|
cmod::Mesh* mesh = new cmod::Mesh();
|
||||||
mesh->setVertexDescription(Mesh::VertexDescription(offset, nAttributes, attributes));
|
mesh->setVertexDescription(cmod::VertexDescription(offset, nAttributes, attributes));
|
||||||
mesh->setVertices(vertexCount, vertexDataCopy);
|
mesh->setVertices(vertexCount, vertexDataCopy);
|
||||||
|
|
||||||
// Add primitive groups
|
// Add primitive groups
|
||||||
|
@ -371,9 +384,9 @@ WavefrontLoader::createMesh(ObjVertex::VertexType vertexType, unsigned int verte
|
||||||
|
|
||||||
if (indexCount > 0)
|
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);
|
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
|
// Functions for converting a Wavefront .obj file into a
|
||||||
// Celestia model (cmod)
|
// Celestia model (cmod)
|
||||||
|
|
||||||
#ifndef _CMOD_CONVERTOBJ_H_
|
#pragma once
|
||||||
#define _CMOD_CONVERTOBJ_H_
|
|
||||||
|
|
||||||
#include <celmodel/model.h>
|
#include <iosfwd>
|
||||||
#include <Eigen/Core>
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <Eigen/Core>
|
||||||
|
|
||||||
|
namespace cmod
|
||||||
|
{
|
||||||
|
class Model;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class WavefrontLoader
|
class WavefrontLoader
|
||||||
|
@ -93,12 +97,10 @@ private:
|
||||||
std::vector<Eigen::Vector2f> m_texCoords;
|
std::vector<Eigen::Vector2f> m_texCoords;
|
||||||
|
|
||||||
std::vector<float> m_vertexData;
|
std::vector<float> m_vertexData;
|
||||||
std::vector<cmod::Mesh::index32> m_indexData;
|
std::vector<cmod::index32> m_indexData;
|
||||||
std::vector<MaterialGroup> m_materialGroups;
|
std::vector<MaterialGroup> m_materialGroups;
|
||||||
|
|
||||||
cmod::Model* m_model;
|
cmod::Model* m_model;
|
||||||
|
|
||||||
std::string m_errorMessage;
|
std::string m_errorMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _CMOD_CONVERTOBJ_H_
|
|
||||||
|
|
Loading…
Reference in New Issue