Merge remote-tracking branch 'upstream/master' into feat/mocha-tests

This commit is contained in:
Par Winzell 2018-12-19 09:31:08 -08:00
commit f94b3650f2
67 changed files with 5426 additions and 5249 deletions

View File

@ -35,7 +35,7 @@ BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false BreakConstructorInitializersBeforeComma: false
BreakAfterJavaFieldAnnotations: false BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false BreakStringLiterals: false
ColumnLimit: 80 ColumnLimit: 100
CommentPragmas: '^ IWYU pragma:' CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4 ConstructorInitializerIndentWidth: 4

View File

@ -35,8 +35,7 @@ int main(int argc, char* argv[]) {
CLI::App app{ CLI::App app{
fmt::sprintf( fmt::sprintf(
"FBX2glTF %s: Generate a glTF 2.0 representation of an FBX model.", "FBX2glTF %s: Generate a glTF 2.0 representation of an FBX model.", FBX2GLTF_VERSION),
FBX2GLTF_VERSION),
"FBX2glTF"}; "FBX2glTF"};
app.add_flag( app.add_flag(
@ -45,32 +44,22 @@ int main(int argc, char* argv[]) {
"Include blend shape tangents, if reported present by the FBX SDK."); "Include blend shape tangents, if reported present by the FBX SDK.");
app.add_flag_function("-V,--version", [&](size_t count) { app.add_flag_function("-V,--version", [&](size_t count) {
fmt::printf( fmt::printf("FBX2glTF version %s\nCopyright (c) 2016-2018 Oculus VR, LLC.\n", FBX2GLTF_VERSION);
"FBX2glTF version %s\nCopyright (c) 2016-2018 Oculus VR, LLC.\n",
FBX2GLTF_VERSION);
exit(0); exit(0);
}); });
std::string inputPath; std::string inputPath;
app.add_option("FBX Model", inputPath, "The FBX model to convert.") app.add_option("FBX Model", inputPath, "The FBX model to convert.")->check(CLI::ExistingFile);
->check(CLI::ExistingFile); app.add_option("-i,--input", inputPath, "The FBX model to convert.")->check(CLI::ExistingFile);
app.add_option("-i,--input", inputPath, "The FBX model to convert.")
->check(CLI::ExistingFile);
std::string outputPath; std::string outputPath;
app.add_option( app.add_option("-o,--output", outputPath, "Where to generate the output, without suffix.");
"-o,--output",
outputPath,
"Where to generate the output, without suffix.");
app.add_flag( app.add_flag(
"-e,--embed", "-e,--embed",
gltfOptions.embedResources, gltfOptions.embedResources,
"Inline buffers as data:// URIs within generated non-binary glTF."); "Inline buffers as data:// URIs within generated non-binary glTF.");
app.add_flag( app.add_flag("-b,--binary", gltfOptions.outputBinary, "Output a single binary format .glb file.");
"-b,--binary",
gltfOptions.outputBinary,
"Output a single binary format .glb file.");
app.add_option( app.add_option(
"--long-indices", "--long-indices",
@ -119,8 +108,7 @@ int main(int argc, char* argv[]) {
"--flip-u", "--flip-u",
[&](size_t count) { [&](size_t count) {
if (count > 0) { if (count > 0) {
texturesTransforms.emplace_back( texturesTransforms.emplace_back([](Vec2f uv) { return Vec2f(1.0f - uv[0], uv[1]); });
[](Vec2f uv) { return Vec2f(1.0f - uv[0], uv[1]); });
if (verboseOutput) { if (verboseOutput) {
fmt::printf("Flipping texture coordinates in the 'U' dimension.\n"); fmt::printf("Flipping texture coordinates in the 'U' dimension.\n");
} }
@ -128,23 +116,20 @@ int main(int argc, char* argv[]) {
}, },
"Flip all U texture coordinates."); "Flip all U texture coordinates.");
app.add_flag("--no-flip-u", "Don't flip U texture coordinates.") app.add_flag("--no-flip-u", "Don't flip U texture coordinates.")->excludes("--flip-u");
->excludes("--flip-u");
app.add_flag_function( app.add_flag_function(
"--no-flip-v", "--no-flip-v",
[&](size_t count) { [&](size_t count) {
if (count > 0) { if (count > 0) {
texturesTransforms.emplace_back( texturesTransforms.emplace_back([](Vec2f uv) { return Vec2f(uv[0], 1.0f - uv[1]); });
[](Vec2f uv) { return Vec2f(uv[0], 1.0f - uv[1]); });
if (verboseOutput) { if (verboseOutput) {
fmt::printf("NOT flipping texture coordinates in the 'V' dimension.\n"); fmt::printf("NOT flipping texture coordinates in the 'V' dimension.\n");
} }
} }
}, },
"Flip all V texture coordinates."); "Flip all V texture coordinates.");
app.add_flag("--flip-v", "Don't flip U texture coordinates.") app.add_flag("--flip-v", "Don't flip U texture coordinates.")->excludes("--no-flip-v");
->excludes("--no-flip-v");
app.add_flag( app.add_flag(
"--pbr-metallic-rougnness", "--pbr-metallic-rougnness",
@ -181,8 +166,8 @@ int main(int argc, char* argv[]) {
app.add_option( app.add_option(
"-k,--keep-attribute", "-k,--keep-attribute",
[&](std::vector<std::string> attributes) -> bool { [&](std::vector<std::string> attributes) -> bool {
gltfOptions.keepAttribs = RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | gltfOptions.keepAttribs =
RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS; RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS;
for (std::string attribute : attributes) { for (std::string attribute : attributes) {
if (attribute == "position") { if (attribute == "position") {
gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_POSITION; gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_POSITION;
@ -212,9 +197,7 @@ int main(int argc, char* argv[]) {
->type_name("(position|normal|tangent|binormial|color|uv0|uv1|auto)"); ->type_name("(position|normal|tangent|binormial|color|uv0|uv1|auto)");
app.add_flag( app.add_flag(
"-d,--draco", "-d,--draco", gltfOptions.draco.enabled, "Apply Draco mesh compression to geometries.")
gltfOptions.draco.enabled,
"Apply Draco mesh compression to geometries.")
->group("Draco"); ->group("Draco");
app.add_option( app.add_option(
@ -301,16 +284,12 @@ int main(int argc, char* argv[]) {
} else { } else {
// in gltf mode, we create a folder and write into that // in gltf mode, we create a folder and write into that
outputFolder = fmt::format( outputFolder =
"{}_out{}", fmt::format("{}_out{}", outputPath.c_str(), (const char)StringUtils::GetPathSeparator());
outputPath.c_str(), modelPath = outputFolder + StringUtils::GetFileNameString(outputPath) + ".gltf";
(const char)StringUtils::GetPathSeparator());
modelPath =
outputFolder + StringUtils::GetFileNameString(outputPath) + ".gltf";
} }
if (!FileUtils::CreatePath(modelPath.c_str())) { if (!FileUtils::CreatePath(modelPath.c_str())) {
fmt::fprintf( fmt::fprintf(stderr, "ERROR: Failed to create folder: %s'\n", outputFolder.c_str());
stderr, "ERROR: Failed to create folder: %s'\n", outputFolder.c_str());
return 1; return 1;
} }
@ -334,14 +313,9 @@ int main(int argc, char* argv[]) {
std::ofstream outStream; // note: auto-flushes in destructor std::ofstream outStream; // note: auto-flushes in destructor
const auto streamStart = outStream.tellp(); const auto streamStart = outStream.tellp();
outStream.open( outStream.open(modelPath, std::ios::trunc | std::ios::ate | std::ios::out | std::ios::binary);
modelPath,
std::ios::trunc | std::ios::ate | std::ios::out | std::ios::binary);
if (outStream.fail()) { if (outStream.fail()) {
fmt::fprintf( fmt::fprintf(stderr, "ERROR:: Couldn't open file for writing: %s\n", modelPath.c_str());
stderr,
"ERROR:: Couldn't open file for writing: %s\n",
modelPath.c_str());
return 1; return 1;
} }
data_render_model = Raw2Gltf(outStream, outputFolder, raw, gltfOptions); data_render_model = Raw2Gltf(outStream, outputFolder, raw, gltfOptions);
@ -371,8 +345,7 @@ int main(int argc, char* argv[]) {
const std::string binaryPath = outputFolder + extBufferFilename; const std::string binaryPath = outputFolder + extBufferFilename;
FILE* fp = fopen(binaryPath.c_str(), "wb"); FILE* fp = fopen(binaryPath.c_str(), "wb");
if (fp == nullptr) { if (fp == nullptr) {
fmt::fprintf( fmt::fprintf(stderr, "ERROR:: Couldn't open file '%s' for writing.\n", binaryPath);
stderr, "ERROR:: Couldn't open file '%s' for writing.\n", binaryPath);
return 1; return 1;
} }
@ -381,16 +354,12 @@ int main(int argc, char* argv[]) {
unsigned long binarySize = data_render_model->binary->size(); unsigned long binarySize = data_render_model->binary->size();
if (fwrite(binaryData, binarySize, 1, fp) != 1) { if (fwrite(binaryData, binarySize, 1, fp) != 1) {
fmt::fprintf( fmt::fprintf(
stderr, stderr, "ERROR: Failed to write %lu bytes to file '%s'.\n", binarySize, binaryPath);
"ERROR: Failed to write %lu bytes to file '%s'.\n",
binarySize,
binaryPath);
fclose(fp); fclose(fp);
return 1; return 1;
} }
fclose(fp); fclose(fp);
fmt::printf( fmt::printf("Wrote %lu bytes of binary data to %s.\n", binarySize, binaryPath);
"Wrote %lu bytes of binary data to %s.\n", binarySize, binaryPath);
} }
delete data_render_model; delete data_render_model;

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,6 @@
#include "raw/RawModel.hpp" #include "raw/RawModel.hpp"
bool LoadFBXFile(RawModel &raw, const char *fbxFileName, const char *textureExtensions); bool LoadFBXFile(RawModel& raw, const char* fbxFileName, const char* textureExtensions);
json TranscribeProperty(FbxProperty &prop); json TranscribeProperty(FbxProperty& prop);

View File

@ -9,55 +9,63 @@
#include "FbxBlendShapesAccess.hpp" #include "FbxBlendShapesAccess.hpp"
FbxBlendShapesAccess::TargetShape::TargetShape(const FbxShape *shape, FbxDouble fullWeight) : FbxBlendShapesAccess::TargetShape::TargetShape(const FbxShape* shape, FbxDouble fullWeight)
shape(shape), : shape(shape),
fullWeight(fullWeight), fullWeight(fullWeight),
count(shape->GetControlPointsCount()), count(shape->GetControlPointsCount()),
positions(shape->GetControlPoints()), positions(shape->GetControlPoints()),
normals(FbxLayerElementAccess<FbxVector4>(shape->GetElementNormal(), shape->GetElementNormalCount())), normals(FbxLayerElementAccess<FbxVector4>(
tangents(FbxLayerElementAccess<FbxVector4>(shape->GetElementTangent(), shape->GetElementTangentCount())) shape->GetElementNormal(),
{} shape->GetElementNormalCount())),
tangents(FbxLayerElementAccess<FbxVector4>(
shape->GetElementTangent(),
shape->GetElementTangentCount())) {}
FbxAnimCurve *FbxBlendShapesAccess::BlendChannel::ExtractAnimation(unsigned int animIx) const FbxAnimCurve* FbxBlendShapesAccess::BlendChannel::ExtractAnimation(unsigned int animIx) const {
{ FbxAnimStack* stack = mesh->GetScene()->GetSrcObject<FbxAnimStack>(animIx);
FbxAnimStack *stack = mesh->GetScene()->GetSrcObject<FbxAnimStack>(animIx); FbxAnimLayer* layer = stack->GetMember<FbxAnimLayer>(0);
FbxAnimLayer *layer = stack->GetMember<FbxAnimLayer>(0);
return mesh->GetShapeChannel(blendShapeIx, channelIx, layer, true); return mesh->GetShapeChannel(blendShapeIx, channelIx, layer, true);
} }
FbxBlendShapesAccess::BlendChannel::BlendChannel( FbxBlendShapesAccess::BlendChannel::BlendChannel(
FbxMesh *mesh, const unsigned int blendShapeIx, const unsigned int channelIx, const FbxDouble deformPercent, FbxMesh* mesh,
const std::vector<FbxBlendShapesAccess::TargetShape> &targetShapes, std::string name) : mesh(mesh), const unsigned int blendShapeIx,
const unsigned int channelIx,
const FbxDouble deformPercent,
const std::vector<FbxBlendShapesAccess::TargetShape>& targetShapes,
std::string name)
: mesh(mesh),
blendShapeIx(blendShapeIx), blendShapeIx(blendShapeIx),
channelIx(channelIx), channelIx(channelIx),
deformPercent(deformPercent), deformPercent(deformPercent),
targetShapes(targetShapes), targetShapes(targetShapes),
name(name) name(name) {}
{}
std::vector<FbxBlendShapesAccess::BlendChannel> FbxBlendShapesAccess::extractChannels(FbxMesh *mesh) const std::vector<FbxBlendShapesAccess::BlendChannel> FbxBlendShapesAccess::extractChannels(
{ FbxMesh* mesh) const {
std::vector<BlendChannel> channels; std::vector<BlendChannel> channels;
for (int shapeIx = 0; shapeIx < mesh->GetDeformerCount(FbxDeformer::eBlendShape); shapeIx++) { for (int shapeIx = 0; shapeIx < mesh->GetDeformerCount(FbxDeformer::eBlendShape); shapeIx++) {
auto *fbxBlendShape = static_cast<FbxBlendShape *>(mesh->GetDeformer(shapeIx, FbxDeformer::eBlendShape)); auto* fbxBlendShape =
static_cast<FbxBlendShape*>(mesh->GetDeformer(shapeIx, FbxDeformer::eBlendShape));
for (int channelIx = 0; channelIx < fbxBlendShape->GetBlendShapeChannelCount(); ++channelIx) { for (int channelIx = 0; channelIx < fbxBlendShape->GetBlendShapeChannelCount(); ++channelIx) {
FbxBlendShapeChannel *fbxChannel = fbxBlendShape->GetBlendShapeChannel(channelIx); FbxBlendShapeChannel* fbxChannel = fbxBlendShape->GetBlendShapeChannel(channelIx);
if (fbxChannel->GetTargetShapeCount() > 0) { if (fbxChannel->GetTargetShapeCount() > 0) {
std::vector<TargetShape> targetShapes; std::vector<TargetShape> targetShapes;
const double *fullWeights = fbxChannel->GetTargetShapeFullWeights(); const double* fullWeights = fbxChannel->GetTargetShapeFullWeights();
std::string name = std::string(fbxChannel->GetName()); std::string name = std::string(fbxChannel->GetName());
if (verboseOutput) { if (verboseOutput) {
fmt::printf("\rblendshape channel: %s\n", name); fmt::printf("\rblendshape channel: %s\n", name);
} }
for (int targetIx = 0; targetIx < fbxChannel->GetTargetShapeCount(); targetIx ++) { for (int targetIx = 0; targetIx < fbxChannel->GetTargetShapeCount(); targetIx++) {
FbxShape *fbxShape = fbxChannel->GetTargetShape(targetIx); FbxShape* fbxShape = fbxChannel->GetTargetShape(targetIx);
targetShapes.emplace_back(fbxShape, fullWeights[targetIx]); targetShapes.emplace_back(fbxShape, fullWeights[targetIx]);
} }
channels.emplace_back(mesh, shapeIx, channelIx, fbxChannel->DeformPercent * 0.01, targetShapes, name); channels.emplace_back(
mesh, shapeIx, channelIx, fbxChannel->DeformPercent * 0.01, targetShapes, name);
} }
} }
} }

View File

@ -9,47 +9,47 @@
#pragma once #pragma once
#include <algorithm>
#include <fstream> #include <fstream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <algorithm>
#include "FBX2glTF.h" #include "FBX2glTF.h"
#include "FbxLayerElementAccess.hpp" #include "FbxLayerElementAccess.hpp"
/** /**
* At the FBX level, each Mesh can have a set of FbxBlendShape deformers; organisational units that contain no data * At the FBX level, each Mesh can have a set of FbxBlendShape deformers; organisational units that
* of their own. The actual deformation is determined by one or more FbxBlendShapeChannels, whose influences are all * contain no data of their own. The actual deformation is determined by one or more
* additively applied to the mesh. In a simpler world, each such channel would extend each base vertex with alternate * FbxBlendShapeChannels, whose influences are all additively applied to the mesh. In a simpler
* position, and optionally normal and tangent. * world, each such channel would extend each base vertex with alternate position, and optionally
* normal and tangent.
* *
* It's not quite so simple, though. We also have progressive morphing, where one logical morph actually consists of * It's not quite so simple, though. We also have progressive morphing, where one logical morph
* several concrete ones, each applied in sequence. For us, this means each channel contains a sequence of FbxShapes * actually consists of several concrete ones, each applied in sequence. For us, this means each
* (aka target shape); these are the actual data-holding entities that provide the alternate vertex attributes. As such * channel contains a sequence of FbxShapes (aka target shape); these are the actual data-holding
* a channel is given more weight, it moves from one target shape to another. * entities that provide the alternate vertex attributes. As such a channel is given more weight, it
* moves from one target shape to another.
* *
* The total number of alternate sets of attributes, then, is the total number of target shapes across all the channels * The total number of alternate sets of attributes, then, is the total number of target shapes
* of all the blend shapes of the mesh. * across all the channels of all the blend shapes of the mesh.
* *
* Each animation in the scene stack can yield one or zero FbxAnimCurves per channel (not target shape). We evaluate * Each animation in the scene stack can yield one or zero FbxAnimCurves per channel (not target
* these curves to get the weight of the channel: this weight is further introspected on to figure out which target * shape). We evaluate these curves to get the weight of the channel: this weight is further
* shapes we're currently interpolation between. * introspected on to figure out which target shapes we're currently interpolation between.
*/ */
class FbxBlendShapesAccess class FbxBlendShapesAccess {
{ public:
public:
/** /**
* A target shape is on a 1:1 basis with the eventual glTF morph target, and is the object which contains the * A target shape is on a 1:1 basis with the eventual glTF morph target, and is the object which
* actual morphed vertex data. * contains the actual morphed vertex data.
*/ */
struct TargetShape struct TargetShape {
{ explicit TargetShape(const FbxShape* shape, FbxDouble fullWeight);
explicit TargetShape(const FbxShape *shape, FbxDouble fullWeight);
const FbxShape *shape; const FbxShape* shape;
const FbxDouble fullWeight; const FbxDouble fullWeight;
const unsigned int count; const unsigned int count;
const FbxVector4 *positions; const FbxVector4* positions;
const FbxLayerElementAccess<FbxVector4> normals; const FbxLayerElementAccess<FbxVector4> normals;
const FbxLayerElementAccess<FbxVector4> tangents; const FbxLayerElementAccess<FbxVector4> tangents;
}; };
@ -57,20 +57,18 @@ public:
/** /**
* A channel collects a sequence (often of length 1) of target shapes. * A channel collects a sequence (often of length 1) of target shapes.
*/ */
struct BlendChannel struct BlendChannel {
{
BlendChannel( BlendChannel(
FbxMesh *mesh, FbxMesh* mesh,
const unsigned int blendShapeIx, const unsigned int blendShapeIx,
const unsigned int channelIx, const unsigned int channelIx,
const FbxDouble deformPercent, const FbxDouble deformPercent,
const std::vector<TargetShape> &targetShapes, const std::vector<TargetShape>& targetShapes,
const std::string name const std::string name);
);
FbxAnimCurve *ExtractAnimation(unsigned int animIx) const; FbxAnimCurve* ExtractAnimation(unsigned int animIx) const;
FbxMesh *const mesh; FbxMesh* const mesh;
const unsigned int blendShapeIx; const unsigned int blendShapeIx;
const unsigned int channelIx; const unsigned int channelIx;
@ -80,26 +78,28 @@ public:
const FbxDouble deformPercent; const FbxDouble deformPercent;
}; };
explicit FbxBlendShapesAccess(FbxMesh *mesh) : explicit FbxBlendShapesAccess(FbxMesh* mesh) : channels(extractChannels(mesh)) {}
channels(extractChannels(mesh))
{ }
size_t GetChannelCount() const { return channels.size(); } size_t GetChannelCount() const {
const BlendChannel &GetBlendChannel(size_t channelIx) const { return channels.size();
}
const BlendChannel& GetBlendChannel(size_t channelIx) const {
return channels.at(channelIx); return channels.at(channelIx);
} }
size_t GetTargetShapeCount(size_t channelIx) const { return channels[channelIx].targetShapes.size(); } size_t GetTargetShapeCount(size_t channelIx) const {
const TargetShape &GetTargetShape(size_t channelIx, size_t targetShapeIx) const { return channels[channelIx].targetShapes.size();
}
const TargetShape& GetTargetShape(size_t channelIx, size_t targetShapeIx) const {
return channels.at(channelIx).targetShapes[targetShapeIx]; return channels.at(channelIx).targetShapes[targetShapeIx];
} }
FbxAnimCurve * GetAnimation(size_t channelIx, size_t animIx) const { FbxAnimCurve* GetAnimation(size_t channelIx, size_t animIx) const {
return channels.at(channelIx).ExtractAnimation(animIx); return channels.at(channelIx).ExtractAnimation(animIx);
} }
private: private:
std::vector<BlendChannel> extractChannels(FbxMesh *mesh) const; std::vector<BlendChannel> extractChannels(FbxMesh* mesh) const;
const std::vector<BlendChannel> channels; const std::vector<BlendChannel> channels;
}; };

View File

@ -9,35 +9,39 @@
#pragma once #pragma once
#include "FBX2glTF.h" #include "FBX2glTF.h"
template<typename _type_> template <typename _type_>
class FbxLayerElementAccess class FbxLayerElementAccess {
{ public:
public: FbxLayerElementAccess(const FbxLayerElementTemplate<_type_>* layer, int count);
FbxLayerElementAccess(const FbxLayerElementTemplate<_type_> *layer, int count); bool LayerPresent() const {
bool LayerPresent() const
{
return (mappingMode != FbxLayerElement::eNone); return (mappingMode != FbxLayerElement::eNone);
} }
_type_ GetElement(const int polygonIndex, const int polygonVertexIndex, const int controlPointIndex, const _type_ defaultValue) const;
_type_ GetElement( _type_ GetElement(
const int polygonIndex, const int polygonVertexIndex, const int controlPointIndex, const _type_ defaultValue, const int polygonIndex,
const FbxMatrix &transform, const bool normalize) const; const int polygonVertexIndex,
const int controlPointIndex,
const _type_ defaultValue) const;
_type_ GetElement(
const int polygonIndex,
const int polygonVertexIndex,
const int controlPointIndex,
const _type_ defaultValue,
const FbxMatrix& transform,
const bool normalize) const;
private: private:
FbxLayerElement::EMappingMode mappingMode; FbxLayerElement::EMappingMode mappingMode;
const FbxLayerElementArrayTemplate<_type_> *elements; const FbxLayerElementArrayTemplate<_type_>* elements;
const FbxLayerElementArrayTemplate<int> *indices; const FbxLayerElementArrayTemplate<int>* indices;
}; };
template<typename _type_> template <typename _type_>
FbxLayerElementAccess<_type_>::FbxLayerElementAccess(const FbxLayerElementTemplate<_type_> *layer, int count) : FbxLayerElementAccess<_type_>::FbxLayerElementAccess(
mappingMode(FbxLayerElement::eNone), const FbxLayerElementTemplate<_type_>* layer,
elements(nullptr), int count)
indices(nullptr) : mappingMode(FbxLayerElement::eNone), elements(nullptr), indices(nullptr) {
{
if (count <= 0 || layer == nullptr) { if (count <= 0 || layer == nullptr) {
return; return;
} }
@ -47,19 +51,23 @@ FbxLayerElementAccess<_type_>::FbxLayerElementAccess(const FbxLayerElementTempla
newMappingMode == FbxLayerElement::eByPolygon) { newMappingMode == FbxLayerElement::eByPolygon) {
mappingMode = newMappingMode; mappingMode = newMappingMode;
elements = &layer->GetDirectArray(); elements = &layer->GetDirectArray();
indices = ( indices = (layer->GetReferenceMode() == FbxLayerElement::eIndexToDirect ||
layer->GetReferenceMode() == FbxLayerElement::eIndexToDirect || layer->GetReferenceMode() == FbxLayerElement::eIndex)
layer->GetReferenceMode() == FbxLayerElement::eIndex) ? &layer->GetIndexArray() : nullptr; ? &layer->GetIndexArray()
: nullptr;
} }
} }
template<typename _type_> template <typename _type_>
_type_ FbxLayerElementAccess<_type_>::GetElement( _type_ FbxLayerElementAccess<_type_>::GetElement(
const int polygonIndex, const int polygonVertexIndex, const int controlPointIndex, const _type_ defaultValue) const const int polygonIndex,
{ const int polygonVertexIndex,
const int controlPointIndex,
const _type_ defaultValue) const {
if (mappingMode != FbxLayerElement::eNone) { if (mappingMode != FbxLayerElement::eNone) {
int index = (mappingMode == FbxLayerElement::eByControlPoint) ? controlPointIndex : int index = (mappingMode == FbxLayerElement::eByControlPoint)
((mappingMode == FbxLayerElement::eByPolygonVertex) ? polygonVertexIndex : polygonIndex); ? controlPointIndex
: ((mappingMode == FbxLayerElement::eByPolygonVertex) ? polygonVertexIndex : polygonIndex);
index = (indices != nullptr) ? (*indices)[index] : index; index = (indices != nullptr) ? (*indices)[index] : index;
_type_ element = elements->GetAt(index); _type_ element = elements->GetAt(index);
return element; return element;
@ -67,13 +75,17 @@ _type_ FbxLayerElementAccess<_type_>::GetElement(
return defaultValue; return defaultValue;
} }
template<typename _type_> template <typename _type_>
_type_ FbxLayerElementAccess<_type_>::GetElement( _type_ FbxLayerElementAccess<_type_>::GetElement(
const int polygonIndex, const int polygonVertexIndex, const int controlPointIndex, const _type_ defaultValue, const int polygonIndex,
const FbxMatrix &transform, const bool normalize) const const int polygonVertexIndex,
{ const int controlPointIndex,
const _type_ defaultValue,
const FbxMatrix& transform,
const bool normalize) const {
if (mappingMode != FbxLayerElement::eNone) { if (mappingMode != FbxLayerElement::eNone) {
_type_ element = transform.MultNormalize(GetElement(polygonIndex, polygonVertexIndex, controlPointIndex, defaultValue)); _type_ element = transform.MultNormalize(
GetElement(polygonIndex, polygonVertexIndex, controlPointIndex, defaultValue));
if (normalize) { if (normalize) {
element.Normalize(); element.Normalize();
} }

View File

@ -12,10 +12,9 @@
#include "FBX2glTF.h" #include "FBX2glTF.h"
class FbxMaterialInfo { class FbxMaterialInfo {
public: public:
FbxMaterialInfo(const FbxString &name, const FbxString &shadingModel) FbxMaterialInfo(const FbxString& name, const FbxString& shadingModel)
: name(name), : name(name), shadingModel(shadingModel) {}
shadingModel(shadingModel) {}
const FbxString name; const FbxString name;
const FbxString shadingModel; const FbxString shadingModel;

View File

@ -10,21 +10,23 @@
#include "FbxMaterialsAccess.hpp" #include "FbxMaterialsAccess.hpp"
#include "Fbx2Raw.hpp" #include "Fbx2Raw.hpp"
FbxMaterialsAccess::FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<const FbxTexture *, FbxString> &textureLocations) : FbxMaterialsAccess::FbxMaterialsAccess(
mappingMode(FbxGeometryElement::eNone), const FbxMesh* pMesh,
mesh(nullptr), const std::map<const FbxTexture*, FbxString>& textureLocations)
indices(nullptr) : mappingMode(FbxGeometryElement::eNone), mesh(nullptr), indices(nullptr) {
{
if (pMesh->GetElementMaterialCount() <= 0) { if (pMesh->GetElementMaterialCount() <= 0) {
return; return;
} }
const FbxGeometryElement::EMappingMode materialMappingMode = pMesh->GetElementMaterial()->GetMappingMode(); const FbxGeometryElement::EMappingMode materialMappingMode =
if (materialMappingMode != FbxGeometryElement::eByPolygon && materialMappingMode != FbxGeometryElement::eAllSame) { pMesh->GetElementMaterial()->GetMappingMode();
if (materialMappingMode != FbxGeometryElement::eByPolygon &&
materialMappingMode != FbxGeometryElement::eAllSame) {
return; return;
} }
const FbxGeometryElement::EReferenceMode materialReferenceMode = pMesh->GetElementMaterial()->GetReferenceMode(); const FbxGeometryElement::EReferenceMode materialReferenceMode =
pMesh->GetElementMaterial()->GetReferenceMode();
if (materialReferenceMode != FbxGeometryElement::eIndexToDirect) { if (materialReferenceMode != FbxGeometryElement::eIndexToDirect) {
return; return;
} }
@ -39,16 +41,15 @@ FbxMaterialsAccess::FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<cons
continue; continue;
} }
FbxSurfaceMaterial* surfaceMaterial = mesh->GetNode()->GetSrcObject<FbxSurfaceMaterial>(materialNum); FbxSurfaceMaterial* surfaceMaterial =
mesh->GetNode()->GetSrcObject<FbxSurfaceMaterial>(materialNum);
if (materialNum >= summaries.size()) { if (materialNum >= summaries.size()) {
summaries.resize(materialNum + 1); summaries.resize(materialNum + 1);
} }
auto summary = summaries[materialNum]; auto summary = summaries[materialNum];
if (summary == nullptr) { if (summary == nullptr) {
summary = summaries[materialNum] = GetMaterialInfo( summary = summaries[materialNum] = GetMaterialInfo(surfaceMaterial, textureLocations);
surfaceMaterial,
textureLocations);
} }
if (materialNum >= userProperties.size()) { if (materialNum >= userProperties.size()) {
@ -56,8 +57,7 @@ FbxMaterialsAccess::FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<cons
} }
if (userProperties[materialNum].empty()) { if (userProperties[materialNum].empty()) {
FbxProperty objectProperty = surfaceMaterial->GetFirstProperty(); FbxProperty objectProperty = surfaceMaterial->GetFirstProperty();
while (objectProperty.IsValid()) while (objectProperty.IsValid()) {
{
if (objectProperty.GetFlag(FbxPropertyFlags::eUserDefined)) { if (objectProperty.GetFlag(FbxPropertyFlags::eUserDefined)) {
userProperties[materialNum].push_back(TranscribeProperty(objectProperty).dump()); userProperties[materialNum].push_back(TranscribeProperty(objectProperty).dump());
} }
@ -67,22 +67,23 @@ FbxMaterialsAccess::FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<cons
} }
} }
const std::shared_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterial(const int polygonIndex) const const std::shared_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterial(
{ const int polygonIndex) const {
if (mappingMode != FbxGeometryElement::eNone) { if (mappingMode != FbxGeometryElement::eNone) {
const int materialNum = indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0); const int materialNum =
indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0);
if (materialNum < 0) { if (materialNum < 0) {
return nullptr; return nullptr;
} }
return summaries.at((unsigned long) materialNum); return summaries.at((unsigned long)materialNum);
} }
return nullptr; return nullptr;
} }
const std::vector<std::string> FbxMaterialsAccess::GetUserProperties(const int polygonIndex) const const std::vector<std::string> FbxMaterialsAccess::GetUserProperties(const int polygonIndex) const {
{
if (mappingMode != FbxGeometryElement::eNone) { if (mappingMode != FbxGeometryElement::eNone) {
const int materialNum = indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0); const int materialNum =
indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0);
if (materialNum < 0) { if (materialNum < 0) {
return std::vector<std::string>(); return std::vector<std::string>();
} }
@ -91,9 +92,9 @@ const std::vector<std::string> FbxMaterialsAccess::GetUserProperties(const int p
return std::vector<std::string>(); return std::vector<std::string>();
} }
std::unique_ptr<FbxMaterialInfo> std::unique_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterialInfo(
FbxMaterialsAccess::GetMaterialInfo(FbxSurfaceMaterial *material, const std::map<const FbxTexture *, FbxString> &textureLocations) FbxSurfaceMaterial* material,
{ const std::map<const FbxTexture*, FbxString>& textureLocations) {
std::unique_ptr<FbxMaterialInfo> res; std::unique_ptr<FbxMaterialInfo> res;
res = FbxRoughMetMaterialInfo::From(material, textureLocations); res = FbxRoughMetMaterialInfo::From(material, textureLocations);
if (!res) { if (!res) {
@ -101,4 +102,3 @@ FbxMaterialsAccess::GetMaterialInfo(FbxSurfaceMaterial *material, const std::map
} }
return res; return res;
} }

View File

@ -11,26 +11,27 @@
#include "Fbx2Raw.hpp" #include "Fbx2Raw.hpp"
#include "FbxMaterialInfo.hpp" #include "FbxMaterialInfo.hpp"
#include "FbxTraditionalMaterialInfo.hpp"
#include "FbxRoughMetMaterialInfo.hpp" #include "FbxRoughMetMaterialInfo.hpp"
#include "FbxTraditionalMaterialInfo.hpp"
class FbxMaterialsAccess class FbxMaterialsAccess {
{ public:
public: FbxMaterialsAccess(
const FbxMesh* pMesh,
FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<const FbxTexture *, FbxString> &textureLocations); const std::map<const FbxTexture*, FbxString>& textureLocations);
const std::shared_ptr<FbxMaterialInfo> GetMaterial(const int polygonIndex) const; const std::shared_ptr<FbxMaterialInfo> GetMaterial(const int polygonIndex) const;
const std::vector<std::string> GetUserProperties(const int polygonIndex) const; const std::vector<std::string> GetUserProperties(const int polygonIndex) const;
std::unique_ptr<FbxMaterialInfo> std::unique_ptr<FbxMaterialInfo> GetMaterialInfo(
GetMaterialInfo(FbxSurfaceMaterial *material, const std::map<const FbxTexture *, FbxString> &textureLocations); FbxSurfaceMaterial* material,
const std::map<const FbxTexture*, FbxString>& textureLocations);
private: private:
FbxGeometryElement::EMappingMode mappingMode; FbxGeometryElement::EMappingMode mappingMode;
std::vector<std::shared_ptr<FbxMaterialInfo>> summaries {}; std::vector<std::shared_ptr<FbxMaterialInfo>> summaries{};
std::vector<std::vector<std::string>> userProperties; std::vector<std::vector<std::string>> userProperties;
const FbxMesh *mesh; const FbxMesh* mesh;
const FbxLayerElementArrayTemplate<int> *indices; const FbxLayerElementArrayTemplate<int>* indices;
}; };

View File

@ -7,24 +7,27 @@
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "FbxRoughMetMaterialInfo.hpp" #include "FbxRoughMetMaterialInfo.hpp"
std::unique_ptr<FbxRoughMetMaterialInfo> std::unique_ptr<FbxRoughMetMaterialInfo> FbxRoughMetMaterialInfo::From(
FbxRoughMetMaterialInfo::From(FbxSurfaceMaterial *fbxMaterial, const std::map<const FbxTexture *, FbxString> &textureLocations) FbxSurfaceMaterial* fbxMaterial,
{ const std::map<const FbxTexture*, FbxString>& textureLocations) {
std::unique_ptr<FbxRoughMetMaterialInfo> res(new FbxRoughMetMaterialInfo(fbxMaterial->GetName(), FBX_SHADER_METROUGH)); std::unique_ptr<FbxRoughMetMaterialInfo> res(
new FbxRoughMetMaterialInfo(fbxMaterial->GetName(), FBX_SHADER_METROUGH));
const FbxProperty mayaProp = fbxMaterial->FindProperty("Maya"); const FbxProperty mayaProp = fbxMaterial->FindProperty("Maya");
if (mayaProp.GetPropertyDataType() != FbxCompoundDT) { if (mayaProp.GetPropertyDataType() != FbxCompoundDT) {
return nullptr; return nullptr;
} }
if (!fbxMaterial->ShadingModel.Get().IsEmpty()) { if (!fbxMaterial->ShadingModel.Get().IsEmpty()) {
::fmt::printf("Warning: Material %s has surprising shading model: %s\n", ::fmt::printf(
fbxMaterial->GetName(), fbxMaterial->ShadingModel.Get()); "Warning: Material %s has surprising shading model: %s\n",
fbxMaterial->GetName(),
fbxMaterial->ShadingModel.Get());
} }
auto getTex = [&](std::string propName) { auto getTex = [&](std::string propName) {
const FbxFileTexture *ptr = nullptr; const FbxFileTexture* ptr = nullptr;
const FbxProperty useProp = mayaProp.FindHierarchical(("use_" + propName + "_map").c_str()); const FbxProperty useProp = mayaProp.FindHierarchical(("use_" + propName + "_map").c_str());
if (useProp.IsValid() && useProp.Get<bool>()) { if (useProp.IsValid() && useProp.Get<bool>()) {
@ -36,8 +39,10 @@ FbxRoughMetMaterialInfo::From(FbxSurfaceMaterial *fbxMaterial, const std::map<co
} }
} }
} else if (verboseOutput && useProp.IsValid()) { } else if (verboseOutput && useProp.IsValid()) {
fmt::printf("Note: Property '%s' of material '%s' exists, but is flagged as 'do not use'.\n", fmt::printf(
propName, fbxMaterial->GetName()); "Note: Property '%s' of material '%s' exists, but is flagged as 'do not use'.\n",
propName,
fbxMaterial->GetName());
} }
return ptr; return ptr;
}; };
@ -48,7 +53,7 @@ FbxRoughMetMaterialInfo::From(FbxSurfaceMaterial *fbxMaterial, const std::map<co
}; };
auto getVal = [&](std::string propName) -> FbxDouble { auto getVal = [&](std::string propName) -> FbxDouble {
const FbxProperty vecProp = mayaProp.FindHierarchical(propName .c_str()); const FbxProperty vecProp = mayaProp.FindHierarchical(propName.c_str());
return vecProp.IsValid() ? vecProp.Get<FbxDouble>() : 0; return vecProp.IsValid() ? vecProp.Get<FbxDouble>() : 0;
}; };

View File

@ -7,36 +7,35 @@
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include <algorithm>
#include <fstream> #include <fstream>
#include <string>
#include <set>
#include <map> #include <map>
#include <set>
#include <string>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include <algorithm>
#include "FbxMaterialInfo.hpp" #include "FbxMaterialInfo.hpp"
struct FbxRoughMetMaterialInfo : FbxMaterialInfo { struct FbxRoughMetMaterialInfo : FbxMaterialInfo {
static constexpr const char *FBX_SHADER_METROUGH = "MetallicRoughness"; static constexpr const char* FBX_SHADER_METROUGH = "MetallicRoughness";
static std::unique_ptr<FbxRoughMetMaterialInfo> From( static std::unique_ptr<FbxRoughMetMaterialInfo> From(
FbxSurfaceMaterial *fbxMaterial, FbxSurfaceMaterial* fbxMaterial,
const std::map<const FbxTexture *, FbxString> &textureLocations); const std::map<const FbxTexture*, FbxString>& textureLocations);
FbxRoughMetMaterialInfo(const FbxString &name, const FbxString &shadingModel) FbxRoughMetMaterialInfo(const FbxString& name, const FbxString& shadingModel)
: FbxMaterialInfo(name, shadingModel) : FbxMaterialInfo(name, shadingModel) {}
{}
const FbxFileTexture *texColor {}; const FbxFileTexture* texColor{};
FbxVector4 colBase {}; FbxVector4 colBase{};
const FbxFileTexture *texNormal {}; const FbxFileTexture* texNormal{};
const FbxFileTexture *texMetallic {}; const FbxFileTexture* texMetallic{};
FbxDouble metallic {}; FbxDouble metallic{};
const FbxFileTexture *texRoughness {}; const FbxFileTexture* texRoughness{};
FbxDouble roughness {}; FbxDouble roughness{};
const FbxFileTexture *texEmissive {}; const FbxFileTexture* texEmissive{};
FbxVector4 colEmissive {}; FbxVector4 colEmissive{};
FbxDouble emissiveIntensity {}; FbxDouble emissiveIntensity{};
const FbxFileTexture *texAmbientOcclusion {}; const FbxFileTexture* texAmbientOcclusion{};
}; };

View File

@ -9,11 +9,11 @@
#include "FbxSkinningAccess.hpp" #include "FbxSkinningAccess.hpp"
FbxSkinningAccess::FbxSkinningAccess(const FbxMesh *pMesh, FbxScene *pScene, FbxNode *pNode) FbxSkinningAccess::FbxSkinningAccess(const FbxMesh* pMesh, FbxScene* pScene, FbxNode* pNode)
: rootIndex(-1) : rootIndex(-1) {
{
for (int deformerIndex = 0; deformerIndex < pMesh->GetDeformerCount(); deformerIndex++) { for (int deformerIndex = 0; deformerIndex < pMesh->GetDeformerCount(); deformerIndex++) {
FbxSkin *skin = reinterpret_cast< FbxSkin * >( pMesh->GetDeformer(deformerIndex, FbxDeformer::eSkin)); FbxSkin* skin =
reinterpret_cast<FbxSkin*>(pMesh->GetDeformer(deformerIndex, FbxDeformer::eSkin));
if (skin != nullptr) { if (skin != nullptr) {
const int clusterCount = skin->GetClusterCount(); const int clusterCount = skin->GetClusterCount();
if (clusterCount == 0) { if (clusterCount == 0) {
@ -24,10 +24,10 @@ FbxSkinningAccess::FbxSkinningAccess(const FbxMesh *pMesh, FbxScene *pScene, Fbx
vertexJointWeights.resize(controlPointCount, Vec4f(0.0f, 0.0f, 0.0f, 0.0f)); vertexJointWeights.resize(controlPointCount, Vec4f(0.0f, 0.0f, 0.0f, 0.0f));
for (int clusterIndex = 0; clusterIndex < clusterCount; clusterIndex++) { for (int clusterIndex = 0; clusterIndex < clusterCount; clusterIndex++) {
FbxCluster *cluster = skin->GetCluster(clusterIndex); FbxCluster* cluster = skin->GetCluster(clusterIndex);
const int indexCount = cluster->GetControlPointIndicesCount(); const int indexCount = cluster->GetControlPointIndicesCount();
const int *clusterIndices = cluster->GetControlPointIndices(); const int* clusterIndices = cluster->GetControlPointIndices();
const double *clusterWeights = cluster->GetControlPointWeights(); const double* clusterWeights = cluster->GetControlPointWeights();
assert(cluster->GetLinkMode() == FbxCluster::eNormalize); assert(cluster->GetLinkMode() == FbxCluster::eNormalize);
@ -47,7 +47,8 @@ FbxSkinningAccess::FbxSkinningAccess(const FbxMesh *pMesh, FbxScene *pScene, Fbx
jointIds.push_back(cluster->GetLink()->GetUniqueID()); jointIds.push_back(cluster->GetLink()->GetUniqueID());
const FbxAMatrix globalNodeTransform = cluster->GetLink()->EvaluateGlobalTransform(); const FbxAMatrix globalNodeTransform = cluster->GetLink()->EvaluateGlobalTransform();
jointSkinningTransforms.push_back(FbxMatrix(globalNodeTransform * globalBindposeInverseMatrix)); jointSkinningTransforms.push_back(
FbxMatrix(globalNodeTransform * globalBindposeInverseMatrix));
jointInverseGlobalTransforms.push_back(FbxMatrix(globalNodeTransform.Inverse())); jointInverseGlobalTransforms.push_back(FbxMatrix(globalNodeTransform.Inverse()));
for (int i = 0; i < indexCount; i++) { for (int i = 0; i < indexCount; i++) {
@ -58,16 +59,20 @@ FbxSkinningAccess::FbxSkinningAccess(const FbxMesh *pMesh, FbxScene *pScene, Fbx
continue; continue;
} }
vertexJointIndices[clusterIndices[i]][MAX_WEIGHTS - 1] = clusterIndex; vertexJointIndices[clusterIndices[i]][MAX_WEIGHTS - 1] = clusterIndex;
vertexJointWeights[clusterIndices[i]][MAX_WEIGHTS - 1] = (float) clusterWeights[i]; vertexJointWeights[clusterIndices[i]][MAX_WEIGHTS - 1] = (float)clusterWeights[i];
for (int j = MAX_WEIGHTS - 1; j > 0; j--) { for (int j = MAX_WEIGHTS - 1; j > 0; j--) {
if (vertexJointWeights[clusterIndices[i]][j - 1] >= vertexJointWeights[clusterIndices[i]][j]) { if (vertexJointWeights[clusterIndices[i]][j - 1] >=
vertexJointWeights[clusterIndices[i]][j]) {
break; break;
} }
std::swap(vertexJointIndices[clusterIndices[i]][j - 1], vertexJointIndices[clusterIndices[i]][j]); std::swap(
std::swap(vertexJointWeights[clusterIndices[i]][j - 1], vertexJointWeights[clusterIndices[i]][j]); vertexJointIndices[clusterIndices[i]][j - 1],
vertexJointIndices[clusterIndices[i]][j]);
std::swap(
vertexJointWeights[clusterIndices[i]][j - 1],
vertexJointWeights[clusterIndices[i]][j]);
} }
} }
} }
for (int i = 0; i < controlPointCount; i++) { for (int i = 0; i < controlPointCount; i++) {
vertexJointWeights[i] = vertexJointWeights[i].Normalized(); vertexJointWeights[i] = vertexJointWeights[i].Normalized();
@ -77,8 +82,8 @@ FbxSkinningAccess::FbxSkinningAccess(const FbxMesh *pMesh, FbxScene *pScene, Fbx
rootIndex = -1; rootIndex = -1;
for (size_t i = 0; i < jointNodes.size() && rootIndex == -1; i++) { for (size_t i = 0; i < jointNodes.size() && rootIndex == -1; i++) {
rootIndex = (int) i; rootIndex = (int)i;
FbxNode *parent = jointNodes[i]->GetParent(); FbxNode* parent = jointNodes[i]->GetParent();
if (parent == nullptr) { if (parent == nullptr) {
break; break;
} }

View File

@ -9,81 +9,69 @@
#pragma once #pragma once
#include <algorithm>
#include <fstream> #include <fstream>
#include <string>
#include <set>
#include <map> #include <map>
#include <set>
#include <string>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include <algorithm>
#include "FBX2glTF.h" #include "FBX2glTF.h"
class FbxSkinningAccess class FbxSkinningAccess {
{ public:
public:
static const int MAX_WEIGHTS = 4; static const int MAX_WEIGHTS = 4;
FbxSkinningAccess(const FbxMesh *pMesh, FbxScene *pScene, FbxNode *pNode); FbxSkinningAccess(const FbxMesh* pMesh, FbxScene* pScene, FbxNode* pNode);
bool IsSkinned() const bool IsSkinned() const {
{
return (vertexJointWeights.size() > 0); return (vertexJointWeights.size() > 0);
} }
int GetNodeCount() const int GetNodeCount() const {
{ return (int)jointNodes.size();
return (int) jointNodes.size();
} }
FbxNode *GetJointNode(const int jointIndex) const FbxNode* GetJointNode(const int jointIndex) const {
{
return jointNodes[jointIndex]; return jointNodes[jointIndex];
} }
const long GetJointId(const int jointIndex) const const long GetJointId(const int jointIndex) const {
{
return jointIds[jointIndex]; return jointIds[jointIndex];
} }
const FbxMatrix &GetJointSkinningTransform(const int jointIndex) const const FbxMatrix& GetJointSkinningTransform(const int jointIndex) const {
{
return jointSkinningTransforms[jointIndex]; return jointSkinningTransforms[jointIndex];
} }
const FbxMatrix &GetJointInverseGlobalTransforms(const int jointIndex) const const FbxMatrix& GetJointInverseGlobalTransforms(const int jointIndex) const {
{
return jointInverseGlobalTransforms[jointIndex]; return jointInverseGlobalTransforms[jointIndex];
} }
const long GetRootNode() const const long GetRootNode() const {
{
assert(rootIndex != -1); assert(rootIndex != -1);
return jointIds[rootIndex]; return jointIds[rootIndex];
} }
const FbxAMatrix &GetInverseBindMatrix(const int jointIndex) const const FbxAMatrix& GetInverseBindMatrix(const int jointIndex) const {
{
return inverseBindMatrices[jointIndex]; return inverseBindMatrices[jointIndex];
} }
const Vec4i GetVertexIndices(const int controlPointIndex) const const Vec4i GetVertexIndices(const int controlPointIndex) const {
{ return (!vertexJointIndices.empty()) ? vertexJointIndices[controlPointIndex]
return (!vertexJointIndices.empty()) ? : Vec4i(0, 0, 0, 0);
vertexJointIndices[controlPointIndex] : Vec4i(0, 0, 0, 0);
} }
const Vec4f GetVertexWeights(const int controlPointIndex) const const Vec4f GetVertexWeights(const int controlPointIndex) const {
{ return (!vertexJointWeights.empty()) ? vertexJointWeights[controlPointIndex]
return (!vertexJointWeights.empty()) ? : Vec4f(0, 0, 0, 0);
vertexJointWeights[controlPointIndex] : Vec4f(0, 0, 0, 0);
} }
private: private:
int rootIndex; int rootIndex;
std::vector<long> jointIds; std::vector<long> jointIds;
std::vector<FbxNode *> jointNodes; std::vector<FbxNode*> jointNodes;
std::vector<FbxMatrix> jointSkinningTransforms; std::vector<FbxMatrix> jointSkinningTransforms;
std::vector<FbxMatrix> jointInverseGlobalTransforms; std::vector<FbxMatrix> jointInverseGlobalTransforms;
std::vector<FbxAMatrix> inverseBindMatrices; std::vector<FbxAMatrix> inverseBindMatrices;

View File

@ -9,14 +9,14 @@
#include "FbxTraditionalMaterialInfo.hpp" #include "FbxTraditionalMaterialInfo.hpp"
std::unique_ptr<FbxTraditionalMaterialInfo> std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialInfo::From(
FbxTraditionalMaterialInfo::From(FbxSurfaceMaterial *fbxMaterial, const std::map<const FbxTexture *, FbxString> &textureLocations) FbxSurfaceMaterial* fbxMaterial,
{ const std::map<const FbxTexture*, FbxString>& textureLocations) {
auto getSurfaceScalar = [&](const char *propName) -> std::tuple<FbxDouble, FbxFileTexture *> { auto getSurfaceScalar = [&](const char* propName) -> std::tuple<FbxDouble, FbxFileTexture*> {
const FbxProperty prop = fbxMaterial->FindProperty(propName); const FbxProperty prop = fbxMaterial->FindProperty(propName);
FbxDouble val(0); FbxDouble val(0);
FbxFileTexture *tex = prop.GetSrcObject<FbxFileTexture>(); FbxFileTexture* tex = prop.GetSrcObject<FbxFileTexture>();
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) { if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
tex = nullptr; tex = nullptr;
} }
@ -26,11 +26,11 @@ FbxTraditionalMaterialInfo::From(FbxSurfaceMaterial *fbxMaterial, const std::map
return std::make_tuple(val, tex); return std::make_tuple(val, tex);
}; };
auto getSurfaceVector = [&](const char *propName) -> std::tuple<FbxDouble3, FbxFileTexture *> { auto getSurfaceVector = [&](const char* propName) -> std::tuple<FbxDouble3, FbxFileTexture*> {
const FbxProperty prop = fbxMaterial->FindProperty(propName); const FbxProperty prop = fbxMaterial->FindProperty(propName);
FbxDouble3 val(1, 1, 1); FbxDouble3 val(1, 1, 1);
FbxFileTexture *tex = prop.GetSrcObject<FbxFileTexture>(); FbxFileTexture* tex = prop.GetSrcObject<FbxFileTexture>();
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) { if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
tex = nullptr; tex = nullptr;
} }
@ -40,21 +40,23 @@ FbxTraditionalMaterialInfo::From(FbxSurfaceMaterial *fbxMaterial, const std::map
return std::make_tuple(val, tex); return std::make_tuple(val, tex);
}; };
auto getSurfaceValues = [&](const char *colName, const char *facName) -> std::tuple<FbxVector4, FbxFileTexture *, FbxFileTexture *> { auto getSurfaceValues =
[&](const char* colName,
const char* facName) -> std::tuple<FbxVector4, FbxFileTexture*, FbxFileTexture*> {
const FbxProperty colProp = fbxMaterial->FindProperty(colName); const FbxProperty colProp = fbxMaterial->FindProperty(colName);
const FbxProperty facProp = fbxMaterial->FindProperty(facName); const FbxProperty facProp = fbxMaterial->FindProperty(facName);
FbxDouble3 colorVal(1, 1, 1); FbxDouble3 colorVal(1, 1, 1);
FbxDouble factorVal(1); FbxDouble factorVal(1);
FbxFileTexture *colTex = colProp.GetSrcObject<FbxFileTexture>(); FbxFileTexture* colTex = colProp.GetSrcObject<FbxFileTexture>();
if (colTex != nullptr && textureLocations.find(colTex) == textureLocations.end()) { if (colTex != nullptr && textureLocations.find(colTex) == textureLocations.end()) {
colTex = nullptr; colTex = nullptr;
} }
if (colTex == nullptr && colProp.IsValid()) { if (colTex == nullptr && colProp.IsValid()) {
colorVal = colProp.Get<FbxDouble3>(); colorVal = colProp.Get<FbxDouble3>();
} }
FbxFileTexture *facTex = facProp.GetSrcObject<FbxFileTexture>(); FbxFileTexture* facTex = facProp.GetSrcObject<FbxFileTexture>();
if (facTex != nullptr && textureLocations.find(facTex) == textureLocations.end()) { if (facTex != nullptr && textureLocations.find(facTex) == textureLocations.end()) {
facTex = nullptr; facTex = nullptr;
} }
@ -63,25 +65,29 @@ FbxTraditionalMaterialInfo::From(FbxSurfaceMaterial *fbxMaterial, const std::map
} }
auto val = FbxVector4( auto val = FbxVector4(
colorVal[0] * factorVal, colorVal[0] * factorVal, colorVal[1] * factorVal, colorVal[2] * factorVal, factorVal);
colorVal[1] * factorVal,
colorVal[2] * factorVal,
factorVal);
return std::make_tuple(val, colTex, facTex); return std::make_tuple(val, colTex, facTex);
}; };
std::string name = fbxMaterial->GetName(); std::string name = fbxMaterial->GetName();
std::unique_ptr<FbxTraditionalMaterialInfo> res(new FbxTraditionalMaterialInfo(name.c_str(), fbxMaterial->ShadingModel.Get())); std::unique_ptr<FbxTraditionalMaterialInfo> res(
new FbxTraditionalMaterialInfo(name.c_str(), fbxMaterial->ShadingModel.Get()));
// four properties are on the same structure and follow the same rules // four properties are on the same structure and follow the same rules
auto handleBasicProperty = [&](const char *colName, const char *facName) -> std::tuple<FbxVector4, FbxFileTexture *>{ auto handleBasicProperty = [&](const char* colName,
const char* facName) -> std::tuple<FbxVector4, FbxFileTexture*> {
FbxFileTexture *colTex, *facTex; FbxFileTexture *colTex, *facTex;
FbxVector4 vec; FbxVector4 vec;
std::tie(vec, colTex, facTex) = getSurfaceValues(colName, facName); std::tie(vec, colTex, facTex) = getSurfaceValues(colName, facName);
if (colTex) { if (colTex) {
if (facTex) { if (facTex) {
fmt::printf("Warning: Mat [%s]: Can't handle both %s and %s textures; discarding %s.\n", name, colName, facName, facName); fmt::printf(
"Warning: Mat [%s]: Can't handle both %s and %s textures; discarding %s.\n",
name,
colName,
facName,
facName);
} }
return std::make_tuple(vec, colTex); return std::make_tuple(vec, colTex);
} }
@ -109,16 +115,23 @@ FbxTraditionalMaterialInfo::From(FbxSurfaceMaterial *fbxMaterial, const std::map
FbxVector4 transparency; FbxVector4 transparency;
// extract any existing textures only so we can warn that we're throwing them away // extract any existing textures only so we can warn that we're throwing them away
FbxFileTexture *colTex, *facTex; FbxFileTexture *colTex, *facTex;
std::tie(transparency, colTex, facTex) = std::tie(transparency, colTex, facTex) = getSurfaceValues(
getSurfaceValues(FbxSurfaceMaterial::sTransparentColor, FbxSurfaceMaterial::sTransparencyFactor); FbxSurfaceMaterial::sTransparentColor, FbxSurfaceMaterial::sTransparencyFactor);
if (colTex) { if (colTex) {
fmt::printf("Warning: Mat [%s]: Can't handle texture for %s; discarding.\n", name, FbxSurfaceMaterial::sTransparentColor); fmt::printf(
"Warning: Mat [%s]: Can't handle texture for %s; discarding.\n",
name,
FbxSurfaceMaterial::sTransparentColor);
} }
if (facTex) { if (facTex) {
fmt::printf("Warning: Mat [%s]: Can't handle texture for %s; discarding.\n", name, FbxSurfaceMaterial::sTransparencyFactor); fmt::printf(
"Warning: Mat [%s]: Can't handle texture for %s; discarding.\n",
name,
FbxSurfaceMaterial::sTransparencyFactor);
} }
// FBX color is RGB, so we calculate the A channel as the average of the FBX transparency color vector // FBX color is RGB, so we calculate the A channel as the average of the FBX transparency color
res->colDiffuse[3] = 1.0 - (transparency[0] + transparency[1] + transparency[2])/3.0; // vector
res->colDiffuse[3] = 1.0 - (transparency[0] + transparency[1] + transparency[2]) / 3.0;
return res; return res;
} }

View File

@ -7,38 +7,37 @@
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include <algorithm>
#include <fstream> #include <fstream>
#include <string>
#include <set>
#include <map> #include <map>
#include <set>
#include <string>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include <algorithm>
#include "FbxMaterialInfo.hpp" #include "FbxMaterialInfo.hpp"
struct FbxTraditionalMaterialInfo : FbxMaterialInfo { struct FbxTraditionalMaterialInfo : FbxMaterialInfo {
static constexpr const char *FBX_SHADER_LAMBERT = "Lambert"; static constexpr const char* FBX_SHADER_LAMBERT = "Lambert";
static constexpr const char *FBX_SHADER_BLINN = "Blinn"; static constexpr const char* FBX_SHADER_BLINN = "Blinn";
static constexpr const char *FBX_SHADER_PHONG = "Phong"; static constexpr const char* FBX_SHADER_PHONG = "Phong";
FbxTraditionalMaterialInfo(const FbxString &name, const FbxString &shadingModel) FbxTraditionalMaterialInfo(const FbxString& name, const FbxString& shadingModel)
: FbxMaterialInfo(name, shadingModel) : FbxMaterialInfo(name, shadingModel) {}
{}
FbxFileTexture *texAmbient {}; FbxFileTexture* texAmbient{};
FbxVector4 colAmbient {}; FbxVector4 colAmbient{};
FbxFileTexture *texSpecular {}; FbxFileTexture* texSpecular{};
FbxVector4 colSpecular {}; FbxVector4 colSpecular{};
FbxFileTexture *texDiffuse {}; FbxFileTexture* texDiffuse{};
FbxVector4 colDiffuse {}; FbxVector4 colDiffuse{};
FbxFileTexture *texEmissive {}; FbxFileTexture* texEmissive{};
FbxVector4 colEmissive {}; FbxVector4 colEmissive{};
FbxFileTexture *texNormal {}; FbxFileTexture* texNormal{};
FbxFileTexture *texShininess {}; FbxFileTexture* texShininess{};
FbxDouble shininess {}; FbxDouble shininess{};
static std::unique_ptr<FbxTraditionalMaterialInfo> From( static std::unique_ptr<FbxTraditionalMaterialInfo> From(
FbxSurfaceMaterial *fbxMaterial, FbxSurfaceMaterial* fbxMaterial,
const std::map<const FbxTexture *, FbxString> &textureLocations); const std::map<const FbxTexture*, FbxString>& textureLocations);
}; };

View File

@ -18,12 +18,14 @@ std::unique_ptr<FbxRoughMetMaterialInfo> Fbx3dsMaxPhysicalMaterialResolver::reso
FbxString shadingModel = fbxMaterial->ShadingModel.Get(); FbxString shadingModel = fbxMaterial->ShadingModel.Get();
if (!shadingModel.IsEmpty() && shadingModel != "unknown") { if (!shadingModel.IsEmpty() && shadingModel != "unknown") {
::fmt::printf("Warning: Material %s has surprising shading model: %s\n", ::fmt::printf(
fbxMaterial->GetName(), shadingModel); "Warning: Material %s has surprising shading model: %s\n",
fbxMaterial->GetName(),
shadingModel);
} }
auto getTex = [&](std::string propName) -> const FbxFileTexture * { auto getTex = [&](std::string propName) -> const FbxFileTexture* {
const FbxFileTexture *ptr = nullptr; const FbxFileTexture* ptr = nullptr;
const FbxProperty useProp = props.FindHierarchical((propName + "_map_on").c_str()); const FbxProperty useProp = props.FindHierarchical((propName + "_map_on").c_str());
if (useProp.IsValid() && useProp.Get<bool>()) { if (useProp.IsValid() && useProp.Get<bool>()) {
@ -35,8 +37,10 @@ std::unique_ptr<FbxRoughMetMaterialInfo> Fbx3dsMaxPhysicalMaterialResolver::reso
} }
} }
} else if (verboseOutput && useProp.IsValid()) { } else if (verboseOutput && useProp.IsValid()) {
fmt::printf("Note: property '%s' of 3dsMax Physical material '%s' exists, but is flagged as 'off'.\n", fmt::printf(
propName, fbxMaterial->GetName()); "Note: property '%s' of 3dsMax Physical material '%s' exists, but is flagged as 'off'.\n",
propName,
fbxMaterial->GetName());
} }
return ptr; return ptr;
}; };
@ -46,21 +50,21 @@ std::unique_ptr<FbxRoughMetMaterialInfo> Fbx3dsMaxPhysicalMaterialResolver::reso
// baseWeight && baseColor // baseWeight && baseColor
FbxDouble baseWeight = getValue(props, "base_weight", 1.0); FbxDouble baseWeight = getValue(props, "base_weight", 1.0);
const auto *baseWeightMap = getTex("base_weight"); const auto* baseWeightMap = getTex("base_weight");
FbxDouble4 baseCol = getValue(props, "base_color", FbxDouble4(0.5, 0.5, 0.5, 1.0)); FbxDouble4 baseCol = getValue(props, "base_color", FbxDouble4(0.5, 0.5, 0.5, 1.0));
const auto *baseTex = getTex("base_color"); const auto* baseTex = getTex("base_color");
double emissiveWeight = getValue(props, "emission", 0.0); double emissiveWeight = getValue(props, "emission", 0.0);
const auto *emissiveWeightMap = getTex("emission"); const auto* emissiveWeightMap = getTex("emission");
FbxDouble4 emissiveColor = getValue(props, "emit_color", FbxDouble4(1, 1, 1, 1)); FbxDouble4 emissiveColor = getValue(props, "emit_color", FbxDouble4(1, 1, 1, 1));
const auto *emissiveColorMap = getTex("emit_color"); const auto* emissiveColorMap = getTex("emit_color");
// TODO: emit_luminance, emit_kelvin? // TODO: emit_luminance, emit_kelvin?
// roughness & metalness: supported // roughness & metalness: supported
double roughness = getValue(props, "roughness", 0.0); double roughness = getValue(props, "roughness", 0.0);
const auto *roughnessMap = getTex("roughness"); const auto* roughnessMap = getTex("roughness");
double metalness = getValue(props, "metalness", 0.0); double metalness = getValue(props, "metalness", 0.0);
const auto *metalnessMap = getTex("metalness"); const auto* metalnessMap = getTex("metalness");
// TODO: does invertRoughness affect roughness_map too? // TODO: does invertRoughness affect roughness_map too?
bool invertRoughness = getValue(props, "inv_roughness", false); bool invertRoughness = getValue(props, "inv_roughness", false);
@ -70,17 +74,17 @@ std::unique_ptr<FbxRoughMetMaterialInfo> Fbx3dsMaxPhysicalMaterialResolver::reso
// TODO: attempt to bake transparency > 0.0f into the alpha of baseColour? // TODO: attempt to bake transparency > 0.0f into the alpha of baseColour?
double transparency = getValue(props, "transparency", 0.0); double transparency = getValue(props, "transparency", 0.0);
const auto *transparencyMap = getTex("transparency"); const auto* transparencyMap = getTex("transparency");
// SSS: not supported // SSS: not supported
double scattering = getValue(props, "scattering", 0.0); double scattering = getValue(props, "scattering", 0.0);
const auto *scatteringMap = getTex("scattering"); const auto* scatteringMap = getTex("scattering");
// reflectivity: not supported // reflectivity: not supported
double reflectivityWeight = getValue(props, "reflectivity", 1.); double reflectivityWeight = getValue(props, "reflectivity", 1.);
const auto *reflectivityWeightMap = getTex("reflectivity"); const auto* reflectivityWeightMap = getTex("reflectivity");
FbxDouble4 reflectivityColor = getValue(props, "refl_color", FbxDouble4(1, 1, 1, 1)); FbxDouble4 reflectivityColor = getValue(props, "refl_color", FbxDouble4(1, 1, 1, 1));
const auto *reflectivityColorMap = getTex("refl_color"); const auto* reflectivityColorMap = getTex("refl_color");
// coatings: not supported // coatings: not supported
double coating = getValue(props, "coating", 0.0); double coating = getValue(props, "coating", 0.0);
@ -95,18 +99,15 @@ std::unique_ptr<FbxRoughMetMaterialInfo> Fbx3dsMaxPhysicalMaterialResolver::reso
double anisotropy = getValue(props, "anisotropy", 1.0); double anisotropy = getValue(props, "anisotropy", 1.0);
// TODO: how the heck do we combine these to generate a normal map? // TODO: how the heck do we combine these to generate a normal map?
const auto *bumpMap = getTex("bump"); const auto* bumpMap = getTex("bump");
const auto *displacementMap = getTex("displacement"); const auto* displacementMap = getTex("displacement");
std::unique_ptr<FbxRoughMetMaterialInfo> res( std::unique_ptr<FbxRoughMetMaterialInfo> res(new FbxRoughMetMaterialInfo(
new FbxRoughMetMaterialInfo(
fbxMaterial->GetName(), fbxMaterial->GetName(),
FbxRoughMetMaterialInfo::FBX_SHADER_METROUGH, FbxRoughMetMaterialInfo::FBX_SHADER_METROUGH,
baseCol, baseCol,
metalness, metalness,
roughness roughness));
)
);
res->texBaseColor = baseTex; res->texBaseColor = baseTex;
res->baseWeight = baseWeight; res->baseWeight = baseWeight;
res->texBaseWeight = baseWeightMap; res->texBaseWeight = baseWeightMap;

View File

@ -11,21 +11,23 @@
#include "RoughnessMetallicMaterials.hpp" #include "RoughnessMetallicMaterials.hpp"
#include "TraditionalMaterials.hpp" #include "TraditionalMaterials.hpp"
FbxMaterialsAccess::FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<const FbxTexture *, FbxString> &textureLocations) : FbxMaterialsAccess::FbxMaterialsAccess(
mappingMode(FbxGeometryElement::eNone), const FbxMesh* pMesh,
mesh(nullptr), const std::map<const FbxTexture*, FbxString>& textureLocations)
indices(nullptr) : mappingMode(FbxGeometryElement::eNone), mesh(nullptr), indices(nullptr) {
{
if (pMesh->GetElementMaterialCount() <= 0) { if (pMesh->GetElementMaterialCount() <= 0) {
return; return;
} }
const FbxGeometryElement::EMappingMode materialMappingMode = pMesh->GetElementMaterial()->GetMappingMode(); const FbxGeometryElement::EMappingMode materialMappingMode =
if (materialMappingMode != FbxGeometryElement::eByPolygon && materialMappingMode != FbxGeometryElement::eAllSame) { pMesh->GetElementMaterial()->GetMappingMode();
if (materialMappingMode != FbxGeometryElement::eByPolygon &&
materialMappingMode != FbxGeometryElement::eAllSame) {
return; return;
} }
const FbxGeometryElement::EReferenceMode materialReferenceMode = pMesh->GetElementMaterial()->GetReferenceMode(); const FbxGeometryElement::EReferenceMode materialReferenceMode =
pMesh->GetElementMaterial()->GetReferenceMode();
if (materialReferenceMode != FbxGeometryElement::eIndexToDirect) { if (materialReferenceMode != FbxGeometryElement::eIndexToDirect) {
return; return;
} }
@ -45,28 +47,29 @@ FbxMaterialsAccess::FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<cons
auto summary = summaries[materialNum]; auto summary = summaries[materialNum];
if (summary == nullptr) { if (summary == nullptr) {
summary = summaries[materialNum] = GetMaterialInfo( summary = summaries[materialNum] = GetMaterialInfo(
mesh->GetNode()->GetSrcObject<FbxSurfaceMaterial>(materialNum), mesh->GetNode()->GetSrcObject<FbxSurfaceMaterial>(materialNum), textureLocations);
textureLocations);
} }
} }
} }
const std::shared_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterial(const int polygonIndex) const const std::shared_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterial(
{ const int polygonIndex) const {
if (mappingMode != FbxGeometryElement::eNone) { if (mappingMode != FbxGeometryElement::eNone) {
const int materialNum = indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0); const int materialNum =
indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0);
if (materialNum < 0) { if (materialNum < 0) {
return nullptr; return nullptr;
} }
return summaries.at((unsigned long) materialNum); return summaries.at((unsigned long)materialNum);
} }
return nullptr; return nullptr;
} }
std::unique_ptr<FbxMaterialInfo> std::unique_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterialInfo(
FbxMaterialsAccess::GetMaterialInfo(FbxSurfaceMaterial *material, const std::map<const FbxTexture *, FbxString> &textureLocations) FbxSurfaceMaterial* material,
{ const std::map<const FbxTexture*, FbxString>& textureLocations) {
std::unique_ptr<FbxMaterialInfo> res = FbxStingrayPBSMaterialResolver(material, textureLocations).resolve(); std::unique_ptr<FbxMaterialInfo> res =
FbxStingrayPBSMaterialResolver(material, textureLocations).resolve();
if (res == nullptr) { if (res == nullptr) {
res = Fbx3dsMaxPhysicalMaterialResolver(material, textureLocations).resolve(); res = Fbx3dsMaxPhysicalMaterialResolver(material, textureLocations).resolve();
if (res == nullptr) { if (res == nullptr) {
@ -75,4 +78,3 @@ FbxMaterialsAccess::GetMaterialInfo(FbxSurfaceMaterial *material, const std::map
} }
return res; return res;
} }

View File

@ -15,46 +15,43 @@
#include "FBX2glTF.h" #include "FBX2glTF.h"
class FbxMaterialInfo { class FbxMaterialInfo {
public: public:
FbxMaterialInfo(const FbxString &name, const FbxString &shadingModel) FbxMaterialInfo(const FbxString& name, const FbxString& shadingModel)
: name(name) : name(name), shadingModel(shadingModel) {}
, shadingModel(shadingModel)
{}
const FbxString name; const FbxString name;
const FbxString shadingModel; const FbxString shadingModel;
}; };
template <class T> template <class T>
class FbxMaterialResolver class FbxMaterialResolver {
{ public:
public:
FbxMaterialResolver( FbxMaterialResolver(
FbxSurfaceMaterial *fbxMaterial, FbxSurfaceMaterial* fbxMaterial,
const std::map<const FbxTexture *, FbxString> &textureLocations) const std::map<const FbxTexture*, FbxString>& textureLocations)
: fbxMaterial(fbxMaterial) : fbxMaterial(fbxMaterial), textureLocations(textureLocations) {}
, textureLocations(textureLocations)
{}
virtual std::unique_ptr<T> resolve() const = 0; virtual std::unique_ptr<T> resolve() const = 0;
protected: protected:
const FbxSurfaceMaterial *fbxMaterial; const FbxSurfaceMaterial* fbxMaterial;
const std::map<const FbxTexture *, FbxString> textureLocations; const std::map<const FbxTexture*, FbxString> textureLocations;
}; };
class FbxMaterialsAccess class FbxMaterialsAccess {
{ public:
public: FbxMaterialsAccess(
FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<const FbxTexture *, FbxString> &textureLocations); const FbxMesh* pMesh,
const std::map<const FbxTexture*, FbxString>& textureLocations);
const std::shared_ptr<FbxMaterialInfo> GetMaterial(const int polygonIndex) const; const std::shared_ptr<FbxMaterialInfo> GetMaterial(const int polygonIndex) const;
std::unique_ptr<FbxMaterialInfo> std::unique_ptr<FbxMaterialInfo> GetMaterialInfo(
GetMaterialInfo(FbxSurfaceMaterial *material, const std::map<const FbxTexture *, FbxString> &textureLocations); FbxSurfaceMaterial* material,
const std::map<const FbxTexture*, FbxString>& textureLocations);
private: private:
FbxGeometryElement::EMappingMode mappingMode; FbxGeometryElement::EMappingMode mappingMode;
std::vector<std::shared_ptr<FbxMaterialInfo>> summaries {}; std::vector<std::shared_ptr<FbxMaterialInfo>> summaries{};
const FbxMesh *mesh; const FbxMesh* mesh;
const FbxLayerElementArrayTemplate<int> *indices; const FbxLayerElementArrayTemplate<int>* indices;
}; };

View File

@ -14,24 +14,22 @@
#include "FbxMaterials.hpp" #include "FbxMaterials.hpp"
struct FbxRoughMetMaterialInfo : FbxMaterialInfo { struct FbxRoughMetMaterialInfo : FbxMaterialInfo {
static constexpr const char *FBX_SHADER_METROUGH = "MetallicRoughness"; static constexpr const char* FBX_SHADER_METROUGH = "MetallicRoughness";
static std::unique_ptr<FbxRoughMetMaterialInfo> From( static std::unique_ptr<FbxRoughMetMaterialInfo> From(
FbxSurfaceMaterial *fbxMaterial, FbxSurfaceMaterial* fbxMaterial,
const std::map<const FbxTexture *, FbxString> &textureLocations); const std::map<const FbxTexture*, FbxString>& textureLocations);
FbxRoughMetMaterialInfo( FbxRoughMetMaterialInfo(
const FbxString &name, const FbxString& name,
const FbxString &shadingModel, const FbxString& shadingModel,
FbxDouble4 baseColor, FbxDouble4 baseColor,
FbxDouble metallic, FbxDouble metallic,
FbxDouble roughness FbxDouble roughness)
) : FbxMaterialInfo(name, shadingModel),
: FbxMaterialInfo(name, shadingModel) baseColor(baseColor),
, baseColor(baseColor) metallic(metallic),
, metallic(metallic) roughness(roughness) {}
, roughness(roughness)
{}
const FbxVector4 baseColor; const FbxVector4 baseColor;
const FbxDouble metallic; const FbxDouble metallic;
@ -41,40 +39,38 @@ struct FbxRoughMetMaterialInfo : FbxMaterialInfo {
FbxVector4 emissive = FbxVector4(0, 0, 0, 1); FbxVector4 emissive = FbxVector4(0, 0, 0, 1);
FbxDouble emissiveIntensity = 1; FbxDouble emissiveIntensity = 1;
const FbxFileTexture *texNormal = nullptr; const FbxFileTexture* texNormal = nullptr;
const FbxFileTexture *texBaseColor = nullptr; const FbxFileTexture* texBaseColor = nullptr;
const FbxFileTexture *texBaseWeight = nullptr; const FbxFileTexture* texBaseWeight = nullptr;
const FbxFileTexture *texMetallic = nullptr; const FbxFileTexture* texMetallic = nullptr;
const FbxFileTexture *texRoughness = nullptr; const FbxFileTexture* texRoughness = nullptr;
const FbxFileTexture *texEmissive = nullptr; const FbxFileTexture* texEmissive = nullptr;
const FbxFileTexture *texEmissiveWeight = nullptr; const FbxFileTexture* texEmissiveWeight = nullptr;
const FbxFileTexture *texAmbientOcclusion = nullptr; const FbxFileTexture* texAmbientOcclusion = nullptr;
}; };
class FbxStingrayPBSMaterialResolver : FbxMaterialResolver<FbxRoughMetMaterialInfo> { class FbxStingrayPBSMaterialResolver : FbxMaterialResolver<FbxRoughMetMaterialInfo> {
public: public:
FbxStingrayPBSMaterialResolver( FbxStingrayPBSMaterialResolver(
FbxSurfaceMaterial *fbxMaterial, FbxSurfaceMaterial* fbxMaterial,
const std::map<const FbxTexture *, FbxString> &textureLocations) const std::map<const FbxTexture*, FbxString>& textureLocations)
: FbxMaterialResolver(fbxMaterial, textureLocations) : FbxMaterialResolver(fbxMaterial, textureLocations) {}
{}
virtual std::unique_ptr<FbxRoughMetMaterialInfo> resolve() const; virtual std::unique_ptr<FbxRoughMetMaterialInfo> resolve() const;
}; };
class Fbx3dsMaxPhysicalMaterialResolver : FbxMaterialResolver<FbxRoughMetMaterialInfo> { class Fbx3dsMaxPhysicalMaterialResolver : FbxMaterialResolver<FbxRoughMetMaterialInfo> {
public: public:
Fbx3dsMaxPhysicalMaterialResolver( Fbx3dsMaxPhysicalMaterialResolver(
FbxSurfaceMaterial *fbxMaterial, FbxSurfaceMaterial* fbxMaterial,
const std::map<const FbxTexture *, FbxString> &textureLocations) const std::map<const FbxTexture*, FbxString>& textureLocations)
: FbxMaterialResolver(fbxMaterial, textureLocations) : FbxMaterialResolver(fbxMaterial, textureLocations) {}
{}
virtual std::unique_ptr<FbxRoughMetMaterialInfo> resolve() const; virtual std::unique_ptr<FbxRoughMetMaterialInfo> resolve() const;
private: private:
template<typename T> template <typename T>
T getValue(const FbxProperty &props, std::string propName, const T& default) const { T getValue(const FbxProperty& props, std::string propName, const T& default) const {
const FbxProperty prop = props.FindHierarchical(propName.c_str()); const FbxProperty prop = props.FindHierarchical(propName.c_str());
return prop.IsValid() ? prop.Get<T>() : default; return prop.IsValid() ? prop.Get<T>() : default;
} }

View File

@ -15,12 +15,14 @@ std::unique_ptr<FbxRoughMetMaterialInfo> FbxStingrayPBSMaterialResolver::resolve
return nullptr; return nullptr;
} }
if (!fbxMaterial->ShadingModel.Get().IsEmpty()) { if (!fbxMaterial->ShadingModel.Get().IsEmpty()) {
::fmt::printf("Warning: Material %s has surprising shading model: %s\n", ::fmt::printf(
fbxMaterial->GetName(), fbxMaterial->ShadingModel.Get()); "Warning: Material %s has surprising shading model: %s\n",
fbxMaterial->GetName(),
fbxMaterial->ShadingModel.Get());
} }
auto getTex = [&](std::string propName) { auto getTex = [&](std::string propName) {
const FbxFileTexture *ptr = nullptr; const FbxFileTexture* ptr = nullptr;
const FbxProperty useProp = mayaProp.FindHierarchical(("use_" + propName + "_map").c_str()); const FbxProperty useProp = mayaProp.FindHierarchical(("use_" + propName + "_map").c_str());
if (useProp.IsValid() && useProp.Get<bool>()) { if (useProp.IsValid() && useProp.Get<bool>()) {
@ -32,8 +34,10 @@ std::unique_ptr<FbxRoughMetMaterialInfo> FbxStingrayPBSMaterialResolver::resolve
} }
} }
} else if (verboseOutput && useProp.IsValid()) { } else if (verboseOutput && useProp.IsValid()) {
fmt::printf("Note: Property '%s' of Stingray PBS material '%s' exists, but is flagged as 'do not use'.\n", fmt::printf(
propName, fbxMaterial->GetName()); "Note: Property '%s' of Stingray PBS material '%s' exists, but is flagged as 'do not use'.\n",
propName,
fbxMaterial->GetName());
} }
return ptr; return ptr;
}; };
@ -44,20 +48,17 @@ std::unique_ptr<FbxRoughMetMaterialInfo> FbxStingrayPBSMaterialResolver::resolve
}; };
auto getVal = [&](std::string propName) -> FbxDouble { auto getVal = [&](std::string propName) -> FbxDouble {
const FbxProperty vecProp = mayaProp.FindHierarchical(propName .c_str()); const FbxProperty vecProp = mayaProp.FindHierarchical(propName.c_str());
return vecProp.IsValid() ? vecProp.Get<FbxDouble>() : 0; return vecProp.IsValid() ? vecProp.Get<FbxDouble>() : 0;
}; };
FbxDouble3 baseColor = getVec("base_color"); FbxDouble3 baseColor = getVec("base_color");
std::unique_ptr<FbxRoughMetMaterialInfo> res( std::unique_ptr<FbxRoughMetMaterialInfo> res(new FbxRoughMetMaterialInfo(
new FbxRoughMetMaterialInfo(
fbxMaterial->GetName(), fbxMaterial->GetName(),
FbxRoughMetMaterialInfo::FBX_SHADER_METROUGH, FbxRoughMetMaterialInfo::FBX_SHADER_METROUGH,
FbxDouble4(baseColor[0], baseColor[1], baseColor[2], 1), FbxDouble4(baseColor[0], baseColor[1], baseColor[2], 1),
getVal("metallic"), getVal("metallic"),
getVal("roughness") getVal("roughness")));
)
);
res->texNormal = getTex("normal"); res->texNormal = getTex("normal");
res->texBaseColor = getTex("color"); res->texBaseColor = getTex("color");
res->texAmbientOcclusion = getTex("ao"); res->texAmbientOcclusion = getTex("ao");

View File

@ -9,13 +9,12 @@
#include "TraditionalMaterials.hpp" #include "TraditionalMaterials.hpp"
std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialResolver::resolve() const std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialResolver::resolve() const {
{ auto getSurfaceScalar = [&](const char* propName) -> std::tuple<FbxDouble, FbxFileTexture*> {
auto getSurfaceScalar = [&](const char *propName) -> std::tuple<FbxDouble, FbxFileTexture *> {
const FbxProperty prop = fbxMaterial->FindProperty(propName); const FbxProperty prop = fbxMaterial->FindProperty(propName);
FbxDouble val(0); FbxDouble val(0);
FbxFileTexture *tex = prop.GetSrcObject<FbxFileTexture>(); FbxFileTexture* tex = prop.GetSrcObject<FbxFileTexture>();
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) { if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
tex = nullptr; tex = nullptr;
} }
@ -25,11 +24,11 @@ std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialResolver::reso
return std::make_tuple(val, tex); return std::make_tuple(val, tex);
}; };
auto getSurfaceVector = [&](const char *propName) -> std::tuple<FbxDouble3, FbxFileTexture *> { auto getSurfaceVector = [&](const char* propName) -> std::tuple<FbxDouble3, FbxFileTexture*> {
const FbxProperty prop = fbxMaterial->FindProperty(propName); const FbxProperty prop = fbxMaterial->FindProperty(propName);
FbxDouble3 val(1, 1, 1); FbxDouble3 val(1, 1, 1);
FbxFileTexture *tex = prop.GetSrcObject<FbxFileTexture>(); FbxFileTexture* tex = prop.GetSrcObject<FbxFileTexture>();
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) { if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
tex = nullptr; tex = nullptr;
} }
@ -39,21 +38,23 @@ std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialResolver::reso
return std::make_tuple(val, tex); return std::make_tuple(val, tex);
}; };
auto getSurfaceValues = [&](const char *colName, const char *facName) -> std::tuple<FbxVector4, FbxFileTexture *, FbxFileTexture *> { auto getSurfaceValues =
[&](const char* colName,
const char* facName) -> std::tuple<FbxVector4, FbxFileTexture*, FbxFileTexture*> {
const FbxProperty colProp = fbxMaterial->FindProperty(colName); const FbxProperty colProp = fbxMaterial->FindProperty(colName);
const FbxProperty facProp = fbxMaterial->FindProperty(facName); const FbxProperty facProp = fbxMaterial->FindProperty(facName);
FbxDouble3 colorVal(1, 1, 1); FbxDouble3 colorVal(1, 1, 1);
FbxDouble factorVal(1); FbxDouble factorVal(1);
FbxFileTexture *colTex = colProp.GetSrcObject<FbxFileTexture>(); FbxFileTexture* colTex = colProp.GetSrcObject<FbxFileTexture>();
if (colTex != nullptr && textureLocations.find(colTex) == textureLocations.end()) { if (colTex != nullptr && textureLocations.find(colTex) == textureLocations.end()) {
colTex = nullptr; colTex = nullptr;
} }
if (colTex == nullptr && colProp.IsValid()) { if (colTex == nullptr && colProp.IsValid()) {
colorVal = colProp.Get<FbxDouble3>(); colorVal = colProp.Get<FbxDouble3>();
} }
FbxFileTexture *facTex = facProp.GetSrcObject<FbxFileTexture>(); FbxFileTexture* facTex = facProp.GetSrcObject<FbxFileTexture>();
if (facTex != nullptr && textureLocations.find(facTex) == textureLocations.end()) { if (facTex != nullptr && textureLocations.find(facTex) == textureLocations.end()) {
facTex = nullptr; facTex = nullptr;
} }
@ -62,25 +63,29 @@ std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialResolver::reso
} }
auto val = FbxVector4( auto val = FbxVector4(
colorVal[0] * factorVal, colorVal[0] * factorVal, colorVal[1] * factorVal, colorVal[2] * factorVal, factorVal);
colorVal[1] * factorVal,
colorVal[2] * factorVal,
factorVal);
return std::make_tuple(val, colTex, facTex); return std::make_tuple(val, colTex, facTex);
}; };
std::string name = fbxMaterial->GetName(); std::string name = fbxMaterial->GetName();
std::unique_ptr<FbxTraditionalMaterialInfo> res(new FbxTraditionalMaterialInfo(name.c_str(), fbxMaterial->ShadingModel.Get())); std::unique_ptr<FbxTraditionalMaterialInfo> res(
new FbxTraditionalMaterialInfo(name.c_str(), fbxMaterial->ShadingModel.Get()));
// four properties are on the same structure and follow the same rules // four properties are on the same structure and follow the same rules
auto handleBasicProperty = [&](const char *colName, const char *facName) -> std::tuple<FbxVector4, FbxFileTexture *>{ auto handleBasicProperty = [&](const char* colName,
const char* facName) -> std::tuple<FbxVector4, FbxFileTexture*> {
FbxFileTexture *colTex, *facTex; FbxFileTexture *colTex, *facTex;
FbxVector4 vec; FbxVector4 vec;
std::tie(vec, colTex, facTex) = getSurfaceValues(colName, facName); std::tie(vec, colTex, facTex) = getSurfaceValues(colName, facName);
if (colTex) { if (colTex) {
if (facTex) { if (facTex) {
fmt::printf("Warning: Mat [%s]: Can't handle both %s and %s textures; discarding %s.\n", name, colName, facName, facName); fmt::printf(
"Warning: Mat [%s]: Can't handle both %s and %s textures; discarding %s.\n",
name,
colName,
facName,
facName);
} }
return std::make_tuple(vec, colTex); return std::make_tuple(vec, colTex);
} }
@ -108,16 +113,23 @@ std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialResolver::reso
FbxVector4 transparency; FbxVector4 transparency;
// extract any existing textures only so we can warn that we're throwing them away // extract any existing textures only so we can warn that we're throwing them away
FbxFileTexture *colTex, *facTex; FbxFileTexture *colTex, *facTex;
std::tie(transparency, colTex, facTex) = std::tie(transparency, colTex, facTex) = getSurfaceValues(
getSurfaceValues(FbxSurfaceMaterial::sTransparentColor, FbxSurfaceMaterial::sTransparencyFactor); FbxSurfaceMaterial::sTransparentColor, FbxSurfaceMaterial::sTransparencyFactor);
if (colTex) { if (colTex) {
fmt::printf("Warning: Mat [%s]: Can't handle texture for %s; discarding.\n", name, FbxSurfaceMaterial::sTransparentColor); fmt::printf(
"Warning: Mat [%s]: Can't handle texture for %s; discarding.\n",
name,
FbxSurfaceMaterial::sTransparentColor);
} }
if (facTex) { if (facTex) {
fmt::printf("Warning: Mat [%s]: Can't handle texture for %s; discarding.\n", name, FbxSurfaceMaterial::sTransparencyFactor); fmt::printf(
"Warning: Mat [%s]: Can't handle texture for %s; discarding.\n",
name,
FbxSurfaceMaterial::sTransparencyFactor);
} }
// FBX color is RGB, so we calculate the A channel as the average of the FBX transparency color vector // FBX color is RGB, so we calculate the A channel as the average of the FBX transparency color
res->colDiffuse[3] = 1.0 - (transparency[0] + transparency[1] + transparency[2])/3.0; // vector
res->colDiffuse[3] = 1.0 - (transparency[0] + transparency[1] + transparency[2]) / 3.0;
return res; return res;
} }

View File

@ -10,34 +10,32 @@
#include "FbxMaterials.hpp" #include "FbxMaterials.hpp"
struct FbxTraditionalMaterialInfo : FbxMaterialInfo { struct FbxTraditionalMaterialInfo : FbxMaterialInfo {
static constexpr const char *FBX_SHADER_LAMBERT = "Lambert"; static constexpr const char* FBX_SHADER_LAMBERT = "Lambert";
static constexpr const char *FBX_SHADER_BLINN = "Blinn"; static constexpr const char* FBX_SHADER_BLINN = "Blinn";
static constexpr const char *FBX_SHADER_PHONG = "Phong"; static constexpr const char* FBX_SHADER_PHONG = "Phong";
FbxTraditionalMaterialInfo(const FbxString &name, const FbxString &shadingModel) FbxTraditionalMaterialInfo(const FbxString& name, const FbxString& shadingModel)
: FbxMaterialInfo(name, shadingModel) : FbxMaterialInfo(name, shadingModel) {}
{}
FbxFileTexture *texAmbient {}; FbxFileTexture* texAmbient{};
FbxVector4 colAmbient {}; FbxVector4 colAmbient{};
FbxFileTexture *texSpecular {}; FbxFileTexture* texSpecular{};
FbxVector4 colSpecular {}; FbxVector4 colSpecular{};
FbxFileTexture *texDiffuse {}; FbxFileTexture* texDiffuse{};
FbxVector4 colDiffuse {}; FbxVector4 colDiffuse{};
FbxFileTexture *texEmissive {}; FbxFileTexture* texEmissive{};
FbxVector4 colEmissive {}; FbxVector4 colEmissive{};
FbxFileTexture *texNormal {}; FbxFileTexture* texNormal{};
FbxFileTexture *texShininess {}; FbxFileTexture* texShininess{};
FbxDouble shininess {}; FbxDouble shininess{};
}; };
class FbxTraditionalMaterialResolver : FbxMaterialResolver<FbxTraditionalMaterialInfo> { class FbxTraditionalMaterialResolver : FbxMaterialResolver<FbxTraditionalMaterialInfo> {
public: public:
FbxTraditionalMaterialResolver( FbxTraditionalMaterialResolver(
FbxSurfaceMaterial *fbxMaterial, FbxSurfaceMaterial* fbxMaterial,
const std::map<const FbxTexture *, FbxString> &textureLocations) const std::map<const FbxTexture*, FbxString>& textureLocations)
: FbxMaterialResolver(fbxMaterial, textureLocations) : FbxMaterialResolver(fbxMaterial, textureLocations) {}
{}
virtual std::unique_ptr<FbxTraditionalMaterialInfo> resolve() const; virtual std::unique_ptr<FbxTraditionalMaterialInfo> resolve() const;
}; };

View File

@ -1,16 +1,17 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "GltfModel.hpp" #include "GltfModel.hpp"
std::shared_ptr<BufferViewData> GltfModel::GetAlignedBufferView(BufferData &buffer, const BufferViewData::GL_ArrayType target) std::shared_ptr<BufferViewData> GltfModel::GetAlignedBufferView(
{ BufferData& buffer,
const BufferViewData::GL_ArrayType target) {
unsigned long bufferSize = this->binary->size(); unsigned long bufferSize = this->binary->size();
if ((bufferSize % 4) > 0) { if ((bufferSize % 4) > 0) {
bufferSize += (4 - (bufferSize % 4)); bufferSize += (4 - (bufferSize % 4));
@ -20,8 +21,8 @@ std::shared_ptr<BufferViewData> GltfModel::GetAlignedBufferView(BufferData &buff
} }
// add a bufferview on the fly and copy data into it // add a bufferview on the fly and copy data into it
std::shared_ptr<BufferViewData> GltfModel::AddRawBufferView(BufferData &buffer, const char *source, uint32_t bytes) std::shared_ptr<BufferViewData>
{ GltfModel::AddRawBufferView(BufferData& buffer, const char* source, uint32_t bytes) {
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE); auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE);
bufferView->byteLength = bytes; bufferView->byteLength = bytes;
@ -34,8 +35,9 @@ std::shared_ptr<BufferViewData> GltfModel::AddRawBufferView(BufferData &buffer,
return bufferView; return bufferView;
} }
std::shared_ptr<BufferViewData> GltfModel::AddBufferViewForFile(BufferData &buffer, const std::string &filename) std::shared_ptr<BufferViewData> GltfModel::AddBufferViewForFile(
{ BufferData& buffer,
const std::string& filename) {
// see if we've already created a BufferViewData for this precise file // see if we've already created a BufferViewData for this precise file
auto iter = filenameToBufferView.find(filename); auto iter = filenameToBufferView.find(filename);
if (iter != filenameToBufferView.end()) { if (iter != filenameToBufferView.end()) {
@ -62,8 +64,7 @@ std::shared_ptr<BufferViewData> GltfModel::AddBufferViewForFile(BufferData &buff
return result; return result;
} }
void GltfModel::serializeHolders(json &glTFJson) void GltfModel::serializeHolders(json& glTFJson) {
{
serializeHolder(glTFJson, "buffers", buffers); serializeHolder(glTFJson, "buffers", buffers);
serializeHolder(glTFJson, "bufferViews", bufferViews); serializeHolder(glTFJson, "bufferViews", bufferViews);
serializeHolder(glTFJson, "scenes", scenes); serializeHolder(glTFJson, "scenes", scenes);

View File

@ -1,11 +1,11 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once
@ -30,21 +30,20 @@
#include "gltf/properties/TextureData.hpp" #include "gltf/properties/TextureData.hpp"
/** /**
* glTF 2.0 is based on the idea that data structs within a file are referenced by index; an accessor will * glTF 2.0 is based on the idea that data structs within a file are referenced by index; an
* point to the n:th buffer view, and so on. The Holder class takes a freshly instantiated class, and then * accessor will point to the n:th buffer view, and so on. The Holder class takes a freshly
* creates, stored, and returns a shared_ptr<T> for it. * instantiated class, and then creates, stored, and returns a shared_ptr<T> for it.
* *
* The idea is that every glTF resource in the file will live as long as the Holder does, and the Holders * The idea is that every glTF resource in the file will live as long as the Holder does, and the
* are all kept in the GLTFData struct. Clients may certainly cnhoose to perpetuate the full shared_ptr<T> * Holders are all kept in the GLTFData struct. Clients may certainly cnhoose to perpetuate the full
* reference counting type, but generally speaking we pass around simple T& and T* types because the GLTFData * shared_ptr<T> reference counting type, but generally speaking we pass around simple T& and T*
* struct will, by design, outlive all other activity that takes place during in a single conversion run. * types because the GLTFData struct will, by design, outlive all other activity that takes place
*/ * during in a single conversion run.
template<typename T> */
class Holder template <typename T>
{ class Holder {
public: public:
std::shared_ptr<T> hold(T *ptr) std::shared_ptr<T> hold(T* ptr) {
{
ptr->ix = ptrs.size(); ptr->ix = ptrs.size();
ptrs.emplace_back(ptr); ptrs.emplace_back(ptr);
return ptrs.back(); return ptrs.back();
@ -52,53 +51,60 @@ public:
std::vector<std::shared_ptr<T>> ptrs; std::vector<std::shared_ptr<T>> ptrs;
}; };
class GltfModel class GltfModel {
{ public:
public: explicit GltfModel(const GltfOptions& options)
explicit GltfModel(const GltfOptions &options) : binary(new std::vector<uint8_t>),
: binary(new std::vector<uint8_t>) isGlb(options.outputBinary),
, isGlb(options.outputBinary) defaultSampler(nullptr),
, defaultSampler(nullptr) defaultBuffer(buffers.hold(buildDefaultBuffer(options))) {
, defaultBuffer(buffers.hold(buildDefaultBuffer(options)))
{
defaultSampler = samplers.hold(buildDefaultSampler()); defaultSampler = samplers.hold(buildDefaultSampler());
} }
std::shared_ptr<BufferViewData> GetAlignedBufferView(BufferData &buffer, const BufferViewData::GL_ArrayType target); std::shared_ptr<BufferViewData> GetAlignedBufferView(
std::shared_ptr<BufferViewData> AddRawBufferView(BufferData &buffer, const char *source, uint32_t bytes); BufferData& buffer,
std::shared_ptr<BufferViewData> AddBufferViewForFile(BufferData &buffer, const std::string &filename); const BufferViewData::GL_ArrayType target);
std::shared_ptr<BufferViewData>
AddRawBufferView(BufferData& buffer, const char* source, uint32_t bytes);
std::shared_ptr<BufferViewData> AddBufferViewForFile(
BufferData& buffer,
const std::string& filename);
template<class T> template <class T>
std::shared_ptr<AccessorData> AddAccessorWithView( std::shared_ptr<AccessorData> AddAccessorWithView(
BufferViewData &bufferView, const GLType &type, const std::vector<T> &source, std::string name) BufferViewData& bufferView,
{ const GLType& type,
const std::vector<T>& source,
std::string name) {
auto accessor = accessors.hold(new AccessorData(bufferView, type, name)); auto accessor = accessors.hold(new AccessorData(bufferView, type, name));
accessor->appendAsBinaryArray(source, *binary); accessor->appendAsBinaryArray(source, *binary);
bufferView.byteLength = accessor->byteLength(); bufferView.byteLength = accessor->byteLength();
return accessor; return accessor;
} }
template<class T> template <class T>
std::shared_ptr<AccessorData> AddAccessorAndView( std::shared_ptr<AccessorData>
BufferData &buffer, const GLType &type, const std::vector<T> &source) AddAccessorAndView(BufferData& buffer, const GLType& type, const std::vector<T>& source) {
{
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE); auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE);
return AddAccessorWithView(*bufferView, type, source, std::string("")); return AddAccessorWithView(*bufferView, type, source, std::string(""));
} }
template<class T> template <class T>
std::shared_ptr<AccessorData> AddAccessorAndView( std::shared_ptr<AccessorData> AddAccessorAndView(
BufferData &buffer, const GLType &type, const std::vector<T> &source, std::string name) BufferData& buffer,
{ const GLType& type,
const std::vector<T>& source,
std::string name) {
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE); auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE);
return AddAccessorWithView(*bufferView, type, source, name); return AddAccessorWithView(*bufferView, type, source, name);
} }
template<class T> template <class T>
std::shared_ptr<AccessorData> AddAttributeToPrimitive( std::shared_ptr<AccessorData> AddAttributeToPrimitive(
BufferData &buffer, const RawModel &surfaceModel, PrimitiveData &primitive, BufferData& buffer,
const AttributeDefinition<T> &attrDef) const RawModel& surfaceModel,
{ PrimitiveData& primitive,
const AttributeDefinition<T>& attrDef) {
// copy attribute data into vector // copy attribute data into vector
std::vector<T> attribArr; std::vector<T> attribArr;
surfaceModel.GetAttributeArray<T>(attribArr, attrDef.rawAttributeIx); surfaceModel.GetAttributeArray<T>(attribArr, attrDef.rawAttributeIx);
@ -117,19 +123,18 @@ public:
return accessor; return accessor;
}; };
template<class T> template <class T>
void serializeHolder(json &glTFJson, std::string key, const Holder<T> holder) void serializeHolder(json& glTFJson, std::string key, const Holder<T> holder) {
{
if (!holder.ptrs.empty()) { if (!holder.ptrs.empty()) {
std::vector<json> bits; std::vector<json> bits;
for (const auto &ptr : holder.ptrs) { for (const auto& ptr : holder.ptrs) {
bits.push_back(ptr->serialize()); bits.push_back(ptr->serialize());
} }
glTFJson[key] = bits; glTFJson[key] = bits;
} }
} }
void serializeHolders(json &glTFJson); void serializeHolders(json& glTFJson);
const bool isGlb; const bool isGlb;
@ -156,13 +161,12 @@ public:
std::shared_ptr<SamplerData> defaultSampler; std::shared_ptr<SamplerData> defaultSampler;
std::shared_ptr<BufferData> defaultBuffer; std::shared_ptr<BufferData> defaultBuffer;
private: private:
SamplerData *buildDefaultSampler() { SamplerData* buildDefaultSampler() {
return new SamplerData(); return new SamplerData();
} }
BufferData *buildDefaultBuffer(const GltfOptions &options) { BufferData* buildDefaultBuffer(const GltfOptions& options) {
return options.outputBinary ? return options.outputBinary ? new BufferData(binary)
new BufferData(binary) : : new BufferData(extBufferFilename, binary, options.embedResources);
new BufferData(extBufferFilename, binary, options.embedResources);
} }
}; };

View File

@ -9,17 +9,17 @@
#include "Raw2Gltf.hpp" #include "Raw2Gltf.hpp"
#include <cstdint>
#include <cassert> #include <cassert>
#include <iostream> #include <cstdint>
#include <fstream> #include <fstream>
#include <iostream>
#include <stb_image.h> #include <stb_image.h>
#include <stb_image_write.h> #include <stb_image_write.h>
#include "utils/String_Utils.hpp"
#include "utils/Image_Utils.hpp"
#include <utils/File_Utils.hpp> #include <utils/File_Utils.hpp>
#include "utils/Image_Utils.hpp"
#include "utils/String_Utils.hpp"
#include "raw/RawModel.hpp" #include "raw/RawModel.hpp"
@ -38,8 +38,8 @@
#include "gltf/properties/SkinData.hpp" #include "gltf/properties/SkinData.hpp"
#include "gltf/properties/TextureData.hpp" #include "gltf/properties/TextureData.hpp"
#include "TextureBuilder.hpp"
#include "GltfModel.hpp" #include "GltfModel.hpp"
#include "TextureBuilder.hpp"
typedef uint32_t TriangleIndex; typedef uint32_t TriangleIndex;
@ -50,53 +50,50 @@ typedef uint32_t TriangleIndex;
* registered under that name. This is safe in the context of this tool, where all such data * registered under that name. This is safe in the context of this tool, where all such data
* classes are guaranteed to stick around for the duration of the process. * classes are guaranteed to stick around for the duration of the process.
*/ */
template<typename T> template <typename T>
T &require(std::map<std::string, std::shared_ptr<T>> map, const std::string &key) T& require(std::map<std::string, std::shared_ptr<T>> map, const std::string& key) {
{
auto iter = map.find(key); auto iter = map.find(key);
assert(iter != map.end()); assert(iter != map.end());
T &result = *iter->second; T& result = *iter->second;
return result; return result;
} }
template<typename T> template <typename T>
T &require(std::map<long, std::shared_ptr<T>> map, long key) T& require(std::map<long, std::shared_ptr<T>> map, long key) {
{
auto iter = map.find(key); auto iter = map.find(key);
assert(iter != map.end()); assert(iter != map.end());
T &result = *iter->second; T& result = *iter->second;
return result; return result;
} }
static const std::vector<TriangleIndex> getIndexArray(const RawModel &raw) static const std::vector<TriangleIndex> getIndexArray(const RawModel& raw) {
{
std::vector<TriangleIndex> result; std::vector<TriangleIndex> result;
for (int i = 0; i < raw.GetTriangleCount(); i++) { for (int i = 0; i < raw.GetTriangleCount(); i++) {
result.push_back((TriangleIndex) raw.GetTriangle(i).verts[0]); result.push_back((TriangleIndex)raw.GetTriangle(i).verts[0]);
result.push_back((TriangleIndex) raw.GetTriangle(i).verts[1]); result.push_back((TriangleIndex)raw.GetTriangle(i).verts[1]);
result.push_back((TriangleIndex) raw.GetTriangle(i).verts[2]); result.push_back((TriangleIndex)raw.GetTriangle(i).verts[2]);
} }
return result; return result;
} }
// TODO: replace with a proper MaterialHasher class // TODO: replace with a proper MaterialHasher class
static const std::string materialHash(const RawMaterial &m) { static const std::string materialHash(const RawMaterial& m) {
return m.name + "_" + std::to_string(m.type); return m.name + "_" + std::to_string(m.type);
} }
ModelData *Raw2Gltf( ModelData* Raw2Gltf(
std::ofstream &gltfOutStream, std::ofstream& gltfOutStream,
const std::string &outputFolder, const std::string& outputFolder,
const RawModel &raw, const RawModel& raw,
const GltfOptions &options const GltfOptions& options) {
)
{
if (verboseOutput) { if (verboseOutput) {
fmt::printf("Building render model...\n"); fmt::printf("Building render model...\n");
for (int i = 0; i < raw.GetMaterialCount(); i++) { for (int i = 0; i < raw.GetMaterialCount(); i++) {
fmt::printf( fmt::printf(
"Material %d: %s [shading: %s]\n", i, raw.GetMaterial(i).name.c_str(), "Material %d: %s [shading: %s]\n",
i,
raw.GetMaterial(i).name.c_str(),
Describe(raw.GetMaterial(i).info->shadingModel)); Describe(raw.GetMaterial(i).info->shadingModel));
} }
if (raw.GetVertexCount() > 2 * raw.GetTriangleCount()) { if (raw.GetVertexCount() > 2 * raw.GetTriangleCount()) {
@ -117,7 +114,7 @@ ModelData *Raw2Gltf(
fmt::printf("%7d triangles\n", raw.GetTriangleCount()); fmt::printf("%7d triangles\n", raw.GetTriangleCount());
fmt::printf("%7d textures\n", raw.GetTextureCount()); fmt::printf("%7d textures\n", raw.GetTextureCount());
fmt::printf("%7d nodes\n", raw.GetNodeCount()); fmt::printf("%7d nodes\n", raw.GetNodeCount());
fmt::printf("%7d surfaces\n", (int) materialModels.size()); fmt::printf("%7d surfaces\n", (int)materialModels.size());
fmt::printf("%7d animations\n", raw.GetAnimationCount()); fmt::printf("%7d animations\n", raw.GetAnimationCount());
fmt::printf("%7d cameras\n", raw.GetCameraCount()); fmt::printf("%7d cameras\n", raw.GetCameraCount());
fmt::printf("%7d lights\n", raw.GetLightCount()); fmt::printf("%7d lights\n", raw.GetLightCount());
@ -130,8 +127,9 @@ ModelData *Raw2Gltf(
std::map<std::string, std::shared_ptr<TextureData>> textureByIndicesKey; std::map<std::string, std::shared_ptr<TextureData>> textureByIndicesKey;
std::map<long, std::shared_ptr<MeshData>> meshBySurfaceId; std::map<long, std::shared_ptr<MeshData>> meshBySurfaceId;
// for now, we only have one buffer; data->binary points to the same vector as that BufferData does. // for now, we only have one buffer; data->binary points to the same vector as that BufferData
BufferData &buffer = *gltf->defaultBuffer; // does.
BufferData& buffer = *gltf->defaultBuffer;
{ {
// //
// nodes // nodes
@ -139,7 +137,7 @@ ModelData *Raw2Gltf(
for (int i = 0; i < raw.GetNodeCount(); i++) { for (int i = 0; i < raw.GetNodeCount(); i++) {
// assumption: RawNode index == NodeData index // assumption: RawNode index == NodeData index
const RawNode &node = raw.GetNode(i); const RawNode& node = raw.GetNode(i);
auto nodeData = gltf->nodes.hold( auto nodeData = gltf->nodes.hold(
new NodeData(node.name, node.translation, node.rotation, node.scale, node.isJoint)); new NodeData(node.name, node.translation, node.rotation, node.scale, node.isJoint));
@ -148,7 +146,7 @@ ModelData *Raw2Gltf(
nodeData->userProperties = node.userProperties; nodeData->userProperties = node.userProperties;
} }
for (const auto &childId : node.childIds) { for (const auto& childId : node.childIds) {
int childIx = raw.GetNodeById(childId); int childIx = raw.GetNodeById(childId);
assert(childIx >= 0); assert(childIx >= 0);
nodeData->AddChildNode(childIx); nodeData->AddChildNode(childIx);
@ -162,45 +160,61 @@ ModelData *Raw2Gltf(
// //
for (int i = 0; i < raw.GetAnimationCount(); i++) { for (int i = 0; i < raw.GetAnimationCount(); i++) {
const RawAnimation &animation = raw.GetAnimation(i); const RawAnimation& animation = raw.GetAnimation(i);
if (animation.channels.size() == 0) { if (animation.channels.size() == 0) {
fmt::printf("Warning: animation '%s' has zero channels. Skipping.\n", animation.name.c_str()); fmt::printf(
"Warning: animation '%s' has zero channels. Skipping.\n", animation.name.c_str());
continue; continue;
} }
auto accessor = gltf->AddAccessorAndView(buffer, GLT_FLOAT, animation.times); auto accessor = gltf->AddAccessorAndView(buffer, GLT_FLOAT, animation.times);
accessor->min = { *std::min_element(std::begin(animation.times), std::end(animation.times)) }; accessor->min = {*std::min_element(std::begin(animation.times), std::end(animation.times))};
accessor->max = { *std::max_element(std::begin(animation.times), std::end(animation.times)) }; accessor->max = {*std::max_element(std::begin(animation.times), std::end(animation.times))};
AnimationData &aDat = *gltf->animations.hold(new AnimationData(animation.name, *accessor)); AnimationData& aDat = *gltf->animations.hold(new AnimationData(animation.name, *accessor));
if (verboseOutput) { if (verboseOutput) {
fmt::printf("Animation '%s' has %lu channels:\n", animation.name.c_str(), animation.channels.size()); fmt::printf(
"Animation '%s' has %lu channels:\n",
animation.name.c_str(),
animation.channels.size());
} }
for (size_t channelIx = 0; channelIx < animation.channels.size(); channelIx++) { for (size_t channelIx = 0; channelIx < animation.channels.size(); channelIx++) {
const RawChannel &channel = animation.channels[channelIx]; const RawChannel& channel = animation.channels[channelIx];
const RawNode &node = raw.GetNode(channel.nodeIndex); const RawNode& node = raw.GetNode(channel.nodeIndex);
if (verboseOutput) { if (verboseOutput) {
fmt::printf( fmt::printf(
" Channel %lu (%s) has translations/rotations/scales/weights: [%lu, %lu, %lu, %lu]\n", " Channel %lu (%s) has translations/rotations/scales/weights: [%lu, %lu, %lu, %lu]\n",
channelIx, node.name.c_str(), channel.translations.size(), channel.rotations.size(), channelIx,
channel.scales.size(), channel.weights.size()); node.name.c_str(),
channel.translations.size(),
channel.rotations.size(),
channel.scales.size(),
channel.weights.size());
} }
NodeData &nDat = require(nodesById, node.id); NodeData& nDat = require(nodesById, node.id);
if (!channel.translations.empty()) { if (!channel.translations.empty()) {
aDat.AddNodeChannel(nDat, *gltf->AddAccessorAndView(buffer, GLT_VEC3F, channel.translations), "translation"); aDat.AddNodeChannel(
nDat,
*gltf->AddAccessorAndView(buffer, GLT_VEC3F, channel.translations),
"translation");
} }
if (!channel.rotations.empty()) { if (!channel.rotations.empty()) {
aDat.AddNodeChannel(nDat, *gltf->AddAccessorAndView(buffer, GLT_QUATF, channel.rotations), "rotation"); aDat.AddNodeChannel(
nDat, *gltf->AddAccessorAndView(buffer, GLT_QUATF, channel.rotations), "rotation");
} }
if (!channel.scales.empty()) { if (!channel.scales.empty()) {
aDat.AddNodeChannel(nDat, *gltf->AddAccessorAndView(buffer, GLT_VEC3F, channel.scales), "scale"); aDat.AddNodeChannel(
nDat, *gltf->AddAccessorAndView(buffer, GLT_VEC3F, channel.scales), "scale");
} }
if (!channel.weights.empty()) { if (!channel.weights.empty()) {
aDat.AddNodeChannel(nDat, *gltf->AddAccessorAndView(buffer, {CT_FLOAT, 1, "SCALAR"}, channel.weights), "weights"); aDat.AddNodeChannel(
nDat,
*gltf->AddAccessorAndView(buffer, {CT_FLOAT, 1, "SCALAR"}, channel.weights),
"weights");
} }
} }
} }
@ -219,9 +233,8 @@ ModelData *Raw2Gltf(
// //
for (int materialIndex = 0; materialIndex < raw.GetMaterialCount(); materialIndex++) { for (int materialIndex = 0; materialIndex < raw.GetMaterialCount(); materialIndex++) {
const RawMaterial &material = raw.GetMaterial(materialIndex); const RawMaterial& material = raw.GetMaterial(materialIndex);
const bool isTransparent = const bool isTransparent = material.type == RAW_MATERIAL_TYPE_TRANSPARENT ||
material.type == RAW_MATERIAL_TYPE_TRANSPARENT ||
material.type == RAW_MATERIAL_TYPE_SKINNED_TRANSPARENT; material.type == RAW_MATERIAL_TYPE_SKINNED_TRANSPARENT;
Vec3f emissiveFactor; Vec3f emissiveFactor;
@ -229,12 +242,14 @@ ModelData *Raw2Gltf(
// acquire the texture of a specific RawTextureUsage as *TextData, or nullptr if none exists // acquire the texture of a specific RawTextureUsage as *TextData, or nullptr if none exists
auto simpleTex = [&](RawTextureUsage usage) -> std::shared_ptr<TextureData> { auto simpleTex = [&](RawTextureUsage usage) -> std::shared_ptr<TextureData> {
return (material.textures[usage] >= 0) ? textureBuilder.simple(material.textures[usage], "simple") : nullptr; return (material.textures[usage] >= 0)
? textureBuilder.simple(material.textures[usage], "simple")
: nullptr;
}; };
TextureData *normalTexture = simpleTex(RAW_TEXTURE_USAGE_NORMAL).get(); TextureData* normalTexture = simpleTex(RAW_TEXTURE_USAGE_NORMAL).get();
TextureData *emissiveTexture = simpleTex(RAW_TEXTURE_USAGE_EMISSIVE).get(); TextureData* emissiveTexture = simpleTex(RAW_TEXTURE_USAGE_EMISSIVE).get();
TextureData *occlusionTexture = nullptr; TextureData* occlusionTexture = nullptr;
std::shared_ptr<PBRMetallicRoughness> pbrMetRough; std::shared_ptr<PBRMetallicRoughness> pbrMetRough;
if (options.usePBRMetRough) { if (options.usePBRMetRough) {
@ -250,8 +265,9 @@ ModelData *Raw2Gltf(
* METALLIC and ROUGHNESS textures are packed in G and B channels of a rough/met texture. * METALLIC and ROUGHNESS textures are packed in G and B channels of a rough/met texture.
* Other values translate directly. * Other values translate directly.
*/ */
RawMetRoughMatProps *props = (RawMetRoughMatProps *) material.info.get(); RawMetRoughMatProps* props = (RawMetRoughMatProps*)material.info.get();
// merge metallic into the blue channel and roughness into the green, of a new combinatory texture // merge metallic into the blue channel and roughness into the green, of a new combinatory
// texture
aoMetRoughTex = textureBuilder.combine( aoMetRoughTex = textureBuilder.combine(
{ {
material.textures[RAW_TEXTURE_USAGE_OCCLUSION], material.textures[RAW_TEXTURE_USAGE_OCCLUSION],
@ -259,8 +275,8 @@ ModelData *Raw2Gltf(
material.textures[RAW_TEXTURE_USAGE_ROUGHNESS], material.textures[RAW_TEXTURE_USAGE_ROUGHNESS],
}, },
"ao_met_rough", "ao_met_rough",
[&](const std::vector<const TextureBuilder::pixel *> pixels) -> TextureBuilder::pixel { [&](const std::vector<const TextureBuilder::pixel*> pixels) -> TextureBuilder::pixel {
return { {(*pixels[0])[0], (*pixels[2])[0], (*pixels[1])[0], 1} }; return {{(*pixels[0])[0], (*pixels[2])[0], (*pixels[1])[0], 1}};
}, },
false); false);
@ -270,7 +286,8 @@ ModelData *Raw2Gltf(
roughness = props->roughness; roughness = props->roughness;
emissiveFactor = props->emissiveFactor; emissiveFactor = props->emissiveFactor;
emissiveIntensity = props->emissiveIntensity; emissiveIntensity = props->emissiveIntensity;
// add the occlusion texture only if actual occlusion pixels exist in the aoNetRough texture. // add the occlusion texture only if actual occlusion pixels exist in the aoNetRough
// texture.
if (material.textures[RAW_TEXTURE_USAGE_OCCLUSION] >= 0) { if (material.textures[RAW_TEXTURE_USAGE_OCCLUSION] >= 0) {
occlusionTexture = aoMetRoughTex.get(); occlusionTexture = aoMetRoughTex.get();
} }
@ -280,12 +297,11 @@ ModelData *Raw2Gltf(
* *
* Diffuse channel is used as base colour. Simple constants for metallic and roughness. * Diffuse channel is used as base colour. Simple constants for metallic and roughness.
*/ */
const RawTraditionalMatProps *props = ((RawTraditionalMatProps *) material.info.get()); const RawTraditionalMatProps* props = ((RawTraditionalMatProps*)material.info.get());
diffuseFactor = props->diffuseFactor; diffuseFactor = props->diffuseFactor;
if (material.info->shadingModel == RAW_SHADING_MODEL_BLINN || if (material.info->shadingModel == RAW_SHADING_MODEL_BLINN ||
material.info->shadingModel == RAW_SHADING_MODEL_PHONG) material.info->shadingModel == RAW_SHADING_MODEL_PHONG) {
{
// blinn/phong hardcoded to 0.4 metallic // blinn/phong hardcoded to 0.4 metallic
metallic = 0.4f; metallic = 0.4f;
@ -295,17 +311,19 @@ ModelData *Raw2Gltf(
// shininess 6 -> roughness 0.5 // shininess 6 -> roughness 0.5
// shininess 16 -> roughness ~0.33 // shininess 16 -> roughness ~0.33
// as shininess ==> oo, roughness ==> 0 // as shininess ==> oo, roughness ==> 0
auto getRoughness = [&](float shininess) { auto getRoughness = [&](float shininess) { return sqrtf(2.0f / (2.0f + shininess)); };
return sqrtf(2.0f / (2.0f + shininess));
};
aoMetRoughTex = textureBuilder.combine( aoMetRoughTex = textureBuilder.combine(
{ material.textures[RAW_TEXTURE_USAGE_SHININESS], }, {
material.textures[RAW_TEXTURE_USAGE_SHININESS],
},
"ao_met_rough", "ao_met_rough",
[&](const std::vector<const TextureBuilder::pixel *> pixels) -> TextureBuilder::pixel { [&](const std::vector<const TextureBuilder::pixel*> pixels)
// do not multiply with props->shininess; that doesn't work like the other factors. -> TextureBuilder::pixel {
// do not multiply with props->shininess; that doesn't work like the other
// factors.
float shininess = props->shininess * (*pixels[0])[0]; float shininess = props->shininess * (*pixels[0])[0];
return { {0, getRoughness(shininess), metallic, 1} }; return {{0, getRoughness(shininess), metallic, 1}};
}, },
false); false);
@ -327,7 +345,8 @@ ModelData *Raw2Gltf(
emissiveFactor = props->emissiveFactor; emissiveFactor = props->emissiveFactor;
emissiveIntensity = 1.0f; emissiveIntensity = 1.0f;
} }
pbrMetRough.reset(new PBRMetallicRoughness(baseColorTex.get(), aoMetRoughTex.get(), diffuseFactor, metallic, roughness)); pbrMetRough.reset(new PBRMetallicRoughness(
baseColorTex.get(), aoMetRoughTex.get(), diffuseFactor, metallic, roughness));
} }
std::shared_ptr<KHRCmnUnlitMaterial> khrCmnUnlitMat; std::shared_ptr<KHRCmnUnlitMaterial> khrCmnUnlitMat;
@ -341,16 +360,17 @@ ModelData *Raw2Gltf(
std::shared_ptr<TextureData> baseColorTex; std::shared_ptr<TextureData> baseColorTex;
if (material.info->shadingModel == RAW_SHADING_MODEL_PBR_MET_ROUGH) { if (material.info->shadingModel == RAW_SHADING_MODEL_PBR_MET_ROUGH) {
RawMetRoughMatProps *props = (RawMetRoughMatProps *) material.info.get(); RawMetRoughMatProps* props = (RawMetRoughMatProps*)material.info.get();
diffuseFactor = props->diffuseFactor; diffuseFactor = props->diffuseFactor;
baseColorTex = simpleTex(RAW_TEXTURE_USAGE_ALBEDO); baseColorTex = simpleTex(RAW_TEXTURE_USAGE_ALBEDO);
} else { } else {
RawTraditionalMatProps *props = ((RawTraditionalMatProps *) material.info.get()); RawTraditionalMatProps* props = ((RawTraditionalMatProps*)material.info.get());
diffuseFactor = props->diffuseFactor; diffuseFactor = props->diffuseFactor;
baseColorTex = simpleTex(RAW_TEXTURE_USAGE_DIFFUSE); baseColorTex = simpleTex(RAW_TEXTURE_USAGE_DIFFUSE);
} }
pbrMetRough.reset(new PBRMetallicRoughness(baseColorTex.get(), nullptr, diffuseFactor, 0.0f, 1.0f)); pbrMetRough.reset(
new PBRMetallicRoughness(baseColorTex.get(), nullptr, diffuseFactor, 0.0f, 1.0f));
khrCmnUnlitMat.reset(new KHRCmnUnlitMaterial()); khrCmnUnlitMat.reset(new KHRCmnUnlitMaterial());
} }
@ -358,11 +378,16 @@ ModelData *Raw2Gltf(
occlusionTexture = simpleTex(RAW_TEXTURE_USAGE_OCCLUSION).get(); occlusionTexture = simpleTex(RAW_TEXTURE_USAGE_OCCLUSION).get();
} }
std::shared_ptr<MaterialData> mData = gltf->materials.hold( std::shared_ptr<MaterialData> mData = gltf->materials.hold(new MaterialData(
new MaterialData( material.name,
material.name, isTransparent, material.info->shadingModel, isTransparent,
normalTexture, occlusionTexture, emissiveTexture, material.info->shadingModel,
emissiveFactor * emissiveIntensity, khrCmnUnlitMat, pbrMetRough)); normalTexture,
occlusionTexture,
emissiveTexture,
emissiveFactor * emissiveIntensity,
khrCmnUnlitMat,
pbrMetRough));
materialsByName[materialHash(material)] = mData; materialsByName[materialHash(material)] = mData;
if (options.enableUserProperties) { if (options.enableUserProperties) {
@ -370,22 +395,23 @@ ModelData *Raw2Gltf(
} }
} }
for (const auto &surfaceModel : materialModels) { for (const auto& surfaceModel : materialModels) {
assert(surfaceModel.GetSurfaceCount() == 1); assert(surfaceModel.GetSurfaceCount() == 1);
const RawSurface &rawSurface = surfaceModel.GetSurface(0); const RawSurface& rawSurface = surfaceModel.GetSurface(0);
const long surfaceId = rawSurface.id; const long surfaceId = rawSurface.id;
const RawMaterial &rawMaterial = surfaceModel.GetMaterial(surfaceModel.GetTriangle(0).materialIndex); const RawMaterial& rawMaterial =
const MaterialData &mData = require(materialsByName, materialHash(rawMaterial)); surfaceModel.GetMaterial(surfaceModel.GetTriangle(0).materialIndex);
const MaterialData& mData = require(materialsByName, materialHash(rawMaterial));
MeshData *mesh = nullptr; MeshData* mesh = nullptr;
auto meshIter = meshBySurfaceId.find(surfaceId); auto meshIter = meshBySurfaceId.find(surfaceId);
if (meshIter != meshBySurfaceId.end()) { if (meshIter != meshBySurfaceId.end()) {
mesh = meshIter->second.get(); mesh = meshIter->second.get();
} else { } else {
std::vector<float> defaultDeforms; std::vector<float> defaultDeforms;
for (const auto &channel : rawSurface.blendChannels) { for (const auto& channel : rawSurface.blendChannels) {
defaultDeforms.push_back(channel.defaultDeform); defaultDeforms.push_back(channel.defaultDeform);
} }
auto meshPtr = gltf->meshes.hold(new MeshData(rawSurface.name, defaultDeforms)); auto meshPtr = gltf->meshes.hold(new MeshData(rawSurface.name, defaultDeforms));
@ -393,10 +419,9 @@ ModelData *Raw2Gltf(
mesh = meshPtr.get(); mesh = meshPtr.get();
} }
bool useLongIndices = bool useLongIndices = (options.useLongIndices == UseLongIndicesOptions::ALWAYS) ||
(options.useLongIndices == UseLongIndicesOptions::ALWAYS) (options.useLongIndices == UseLongIndicesOptions::AUTO &&
|| (options.useLongIndices == UseLongIndicesOptions::AUTO surfaceModel.GetVertexCount() > 65535);
&& surfaceModel.GetVertexCount() > 65535);
std::shared_ptr<PrimitiveData> primitive; std::shared_ptr<PrimitiveData> primitive;
if (options.draco.enabled) { if (options.draco.enabled) {
@ -414,13 +439,16 @@ ModelData *Raw2Gltf(
dracoMesh->SetFace(draco::FaceIndex(ii), face); dracoMesh->SetFace(draco::FaceIndex(ii), face);
} }
AccessorData &indexes = *gltf->accessors.hold(new AccessorData(useLongIndices ? GLT_UINT : GLT_USHORT)); AccessorData& indexes =
*gltf->accessors.hold(new AccessorData(useLongIndices ? GLT_UINT : GLT_USHORT));
indexes.count = 3 * triangleCount; indexes.count = 3 * triangleCount;
primitive.reset(new PrimitiveData(indexes, mData, dracoMesh)); primitive.reset(new PrimitiveData(indexes, mData, dracoMesh));
} else { } else {
const AccessorData &indexes = *gltf->AddAccessorWithView( const AccessorData& indexes = *gltf->AddAccessorWithView(
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ELEMENT_ARRAY_BUFFER), *gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ELEMENT_ARRAY_BUFFER),
useLongIndices ? GLT_UINT : GLT_USHORT, getIndexArray(surfaceModel), std::string("")); useLongIndices ? GLT_UINT : GLT_USHORT,
getIndexArray(surfaceModel),
std::string(""));
primitive.reset(new PrimitiveData(indexes, mData)); primitive.reset(new PrimitiveData(indexes, mData));
}; };
@ -429,17 +457,25 @@ ModelData *Raw2Gltf(
// //
{ {
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_POSITION) != 0) { if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_POSITION) != 0) {
const AttributeDefinition<Vec3f> ATTR_POSITION("POSITION", &RawVertex::position, const AttributeDefinition<Vec3f> ATTR_POSITION(
GLT_VEC3F, draco::GeometryAttribute::POSITION, draco::DT_FLOAT32); "POSITION",
auto accessor = gltf->AddAttributeToPrimitive<Vec3f>( &RawVertex::position,
buffer, surfaceModel, *primitive, ATTR_POSITION); GLT_VEC3F,
draco::GeometryAttribute::POSITION,
draco::DT_FLOAT32);
auto accessor =
gltf->AddAttributeToPrimitive<Vec3f>(buffer, surfaceModel, *primitive, ATTR_POSITION);
accessor->min = toStdVec(rawSurface.bounds.min); accessor->min = toStdVec(rawSurface.bounds.min);
accessor->max = toStdVec(rawSurface.bounds.max); accessor->max = toStdVec(rawSurface.bounds.max);
} }
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_NORMAL) != 0) { if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_NORMAL) != 0) {
const AttributeDefinition<Vec3f> ATTR_NORMAL("NORMAL", &RawVertex::normal, const AttributeDefinition<Vec3f> ATTR_NORMAL(
GLT_VEC3F, draco::GeometryAttribute::NORMAL, draco::DT_FLOAT32); "NORMAL",
&RawVertex::normal,
GLT_VEC3F,
draco::GeometryAttribute::NORMAL,
draco::DT_FLOAT32);
gltf->AddAttributeToPrimitive<Vec3f>(buffer, surfaceModel, *primitive, ATTR_NORMAL); gltf->AddAttributeToPrimitive<Vec3f>(buffer, surfaceModel, *primitive, ATTR_NORMAL);
} }
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_TANGENT) != 0) { if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_TANGENT) != 0) {
@ -447,41 +483,61 @@ ModelData *Raw2Gltf(
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_TANGENT); gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_TANGENT);
} }
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_COLOR) != 0) { if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_COLOR) != 0) {
const AttributeDefinition<Vec4f> ATTR_COLOR("COLOR_0", &RawVertex::color, GLT_VEC4F, const AttributeDefinition<Vec4f> ATTR_COLOR(
draco::GeometryAttribute::COLOR, draco::DT_FLOAT32); "COLOR_0",
&RawVertex::color,
GLT_VEC4F,
draco::GeometryAttribute::COLOR,
draco::DT_FLOAT32);
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_COLOR); gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_COLOR);
} }
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_UV0) != 0) { if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_UV0) != 0) {
const AttributeDefinition<Vec2f> ATTR_TEXCOORD_0("TEXCOORD_0", &RawVertex::uv0, const AttributeDefinition<Vec2f> ATTR_TEXCOORD_0(
GLT_VEC2F, draco::GeometryAttribute::TEX_COORD, draco::DT_FLOAT32); "TEXCOORD_0",
&RawVertex::uv0,
GLT_VEC2F,
draco::GeometryAttribute::TEX_COORD,
draco::DT_FLOAT32);
gltf->AddAttributeToPrimitive<Vec2f>(buffer, surfaceModel, *primitive, ATTR_TEXCOORD_0); gltf->AddAttributeToPrimitive<Vec2f>(buffer, surfaceModel, *primitive, ATTR_TEXCOORD_0);
} }
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_UV1) != 0) { if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_UV1) != 0) {
const AttributeDefinition<Vec2f> ATTR_TEXCOORD_1("TEXCOORD_1", &RawVertex::uv1, const AttributeDefinition<Vec2f> ATTR_TEXCOORD_1(
GLT_VEC2F, draco::GeometryAttribute::TEX_COORD, draco::DT_FLOAT32); "TEXCOORD_1",
&RawVertex::uv1,
GLT_VEC2F,
draco::GeometryAttribute::TEX_COORD,
draco::DT_FLOAT32);
gltf->AddAttributeToPrimitive<Vec2f>(buffer, surfaceModel, *primitive, ATTR_TEXCOORD_1); gltf->AddAttributeToPrimitive<Vec2f>(buffer, surfaceModel, *primitive, ATTR_TEXCOORD_1);
} }
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES) != 0) { if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES) != 0) {
const AttributeDefinition<Vec4i> ATTR_JOINTS("JOINTS_0", &RawVertex::jointIndices, const AttributeDefinition<Vec4i> ATTR_JOINTS(
GLT_VEC4I, draco::GeometryAttribute::GENERIC, draco::DT_UINT16); "JOINTS_0",
&RawVertex::jointIndices,
GLT_VEC4I,
draco::GeometryAttribute::GENERIC,
draco::DT_UINT16);
gltf->AddAttributeToPrimitive<Vec4i>(buffer, surfaceModel, *primitive, ATTR_JOINTS); gltf->AddAttributeToPrimitive<Vec4i>(buffer, surfaceModel, *primitive, ATTR_JOINTS);
} }
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS) != 0) { if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS) != 0) {
const AttributeDefinition<Vec4f> ATTR_WEIGHTS("WEIGHTS_0", &RawVertex::jointWeights, const AttributeDefinition<Vec4f> ATTR_WEIGHTS(
GLT_VEC4F, draco::GeometryAttribute::GENERIC, draco::DT_FLOAT32); "WEIGHTS_0",
&RawVertex::jointWeights,
GLT_VEC4F,
draco::GeometryAttribute::GENERIC,
draco::DT_FLOAT32);
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_WEIGHTS); gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_WEIGHTS);
} }
// each channel present in the mesh always ends up a target in the primitive // each channel present in the mesh always ends up a target in the primitive
for (int channelIx = 0; channelIx < rawSurface.blendChannels.size(); channelIx ++) { for (int channelIx = 0; channelIx < rawSurface.blendChannels.size(); channelIx++) {
const auto &channel = rawSurface.blendChannels[channelIx]; const auto& channel = rawSurface.blendChannels[channelIx];
// track the bounds of each shape channel // track the bounds of each shape channel
Bounds<float, 3> shapeBounds; Bounds<float, 3> shapeBounds;
std::vector<Vec3f> positions, normals; std::vector<Vec3f> positions, normals;
std::vector<Vec4f> tangents; std::vector<Vec4f> tangents;
for (int jj = 0; jj < surfaceModel.GetVertexCount(); jj ++) { for (int jj = 0; jj < surfaceModel.GetVertexCount(); jj++) {
auto blendVertex = surfaceModel.GetVertex(jj).blends[channelIx]; auto blendVertex = surfaceModel.GetVertex(jj).blends[channelIx];
shapeBounds.AddPoint(blendVertex.position); shapeBounds.AddPoint(blendVertex.position);
positions.push_back(blendVertex.position); positions.push_back(blendVertex.position);
@ -494,7 +550,9 @@ ModelData *Raw2Gltf(
} }
std::shared_ptr<AccessorData> pAcc = gltf->AddAccessorWithView( std::shared_ptr<AccessorData> pAcc = gltf->AddAccessorWithView(
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER), *gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER),
GLT_VEC3F, positions, channel.name); GLT_VEC3F,
positions,
channel.name);
pAcc->min = toStdVec(shapeBounds.min); pAcc->min = toStdVec(shapeBounds.min);
pAcc->max = toStdVec(shapeBounds.max); pAcc->max = toStdVec(shapeBounds.max);
@ -502,14 +560,18 @@ ModelData *Raw2Gltf(
if (!normals.empty()) { if (!normals.empty()) {
nAcc = gltf->AddAccessorWithView( nAcc = gltf->AddAccessorWithView(
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER), *gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER),
GLT_VEC3F, normals, channel.name); GLT_VEC3F,
normals,
channel.name);
} }
std::shared_ptr<AccessorData> tAcc; std::shared_ptr<AccessorData> tAcc;
if (!tangents.empty()) { if (!tangents.empty()) {
nAcc = gltf->AddAccessorWithView( nAcc = gltf->AddAccessorWithView(
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER), *gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER),
GLT_VEC4F, tangents, channel.name); GLT_VEC4F,
tangents,
channel.name);
} }
primitive->AddTarget(pAcc.get(), nAcc.get(), tAcc.get()); primitive->AddTarget(pAcc.get(), nAcc.get(), tAcc.get());
@ -524,19 +586,24 @@ ModelData *Raw2Gltf(
encoder.SetSpeedOptions(dracoSpeed, dracoSpeed); encoder.SetSpeedOptions(dracoSpeed, dracoSpeed);
} }
if (options.draco.quantBitsPosition != -1) { if (options.draco.quantBitsPosition != -1) {
encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, options.draco.quantBitsPosition); encoder.SetAttributeQuantization(
draco::GeometryAttribute::POSITION, options.draco.quantBitsPosition);
} }
if (options.draco.quantBitsTexCoord != -1) { if (options.draco.quantBitsTexCoord != -1) {
encoder.SetAttributeQuantization(draco::GeometryAttribute::TEX_COORD, options.draco.quantBitsTexCoord); encoder.SetAttributeQuantization(
draco::GeometryAttribute::TEX_COORD, options.draco.quantBitsTexCoord);
} }
if (options.draco.quantBitsNormal != -1) { if (options.draco.quantBitsNormal != -1) {
encoder.SetAttributeQuantization(draco::GeometryAttribute::NORMAL, options.draco.quantBitsNormal); encoder.SetAttributeQuantization(
draco::GeometryAttribute::NORMAL, options.draco.quantBitsNormal);
} }
if (options.draco.quantBitsColor != -1) { if (options.draco.quantBitsColor != -1) {
encoder.SetAttributeQuantization(draco::GeometryAttribute::COLOR, options.draco.quantBitsColor); encoder.SetAttributeQuantization(
draco::GeometryAttribute::COLOR, options.draco.quantBitsColor);
} }
if (options.draco.quantBitsGeneric != -1) { if (options.draco.quantBitsGeneric != -1) {
encoder.SetAttributeQuantization(draco::GeometryAttribute::GENERIC, options.draco.quantBitsGeneric); encoder.SetAttributeQuantization(
draco::GeometryAttribute::GENERIC, options.draco.quantBitsGeneric);
} }
draco::EncoderBuffer dracoBuffer; draco::EncoderBuffer dracoBuffer;
@ -554,18 +621,17 @@ ModelData *Raw2Gltf(
// //
for (int i = 0; i < raw.GetNodeCount(); i++) { for (int i = 0; i < raw.GetNodeCount(); i++) {
const RawNode &node = raw.GetNode(i); const RawNode& node = raw.GetNode(i);
auto nodeData = gltf->nodes.ptrs[i]; auto nodeData = gltf->nodes.ptrs[i];
// //
// Assign mesh to node // Assign mesh to node
// //
if (node.surfaceId > 0) if (node.surfaceId > 0) {
{
int surfaceIndex = raw.GetSurfaceById(node.surfaceId); int surfaceIndex = raw.GetSurfaceById(node.surfaceId);
const RawSurface &rawSurface = raw.GetSurface(surfaceIndex); const RawSurface& rawSurface = raw.GetSurface(surfaceIndex);
MeshData &meshData = require(meshBySurfaceId, rawSurface.id); MeshData& meshData = require(meshBySurfaceId, rawSurface.id);
nodeData->SetMesh(meshData.ix); nodeData->SetMesh(meshData.ix);
// //
@ -575,12 +641,12 @@ ModelData *Raw2Gltf(
if (nodeData->skin == -1) { if (nodeData->skin == -1) {
// glTF uses column-major matrices // glTF uses column-major matrices
std::vector<Mat4f> inverseBindMatrices; std::vector<Mat4f> inverseBindMatrices;
for (const auto &inverseBindMatrice : rawSurface.inverseBindMatrices) { for (const auto& inverseBindMatrice : rawSurface.inverseBindMatrices) {
inverseBindMatrices.push_back(inverseBindMatrice.Transpose()); inverseBindMatrices.push_back(inverseBindMatrice.Transpose());
} }
std::vector<uint32_t> jointIndexes; std::vector<uint32_t> jointIndexes;
for (const auto &jointId : rawSurface.jointIds) { for (const auto& jointId : rawSurface.jointIds) {
jointIndexes.push_back(require(nodesById, jointId).ix); jointIndexes.push_back(require(nodesById, jointId).ix);
} }
@ -600,14 +666,14 @@ ModelData *Raw2Gltf(
// //
for (int i = 0; i < raw.GetCameraCount(); i++) { for (int i = 0; i < raw.GetCameraCount(); i++) {
const RawCamera &cam = raw.GetCamera(i); const RawCamera& cam = raw.GetCamera(i);
CameraData &camera = *gltf->cameras.hold(new CameraData()); CameraData& camera = *gltf->cameras.hold(new CameraData());
camera.name = cam.name; camera.name = cam.name;
if (cam.mode == RawCamera::CAMERA_MODE_PERSPECTIVE) { if (cam.mode == RawCamera::CAMERA_MODE_PERSPECTIVE) {
camera.type = "perspective"; camera.type = "perspective";
camera.aspectRatio = cam.perspective.aspectRatio; camera.aspectRatio = cam.perspective.aspectRatio;
camera.yfov = cam.perspective.fovDegreesY * ((float) M_PI / 180.0f); camera.yfov = cam.perspective.fovDegreesY * ((float)M_PI / 180.0f);
camera.znear = cam.perspective.nearZ; camera.znear = cam.perspective.nearZ;
camera.zfar = cam.perspective.farZ; camera.zfar = cam.perspective.farZ;
} else { } else {
@ -632,10 +698,10 @@ ModelData *Raw2Gltf(
// //
std::vector<json> khrPunctualLights; std::vector<json> khrPunctualLights;
if (options.useKHRLightsPunctual) { if (options.useKHRLightsPunctual) {
for (int i = 0; i < raw.GetLightCount(); i ++) { for (int i = 0; i < raw.GetLightCount(); i++) {
const RawLight &light = raw.GetLight(i); const RawLight& light = raw.GetLight(i);
LightData::Type type; LightData::Type type;
switch(light.type) { switch (light.type) {
case RAW_LIGHT_TYPE_DIRECTIONAL: case RAW_LIGHT_TYPE_DIRECTIONAL:
type = LightData::Type::Directional; type = LightData::Type::Directional;
break; break;
@ -659,7 +725,7 @@ ModelData *Raw2Gltf(
} }
} }
for (int i = 0; i < raw.GetNodeCount(); i++) { for (int i = 0; i < raw.GetNodeCount(); i++) {
const RawNode &node = raw.GetNode(i); const RawNode& node = raw.GetNode(i);
const auto nodeData = gltf->nodes.ptrs[i]; const auto nodeData = gltf->nodes.ptrs[i];
if (node.lightIx >= 0) { if (node.lightIx >= 0) {
@ -669,22 +735,37 @@ ModelData *Raw2Gltf(
} }
} }
NodeData &rootNode = require(nodesById, raw.GetRootNode()); NodeData& rootNode = require(nodesById, raw.GetRootNode());
const SceneData &rootScene = *gltf->scenes.hold(new SceneData(DEFAULT_SCENE_NAME, rootNode)); const SceneData& rootScene = *gltf->scenes.hold(new SceneData(DEFAULT_SCENE_NAME, rootNode));
if (options.outputBinary) { if (options.outputBinary) {
// note: glTF binary is little-endian // note: glTF binary is little-endian
const char glbHeader[] = { const char glbHeader[] = {
'g', 'l', 'T', 'F', // magic 'g',
0x02, 0x00, 0x00, 0x00, // version 'l',
0x00, 0x00, 0x00, 0x00, // total length: written in later 'T',
'F', // magic
0x02,
0x00,
0x00,
0x00, // version
0x00,
0x00,
0x00,
0x00, // total length: written in later
}; };
gltfOutStream.write(glbHeader, 12); gltfOutStream.write(glbHeader, 12);
// binary glTF 2.0 has a sub-header for each of the JSON and BIN chunks // binary glTF 2.0 has a sub-header for each of the JSON and BIN chunks
const char glb2JsonHeader[] = { const char glb2JsonHeader[] = {
0x00, 0x00, 0x00, 0x00, // chunk length: written in later 0x00,
'J', 'S', 'O', 'N', // chunk type: 0x4E4F534A aka JSON 0x00,
0x00,
0x00, // chunk length: written in later
'J',
'S',
'O',
'N', // chunk type: 0x4E4F534A aka JSON
}; };
gltfOutStream.write(glb2JsonHeader, 8); gltfOutStream.write(glb2JsonHeader, 8);
} }
@ -702,12 +783,8 @@ ModelData *Raw2Gltf(
extensionsRequired.push_back(KHR_DRACO_MESH_COMPRESSION); extensionsRequired.push_back(KHR_DRACO_MESH_COMPRESSION);
} }
json glTFJson { json glTFJson{{"asset", {{"generator", "FBX2glTF v" + FBX2GLTF_VERSION}, {"version", "2.0"}}},
{ "asset", { {"scene", rootScene.ix}};
{ "generator", "FBX2glTF v" + FBX2GLTF_VERSION },
{ "version", "2.0" }}},
{ "scene", rootScene.ix }
};
if (!extensionsUsed.empty()) { if (!extensionsUsed.empty()) {
glTFJson["extensionsUsed"] = extensionsUsed; glTFJson["extensionsUsed"] = extensionsUsed;
} }
@ -720,29 +797,35 @@ ModelData *Raw2Gltf(
gltfOutStream << glTFJson.dump(options.outputBinary ? 0 : 4); gltfOutStream << glTFJson.dump(options.outputBinary ? 0 : 4);
} }
if (options.outputBinary) { if (options.outputBinary) {
uint32_t jsonLength = (uint32_t) gltfOutStream.tellp() - 20; uint32_t jsonLength = (uint32_t)gltfOutStream.tellp() - 20;
// the binary body must begin on a 4-aligned address, so pad json with spaces if necessary // the binary body must begin on a 4-aligned address, so pad json with spaces if necessary
while ((jsonLength % 4) != 0) { while ((jsonLength % 4) != 0) {
gltfOutStream.put(' '); gltfOutStream.put(' ');
jsonLength++; jsonLength++;
} }
uint32_t binHeader = (uint32_t) gltfOutStream.tellp(); uint32_t binHeader = (uint32_t)gltfOutStream.tellp();
// binary glTF 2.0 has a sub-header for each of the JSON and BIN chunks // binary glTF 2.0 has a sub-header for each of the JSON and BIN chunks
const char glb2BinaryHeader[] = { const char glb2BinaryHeader[] = {
0x00, 0x00, 0x00, 0x00, // chunk length: written in later 0x00,
'B', 'I', 'N', 0x00, // chunk type: 0x004E4942 aka BIN 0x00,
0x00,
0x00, // chunk length: written in later
'B',
'I',
'N',
0x00, // chunk type: 0x004E4942 aka BIN
}; };
gltfOutStream.write(glb2BinaryHeader, 8); gltfOutStream.write(glb2BinaryHeader, 8);
// append binary buffer directly to .glb file // append binary buffer directly to .glb file
uint32_t binaryLength = gltf->binary->size(); uint32_t binaryLength = gltf->binary->size();
gltfOutStream.write((const char *) &(*gltf->binary)[0], binaryLength); gltfOutStream.write((const char*)&(*gltf->binary)[0], binaryLength);
while ((binaryLength % 4) != 0) { while ((binaryLength % 4) != 0) {
gltfOutStream.put('\0'); gltfOutStream.put('\0');
binaryLength++; binaryLength++;
} }
uint32_t totalLength = (uint32_t) gltfOutStream.tellp(); uint32_t totalLength = (uint32_t)gltfOutStream.tellp();
// seek back to sub-header for json chunk // seek back to sub-header for json chunk
gltfOutStream.seekp(8); gltfOutStream.seekp(8);

View File

@ -27,8 +27,7 @@ const std::string extBufferFilename = "buffer.bin";
struct ComponentType { struct ComponentType {
// OpenGL Datatype enums // OpenGL Datatype enums
enum GL_DataType enum GL_DataType {
{
GL_BYTE = 5120, GL_BYTE = 5120,
GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE,
GL_SHORT, GL_SHORT,
@ -48,55 +47,56 @@ const ComponentType CT_FLOAT = {ComponentType::GL_FLOAT, 4};
// Map our low-level data types for glTF output // Map our low-level data types for glTF output
struct GLType { struct GLType {
GLType(const ComponentType &componentType, unsigned int count, const std::string dataType) GLType(const ComponentType& componentType, unsigned int count, const std::string dataType)
: componentType(componentType), : componentType(componentType), count(count), dataType(dataType) {}
count(count),
dataType(dataType)
{}
unsigned int byteStride() const { return componentType.size * count; } unsigned int byteStride() const {
return componentType.size * count;
}
void write(uint8_t *buf, const float scalar) const { *((float *) buf) = scalar; } void write(uint8_t* buf, const float scalar) const {
void write(uint8_t *buf, const uint32_t scalar) const { *((float*)buf) = scalar;
switch(componentType.size) { }
void write(uint8_t* buf, const uint32_t scalar) const {
switch (componentType.size) {
case 1: case 1:
*buf = (uint8_t)scalar; *buf = (uint8_t)scalar;
break; break;
case 2: case 2:
*((uint16_t *) buf) = (uint16_t)scalar; *((uint16_t*)buf) = (uint16_t)scalar;
break; break;
case 4: case 4:
*((uint32_t *) buf) = scalar; *((uint32_t*)buf) = scalar;
break; break;
} }
} }
template<class T, int d> template <class T, int d>
void write(uint8_t *buf, const mathfu::Vector<T, d> &vector) const { void write(uint8_t* buf, const mathfu::Vector<T, d>& vector) const {
for (int ii = 0; ii < d; ii ++) { for (int ii = 0; ii < d; ii++) {
((T *)buf)[ii] = vector(ii); ((T*)buf)[ii] = vector(ii);
} }
} }
template<class T, int d> template <class T, int d>
void write(uint8_t *buf, const mathfu::Matrix<T, d> &matrix) const { void write(uint8_t* buf, const mathfu::Matrix<T, d>& matrix) const {
// three matrix types require special alignment considerations that we don't handle // three matrix types require special alignment considerations that we don't handle
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment
assert(!(sizeof(T) == 1 && d == 2)); assert(!(sizeof(T) == 1 && d == 2));
assert(!(sizeof(T) == 1 && d == 3)); assert(!(sizeof(T) == 1 && d == 3));
assert(!(sizeof(T) == 2 && d == 2)); assert(!(sizeof(T) == 2 && d == 2));
for (int col = 0; col < d; col ++) { for (int col = 0; col < d; col++) {
for (int row = 0; row < d; row ++) { for (int row = 0; row < d; row++) {
// glTF matrices are column-major // glTF matrices are column-major
((T *)buf)[col * d + row] = matrix(row, col); ((T*)buf)[col * d + row] = matrix(row, col);
} }
} }
} }
template<class T> template <class T>
void write(uint8_t *buf, const mathfu::Quaternion<T> &quaternion) const { void write(uint8_t* buf, const mathfu::Quaternion<T>& quaternion) const {
for (int ii = 0; ii < 3; ii++) { for (int ii = 0; ii < 3; ii++) {
((T *)buf)[ii] = quaternion.vector()(ii); ((T*)buf)[ii] = quaternion.vector()(ii);
} }
((T *)buf)[3] = quaternion.scalar(); ((T*)buf)[3] = quaternion.scalar();
} }
const ComponentType componentType; const ComponentType componentType;
@ -119,25 +119,26 @@ const GLType GLT_QUATF = {CT_FLOAT, 4, "VEC4"};
/** /**
* The base of any indexed glTF entity. * The base of any indexed glTF entity.
*/ */
struct Holdable struct Holdable {
{
uint32_t ix; uint32_t ix;
virtual json serialize() const = 0; virtual json serialize() const = 0;
}; };
template<class T> template <class T>
struct AttributeDefinition struct AttributeDefinition {
{
const std::string gltfName; const std::string gltfName;
const T RawVertex::* rawAttributeIx; const T RawVertex::*rawAttributeIx;
const GLType glType; const GLType glType;
const draco::GeometryAttribute::Type dracoAttribute; const draco::GeometryAttribute::Type dracoAttribute;
const draco::DataType dracoComponentType; const draco::DataType dracoComponentType;
AttributeDefinition( AttributeDefinition(
const std::string gltfName, const T RawVertex::*rawAttributeIx, const GLType &_glType, const std::string gltfName,
const draco::GeometryAttribute::Type dracoAttribute, const draco::DataType dracoComponentType) const T RawVertex::*rawAttributeIx,
const GLType& _glType,
const draco::GeometryAttribute::Type dracoAttribute,
const draco::DataType dracoComponentType)
: gltfName(gltfName), : gltfName(gltfName),
rawAttributeIx(rawAttributeIx), rawAttributeIx(rawAttributeIx),
glType(_glType), glType(_glType),
@ -145,7 +146,9 @@ struct AttributeDefinition
dracoComponentType(dracoComponentType) {} dracoComponentType(dracoComponentType) {}
AttributeDefinition( AttributeDefinition(
const std::string gltfName, const T RawVertex::*rawAttributeIx, const GLType &_glType) const std::string gltfName,
const T RawVertex::*rawAttributeIx,
const GLType& _glType)
: gltfName(gltfName), : gltfName(gltfName),
rawAttributeIx(rawAttributeIx), rawAttributeIx(rawAttributeIx),
glType(_glType), glType(_glType),
@ -169,19 +172,15 @@ struct SceneData;
struct SkinData; struct SkinData;
struct TextureData; struct TextureData;
struct ModelData struct ModelData {
{ explicit ModelData(std::shared_ptr<const std::vector<uint8_t>> const& _binary)
explicit ModelData(std::shared_ptr<const std::vector<uint8_t> > const &_binary) : binary(_binary) {}
: binary(_binary)
{
}
std::shared_ptr<const std::vector<uint8_t> > const binary; std::shared_ptr<const std::vector<uint8_t>> const binary;
}; };
ModelData *Raw2Gltf( ModelData* Raw2Gltf(
std::ofstream &gltfOutStream, std::ofstream& gltfOutStream,
const std::string &outputFolder, const std::string& outputFolder,
const RawModel &raw, const RawModel& raw,
const GltfOptions &options const GltfOptions& options);
);

View File

@ -1,20 +1,20 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "TextureBuilder.hpp" #include "TextureBuilder.hpp"
#include <stb_image.h> #include <stb_image.h>
#include <stb_image_write.h> #include <stb_image_write.h>
#include <utils/File_Utils.hpp>
#include <utils/Image_Utils.hpp> #include <utils/Image_Utils.hpp>
#include <utils/String_Utils.hpp> #include <utils/String_Utils.hpp>
#include <utils/File_Utils.hpp>
#include <gltf/properties/ImageData.hpp> #include <gltf/properties/ImageData.hpp>
#include <gltf/properties/TextureData.hpp> #include <gltf/properties/TextureData.hpp>
@ -24,18 +24,17 @@ struct TexInfo {
explicit TexInfo(int rawTexIx) : rawTexIx(rawTexIx) {} explicit TexInfo(int rawTexIx) : rawTexIx(rawTexIx) {}
const int rawTexIx; const int rawTexIx;
int width {}; int width{};
int height {}; int height{};
int channels {}; int channels{};
uint8_t *pixels {}; uint8_t* pixels{};
}; };
std::shared_ptr<TextureData> TextureBuilder::combine( std::shared_ptr<TextureData> TextureBuilder::combine(
const std::vector<int> &ixVec, const std::vector<int>& ixVec,
const std::string &tag, const std::string& tag,
const pixel_merger &computePixel, const pixel_merger& computePixel,
bool includeAlphaChannel) bool includeAlphaChannel) {
{
const std::string key = texIndicesKey(ixVec, tag); const std::string key = texIndicesKey(ixVec, tag);
auto iter = textureByIndicesKey.find(key); auto iter = textureByIndicesKey.find(key);
if (iter != textureByIndicesKey.end()) { if (iter != textureByIndicesKey.end()) {
@ -44,27 +43,30 @@ std::shared_ptr<TextureData> TextureBuilder::combine(
int width = -1, height = -1; int width = -1, height = -1;
std::string mergedFilename = tag; std::string mergedFilename = tag;
std::vector<TexInfo> texes { }; std::vector<TexInfo> texes{};
for (const int rawTexIx : ixVec) { for (const int rawTexIx : ixVec) {
TexInfo info(rawTexIx); TexInfo info(rawTexIx);
if (rawTexIx >= 0) { if (rawTexIx >= 0) {
const RawTexture &rawTex = raw.GetTexture(rawTexIx); const RawTexture& rawTex = raw.GetTexture(rawTexIx);
const std::string &fileLoc = rawTex.fileLocation; const std::string& fileLoc = rawTex.fileLocation;
const std::string &name = StringUtils::GetFileBaseString(StringUtils::GetFileNameString(fileLoc)); const std::string& name =
StringUtils::GetFileBaseString(StringUtils::GetFileNameString(fileLoc));
if (!fileLoc.empty()) { if (!fileLoc.empty()) {
info.pixels = stbi_load(fileLoc.c_str(), &info.width, &info.height, &info.channels, 0); info.pixels = stbi_load(fileLoc.c_str(), &info.width, &info.height, &info.channels, 0);
if (!info.pixels) { if (!info.pixels) {
fmt::printf("Warning: merge texture [%d](%s) could not be loaded.\n", fmt::printf("Warning: merge texture [%d](%s) could not be loaded.\n", rawTexIx, name);
rawTexIx,
name);
} else { } else {
if (width < 0) { if (width < 0) {
width = info.width; width = info.width;
height = info.height; height = info.height;
} else if (width != info.width || height != info.height) { } else if (width != info.width || height != info.height) {
fmt::printf("Warning: texture %s (%d, %d) can't be merged with previous texture(s) of dimension (%d, %d)\n", fmt::printf(
"Warning: texture %s (%d, %d) can't be merged with previous texture(s) of dimension (%d, %d)\n",
name, name,
info.width, info.height, width, height); info.width,
info.height,
width,
height);
// this is bad enough that we abort the whole merge // this is bad enough that we abort the whole merge
return nullptr; return nullptr;
} }
@ -88,28 +90,28 @@ std::shared_ptr<TextureData> TextureBuilder::combine(
std::vector<uint8_t> mergedPixels(static_cast<size_t>(channels * width * height)); std::vector<uint8_t> mergedPixels(static_cast<size_t>(channels * width * height));
std::vector<pixel> pixels(texes.size()); std::vector<pixel> pixels(texes.size());
std::vector<const pixel *> pixelPointers(texes.size()); std::vector<const pixel*> pixelPointers(texes.size());
for (int xx = 0; xx < width; xx ++) { for (int xx = 0; xx < width; xx++) {
for (int yy = 0; yy < height; yy ++) { for (int yy = 0; yy < height; yy++) {
pixels.clear(); pixels.clear();
for (int jj = 0; jj < texes.size(); jj ++) { for (int jj = 0; jj < texes.size(); jj++) {
const TexInfo &tex = texes[jj]; const TexInfo& tex = texes[jj];
// each texture's structure will depend on its channel count // each texture's structure will depend on its channel count
int ii = tex.channels * (xx + yy*width); int ii = tex.channels * (xx + yy * width);
int kk = 0; int kk = 0;
if (tex.pixels != nullptr) { if (tex.pixels != nullptr) {
for (; kk < tex.channels; kk ++) { for (; kk < tex.channels; kk++) {
pixels[jj][kk] = tex.pixels[ii++] / 255.0f; pixels[jj][kk] = tex.pixels[ii++] / 255.0f;
} }
} }
for (; kk < pixels[jj].size(); kk ++) { for (; kk < pixels[jj].size(); kk++) {
pixels[jj][kk] = 1.0f; pixels[jj][kk] = 1.0f;
} }
pixelPointers[jj] = &pixels[jj]; pixelPointers[jj] = &pixels[jj];
} }
const pixel merged = computePixel(pixelPointers); const pixel merged = computePixel(pixelPointers);
int ii = channels * (xx + yy*width); int ii = channels * (xx + yy * width);
for (int jj = 0; jj < channels; jj ++) { for (int jj = 0; jj < channels; jj++) {
mergedPixels[ii + jj] = static_cast<uint8_t>(fmax(0, fmin(255.0f, merged[jj] * 255.0f))); mergedPixels[ii + jj] = static_cast<uint8_t>(fmax(0, fmin(255.0f, merged[jj] * 255.0f)));
} }
} }
@ -121,32 +123,40 @@ std::shared_ptr<TextureData> TextureBuilder::combine(
std::vector<char> imgBuffer; std::vector<char> imgBuffer;
int res; int res;
if (png) { if (png) {
res = stbi_write_png_to_func(WriteToVectorContext, &imgBuffer, res = stbi_write_png_to_func(
width, height, channels, mergedPixels.data(), width * channels); WriteToVectorContext,
&imgBuffer,
width,
height,
channels,
mergedPixels.data(),
width * channels);
} else { } else {
res = stbi_write_jpg_to_func(WriteToVectorContext, &imgBuffer, res = stbi_write_jpg_to_func(
width, height, channels, mergedPixels.data(), 80); WriteToVectorContext, &imgBuffer, width, height, channels, mergedPixels.data(), 80);
} }
if (!res) { if (!res) {
fmt::printf("Warning: failed to generate merge texture '%s'.\n", mergedFilename); fmt::printf("Warning: failed to generate merge texture '%s'.\n", mergedFilename);
return nullptr; return nullptr;
} }
ImageData *image; ImageData* image;
if (options.outputBinary) { if (options.outputBinary) {
const auto bufferView = gltf.AddRawBufferView(*gltf.defaultBuffer, imgBuffer.data(), imgBuffer.size()); const auto bufferView =
gltf.AddRawBufferView(*gltf.defaultBuffer, imgBuffer.data(), imgBuffer.size());
image = new ImageData(mergedName, *bufferView, png ? "image/png" : "image/jpeg"); image = new ImageData(mergedName, *bufferView, png ? "image/png" : "image/jpeg");
} else { } else {
const std::string imageFilename = mergedFilename + (png ? ".png" : ".jpg"); const std::string imageFilename = mergedFilename + (png ? ".png" : ".jpg");
const std::string imagePath = outputFolder + imageFilename; const std::string imagePath = outputFolder + imageFilename;
FILE *fp = fopen(imagePath.c_str(), "wb"); FILE* fp = fopen(imagePath.c_str(), "wb");
if (fp == nullptr) { if (fp == nullptr) {
fmt::printf("Warning:: Couldn't write file '%s' for writing.\n", imagePath); fmt::printf("Warning:: Couldn't write file '%s' for writing.\n", imagePath);
return nullptr; return nullptr;
} }
if (fwrite(imgBuffer.data(), imgBuffer.size(), 1, fp) != 1) { if (fwrite(imgBuffer.data(), imgBuffer.size(), 1, fp) != 1) {
fmt::printf("Warning: Failed to write %lu bytes to file '%s'.\n", imgBuffer.size(), imagePath); fmt::printf(
"Warning: Failed to write %lu bytes to file '%s'.\n", imgBuffer.size(), imagePath);
fclose(fp); fclose(fp);
return nullptr; return nullptr;
} }
@ -163,18 +173,18 @@ std::shared_ptr<TextureData> TextureBuilder::combine(
} }
/** Create a new TextureData for the given RawTexture index, or return a previously created one. */ /** Create a new TextureData for the given RawTexture index, or return a previously created one. */
std::shared_ptr<TextureData> TextureBuilder::simple(int rawTexIndex, const std::string &tag) { std::shared_ptr<TextureData> TextureBuilder::simple(int rawTexIndex, const std::string& tag) {
const std::string key = texIndicesKey({ rawTexIndex }, tag); const std::string key = texIndicesKey({rawTexIndex}, tag);
auto iter = textureByIndicesKey.find(key); auto iter = textureByIndicesKey.find(key);
if (iter != textureByIndicesKey.end()) { if (iter != textureByIndicesKey.end()) {
return iter->second; return iter->second;
} }
const RawTexture &rawTexture = raw.GetTexture(rawTexIndex); const RawTexture& rawTexture = raw.GetTexture(rawTexIndex);
const std::string textureName = StringUtils::GetFileBaseString(rawTexture.name); const std::string textureName = StringUtils::GetFileBaseString(rawTexture.name);
const std::string relativeFilename = StringUtils::GetFileNameString(rawTexture.fileLocation); const std::string relativeFilename = StringUtils::GetFileNameString(rawTexture.fileLocation);
ImageData *image = nullptr; ImageData* image = nullptr;
if (options.outputBinary) { if (options.outputBinary) {
auto bufferView = gltf.AddBufferViewForFile(*gltf.defaultBuffer, rawTexture.fileLocation); auto bufferView = gltf.AddBufferViewForFile(*gltf.defaultBuffer, rawTexture.fileLocation);
if (bufferView) { if (bufferView) {
@ -185,8 +195,7 @@ std::shared_ptr<TextureData> TextureBuilder::simple(int rawTexIndex, const std::
} else if (!relativeFilename.empty()) { } else if (!relativeFilename.empty()) {
image = new ImageData(relativeFilename, relativeFilename); image = new ImageData(relativeFilename, relativeFilename);
std::string outputPath = outputFolder + StringUtils::NormalizePath(relativeFilename); std::string outputPath = outputFolder + StringUtils::NormalizePath(relativeFilename);
if (FileUtils::CopyFile(rawTexture.fileLocation, outputPath, true)) if (FileUtils::CopyFile(rawTexture.fileLocation, outputPath, true)) {
{
if (verboseOutput) { if (verboseOutput) {
fmt::printf("Copied texture '%s' to output folder: %s\n", textureName, outputPath); fmt::printf("Copied texture '%s' to output folder: %s\n", textureName, outputPath);
} }
@ -200,13 +209,11 @@ std::shared_ptr<TextureData> TextureBuilder::simple(int rawTexIndex, const std::
// fallback is tiny transparent PNG // fallback is tiny transparent PNG
image = new ImageData( image = new ImageData(
textureName, textureName,
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==" "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==");
);
} }
std::shared_ptr<TextureData> texDat = gltf.textures.hold( std::shared_ptr<TextureData> texDat = gltf.textures.hold(
new TextureData(textureName, *gltf.defaultSampler, *gltf.images.hold(image))); new TextureData(textureName, *gltf.defaultSampler, *gltf.images.hold(image)));
textureByIndicesKey.insert(std::make_pair(key, texDat)); textureByIndicesKey.insert(std::make_pair(key, texDat));
return texDat; return texDat;
} }

View File

@ -1,11 +1,11 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once
@ -17,30 +17,28 @@
#include "GltfModel.hpp" #include "GltfModel.hpp"
class TextureBuilder class TextureBuilder {
{ public:
public:
using pixel = std::array<float, 4>; // pixel components are floats in [0, 1] using pixel = std::array<float, 4>; // pixel components are floats in [0, 1]
using pixel_merger = std::function<pixel(const std::vector<const pixel *>)>; using pixel_merger = std::function<pixel(const std::vector<const pixel*>)>;
TextureBuilder(const RawModel &raw, const GltfOptions &options, const std::string &outputFolder, GltfModel &gltf) TextureBuilder(
: raw(raw) const RawModel& raw,
, options(options) const GltfOptions& options,
, outputFolder(outputFolder) const std::string& outputFolder,
, gltf(gltf) GltfModel& gltf)
{} : raw(raw), options(options), outputFolder(outputFolder), gltf(gltf) {}
~TextureBuilder() {} ~TextureBuilder() {}
std::shared_ptr<TextureData> combine( std::shared_ptr<TextureData> combine(
const std::vector<int> &ixVec, const std::vector<int>& ixVec,
const std::string &tag, const std::string& tag,
const pixel_merger &mergeFunction, const pixel_merger& mergeFunction,
bool transparency bool transparency);
);
std::shared_ptr<TextureData> simple(int rawTexIndex, const std::string &tag); std::shared_ptr<TextureData> simple(int rawTexIndex, const std::string& tag);
static std::string texIndicesKey(const std::vector<int> &ixVec, const std::string &tag) { static std::string texIndicesKey(const std::vector<int>& ixVec, const std::string& tag) {
std::string result = tag; std::string result = tag;
for (int ix : ixVec) { for (int ix : ixVec) {
result += "_" + std::to_string(ix); result += "_" + std::to_string(ix);
@ -49,28 +47,32 @@ public:
}; };
static std::string describeChannel(int channels) { static std::string describeChannel(int channels) {
switch(channels) { switch (channels) {
case 1: return "G"; case 1:
case 2: return "GA"; return "G";
case 3: return "RGB"; case 2:
case 4: return "RGBA"; return "GA";
case 3:
return "RGB";
case 4:
return "RGBA";
default: default:
return fmt::format("?%d?", channels); return fmt::format("?%d?", channels);
} }
}; };
static void WriteToVectorContext(void *context, void *data, int size) { static void WriteToVectorContext(void* context, void* data, int size) {
auto *vec = static_cast<std::vector<char> *>(context); auto* vec = static_cast<std::vector<char>*>(context);
for (int ii = 0; ii < size; ii ++) { for (int ii = 0; ii < size; ii++) {
vec->push_back(((char *) data)[ii]); vec->push_back(((char*)data)[ii]);
} }
} }
private: private:
const RawModel &raw; const RawModel& raw;
const GltfOptions &options; const GltfOptions& options;
const std::string outputFolder; const std::string outputFolder;
GltfModel &gltf; GltfModel& gltf;
std::map<std::string, std::shared_ptr<TextureData>> textureByIndicesKey; std::map<std::string, std::shared_ptr<TextureData>> textureByIndicesKey;
}; };

View File

@ -10,32 +10,20 @@
#include "AccessorData.hpp" #include "AccessorData.hpp"
#include "BufferViewData.hpp" #include "BufferViewData.hpp"
AccessorData::AccessorData(const BufferViewData &bufferView, GLType type, std::string name) AccessorData::AccessorData(const BufferViewData& bufferView, GLType type, std::string name)
: Holdable(), : Holdable(),
bufferView(bufferView.ix), bufferView(bufferView.ix),
type(std::move(type)), type(std::move(type)),
byteOffset(0), byteOffset(0),
count(0), count(0),
name(name) name(name) {}
{
}
AccessorData::AccessorData(GLType type) AccessorData::AccessorData(GLType type)
: Holdable(), : Holdable(), bufferView(-1), type(std::move(type)), byteOffset(0), count(0) {}
bufferView(-1),
type(std::move(type)),
byteOffset(0),
count(0)
{
}
json AccessorData::serialize() const json AccessorData::serialize() const {
{ json result{
json result { {"componentType", type.componentType.glType}, {"type", type.dataType}, {"count", count}};
{ "componentType", type.componentType.glType },
{ "type", type.dataType },
{ "count", count }
};
if (bufferView >= 0) { if (bufferView >= 0) {
result["bufferView"] = bufferView; result["bufferView"] = bufferView;
result["byteOffset"] = byteOffset; result["byteOffset"] = byteOffset;

View File

@ -11,29 +11,29 @@
#include "gltf/Raw2Gltf.hpp" #include "gltf/Raw2Gltf.hpp"
struct AccessorData : Holdable struct AccessorData : Holdable {
{ AccessorData(const BufferViewData& bufferView, GLType type, std::string name);
AccessorData(const BufferViewData &bufferView, GLType type, std::string name);
explicit AccessorData(GLType type); explicit AccessorData(GLType type);
json serialize() const override; json serialize() const override;
template<class T> template <class T>
void appendAsBinaryArray(const std::vector<T> &in, std::vector<uint8_t> &out) void appendAsBinaryArray(const std::vector<T>& in, std::vector<uint8_t>& out) {
{
const unsigned int stride = type.byteStride(); const unsigned int stride = type.byteStride();
const size_t offset = out.size(); const size_t offset = out.size();
const size_t count = in.size(); const size_t count = in.size();
this->count = (unsigned int) count; this->count = (unsigned int)count;
out.resize(offset + count * stride); out.resize(offset + count * stride);
for (int ii = 0; ii < count; ii ++) { for (int ii = 0; ii < count; ii++) {
type.write(&out[offset + ii * stride], in[ii]); type.write(&out[offset + ii * stride], in[ii]);
} }
} }
unsigned int byteLength() const { return type.byteStride() * count; } unsigned int byteLength() const {
return type.byteStride() * count;
}
const int bufferView; const int bufferView;
const GLType type; const GLType type;

View File

@ -14,57 +14,42 @@
#include "AccessorData.hpp" #include "AccessorData.hpp"
#include "NodeData.hpp" #include "NodeData.hpp"
AnimationData::AnimationData(std::string name, const AccessorData &timeAccessor) AnimationData::AnimationData(std::string name, const AccessorData& timeAccessor)
: Holdable(), : Holdable(), name(std::move(name)), timeAccessor(timeAccessor.ix) {}
name(std::move(name)),
timeAccessor(timeAccessor.ix) {}
// assumption: 1-to-1 relationship between channels and samplers; this is a simplification on what // assumption: 1-to-1 relationship between channels and samplers; this is a simplification on what
// glTF can express, but it means we can rely on samplerIx == channelIx throughout an animation // glTF can express, but it means we can rely on samplerIx == channelIx throughout an animation
void AnimationData::AddNodeChannel(const NodeData &node, const AccessorData &accessor, std::string path) void AnimationData::AddNodeChannel(
{ const NodeData& node,
const AccessorData& accessor,
std::string path) {
assert(channels.size() == samplers.size()); assert(channels.size() == samplers.size());
uint32_t ix = channels.size(); uint32_t ix = channels.size();
channels.emplace_back(channel_t(ix, node, std::move(path))); channels.emplace_back(channel_t(ix, node, std::move(path)));
samplers.emplace_back(sampler_t(timeAccessor, accessor.ix)); samplers.emplace_back(sampler_t(timeAccessor, accessor.ix));
} }
json AnimationData::serialize() const json AnimationData::serialize() const {
{ return {{"name", name}, {"channels", channels}, {"samplers", samplers}};
return { }
{ "name", name },
{ "channels", channels }, AnimationData::channel_t::channel_t(uint32_t ix, const NodeData& node, std::string path)
{ "samplers", samplers } : ix(ix), node(node.ix), path(std::move(path)) {}
};
} AnimationData::sampler_t::sampler_t(uint32_t time, uint32_t output) : time(time), output(output) {}
AnimationData::channel_t::channel_t(uint32_t ix, const NodeData &node, std::string path) void to_json(json& j, const AnimationData::channel_t& data) {
: ix(ix), j = json{{"sampler", data.ix},
node(node.ix), {
path(std::move(path)) "target",
{ {{"node", data.node}, {"path", data.path}},
} }};
}
AnimationData::sampler_t::sampler_t(uint32_t time, uint32_t output)
: time(time), void to_json(json& j, const AnimationData::sampler_t& data) {
output(output) j = json{
{ {"input", data.time},
} {"interpolation", "LINEAR"},
{"output", data.output},
void to_json(json &j, const AnimationData::channel_t &data) {
j = json {
{ "sampler", data.ix },
{ "target", {
{ "node", data.node },
{ "path", data.path }},
}
};
}
void to_json(json &j, const AnimationData::sampler_t &data) {
j = json {
{ "input", data.time },
{ "interpolation", "LINEAR" },
{ "output", data.output },
}; };
} }

View File

@ -11,27 +11,24 @@
#include "gltf/Raw2Gltf.hpp" #include "gltf/Raw2Gltf.hpp"
struct AnimationData : Holdable struct AnimationData : Holdable {
{ AnimationData(std::string name, const AccessorData& timeAccessor);
AnimationData(std::string name, const AccessorData &timeAccessor);
// assumption: 1-to-1 relationship between channels and samplers; this is a simplification on what // assumption: 1-to-1 relationship between channels and samplers; this is a simplification on what
// glTF can express, but it means we can rely on samplerIx == channelIx throughout an animation // glTF can express, but it means we can rely on samplerIx == channelIx throughout an animation
void AddNodeChannel(const NodeData &node, const AccessorData &accessor, std::string path); void AddNodeChannel(const NodeData& node, const AccessorData& accessor, std::string path);
json serialize() const override; json serialize() const override;
struct channel_t struct channel_t {
{ channel_t(uint32_t _ix, const NodeData& node, std::string path);
channel_t(uint32_t _ix, const NodeData &node, std::string path);
const uint32_t ix; const uint32_t ix;
const uint32_t node; const uint32_t node;
const std::string path; const std::string path;
}; };
struct sampler_t struct sampler_t {
{
sampler_t(uint32_t time, uint32_t output); sampler_t(uint32_t time, uint32_t output);
const uint32_t time; const uint32_t time;
@ -44,5 +41,5 @@ struct AnimationData : Holdable
std::vector<sampler_t> samplers; std::vector<sampler_t> samplers;
}; };
void to_json(json &j, const AnimationData::channel_t &data); void to_json(json& j, const AnimationData::channel_t& data);
void to_json(json &j, const AnimationData::sampler_t &data); void to_json(json& j, const AnimationData::sampler_t& data);

View File

@ -11,26 +11,17 @@
#include "BufferData.hpp" #include "BufferData.hpp"
BufferData::BufferData(const std::shared_ptr<const std::vector<uint8_t> > &binData) BufferData::BufferData(const std::shared_ptr<const std::vector<uint8_t>>& binData)
: Holdable(), : Holdable(), isGlb(true), binData(binData) {}
isGlb(true),
binData(binData)
{
}
BufferData::BufferData(std::string uri, const std::shared_ptr<const std::vector<uint8_t> > &binData, bool isEmbedded) BufferData::BufferData(
: Holdable(), std::string uri,
isGlb(false), const std::shared_ptr<const std::vector<uint8_t>>& binData,
uri(isEmbedded ? "" : std::move(uri)), bool isEmbedded)
binData(binData) : Holdable(), isGlb(false), uri(isEmbedded ? "" : std::move(uri)), binData(binData) {}
{
}
json BufferData::serialize() const json BufferData::serialize() const {
{ json result{{"byteLength", binData->size()}};
json result{
{"byteLength", binData->size()}
};
if (!isGlb) { if (!isGlb) {
if (!uri.empty()) { if (!uri.empty()) {
result["uri"] = uri; result["uri"] = uri;

View File

@ -11,15 +11,17 @@
#include "gltf/Raw2Gltf.hpp" #include "gltf/Raw2Gltf.hpp"
struct BufferData : Holdable struct BufferData : Holdable {
{ explicit BufferData(const std::shared_ptr<const std::vector<uint8_t>>& binData);
explicit BufferData(const std::shared_ptr<const std::vector<uint8_t> > &binData);
BufferData(std::string uri, const std::shared_ptr<const std::vector<uint8_t> > &binData, bool isEmbedded = false); BufferData(
std::string uri,
const std::shared_ptr<const std::vector<uint8_t>>& binData,
bool isEmbedded = false);
json serialize() const override; json serialize() const override;
const bool isGlb; const bool isGlb;
const std::string uri; const std::string uri;
const std::shared_ptr<const std::vector<uint8_t> > binData; // TODO this is just weird const std::shared_ptr<const std::vector<uint8_t>> binData; // TODO this is just weird
}; };

View File

@ -10,21 +10,14 @@
#include "BufferViewData.hpp" #include "BufferViewData.hpp"
#include "BufferData.hpp" #include "BufferData.hpp"
BufferViewData::BufferViewData(const BufferData &_buffer, const size_t _byteOffset, const GL_ArrayType _target) BufferViewData::BufferViewData(
: Holdable(), const BufferData& _buffer,
buffer(_buffer.ix), const size_t _byteOffset,
byteOffset((unsigned int) _byteOffset), const GL_ArrayType _target)
target(_target) : Holdable(), buffer(_buffer.ix), byteOffset((unsigned int)_byteOffset), target(_target) {}
{
}
json BufferViewData::serialize() const json BufferViewData::serialize() const {
{ json result{{"buffer", buffer}, {"byteLength", byteLength}, {"byteOffset", byteOffset}};
json result {
{ "buffer", buffer },
{ "byteLength", byteLength },
{ "byteOffset", byteOffset }
};
if (target != GL_ARRAY_NONE) { if (target != GL_ARRAY_NONE) {
result["target"] = target; result["target"] = target;
} }

View File

@ -11,16 +11,14 @@
#include "gltf/Raw2Gltf.hpp" #include "gltf/Raw2Gltf.hpp"
struct BufferViewData : Holdable struct BufferViewData : Holdable {
{ enum GL_ArrayType {
enum GL_ArrayType
{
GL_ARRAY_NONE = 0, // no GL buffer is being set GL_ARRAY_NONE = 0, // no GL buffer is being set
GL_ARRAY_BUFFER = 34962, GL_ARRAY_BUFFER = 34962,
GL_ELEMENT_ARRAY_BUFFER = 34963 GL_ELEMENT_ARRAY_BUFFER = 34963
}; };
BufferViewData(const BufferData &_buffer, const size_t _byteOffset, const GL_ArrayType _target); BufferViewData(const BufferData& _buffer, const size_t _byteOffset, const GL_ArrayType _target);
json serialize() const override; json serialize() const override;

View File

@ -10,26 +10,14 @@
#include "CameraData.hpp" #include "CameraData.hpp"
CameraData::CameraData() CameraData::CameraData()
: Holdable(), : Holdable(), aspectRatio(0.0f), yfov(0.0f), xmag(0.0f), ymag(0.0f), znear(0.0f), zfar(0.0f) {}
aspectRatio(0.0f),
yfov(0.0f),
xmag(0.0f),
ymag(0.0f),
znear(0.0f),
zfar(0.0f)
{
}
json CameraData::serialize() const json CameraData::serialize() const {
{ json result{
json result { {"name", name},
{ "name", name }, {"type", type},
{ "type", type },
};
json subResult {
{ "znear", znear },
{ "zfar", zfar }
}; };
json subResult{{"znear", znear}, {"zfar", zfar}};
if (type == "perspective") { if (type == "perspective") {
subResult["aspectRatio"] = aspectRatio; subResult["aspectRatio"] = aspectRatio;
subResult["yfov"] = yfov; subResult["yfov"] = yfov;

View File

@ -12,8 +12,7 @@
#include "gltf/Raw2Gltf.hpp" #include "gltf/Raw2Gltf.hpp"
// TODO: this class needs some work // TODO: this class needs some work
struct CameraData : Holdable struct CameraData : Holdable {
{
CameraData(); CameraData();
json serialize() const override; json serialize() const override;

View File

@ -14,32 +14,14 @@
#include "BufferViewData.hpp" #include "BufferViewData.hpp"
ImageData::ImageData(std::string name, std::string uri) ImageData::ImageData(std::string name, std::string uri)
: Holdable(), : Holdable(), name(std::move(name)), uri(std::move(uri)), bufferView(-1) {}
name(std::move(name)),
uri(std::move(uri)),
bufferView(-1)
{
}
ImageData::ImageData(std::string name, const BufferViewData &bufferView, std::string mimeType) ImageData::ImageData(std::string name, const BufferViewData& bufferView, std::string mimeType)
: Holdable(), : Holdable(), name(std::move(name)), bufferView(bufferView.ix), mimeType(std::move(mimeType)) {}
name(std::move(name)),
bufferView(bufferView.ix),
mimeType(std::move(mimeType))
{
}
json ImageData::serialize() const json ImageData::serialize() const {
{
if (bufferView < 0) { if (bufferView < 0) {
return { return {{"name", name}, {"uri", uri}};
{ "name", name },
{ "uri", uri }
};
} }
return { return {{"name", name}, {"bufferView", bufferView}, {"mimeType", mimeType}};
{ "name", name },
{ "bufferView", bufferView },
{ "mimeType", mimeType }
};
} }

View File

@ -11,10 +11,9 @@
#include "gltf/Raw2Gltf.hpp" #include "gltf/Raw2Gltf.hpp"
struct ImageData : Holdable struct ImageData : Holdable {
{
ImageData(std::string name, std::string uri); ImageData(std::string name, std::string uri);
ImageData(std::string name, const BufferViewData &bufferView, std::string mimeType); ImageData(std::string name, const BufferViewData& bufferView, std::string mimeType);
json serialize() const override; json serialize() const override;

View File

@ -10,25 +10,22 @@
#include "LightData.hpp" #include "LightData.hpp"
LightData::LightData( LightData::LightData(
std::string name, Type type, Vec3f color, float intensity, std::string name,
float innerConeAngle, float outerConeAngle) Type type,
Vec3f color,
float intensity,
float innerConeAngle,
float outerConeAngle)
: Holdable(), : Holdable(),
type(type), type(type),
color(color), color(color),
intensity(intensity), intensity(intensity),
innerConeAngle(innerConeAngle), innerConeAngle(innerConeAngle),
outerConeAngle(outerConeAngle) outerConeAngle(outerConeAngle) {}
{
}
json LightData::serialize() const json LightData::serialize() const {
{ json result{{"name", name}, {"color", toStdVec(color)}, {"intensity", intensity}};
json result { switch (type) {
{ "name", name },
{ "color", toStdVec(color) },
{ "intensity", intensity }
};
switch(type) {
case Directional: case Directional:
result["type"] = "directional"; result["type"] = "directional";
break; break;

View File

@ -11,16 +11,20 @@
#include "gltf/Raw2Gltf.hpp" #include "gltf/Raw2Gltf.hpp"
struct LightData : Holdable struct LightData : Holdable {
{
enum Type { enum Type {
Directional, Directional,
Point, Point,
Spot, Spot,
}; };
LightData(std::string name, Type type, Vec3f color, float intensity, LightData(
float innerConeAngle, float outerConeAngle); std::string name,
Type type,
Vec3f color,
float intensity,
float innerConeAngle,
float outerConeAngle);
json serialize() const override; json serialize() const override;

View File

@ -11,55 +11,48 @@
#include "TextureData.hpp" #include "TextureData.hpp"
// TODO: retrieve & pass in correct UV set from FBX // TODO: retrieve & pass in correct UV set from FBX
std::unique_ptr<Tex> Tex::ref(const TextureData *tex, uint32_t texCoord) std::unique_ptr<Tex> Tex::ref(const TextureData* tex, uint32_t texCoord) {
{ return std::unique_ptr<Tex>{(tex != nullptr) ? new Tex(tex->ix, texCoord) : nullptr};
return std::unique_ptr<Tex> { (tex != nullptr) ? new Tex(tex->ix, texCoord) : nullptr };
} }
Tex::Tex(uint32_t texRef, uint32_t texCoord) Tex::Tex(uint32_t texRef, uint32_t texCoord) : texRef(texRef), texCoord(texCoord) {}
: texRef(texRef),
texCoord(texCoord) {}
void to_json(json &j, const Tex &data) { void to_json(json& j, const Tex& data) {
j = json { j = json{{"index", data.texRef}, {"texCoord", data.texCoord}};
{ "index", data.texRef },
{ "texCoord", data.texCoord }
};
} }
KHRCmnUnlitMaterial::KHRCmnUnlitMaterial() KHRCmnUnlitMaterial::KHRCmnUnlitMaterial() {}
{
}
void to_json(json &j, const KHRCmnUnlitMaterial &d) void to_json(json& j, const KHRCmnUnlitMaterial& d) {
{
j = json({}); j = json({});
} }
inline float clamp(float d, float bottom = 0, float top = 1) { inline float clamp(float d, float bottom = 0, float top = 1) {
return std::max(bottom, std::min(top, d)); return std::max(bottom, std::min(top, d));
} }
inline Vec3f clamp(const Vec3f &vec, const Vec3f &bottom = VEC3F_ZERO, const Vec3f &top = VEC3F_ONE) { inline Vec3f
clamp(const Vec3f& vec, const Vec3f& bottom = VEC3F_ZERO, const Vec3f& top = VEC3F_ONE) {
return Vec3f::Max(bottom, Vec3f::Min(top, vec)); return Vec3f::Max(bottom, Vec3f::Min(top, vec));
} }
inline Vec4f clamp(const Vec4f &vec, const Vec4f &bottom = VEC4F_ZERO, const Vec4f &top = VEC4F_ONE) { inline Vec4f
clamp(const Vec4f& vec, const Vec4f& bottom = VEC4F_ZERO, const Vec4f& top = VEC4F_ONE) {
return Vec4f::Max(bottom, Vec4f::Min(top, vec)); return Vec4f::Max(bottom, Vec4f::Min(top, vec));
} }
PBRMetallicRoughness::PBRMetallicRoughness( PBRMetallicRoughness::PBRMetallicRoughness(
const TextureData *baseColorTexture, const TextureData *metRoughTexture, const TextureData* baseColorTexture,
const Vec4f &baseColorFactor, float metallic, float roughness) const TextureData* metRoughTexture,
const Vec4f& baseColorFactor,
float metallic,
float roughness)
: baseColorTexture(Tex::ref(baseColorTexture)), : baseColorTexture(Tex::ref(baseColorTexture)),
metRoughTexture(Tex::ref(metRoughTexture)), metRoughTexture(Tex::ref(metRoughTexture)),
baseColorFactor(clamp(baseColorFactor)), baseColorFactor(clamp(baseColorFactor)),
metallic(clamp(metallic)), metallic(clamp(metallic)),
roughness(clamp(roughness)) roughness(clamp(roughness)) {}
{
}
void to_json(json &j, const PBRMetallicRoughness &d) void to_json(json& j, const PBRMetallicRoughness& d) {
{ j = {};
j = { };
if (d.baseColorTexture != nullptr) { if (d.baseColorTexture != nullptr) {
j["baseColorTexture"] = *d.baseColorTexture; j["baseColorTexture"] = *d.baseColorTexture;
} }
@ -79,9 +72,13 @@ void to_json(json &j, const PBRMetallicRoughness &d)
} }
MaterialData::MaterialData( MaterialData::MaterialData(
std::string name, bool isTransparent, const RawShadingModel shadingModel, std::string name,
const TextureData *normalTexture, const TextureData *occlusionTexture, bool isTransparent,
const TextureData *emissiveTexture, const Vec3f & emissiveFactor, const RawShadingModel shadingModel,
const TextureData* normalTexture,
const TextureData* occlusionTexture,
const TextureData* emissiveTexture,
const Vec3f& emissiveFactor,
std::shared_ptr<KHRCmnUnlitMaterial> const khrCmnConstantMaterial, std::shared_ptr<KHRCmnUnlitMaterial> const khrCmnConstantMaterial,
std::shared_ptr<PBRMetallicRoughness> const pbrMetallicRoughness) std::shared_ptr<PBRMetallicRoughness> const pbrMetallicRoughness)
: Holdable(), : Holdable(),
@ -95,18 +92,13 @@ MaterialData::MaterialData(
khrCmnConstantMaterial(khrCmnConstantMaterial), khrCmnConstantMaterial(khrCmnConstantMaterial),
pbrMetallicRoughness(pbrMetallicRoughness) {} pbrMetallicRoughness(pbrMetallicRoughness) {}
json MaterialData::serialize() const json MaterialData::serialize() const {
{ json result = {{"name", name},
json result = { {"alphaMode", isTransparent ? "BLEND" : "OPAQUE"},
{ "name", name }, {"extras",
{ "alphaMode", isTransparent ? "BLEND" : "OPAQUE" }, {{"fromFBX",
{ "extras", { {{"shadingModel", Describe(shadingModel)},
{ "fromFBX", { {"isTruePBR", shadingModel == RAW_SHADING_MODEL_PBR_MET_ROUGH}}}}}};
{ "shadingModel", Describe(shadingModel) },
{ "isTruePBR", shadingModel == RAW_SHADING_MODEL_PBR_MET_ROUGH }
}}
}}
};
if (normalTexture != nullptr) { if (normalTexture != nullptr) {
result["normalTexture"] = *normalTexture; result["normalTexture"] = *normalTexture;
@ -124,18 +116,16 @@ json MaterialData::serialize() const
result["pbrMetallicRoughness"] = *pbrMetallicRoughness; result["pbrMetallicRoughness"] = *pbrMetallicRoughness;
} }
if (khrCmnConstantMaterial != nullptr) { if (khrCmnConstantMaterial != nullptr) {
json extensions = { }; json extensions = {};
extensions[KHR_MATERIALS_CMN_UNLIT] = *khrCmnConstantMaterial; extensions[KHR_MATERIALS_CMN_UNLIT] = *khrCmnConstantMaterial;
result["extensions"] = extensions; result["extensions"] = extensions;
} }
for (const auto& i : userProperties) for (const auto& i : userProperties) {
{
auto& prop_map = result["extras"]["fromFBX"]["userProperties"]; auto& prop_map = result["extras"]["fromFBX"]["userProperties"];
json j = json::parse(i); json j = json::parse(i);
for (const auto& k : json::iterator_wrapper(j)) for (const auto& k : json::iterator_wrapper(j)) {
{
prop_map[k.key()] = k.value(); prop_map[k.key()] = k.value();
} }
} }

View File

@ -13,25 +13,25 @@
#include "gltf/Raw2Gltf.hpp" #include "gltf/Raw2Gltf.hpp"
struct Tex struct Tex {
{ static std::unique_ptr<Tex> ref(const TextureData* tex, uint32_t texCoord = 0);
static std::unique_ptr<Tex> ref(const TextureData *tex, uint32_t texCoord = 0);
explicit Tex(uint32_t texRef, uint32_t texCoord); explicit Tex(uint32_t texRef, uint32_t texCoord);
const uint32_t texRef; const uint32_t texRef;
const uint32_t texCoord; const uint32_t texCoord;
}; };
struct KHRCmnUnlitMaterial struct KHRCmnUnlitMaterial {
{
KHRCmnUnlitMaterial(); KHRCmnUnlitMaterial();
}; };
struct PBRMetallicRoughness struct PBRMetallicRoughness {
{
PBRMetallicRoughness( PBRMetallicRoughness(
const TextureData *baseColorTexture, const TextureData *metRoughTexture, const TextureData* baseColorTexture,
const Vec4f &baseColorFactor, float metallic = 0.1f, float roughness = 0.6f); const TextureData* metRoughTexture,
const Vec4f& baseColorFactor,
float metallic = 0.1f,
float roughness = 0.6f);
std::unique_ptr<Tex> baseColorTexture; std::unique_ptr<Tex> baseColorTexture;
std::unique_ptr<Tex> metRoughTexture; std::unique_ptr<Tex> metRoughTexture;
@ -40,12 +40,15 @@ struct PBRMetallicRoughness
const float roughness; const float roughness;
}; };
struct MaterialData : Holdable struct MaterialData : Holdable {
{
MaterialData( MaterialData(
std::string name, bool isTransparent, RawShadingModel shadingModel, std::string name,
const TextureData *normalTexture, const TextureData *occlusionTexture, bool isTransparent,
const TextureData *emissiveTexture, const Vec3f &emissiveFactor, RawShadingModel shadingModel,
const TextureData* normalTexture,
const TextureData* occlusionTexture,
const TextureData* emissiveTexture,
const Vec3f& emissiveFactor,
std::shared_ptr<KHRCmnUnlitMaterial> const khrCmnConstantMaterial, std::shared_ptr<KHRCmnUnlitMaterial> const khrCmnConstantMaterial,
std::shared_ptr<PBRMetallicRoughness> const pbrMetallicRoughness); std::shared_ptr<PBRMetallicRoughness> const pbrMetallicRoughness);
@ -65,6 +68,6 @@ struct MaterialData : Holdable
std::vector<std::string> userProperties; std::vector<std::string> userProperties;
}; };
void to_json(json &j, const Tex &data); void to_json(json& j, const Tex& data);
void to_json(json &j, const KHRCmnUnlitMaterial &d); void to_json(json& j, const KHRCmnUnlitMaterial& d);
void to_json(json &j, const PBRMetallicRoughness &d); void to_json(json& j, const PBRMetallicRoughness& d);

View File

@ -10,23 +10,15 @@
#include "MeshData.hpp" #include "MeshData.hpp"
#include "PrimitiveData.hpp" #include "PrimitiveData.hpp"
MeshData::MeshData(const std::string &name, const std::vector<float> &weights) MeshData::MeshData(const std::string& name, const std::vector<float>& weights)
: Holdable(), : Holdable(), name(name), weights(weights) {}
name(name),
weights(weights)
{
}
json MeshData::serialize() const json MeshData::serialize() const {
{
json jsonPrimitivesArray = json::array(); json jsonPrimitivesArray = json::array();
for (const auto &primitive : primitives) { for (const auto& primitive : primitives) {
jsonPrimitivesArray.push_back(*primitive); jsonPrimitivesArray.push_back(*primitive);
} }
json result = { json result = {{"name", name}, {"primitives", jsonPrimitivesArray}};
{ "name", name },
{ "primitives", jsonPrimitivesArray }
};
if (!weights.empty()) { if (!weights.empty()) {
result["weights"] = weights; result["weights"] = weights;
} }

View File

@ -17,12 +17,10 @@
#include "PrimitiveData.hpp" #include "PrimitiveData.hpp"
struct MeshData : Holdable struct MeshData : Holdable {
{ MeshData(const std::string& name, const std::vector<float>& weights);
MeshData(const std::string &name, const std::vector<float> &weights);
void AddPrimitive(std::shared_ptr<PrimitiveData> primitive) void AddPrimitive(std::shared_ptr<PrimitiveData> primitive) {
{
primitives.push_back(std::move(primitive)); primitives.push_back(std::move(primitive));
} }

View File

@ -10,8 +10,11 @@
#include "NodeData.hpp" #include "NodeData.hpp"
NodeData::NodeData( NodeData::NodeData(
std::string name, const Vec3f &translation, std::string name,
const Quatf &rotation, const Vec3f &scale, bool isJoint) const Vec3f& translation,
const Quatf& rotation,
const Vec3f& scale,
bool isJoint)
: Holdable(), : Holdable(),
name(std::move(name)), name(std::move(name)),
isJoint(isJoint), isJoint(isJoint),
@ -22,44 +25,36 @@ NodeData::NodeData(
mesh(-1), mesh(-1),
camera(-1), camera(-1),
light(-1), light(-1),
skin(-1) skin(-1) {}
{
}
void NodeData::AddChildNode(uint32_t childIx) void NodeData::AddChildNode(uint32_t childIx) {
{
children.push_back(childIx); children.push_back(childIx);
} }
void NodeData::SetMesh(uint32_t meshIx) void NodeData::SetMesh(uint32_t meshIx) {
{
assert(mesh < 0); assert(mesh < 0);
assert(!isJoint); assert(!isJoint);
mesh = meshIx; mesh = meshIx;
} }
void NodeData::SetSkin(uint32_t skinIx) void NodeData::SetSkin(uint32_t skinIx) {
{
assert(skin < 0); assert(skin < 0);
assert(!isJoint); assert(!isJoint);
skin = skinIx; skin = skinIx;
} }
void NodeData::SetCamera(uint32_t cameraIndex) void NodeData::SetCamera(uint32_t cameraIndex) {
{
assert(!isJoint); assert(!isJoint);
camera = cameraIndex; camera = cameraIndex;
} }
void NodeData::SetLight(uint32_t lightIndex) void NodeData::SetLight(uint32_t lightIndex) {
{
assert(!isJoint); assert(!isJoint);
light = lightIndex; light = lightIndex;
} }
json NodeData::serialize() const json NodeData::serialize() const {
{ json result = {{"name", name}};
json result = { { "name", name } };
// if any of the T/R/S have NaN components, just leave them out of the glTF // if any of the T/R/S have NaN components, just leave them out of the glTF
auto maybeAdd = [&](std::string key, std::vector<float> vec) -> void { auto maybeAdd = [&](std::string key, std::vector<float> vec) -> void {
@ -96,13 +91,11 @@ json NodeData::serialize() const
} }
} }
for (const auto& i : userProperties) for (const auto& i : userProperties) {
{
auto& prop_map = result["extras"]["fromFBX"]["userProperties"]; auto& prop_map = result["extras"]["fromFBX"]["userProperties"];
json j = json::parse(i); json j = json::parse(i);
for (const auto& k : json::iterator_wrapper(j)) for (const auto& k : json::iterator_wrapper(j)) {
{
prop_map[k.key()] = k.value(); prop_map[k.key()] = k.value();
} }
} }

View File

@ -11,9 +11,13 @@
#include "gltf/Raw2Gltf.hpp" #include "gltf/Raw2Gltf.hpp"
struct NodeData : Holdable struct NodeData : Holdable {
{ NodeData(
NodeData(std::string name, const Vec3f &translation, const Quatf &rotation, const Vec3f &scale, bool isJoint); std::string name,
const Vec3f& translation,
const Quatf& rotation,
const Vec3f& scale,
bool isJoint);
void AddChildNode(uint32_t childIx); void AddChildNode(uint32_t childIx);
void SetMesh(uint32_t meshIx); void SetMesh(uint32_t meshIx);

View File

@ -9,73 +9,71 @@
#include "PrimitiveData.hpp" #include "PrimitiveData.hpp"
#include "MaterialData.hpp"
#include "AccessorData.hpp" #include "AccessorData.hpp"
#include "BufferViewData.hpp" #include "BufferViewData.hpp"
#include "MaterialData.hpp"
PrimitiveData::PrimitiveData(const AccessorData &indices, const MaterialData &material, std::shared_ptr<draco::Mesh> dracoMesh) PrimitiveData::PrimitiveData(
const AccessorData& indices,
const MaterialData& material,
std::shared_ptr<draco::Mesh> dracoMesh)
: indices(indices.ix), : indices(indices.ix),
material(material.ix), material(material.ix),
mode(TRIANGLES), mode(TRIANGLES),
dracoMesh(dracoMesh), dracoMesh(dracoMesh),
dracoBufferView(-1) {} dracoBufferView(-1) {}
PrimitiveData::PrimitiveData(const AccessorData &indices, const MaterialData &material) PrimitiveData::PrimitiveData(const AccessorData& indices, const MaterialData& material)
: indices(indices.ix), : indices(indices.ix),
material(material.ix), material(material.ix),
mode(TRIANGLES), mode(TRIANGLES),
dracoMesh(nullptr), dracoMesh(nullptr),
dracoBufferView(-1) dracoBufferView(-1) {}
{
}
void PrimitiveData::AddAttrib(std::string name, const AccessorData &accessor) void PrimitiveData::AddAttrib(std::string name, const AccessorData& accessor) {
{
attributes[name] = accessor.ix; attributes[name] = accessor.ix;
} }
void PrimitiveData::NoteDracoBuffer(const BufferViewData &data) void PrimitiveData::NoteDracoBuffer(const BufferViewData& data) {
{
dracoBufferView = data.ix; dracoBufferView = data.ix;
} }
void PrimitiveData::AddTarget(const AccessorData *positions, const AccessorData *normals, const AccessorData *tangents) void PrimitiveData::AddTarget(
{ const AccessorData* positions,
const AccessorData* normals,
const AccessorData* tangents) {
targetAccessors.push_back(std::make_tuple( targetAccessors.push_back(std::make_tuple(
positions->ix, positions->ix,
normals != nullptr ? normals->ix : -1, normals != nullptr ? normals->ix : -1,
tangents != nullptr ? tangents ->ix : -1 tangents != nullptr ? tangents->ix : -1));
));
} }
void to_json(json &j, const PrimitiveData &d) { void to_json(json& j, const PrimitiveData& d) {
j = { j = {{"material", d.material}, {"mode", d.mode}, {"attributes", d.attributes}};
{ "material", d.material },
{ "mode", d.mode },
{ "attributes", d.attributes }
};
if (d.indices >= 0) { if (d.indices >= 0) {
j["indices"] = d.indices; j["indices"] = d.indices;
} }
if (!d.targetAccessors.empty()) { if (!d.targetAccessors.empty()) {
json targets {}; json targets{};
int pIx, nIx, tIx; int pIx, nIx, tIx;
for (auto accessor : d.targetAccessors) { for (auto accessor : d.targetAccessors) {
std::tie(pIx, nIx, tIx) = accessor; std::tie(pIx, nIx, tIx) = accessor;
json target {}; json target{};
if (pIx >= 0) { target["POSITION"] = pIx; } if (pIx >= 0) {
if (nIx >= 0) { target["NORMAL"] = nIx; } target["POSITION"] = pIx;
if (tIx >= 0) { target["TANGENT"] = tIx; } }
if (nIx >= 0) {
target["NORMAL"] = nIx;
}
if (tIx >= 0) {
target["TANGENT"] = tIx;
}
targets.push_back(target); targets.push_back(target);
} }
j["targets"] = targets; j["targets"] = targets;
} }
if (!d.dracoAttributes.empty()) { if (!d.dracoAttributes.empty()) {
j["extensions"] = { j["extensions"] = {{KHR_DRACO_MESH_COMPRESSION,
{ KHR_DRACO_MESH_COMPRESSION, { {{"bufferView", d.dracoBufferView}, {"attributes", d.dracoAttributes}}}};
{ "bufferView", d.dracoBufferView },
{ "attributes", d.dracoAttributes }
}}
};
} }
} }

View File

@ -11,10 +11,8 @@
#include "gltf/Raw2Gltf.hpp" #include "gltf/Raw2Gltf.hpp"
struct PrimitiveData struct PrimitiveData {
{ enum MeshMode {
enum MeshMode
{
POINTS = 0, POINTS = 0,
LINES, LINES,
LINE_LOOP, LINE_LOOP,
@ -24,29 +22,39 @@ struct PrimitiveData
TRIANGLE_FAN TRIANGLE_FAN
}; };
PrimitiveData(const AccessorData &indices, const MaterialData &material, std::shared_ptr<draco::Mesh> dracoMesh); PrimitiveData(
const AccessorData& indices,
const MaterialData& material,
std::shared_ptr<draco::Mesh> dracoMesh);
PrimitiveData(const AccessorData &indices, const MaterialData &material); PrimitiveData(const AccessorData& indices, const MaterialData& material);
void AddAttrib(std::string name, const AccessorData &accessor); void AddAttrib(std::string name, const AccessorData& accessor);
void AddTarget(const AccessorData *positions, const AccessorData *normals, const AccessorData *tangents); void AddTarget(
const AccessorData* positions,
const AccessorData* normals,
const AccessorData* tangents);
template<class T> template <class T>
void AddDracoAttrib(const AttributeDefinition<T> attribute, const std::vector<T> &attribArr) void AddDracoAttrib(const AttributeDefinition<T> attribute, const std::vector<T>& attribArr) {
{
draco::PointAttribute att; draco::PointAttribute att;
int8_t componentCount = attribute.glType.count; int8_t componentCount = attribute.glType.count;
att.Init( att.Init(
attribute.dracoAttribute, nullptr, componentCount, attribute.dracoComponentType, attribute.dracoAttribute,
false, componentCount * draco::DataTypeLength(attribute.dracoComponentType), 0); nullptr,
componentCount,
attribute.dracoComponentType,
false,
componentCount * draco::DataTypeLength(attribute.dracoComponentType),
0);
const int dracoAttId = dracoMesh->AddAttribute(att, true, attribArr.size()); const int dracoAttId = dracoMesh->AddAttribute(att, true, attribArr.size());
draco::PointAttribute *attPtr = dracoMesh->attribute(dracoAttId); draco::PointAttribute* attPtr = dracoMesh->attribute(dracoAttId);
std::vector<uint8_t> buf(sizeof(T)); std::vector<uint8_t> buf(sizeof(T));
for (uint32_t ii = 0; ii < attribArr.size(); ii++) { for (uint32_t ii = 0; ii < attribArr.size(); ii++) {
uint8_t *ptr = &buf[0]; uint8_t* ptr = &buf[0];
attribute.glType.write(ptr, attribArr[ii]); attribute.glType.write(ptr, attribArr[ii]);
attPtr->SetAttributeValue(attPtr->mapped_index(draco::PointIndex(ii)), ptr); attPtr->SetAttributeValue(attPtr->mapped_index(draco::PointIndex(ii)), ptr);
} }
@ -54,13 +62,13 @@ struct PrimitiveData
dracoAttributes[attribute.gltfName] = dracoAttId; dracoAttributes[attribute.gltfName] = dracoAttId;
} }
void NoteDracoBuffer(const BufferViewData &data); void NoteDracoBuffer(const BufferViewData& data);
const int indices; const int indices;
const unsigned int material; const unsigned int material;
const MeshMode mode; const MeshMode mode;
std::vector<std::tuple<int, int, int>> targetAccessors {}; std::vector<std::tuple<int, int, int>> targetAccessors{};
std::map<std::string, int> attributes; std::map<std::string, int> attributes;
std::map<std::string, int> dracoAttributes; std::map<std::string, int> dracoAttributes;
@ -69,4 +77,4 @@ struct PrimitiveData
int dracoBufferView; int dracoBufferView;
}; };
void to_json(json &j, const PrimitiveData &d); void to_json(json& j, const PrimitiveData& d);

View File

@ -11,13 +11,9 @@
#include "gltf/Raw2Gltf.hpp" #include "gltf/Raw2Gltf.hpp"
struct SamplerData : Holdable struct SamplerData : Holdable {
{
// this is where magFilter, minFilter, wrapS and wrapT would go, should we want it // this is where magFilter, minFilter, wrapS and wrapT would go, should we want it
SamplerData() SamplerData() : Holdable() {}
: Holdable()
{
}
json serialize() const override { json serialize() const override {
return json::object(); return json::object();

View File

@ -11,18 +11,10 @@
#include "NodeData.hpp" #include "NodeData.hpp"
SceneData::SceneData(std::string name, const NodeData &rootNode) SceneData::SceneData(std::string name, const NodeData& rootNode)
: Holdable(), : Holdable(), name(std::move(name)), nodes({rootNode.ix}) {}
name(std::move(name)),
nodes({rootNode.ix})
{
}
json SceneData::serialize() const json SceneData::serialize() const {
{
assert(nodes.size() <= 1); assert(nodes.size() <= 1);
return { return {{"name", name}, {"nodes", nodes}};
{ "name", name },
{ "nodes", nodes }
};
} }

View File

@ -11,9 +11,8 @@
#include "gltf/Raw2Gltf.hpp" #include "gltf/Raw2Gltf.hpp"
struct SceneData : Holdable struct SceneData : Holdable {
{ SceneData(std::string name, const NodeData& rootNode);
SceneData(std::string name, const NodeData &rootNode);
json serialize() const override; json serialize() const override;

View File

@ -13,20 +13,16 @@
#include "NodeData.hpp" #include "NodeData.hpp"
SkinData::SkinData( SkinData::SkinData(
const std::vector<uint32_t> joints, const AccessorData &inverseBindMatricesAccessor, const std::vector<uint32_t> joints,
const NodeData &skeletonRootNode) const AccessorData& inverseBindMatricesAccessor,
const NodeData& skeletonRootNode)
: Holdable(), : Holdable(),
joints(joints), joints(joints),
inverseBindMatrices(inverseBindMatricesAccessor.ix), inverseBindMatrices(inverseBindMatricesAccessor.ix),
skeletonRootNode(skeletonRootNode.ix) skeletonRootNode(skeletonRootNode.ix) {}
{
}
json SkinData::serialize() const json SkinData::serialize() const {
{ return {{"joints", joints},
return { {"inverseBindMatrices", inverseBindMatrices},
{ "joints", joints }, {"skeleton", skeletonRootNode}};
{ "inverseBindMatrices", inverseBindMatrices },
{ "skeleton", skeletonRootNode }
};
} }

View File

@ -11,11 +11,11 @@
#include "gltf/Raw2Gltf.hpp" #include "gltf/Raw2Gltf.hpp"
struct SkinData : Holdable struct SkinData : Holdable {
{
SkinData( SkinData(
const std::vector<uint32_t> joints, const AccessorData &inverseBindMatricesAccessor, const std::vector<uint32_t> joints,
const NodeData &skeletonRootNode); const AccessorData& inverseBindMatricesAccessor,
const NodeData& skeletonRootNode);
json serialize() const override; json serialize() const override;

View File

@ -12,19 +12,9 @@
#include "ImageData.hpp" #include "ImageData.hpp"
#include "SamplerData.hpp" #include "SamplerData.hpp"
TextureData::TextureData(std::string name, const SamplerData &sampler, const ImageData &source) TextureData::TextureData(std::string name, const SamplerData& sampler, const ImageData& source)
: Holdable(), : Holdable(), name(std::move(name)), sampler(sampler.ix), source(source.ix) {}
name(std::move(name)),
sampler(sampler.ix),
source(source.ix)
{
}
json TextureData::serialize() const json TextureData::serialize() const {
{ return {{"name", name}, {"sampler", sampler}, {"source", source}};
return {
{ "name", name },
{ "sampler", sampler },
{ "source", source }
};
} }

View File

@ -11,9 +11,8 @@
#include "gltf/Raw2Gltf.hpp" #include "gltf/Raw2Gltf.hpp"
struct TextureData : Holdable struct TextureData : Holdable {
{ TextureData(std::string name, const SamplerData& sampler, const ImageData& source);
TextureData(std::string name, const SamplerData &sampler, const ImageData &source);
json serialize() const override; json serialize() const override;

View File

@ -11,18 +11,17 @@
#include <fbxsdk.h> #include <fbxsdk.h>
#include <mathfu/vector.h>
#include <mathfu/matrix.h> #include <mathfu/matrix.h>
#include <mathfu/quaternion.h> #include <mathfu/quaternion.h>
#include <mathfu/rect.h> #include <mathfu/rect.h>
#include <mathfu/vector.h>
/** /**
* All the mathfu:: implementations of our core data types. * All the mathfu:: implementations of our core data types.
*/ */
template<class T, int d> template <class T, int d>
struct Bounds struct Bounds {
{
mathfu::Vector<T, d> min; mathfu::Vector<T, d> min;
mathfu::Vector<T, d> max; mathfu::Vector<T, d> max;
bool initialized = false; bool initialized = false;
@ -33,9 +32,9 @@ struct Bounds
initialized = false; initialized = false;
} }
void AddPoint(const mathfu::Vector<T, d> &p) { void AddPoint(const mathfu::Vector<T, d>& p) {
if (initialized) { if (initialized) {
for (int ii = 0; ii < d; ii ++) { for (int ii = 0; ii < d; ii++) {
min(ii) = std::min(min(ii), p(ii)); min(ii) = std::min(min(ii), p(ii));
max(ii) = std::max(max(ii), p(ii)); max(ii) = std::max(max(ii), p(ii));
} }
@ -58,46 +57,47 @@ typedef mathfu::Matrix<float, 4> Mat4f;
typedef mathfu::Quaternion<float> Quatf; typedef mathfu::Quaternion<float> Quatf;
typedef Bounds<float, 3> Boundsf; typedef Bounds<float, 3> Boundsf;
#define VEC3F_ONE (Vec3f {1.0f}) #define VEC3F_ONE (Vec3f{1.0f})
#define VEC3F_ZERO (Vec3f {0.0f}) #define VEC3F_ZERO (Vec3f{0.0f})
#define VEC4F_ONE (Vec4f {1.0f}) #define VEC4F_ONE (Vec4f{1.0f})
#define VEC4F_ZERO (Vec4f {0.0f}) #define VEC4F_ZERO (Vec4f{0.0f})
template<class T, int d> inline std::vector<T> toStdVec(const mathfu::Vector <T, d> &vec) template <class T, int d>
{ inline std::vector<T> toStdVec(const mathfu::Vector<T, d>& vec) {
std::vector<T> result(d); std::vector<T> result(d);
for (int ii = 0; ii < d; ii ++) { for (int ii = 0; ii < d; ii++) {
result[ii] = vec[ii]; result[ii] = vec[ii];
} }
return result; return result;
} }
template<class T> std::vector<T> toStdVec(const mathfu::Quaternion<T> &quat) { template <class T>
return std::vector<T> { quat.vector()[0], quat.vector()[1], quat.vector()[2], quat.scalar() }; std::vector<T> toStdVec(const mathfu::Quaternion<T>& quat) {
return std::vector<T>{quat.vector()[0], quat.vector()[1], quat.vector()[2], quat.scalar()};
} }
inline Vec3f toVec3f(const FbxDouble3 &v) { inline Vec3f toVec3f(const FbxDouble3& v) {
return Vec3f((float) v[0], (float) v[1], (float) v[2]); return Vec3f((float)v[0], (float)v[1], (float)v[2]);
} }
inline Vec3f toVec3f(const FbxVector4 &v) { inline Vec3f toVec3f(const FbxVector4& v) {
return Vec3f((float) v[0], (float) v[1], (float) v[2]); return Vec3f((float)v[0], (float)v[1], (float)v[2]);
} }
inline Vec4f toVec4f(const FbxVector4 &v) { inline Vec4f toVec4f(const FbxVector4& v) {
return Vec4f((float) v[0], (float) v[1], (float) v[2], (float) v[3]); return Vec4f((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
} }
inline Mat4f toMat4f(const FbxAMatrix &m) { inline Mat4f toMat4f(const FbxAMatrix& m) {
auto result = Mat4f(); auto result = Mat4f();
for (int row = 0; row < 4; row ++) { for (int row = 0; row < 4; row++) {
for (int col = 0; col < 4; col ++) { for (int col = 0; col < 4; col++) {
result(row, col) = (float) m[row][col]; result(row, col) = (float)m[row][col];
} }
} }
return result; return result;
} }
inline Quatf toQuatf(const FbxQuaternion &q) { inline Quatf toQuatf(const FbxQuaternion& q) {
return Quatf((float) q[3], (float) q[0], (float) q[1], (float) q[2]); return Quatf((float)q[3], (float)q[0], (float)q[1], (float)q[2]);
} }

View File

@ -9,120 +9,136 @@
#include "RawModel.hpp" #include "RawModel.hpp"
#include <vector>
#include <string>
#include <unordered_map>
#include <cmath> #include <cmath>
#include <map> #include <map>
#include <set> #include <set>
#include <string>
#include <unordered_map>
#include <vector>
#if defined( __unix__ ) #if defined(__unix__)
#include <algorithm> #include <algorithm>
#endif #endif
#include "utils/String_Utils.hpp"
#include "utils/Image_Utils.hpp" #include "utils/Image_Utils.hpp"
#include "utils/String_Utils.hpp"
bool RawVertex::operator==(const RawVertex &other) const bool RawVertex::operator==(const RawVertex& other) const {
{ return (position == other.position) && (normal == other.normal) && (tangent == other.tangent) &&
return (position == other.position) && (binormal == other.binormal) && (color == other.color) && (uv0 == other.uv0) &&
(normal == other.normal) && (uv1 == other.uv1) && (jointIndices == other.jointIndices) &&
(tangent == other.tangent) && (jointWeights == other.jointWeights) && (polarityUv0 == other.polarityUv0) &&
(binormal == other.binormal) && (blendSurfaceIx == other.blendSurfaceIx) && (blends == other.blends);
(color == other.color) &&
(uv0 == other.uv0) &&
(uv1 == other.uv1) &&
(jointIndices == other.jointIndices) &&
(jointWeights == other.jointWeights) &&
(polarityUv0 == other.polarityUv0) &&
(blendSurfaceIx == other.blendSurfaceIx) &&
(blends == other.blends);
} }
size_t RawVertex::Difference(const RawVertex &other) const size_t RawVertex::Difference(const RawVertex& other) const {
{
size_t attributes = 0; size_t attributes = 0;
if (position != other.position) { attributes |= RAW_VERTEX_ATTRIBUTE_POSITION; } if (position != other.position) {
if (normal != other.normal) { attributes |= RAW_VERTEX_ATTRIBUTE_NORMAL; } attributes |= RAW_VERTEX_ATTRIBUTE_POSITION;
if (tangent != other.tangent) { attributes |= RAW_VERTEX_ATTRIBUTE_TANGENT; } }
if (binormal != other.binormal) { attributes |= RAW_VERTEX_ATTRIBUTE_BINORMAL; } if (normal != other.normal) {
if (color != other.color) { attributes |= RAW_VERTEX_ATTRIBUTE_COLOR; } attributes |= RAW_VERTEX_ATTRIBUTE_NORMAL;
if (uv0 != other.uv0) { attributes |= RAW_VERTEX_ATTRIBUTE_UV0; } }
if (uv1 != other.uv1) { attributes |= RAW_VERTEX_ATTRIBUTE_UV1; } if (tangent != other.tangent) {
attributes |= RAW_VERTEX_ATTRIBUTE_TANGENT;
}
if (binormal != other.binormal) {
attributes |= RAW_VERTEX_ATTRIBUTE_BINORMAL;
}
if (color != other.color) {
attributes |= RAW_VERTEX_ATTRIBUTE_COLOR;
}
if (uv0 != other.uv0) {
attributes |= RAW_VERTEX_ATTRIBUTE_UV0;
}
if (uv1 != other.uv1) {
attributes |= RAW_VERTEX_ATTRIBUTE_UV1;
}
// Always need both or neither. // Always need both or neither.
if (jointIndices != other.jointIndices) { attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS; } if (jointIndices != other.jointIndices) {
if (jointWeights != other.jointWeights) { attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS; } attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS;
}
if (jointWeights != other.jointWeights) {
attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS;
}
return attributes; return attributes;
} }
RawModel::RawModel() RawModel::RawModel() : vertexAttributes(0) {}
: vertexAttributes(0)
{
}
void RawModel::AddVertexAttribute(const RawVertexAttribute attrib) void RawModel::AddVertexAttribute(const RawVertexAttribute attrib) {
{
vertexAttributes |= attrib; vertexAttributes |= attrib;
} }
int RawModel::AddVertex(const RawVertex &vertex) int RawModel::AddVertex(const RawVertex& vertex) {
{
auto it = vertexHash.find(vertex); auto it = vertexHash.find(vertex);
if (it != vertexHash.end()) { if (it != vertexHash.end()) {
return it->second; return it->second;
} }
vertexHash.emplace(vertex, (int) vertices.size()); vertexHash.emplace(vertex, (int)vertices.size());
vertices.push_back(vertex); vertices.push_back(vertex);
return (int) vertices.size() - 1; return (int)vertices.size() - 1;
} }
int RawModel::AddTriangle(const int v0, const int v1, const int v2, const int materialIndex, const int surfaceIndex) int RawModel::AddTriangle(
{ const int v0,
const int v1,
const int v2,
const int materialIndex,
const int surfaceIndex) {
const RawTriangle triangle = {{v0, v1, v2}, materialIndex, surfaceIndex}; const RawTriangle triangle = {{v0, v1, v2}, materialIndex, surfaceIndex};
triangles.push_back(triangle); triangles.push_back(triangle);
return (int) triangles.size() - 1; return (int)triangles.size() - 1;
} }
int RawModel::AddTexture(const std::string &name, const std::string &fileName, const std::string &fileLocation, RawTextureUsage usage) int RawModel::AddTexture(
{ const std::string& name,
const std::string& fileName,
const std::string& fileLocation,
RawTextureUsage usage) {
if (name.empty()) { if (name.empty()) {
return -1; return -1;
} }
for (size_t i = 0; i < textures.size(); i++) { for (size_t i = 0; i < textures.size(); i++) {
if (StringUtils::CompareNoCase(textures[i].name, name) == 0 && textures[i].usage == usage) { if (StringUtils::CompareNoCase(textures[i].name, name) == 0 && textures[i].usage == usage) {
return (int) i; return (int)i;
} }
} }
const ImageUtils::ImageProperties const ImageUtils::ImageProperties properties = ImageUtils::GetImageProperties(
properties = ImageUtils::GetImageProperties(!fileLocation.empty() ? fileLocation.c_str() : fileName.c_str()); !fileLocation.empty() ? fileLocation.c_str() : fileName.c_str());
RawTexture texture; RawTexture texture;
texture.name = name; texture.name = name;
texture.width = properties.width; texture.width = properties.width;
texture.height = properties.height; texture.height = properties.height;
texture.mipLevels = (int) ceilf(log2f(std::max((float) properties.width, (float) properties.height))); texture.mipLevels =
(int)ceilf(log2f(std::max((float)properties.width, (float)properties.height)));
texture.usage = usage; texture.usage = usage;
texture.occlusion = (properties.occlusion == ImageUtils::IMAGE_TRANSPARENT) ? texture.occlusion = (properties.occlusion == ImageUtils::IMAGE_TRANSPARENT)
RAW_TEXTURE_OCCLUSION_TRANSPARENT : RAW_TEXTURE_OCCLUSION_OPAQUE; ? RAW_TEXTURE_OCCLUSION_TRANSPARENT
: RAW_TEXTURE_OCCLUSION_OPAQUE;
texture.fileName = fileName; texture.fileName = fileName;
texture.fileLocation = fileLocation; texture.fileLocation = fileLocation;
textures.emplace_back(texture); textures.emplace_back(texture);
return (int) textures.size() - 1; return (int)textures.size() - 1;
} }
int RawModel::AddMaterial(const RawMaterial &material) int RawModel::AddMaterial(const RawMaterial& material) {
{ return AddMaterial(
return AddMaterial(material.name.c_str(), material.type, material.textures, material.info, material.userProperties); material.name.c_str(),
material.type,
material.textures,
material.info,
material.userProperties);
} }
int RawModel::AddMaterial( int RawModel::AddMaterial(
const char *name, const char* name,
const RawMaterialType materialType, const RawMaterialType materialType,
const int textures[RAW_TEXTURE_USAGE_MAX], const int textures[RAW_TEXTURE_USAGE_MAX],
std::shared_ptr<RawMatProps> materialInfo, std::shared_ptr<RawMatProps> materialInfo,
const std::vector<std::string>& userProperties) const std::vector<std::string>& userProperties) {
{
for (size_t i = 0; i < materials.size(); i++) { for (size_t i = 0; i < materials.size(); i++) {
if (materials[i].name != name) { if (materials[i].name != name) {
continue; continue;
@ -139,14 +155,13 @@ int RawModel::AddMaterial(
} }
if (materials[i].userProperties.size() != userProperties.size()) { if (materials[i].userProperties.size() != userProperties.size()) {
match = false; match = false;
} } else {
else {
for (int j = 0; match && j < userProperties.size(); j++) { for (int j = 0; match && j < userProperties.size(); j++) {
match = match && (materials[i].userProperties[j] == userProperties[j]); match = match && (materials[i].userProperties[j] == userProperties[j]);
} }
} }
if (match) { if (match) {
return (int) i; return (int)i;
} }
} }
@ -162,18 +177,17 @@ int RawModel::AddMaterial(
materials.emplace_back(material); materials.emplace_back(material);
return (int) materials.size() - 1; return (int)materials.size() - 1;
} }
int RawModel::AddLight( int RawModel::AddLight(
const char *name, const char* name,
const RawLightType lightType, const RawLightType lightType,
const Vec3f color, const Vec3f color,
const float intensity, const float intensity,
const float innerConeAngle, const float innerConeAngle,
const float outerConeAngle) const float outerConeAngle) {
{ for (size_t i = 0; i < lights.size(); i++) {
for (size_t i = 0; i < lights.size(); i ++) {
if (lights[i].name != name || lights[i].type != lightType) { if (lights[i].name != name || lights[i].type != lightType) {
continue; continue;
} }
@ -184,9 +198,9 @@ int RawModel::AddLight(
continue; continue;
} }
} }
return (int) i; return (int)i;
} }
RawLight light { RawLight light{
name, name,
lightType, lightType,
color, color,
@ -195,29 +209,26 @@ int RawModel::AddLight(
outerConeAngle, outerConeAngle,
}; };
lights.push_back(light); lights.push_back(light);
return (int) lights.size() - 1; return (int)lights.size() - 1;
} }
int RawModel::AddSurface(const RawSurface& surface) {
int RawModel::AddSurface(const RawSurface &surface)
{
for (size_t i = 0; i < surfaces.size(); i++) { for (size_t i = 0; i < surfaces.size(); i++) {
if (StringUtils::CompareNoCase(surfaces[i].name, surface.name) == 0) { if (StringUtils::CompareNoCase(surfaces[i].name, surface.name) == 0) {
return (int) i; return (int)i;
} }
} }
surfaces.emplace_back(surface); surfaces.emplace_back(surface);
return (int) (surfaces.size() - 1); return (int)(surfaces.size() - 1);
} }
int RawModel::AddSurface(const char *name, const long surfaceId) int RawModel::AddSurface(const char* name, const long surfaceId) {
{
assert(name[0] != '\0'); assert(name[0] != '\0');
for (size_t i = 0; i < surfaces.size(); i++) { for (size_t i = 0; i < surfaces.size(); i++) {
if (surfaces[i].id == surfaceId) { if (surfaces[i].id == surfaceId) {
return (int) i; return (int)i;
} }
} }
RawSurface surface; RawSurface surface;
@ -227,17 +238,15 @@ int RawModel::AddSurface(const char *name, const long surfaceId)
surface.discrete = false; surface.discrete = false;
surfaces.emplace_back(surface); surfaces.emplace_back(surface);
return (int) (surfaces.size() - 1); return (int)(surfaces.size() - 1);
} }
int RawModel::AddAnimation(const RawAnimation &animation) int RawModel::AddAnimation(const RawAnimation& animation) {
{
animations.emplace_back(animation); animations.emplace_back(animation);
return (int) (animations.size() - 1); return (int)(animations.size() - 1);
} }
int RawModel::AddNode(const RawNode &node) int RawModel::AddNode(const RawNode& node) {
{
for (size_t i = 0; i < nodes.size(); i++) { for (size_t i = 0; i < nodes.size(); i++) {
if (nodes[i].id == node.id) { if (nodes[i].id == node.id) {
return (int)i; return (int)i;
@ -245,13 +254,17 @@ int RawModel::AddNode(const RawNode &node)
} }
nodes.emplace_back(node); nodes.emplace_back(node);
return (int) nodes.size() - 1; return (int)nodes.size() - 1;
} }
int RawModel::AddCameraPerspective( int RawModel::AddCameraPerspective(
const char *name, const long nodeId, const float aspectRatio, const float fovDegreesX, const float fovDegreesY, const float nearZ, const char* name,
const float farZ) const long nodeId,
{ const float aspectRatio,
const float fovDegreesX,
const float fovDegreesY,
const float nearZ,
const float farZ) {
RawCamera camera; RawCamera camera;
camera.name = name; camera.name = name;
camera.nodeId = nodeId; camera.nodeId = nodeId;
@ -262,12 +275,16 @@ int RawModel::AddCameraPerspective(
camera.perspective.nearZ = nearZ; camera.perspective.nearZ = nearZ;
camera.perspective.farZ = farZ; camera.perspective.farZ = farZ;
cameras.emplace_back(camera); cameras.emplace_back(camera);
return (int) cameras.size() - 1; return (int)cameras.size() - 1;
} }
int RawModel::AddCameraOrthographic( int RawModel::AddCameraOrthographic(
const char *name, const long nodeId, const float magX, const float magY, const float nearZ, const float farZ) const char* name,
{ const long nodeId,
const float magX,
const float magY,
const float nearZ,
const float farZ) {
RawCamera camera; RawCamera camera;
camera.name = name; camera.name = name;
camera.nodeId = nodeId; camera.nodeId = nodeId;
@ -277,16 +294,15 @@ int RawModel::AddCameraOrthographic(
camera.orthographic.nearZ = nearZ; camera.orthographic.nearZ = nearZ;
camera.orthographic.farZ = farZ; camera.orthographic.farZ = farZ;
cameras.emplace_back(camera); cameras.emplace_back(camera);
return (int) cameras.size() - 1; return (int)cameras.size() - 1;
} }
int RawModel::AddNode(const long id, const char *name, const long parentId) int RawModel::AddNode(const long id, const char* name, const long parentId) {
{
assert(name[0] != '\0'); assert(name[0] != '\0');
for (size_t i = 0; i < nodes.size(); i++) { for (size_t i = 0; i < nodes.size(); i++) {
if (nodes[i].id == id ) { if (nodes[i].id == id) {
return (int) i; return (int)i;
} }
} }
@ -302,11 +318,10 @@ int RawModel::AddNode(const long id, const char *name, const long parentId)
joint.scale = Vec3f(1, 1, 1); joint.scale = Vec3f(1, 1, 1);
nodes.emplace_back(joint); nodes.emplace_back(joint);
return (int) nodes.size() - 1; return (int)nodes.size() - 1;
} }
void RawModel::Condense() void RawModel::Condense() {
{
// Only keep surfaces that are referenced by one or more triangles. // Only keep surfaces that are referenced by one or more triangles.
{ {
std::vector<RawSurface> oldSurfaces = surfaces; std::vector<RawSurface> oldSurfaces = surfaces;
@ -314,16 +329,17 @@ void RawModel::Condense()
surfaces.clear(); surfaces.clear();
std::set<int> survivingSurfaceIds; std::set<int> survivingSurfaceIds;
for (auto &triangle : triangles) { for (auto& triangle : triangles) {
const RawSurface &surface = oldSurfaces[triangle.surfaceIndex]; const RawSurface& surface = oldSurfaces[triangle.surfaceIndex];
const int surfaceIndex = AddSurface(surface.name.c_str(), surface.id); const int surfaceIndex = AddSurface(surface.name.c_str(), surface.id);
surfaces[surfaceIndex] = surface; surfaces[surfaceIndex] = surface;
triangle.surfaceIndex = surfaceIndex; triangle.surfaceIndex = surfaceIndex;
survivingSurfaceIds.emplace(surface.id); survivingSurfaceIds.emplace(surface.id);
} }
// clear out references to meshes that no longer exist // clear out references to meshes that no longer exist
for (auto &node : nodes) { for (auto& node : nodes) {
if (node.surfaceId != 0 && survivingSurfaceIds.find(node.surfaceId) == survivingSurfaceIds.end()) { if (node.surfaceId != 0 &&
survivingSurfaceIds.find(node.surfaceId) == survivingSurfaceIds.end()) {
node.surfaceId = 0; node.surfaceId = 0;
} }
} }
@ -335,8 +351,8 @@ void RawModel::Condense()
materials.clear(); materials.clear();
for (auto &triangle : triangles) { for (auto& triangle : triangles) {
const RawMaterial &material = oldMaterials[triangle.materialIndex]; const RawMaterial& material = oldMaterials[triangle.materialIndex];
const int materialIndex = AddMaterial(material); const int materialIndex = AddMaterial(material);
materials[materialIndex] = material; materials[materialIndex] = material;
triangle.materialIndex = materialIndex; triangle.materialIndex = materialIndex;
@ -349,11 +365,12 @@ void RawModel::Condense()
textures.clear(); textures.clear();
for (auto &material : materials) { for (auto& material : materials) {
for (int j = 0; j < RAW_TEXTURE_USAGE_MAX; j++) { for (int j = 0; j < RAW_TEXTURE_USAGE_MAX; j++) {
if (material.textures[j] >= 0) { if (material.textures[j] >= 0) {
const RawTexture &texture = oldTextures[material.textures[j]]; const RawTexture& texture = oldTextures[material.textures[j]];
const int textureIndex = AddTexture(texture.name, texture.fileName, texture.fileLocation, texture.usage); const int textureIndex =
AddTexture(texture.name, texture.fileName, texture.fileLocation, texture.usage);
textures[textureIndex] = texture; textures[textureIndex] = texture;
material.textures[j] = textureIndex; material.textures[j] = textureIndex;
} }
@ -368,7 +385,7 @@ void RawModel::Condense()
vertexHash.clear(); vertexHash.clear();
vertices.clear(); vertices.clear();
for (auto &triangle : triangles) { for (auto& triangle : triangles) {
for (int j = 0; j < 3; j++) { for (int j = 0; j < 3; j++) {
triangle.verts[j] = AddVertex(oldVertices[triangle.verts[j]]); triangle.verts[j] = AddVertex(oldVertices[triangle.verts[j]]);
} }
@ -376,9 +393,8 @@ void RawModel::Condense()
} }
} }
void RawModel::TransformGeometry(ComputeNormalsOption normals) void RawModel::TransformGeometry(ComputeNormalsOption normals) {
{ switch (normals) {
switch(normals) {
case ComputeNormalsOption::NEVER: case ComputeNormalsOption::NEVER:
break; break;
case ComputeNormalsOption::MISSING: case ComputeNormalsOption::MISSING:
@ -404,26 +420,23 @@ void RawModel::TransformGeometry(ComputeNormalsOption normals)
} }
} }
void RawModel::TransformTextures(const std::vector<std::function<Vec2f(Vec2f)>> &transforms) void RawModel::TransformTextures(const std::vector<std::function<Vec2f(Vec2f)>>& transforms) {
{ for (auto& vertice : vertices) {
for (auto &vertice : vertices) {
if ((vertexAttributes & RAW_VERTEX_ATTRIBUTE_UV0) != 0) { if ((vertexAttributes & RAW_VERTEX_ATTRIBUTE_UV0) != 0) {
for (const auto &fun : transforms) { for (const auto& fun : transforms) {
vertice.uv0 = fun(vertice.uv0); vertice.uv0 = fun(vertice.uv0);
} }
} }
if ((vertexAttributes & RAW_VERTEX_ATTRIBUTE_UV1) != 0) { if ((vertexAttributes & RAW_VERTEX_ATTRIBUTE_UV1) != 0) {
for (const auto &fun : transforms) { for (const auto& fun : transforms) {
vertice.uv1 = fun(vertice.uv1); vertice.uv1 = fun(vertice.uv1);
} }
} }
} }
} }
struct TriangleModelSortPos struct TriangleModelSortPos {
{ static bool Compare(const RawTriangle& a, const RawTriangle& b) {
static bool Compare(const RawTriangle &a, const RawTriangle &b)
{
if (a.materialIndex != b.materialIndex) { if (a.materialIndex != b.materialIndex) {
return a.materialIndex < b.materialIndex; return a.materialIndex < b.materialIndex;
} }
@ -434,10 +447,8 @@ struct TriangleModelSortPos
} }
}; };
struct TriangleModelSortNeg struct TriangleModelSortNeg {
{ static bool Compare(const RawTriangle& a, const RawTriangle& b) {
static bool Compare(const RawTriangle &a, const RawTriangle &b)
{
if (a.materialIndex != b.materialIndex) { if (a.materialIndex != b.materialIndex) {
return a.materialIndex < b.materialIndex; return a.materialIndex < b.materialIndex;
} }
@ -449,8 +460,10 @@ struct TriangleModelSortNeg
}; };
void RawModel::CreateMaterialModels( void RawModel::CreateMaterialModels(
std::vector<RawModel> &materialModels, bool shortIndices, const int keepAttribs, const bool forceDiscrete) const std::vector<RawModel>& materialModels,
{ bool shortIndices,
const int keepAttribs,
const bool forceDiscrete) const {
// Sort all triangles based on material first, then surface, then first vertex index. // Sort all triangles based on material first, then surface, then first vertex index.
std::vector<RawTriangle> sortedTriangles; std::vector<RawTriangle> sortedTriangles;
@ -459,7 +472,7 @@ void RawModel::CreateMaterialModels(
// Split the triangles into opaque and transparent triangles. // Split the triangles into opaque and transparent triangles.
std::vector<RawTriangle> opaqueTriangles; std::vector<RawTriangle> opaqueTriangles;
std::vector<RawTriangle> transparentTriangles; std::vector<RawTriangle> transparentTriangles;
for (const auto &triangle : triangles) { for (const auto& triangle : triangles) {
const int materialIndex = triangle.materialIndex; const int materialIndex = triangle.materialIndex;
if (materialIndex < 0) { if (materialIndex < 0) {
opaqueTriangles.push_back(triangle); opaqueTriangles.push_back(triangle);
@ -487,13 +500,14 @@ void RawModel::CreateMaterialModels(
std::sort(opaqueTriangles.begin(), opaqueTriangles.end(), TriangleModelSortPos::Compare); std::sort(opaqueTriangles.begin(), opaqueTriangles.end(), TriangleModelSortPos::Compare);
// Sort the transparent triangles in the reverse direction. // Sort the transparent triangles in the reverse direction.
std::sort(transparentTriangles.begin(), transparentTriangles.end(), TriangleModelSortNeg::Compare); std::sort(
transparentTriangles.begin(), transparentTriangles.end(), TriangleModelSortNeg::Compare);
// Add the triangles to the sorted list. // Add the triangles to the sorted list.
for (const auto &opaqueTriangle : opaqueTriangles) { for (const auto& opaqueTriangle : opaqueTriangles) {
sortedTriangles.push_back(opaqueTriangle); sortedTriangles.push_back(opaqueTriangle);
} }
for (const auto &transparentTriangle : transparentTriangles) { for (const auto& transparentTriangle : transparentTriangles) {
sortedTriangles.push_back(transparentTriangle); sortedTriangles.push_back(transparentTriangle);
} }
} else { } else {
@ -503,7 +517,7 @@ void RawModel::CreateMaterialModels(
// Overestimate the number of models that will be created to avoid massive reallocation. // Overestimate the number of models that will be created to avoid massive reallocation.
int discreteCount = 0; int discreteCount = 0;
for (const auto &surface : surfaces) { for (const auto& surface : surfaces) {
discreteCount += surface.discrete ? 1 : 0; discreteCount += surface.discrete ? 1 : 0;
} }
@ -513,15 +527,13 @@ void RawModel::CreateMaterialModels(
const RawVertex defaultVertex; const RawVertex defaultVertex;
// Create a separate model for each material. // Create a separate model for each material.
RawModel *model; RawModel* model;
for (size_t i = 0; i < sortedTriangles.size(); i++) { for (size_t i = 0; i < sortedTriangles.size(); i++) {
if (sortedTriangles[i].materialIndex < 0 || sortedTriangles[i].surfaceIndex < 0) { if (sortedTriangles[i].materialIndex < 0 || sortedTriangles[i].surfaceIndex < 0) {
continue; continue;
} }
if (i == 0 || if (i == 0 || (shortIndices && model->GetVertexCount() >= 0xFFFE) ||
(shortIndices && model->GetVertexCount() >= 0xFFFE) ||
sortedTriangles[i].materialIndex != sortedTriangles[i - 1].materialIndex || sortedTriangles[i].materialIndex != sortedTriangles[i - 1].materialIndex ||
(sortedTriangles[i].surfaceIndex != sortedTriangles[i - 1].surfaceIndex && (sortedTriangles[i].surfaceIndex != sortedTriangles[i - 1].surfaceIndex &&
(forceDiscrete || surfaces[sortedTriangles[i].surfaceIndex].discrete || (forceDiscrete || surfaces[sortedTriangles[i].surfaceIndex].discrete ||
@ -536,11 +548,11 @@ void RawModel::CreateMaterialModels(
const int prevSurfaceCount = model->GetSurfaceCount(); const int prevSurfaceCount = model->GetSurfaceCount();
const int materialIndex = model->AddMaterial(materials[sortedTriangles[i].materialIndex]); const int materialIndex = model->AddMaterial(materials[sortedTriangles[i].materialIndex]);
const int surfaceIndex = model->AddSurface(surfaces[sortedTriangles[i].surfaceIndex]); const int surfaceIndex = model->AddSurface(surfaces[sortedTriangles[i].surfaceIndex]);
RawSurface &rawSurface = model->GetSurface(surfaceIndex); RawSurface& rawSurface = model->GetSurface(surfaceIndex);
if (model->GetSurfaceCount() > prevSurfaceCount) { if (model->GetSurfaceCount() > prevSurfaceCount) {
const std::vector<long> &jointIds = surfaces[sortedTriangles[i].surfaceIndex].jointIds; const std::vector<long>& jointIds = surfaces[sortedTriangles[i].surfaceIndex].jointIds;
for (const auto &jointId : jointIds) { for (const auto& jointId : jointIds) {
const int nodeIndex = GetNodeById(jointId); const int nodeIndex = GetNodeById(jointId);
assert(nodeIndex != -1); assert(nodeIndex != -1);
model->AddNode(GetNode(nodeIndex)); model->AddNode(GetNode(nodeIndex));
@ -560,33 +572,48 @@ void RawModel::CreateMaterialModels(
if ((keepAttribs & RAW_VERTEX_ATTRIBUTE_AUTO) != 0) { if ((keepAttribs & RAW_VERTEX_ATTRIBUTE_AUTO) != 0) {
keep |= RAW_VERTEX_ATTRIBUTE_POSITION; keep |= RAW_VERTEX_ATTRIBUTE_POSITION;
const RawMaterial &mat = model->GetMaterial(materialIndex); const RawMaterial& mat = model->GetMaterial(materialIndex);
if (mat.textures[RAW_TEXTURE_USAGE_DIFFUSE] != -1) { if (mat.textures[RAW_TEXTURE_USAGE_DIFFUSE] != -1) {
keep |= RAW_VERTEX_ATTRIBUTE_UV0; keep |= RAW_VERTEX_ATTRIBUTE_UV0;
} }
if (mat.textures[RAW_TEXTURE_USAGE_NORMAL] != -1) { if (mat.textures[RAW_TEXTURE_USAGE_NORMAL] != -1) {
keep |= RAW_VERTEX_ATTRIBUTE_NORMAL | keep |= RAW_VERTEX_ATTRIBUTE_NORMAL | RAW_VERTEX_ATTRIBUTE_TANGENT |
RAW_VERTEX_ATTRIBUTE_TANGENT | RAW_VERTEX_ATTRIBUTE_BINORMAL | RAW_VERTEX_ATTRIBUTE_UV0;
RAW_VERTEX_ATTRIBUTE_BINORMAL |
RAW_VERTEX_ATTRIBUTE_UV0;
} }
if (mat.textures[RAW_TEXTURE_USAGE_SPECULAR] != -1) { if (mat.textures[RAW_TEXTURE_USAGE_SPECULAR] != -1) {
keep |= RAW_VERTEX_ATTRIBUTE_NORMAL | keep |= RAW_VERTEX_ATTRIBUTE_NORMAL | RAW_VERTEX_ATTRIBUTE_UV0;
RAW_VERTEX_ATTRIBUTE_UV0;
} }
if (mat.textures[RAW_TEXTURE_USAGE_EMISSIVE] != -1) { if (mat.textures[RAW_TEXTURE_USAGE_EMISSIVE] != -1) {
keep |= RAW_VERTEX_ATTRIBUTE_UV1; keep |= RAW_VERTEX_ATTRIBUTE_UV1;
} }
} }
if ((keep & RAW_VERTEX_ATTRIBUTE_POSITION) == 0) { vertex.position = defaultVertex.position; } if ((keep & RAW_VERTEX_ATTRIBUTE_POSITION) == 0) {
if ((keep & RAW_VERTEX_ATTRIBUTE_NORMAL) == 0) { vertex.normal = defaultVertex.normal; } vertex.position = defaultVertex.position;
if ((keep & RAW_VERTEX_ATTRIBUTE_TANGENT) == 0) { vertex.tangent = defaultVertex.tangent; } }
if ((keep & RAW_VERTEX_ATTRIBUTE_BINORMAL) == 0) { vertex.binormal = defaultVertex.binormal; } if ((keep & RAW_VERTEX_ATTRIBUTE_NORMAL) == 0) {
if ((keep & RAW_VERTEX_ATTRIBUTE_COLOR) == 0) { vertex.color = defaultVertex.color; } vertex.normal = defaultVertex.normal;
if ((keep & RAW_VERTEX_ATTRIBUTE_UV0) == 0) { vertex.uv0 = defaultVertex.uv0; } }
if ((keep & RAW_VERTEX_ATTRIBUTE_UV1) == 0) { vertex.uv1 = defaultVertex.uv1; } if ((keep & RAW_VERTEX_ATTRIBUTE_TANGENT) == 0) {
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES) == 0) { vertex.jointIndices = defaultVertex.jointIndices; } vertex.tangent = defaultVertex.tangent;
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS) == 0) { vertex.jointWeights = defaultVertex.jointWeights; } }
if ((keep & RAW_VERTEX_ATTRIBUTE_BINORMAL) == 0) {
vertex.binormal = defaultVertex.binormal;
}
if ((keep & RAW_VERTEX_ATTRIBUTE_COLOR) == 0) {
vertex.color = defaultVertex.color;
}
if ((keep & RAW_VERTEX_ATTRIBUTE_UV0) == 0) {
vertex.uv0 = defaultVertex.uv0;
}
if ((keep & RAW_VERTEX_ATTRIBUTE_UV1) == 0) {
vertex.uv1 = defaultVertex.uv1;
}
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES) == 0) {
vertex.jointIndices = defaultVertex.jointIndices;
}
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS) == 0) {
vertex.jointWeights = defaultVertex.jointWeights;
}
} }
verts[j] = model->AddVertex(vertex); verts[j] = model->AddVertex(vertex);
@ -599,18 +626,16 @@ void RawModel::CreateMaterialModels(
} }
} }
int RawModel::GetNodeById(const long nodeId) const int RawModel::GetNodeById(const long nodeId) const {
{
for (size_t i = 0; i < nodes.size(); i++) { for (size_t i = 0; i < nodes.size(); i++) {
if (nodes[i].id == nodeId) { if (nodes[i].id == nodeId) {
return (int) i; return (int)i;
} }
} }
return -1; return -1;
} }
int RawModel::GetSurfaceById(const long surfaceId) const int RawModel::GetSurfaceById(const long surfaceId) const {
{
for (size_t i = 0; i < surfaces.size(); i++) { for (size_t i = 0; i < surfaces.size(); i++) {
if (surfaces[i].id == surfaceId) { if (surfaces[i].id == surfaceId) {
return (int)i; return (int)i;
@ -619,22 +644,21 @@ int RawModel::GetSurfaceById(const long surfaceId) const
return -1; return -1;
} }
Vec3f RawModel::getFaceNormal(int verts[3]) const Vec3f RawModel::getFaceNormal(int verts[3]) const {
{ const float l0 = (vertices[verts[1]].position - vertices[verts[0]].position).LengthSquared();
const float l0 = (vertices[verts[1]].position - vertices[verts[0]].position ).LengthSquared(); const float l1 = (vertices[verts[2]].position - vertices[verts[1]].position).LengthSquared();
const float l1 = (vertices[verts[2]].position - vertices[verts[1]].position ).LengthSquared(); const float l2 = (vertices[verts[0]].position - vertices[verts[2]].position).LengthSquared();
const float l2 = (vertices[verts[0]].position - vertices[verts[2]].position ).LengthSquared(); const int index = (l0 > l1) ? (l0 > l2 ? 2 : 1) : (l1 > l2 ? 0 : 1);
const int index = ( l0 > l1 ) ? ( l0 > l2 ? 2 : 1 ) : ( l1 > l2 ? 0 : 1 );
const Vec3f e0 = vertices[verts[(index + 1) % 3]].position - vertices[verts[index]].position; const Vec3f e0 = vertices[verts[(index + 1) % 3]].position - vertices[verts[index]].position;
const Vec3f e1 = vertices[verts[(index + 2) % 3]].position - vertices[verts[index]].position; const Vec3f e1 = vertices[verts[(index + 2) % 3]].position - vertices[verts[index]].position;
if (e0.LengthSquared() < FLT_MIN || e1.LengthSquared() < FLT_MIN) { if (e0.LengthSquared() < FLT_MIN || e1.LengthSquared() < FLT_MIN) {
return Vec3f { 0.0f }; return Vec3f{0.0f};
} }
auto result = Vec3f::CrossProduct(e0, e1); auto result = Vec3f::CrossProduct(e0, e1);
auto resultLengthSquared = result.LengthSquared(); auto resultLengthSquared = result.LengthSquared();
if (resultLengthSquared < FLT_MIN) { if (resultLengthSquared < FLT_MIN) {
return Vec3f { 0.0f }; return Vec3f{0.0f};
} }
float edgeDot = std::max(-1.0f, std::min(1.0f, Vec3f::DotProduct(e0, e1))); float edgeDot = std::max(-1.0f, std::min(1.0f, Vec3f::DotProduct(e0, e1)));
float angle = acos(edgeDot); float angle = acos(edgeDot);
@ -642,23 +666,22 @@ Vec3f RawModel::getFaceNormal(int verts[3]) const
return result.Normalized() * angle * area; return result.Normalized() * angle * area;
} }
size_t RawModel::CalculateNormals(bool onlyBroken) size_t RawModel::CalculateNormals(bool onlyBroken) {
{ Vec3f averagePos = Vec3f{0.0f};
Vec3f averagePos = Vec3f { 0.0f };
std::set<int> brokenVerts; std::set<int> brokenVerts;
for (int vertIx = 0; vertIx < vertices.size(); vertIx ++) { for (int vertIx = 0; vertIx < vertices.size(); vertIx++) {
RawVertex &vertex = vertices[vertIx]; RawVertex& vertex = vertices[vertIx];
averagePos += (vertex.position / (float)vertices.size()); averagePos += (vertex.position / (float)vertices.size());
if (onlyBroken && (vertex.normal.LengthSquared() >= FLT_MIN)) { if (onlyBroken && (vertex.normal.LengthSquared() >= FLT_MIN)) {
continue; continue;
} }
vertex.normal = Vec3f { 0.0f }; vertex.normal = Vec3f{0.0f};
if (onlyBroken) { if (onlyBroken) {
brokenVerts.emplace(vertIx); brokenVerts.emplace(vertIx);
} }
} }
for (auto &triangle : triangles) { for (auto& triangle : triangles) {
bool relevant = false; bool relevant = false;
for (int vertIx : triangle.verts) { for (int vertIx : triangle.verts) {
relevant |= (brokenVerts.count(vertIx) > 0); relevant |= (brokenVerts.count(vertIx) > 0);
@ -674,15 +697,15 @@ size_t RawModel::CalculateNormals(bool onlyBroken)
} }
} }
for (int vertIx = 0; vertIx < vertices.size(); vertIx ++) { for (int vertIx = 0; vertIx < vertices.size(); vertIx++) {
if (onlyBroken && brokenVerts.count(vertIx) == 0) { if (onlyBroken && brokenVerts.count(vertIx) == 0) {
continue; continue;
} }
RawVertex &vertex = vertices[vertIx]; RawVertex& vertex = vertices[vertIx];
if (vertex.normal.LengthSquared() < FLT_MIN) { if (vertex.normal.LengthSquared() < FLT_MIN) {
vertex.normal = vertex.position - averagePos; vertex.normal = vertex.position - averagePos;
if (vertex.normal.LengthSquared() < FLT_MIN) { if (vertex.normal.LengthSquared() < FLT_MIN) {
vertex.normal = Vec3f { 0.0f, 1.0f, 0.0f }; vertex.normal = Vec3f{0.0f, 1.0f, 0.0f};
continue; continue;
} }
} }

View File

@ -9,15 +9,13 @@
#pragma once #pragma once
#include <unordered_map>
#include <functional> #include <functional>
#include <set> #include <set>
#include <unordered_map>
#include "FBX2glTF.h" #include "FBX2glTF.h"
enum RawVertexAttribute {
enum RawVertexAttribute
{
RAW_VERTEX_ATTRIBUTE_POSITION = 1 << 0, RAW_VERTEX_ATTRIBUTE_POSITION = 1 << 0,
RAW_VERTEX_ATTRIBUTE_NORMAL = 1 << 1, RAW_VERTEX_ATTRIBUTE_NORMAL = 1 << 1,
RAW_VERTEX_ATTRIBUTE_TANGENT = 1 << 2, RAW_VERTEX_ATTRIBUTE_TANGENT = 1 << 2,
@ -31,75 +29,65 @@ enum RawVertexAttribute
RAW_VERTEX_ATTRIBUTE_AUTO = 1 << 31 RAW_VERTEX_ATTRIBUTE_AUTO = 1 << 31
}; };
struct RawBlendVertex struct RawBlendVertex {
{ Vec3f position{};
Vec3f position {}; Vec3f normal{};
Vec3f normal {}; Vec4f tangent{};
Vec4f tangent {};
bool operator==(const RawBlendVertex &other) const { bool operator==(const RawBlendVertex& other) const {
return position == other.position && return position == other.position && normal == other.normal && tangent == other.tangent;
normal == other.normal &&
tangent == other.tangent;
} }
}; };
struct RawVertex struct RawVertex {
{ RawVertex() : polarityUv0(false), pad1(false), pad2(false), pad3(false) {}
RawVertex() :
polarityUv0(false),
pad1(false),
pad2(false),
pad3(false) {}
Vec3f position { 0.0f }; Vec3f position{0.0f};
Vec3f normal { 0.0f }; Vec3f normal{0.0f};
Vec3f binormal { 0.0f }; Vec3f binormal{0.0f};
Vec4f tangent { 0.0f }; Vec4f tangent{0.0f};
Vec4f color { 0.0f }; Vec4f color{0.0f};
Vec2f uv0 { 0.0f }; Vec2f uv0{0.0f};
Vec2f uv1 { 0.0f }; Vec2f uv1{0.0f};
Vec4i jointIndices { 0, 0, 0, 0 }; Vec4i jointIndices{0, 0, 0, 0};
Vec4f jointWeights { 0.0f }; Vec4f jointWeights{0.0f};
// end of members that directly correspond to vertex attributes // end of members that directly correspond to vertex attributes
// if this vertex participates in a blend shape setup, the surfaceIx of its dedicated mesh; otherwise, -1 // if this vertex participates in a blend shape setup, the surfaceIx of its dedicated mesh;
// otherwise, -1
int blendSurfaceIx = -1; int blendSurfaceIx = -1;
// the size of this vector is always identical to the size of the corresponding RawSurface.blendChannels // the size of this vector is always identical to the size of the corresponding
std::vector<RawBlendVertex> blends { }; // RawSurface.blendChannels
std::vector<RawBlendVertex> blends{};
bool polarityUv0; bool polarityUv0;
bool pad1; bool pad1;
bool pad2; bool pad2;
bool pad3; bool pad3;
bool operator==(const RawVertex &other) const; bool operator==(const RawVertex& other) const;
size_t Difference(const RawVertex &other) const; size_t Difference(const RawVertex& other) const;
}; };
class VertexHasher class VertexHasher {
{ public:
public: size_t operator()(const RawVertex& v) const {
size_t operator()(const RawVertex &v) const
{
size_t seed = 5381; size_t seed = 5381;
const auto hasher = std::hash<float>{}; const auto hasher = std::hash<float>{};
seed ^= hasher(v.position[0]) + 0x9e3779b9 + (seed<<6) + (seed>>2); seed ^= hasher(v.position[0]) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
seed ^= hasher(v.position[1]) + 0x9e3779b9 + (seed<<6) + (seed>>2); seed ^= hasher(v.position[1]) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
seed ^= hasher(v.position[2]) + 0x9e3779b9 + (seed<<6) + (seed>>2); seed ^= hasher(v.position[2]) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed; return seed;
} }
}; };
struct RawTriangle struct RawTriangle {
{
int verts[3]; int verts[3];
int materialIndex; int materialIndex;
int surfaceIndex; int surfaceIndex;
}; };
enum RawShadingModel enum RawShadingModel {
{
RAW_SHADING_MODEL_UNKNOWN = -1, RAW_SHADING_MODEL_UNKNOWN = -1,
RAW_SHADING_MODEL_CONSTANT, RAW_SHADING_MODEL_CONSTANT,
RAW_SHADING_MODEL_LAMBERT, RAW_SHADING_MODEL_LAMBERT,
@ -110,19 +98,26 @@ enum RawShadingModel
}; };
inline std::string Describe(RawShadingModel model) { inline std::string Describe(RawShadingModel model) {
switch(model) { switch (model) {
case RAW_SHADING_MODEL_UNKNOWN: return "<unknown>"; case RAW_SHADING_MODEL_UNKNOWN:
case RAW_SHADING_MODEL_CONSTANT: return "Constant"; return "<unknown>";
case RAW_SHADING_MODEL_LAMBERT: return "Lambert"; case RAW_SHADING_MODEL_CONSTANT:
case RAW_SHADING_MODEL_BLINN: return "Blinn"; return "Constant";
case RAW_SHADING_MODEL_PHONG: return "Phong"; case RAW_SHADING_MODEL_LAMBERT:
case RAW_SHADING_MODEL_PBR_MET_ROUGH: return "Metallic/Roughness"; return "Lambert";
case RAW_SHADING_MODEL_MAX: default: return "<unknown>"; case RAW_SHADING_MODEL_BLINN:
return "Blinn";
case RAW_SHADING_MODEL_PHONG:
return "Phong";
case RAW_SHADING_MODEL_PBR_MET_ROUGH:
return "Metallic/Roughness";
case RAW_SHADING_MODEL_MAX:
default:
return "<unknown>";
} }
} }
enum RawTextureUsage enum RawTextureUsage {
{
RAW_TEXTURE_USAGE_NONE = -1, RAW_TEXTURE_USAGE_NONE = -1,
RAW_TEXTURE_USAGE_AMBIENT, RAW_TEXTURE_USAGE_AMBIENT,
RAW_TEXTURE_USAGE_DIFFUSE, RAW_TEXTURE_USAGE_DIFFUSE,
@ -138,32 +133,39 @@ enum RawTextureUsage
RAW_TEXTURE_USAGE_MAX RAW_TEXTURE_USAGE_MAX
}; };
inline std::string Describe(RawTextureUsage usage) inline std::string Describe(RawTextureUsage usage) {
{
switch (usage) { switch (usage) {
case RAW_TEXTURE_USAGE_NONE: return "<none>"; case RAW_TEXTURE_USAGE_NONE:
case RAW_TEXTURE_USAGE_AMBIENT: return "ambient"; return "<none>";
case RAW_TEXTURE_USAGE_DIFFUSE: return "diffuse"; case RAW_TEXTURE_USAGE_AMBIENT:
case RAW_TEXTURE_USAGE_NORMAL: return "normal"; return "ambient";
case RAW_TEXTURE_USAGE_SPECULAR: return "specular"; case RAW_TEXTURE_USAGE_DIFFUSE:
case RAW_TEXTURE_USAGE_SHININESS: return "shininess"; return "diffuse";
case RAW_TEXTURE_USAGE_EMISSIVE: return "emissive"; case RAW_TEXTURE_USAGE_NORMAL:
case RAW_TEXTURE_USAGE_REFLECTION: return "reflection"; return "normal";
case RAW_TEXTURE_USAGE_OCCLUSION: return "occlusion"; case RAW_TEXTURE_USAGE_SPECULAR:
case RAW_TEXTURE_USAGE_ROUGHNESS: return "roughness"; return "specular";
case RAW_TEXTURE_USAGE_METALLIC: return "metallic"; case RAW_TEXTURE_USAGE_SHININESS:
case RAW_TEXTURE_USAGE_MAX:default: return "unknown"; return "shininess";
case RAW_TEXTURE_USAGE_EMISSIVE:
return "emissive";
case RAW_TEXTURE_USAGE_REFLECTION:
return "reflection";
case RAW_TEXTURE_USAGE_OCCLUSION:
return "occlusion";
case RAW_TEXTURE_USAGE_ROUGHNESS:
return "roughness";
case RAW_TEXTURE_USAGE_METALLIC:
return "metallic";
case RAW_TEXTURE_USAGE_MAX:
default:
return "unknown";
} }
}; };
enum RawTextureOcclusion enum RawTextureOcclusion { RAW_TEXTURE_OCCLUSION_OPAQUE, RAW_TEXTURE_OCCLUSION_TRANSPARENT };
{
RAW_TEXTURE_OCCLUSION_OPAQUE,
RAW_TEXTURE_OCCLUSION_TRANSPARENT
};
struct RawTexture struct RawTexture {
{
std::string name; // logical name in FBX file std::string name; // logical name in FBX file
int width; int width;
int height; int height;
@ -174,8 +176,7 @@ struct RawTexture
std::string fileLocation; // inferred path in local filesystem, or "" std::string fileLocation; // inferred path in local filesystem, or ""
}; };
enum RawMaterialType enum RawMaterialType {
{
RAW_MATERIAL_TYPE_OPAQUE, RAW_MATERIAL_TYPE_OPAQUE,
RAW_MATERIAL_TYPE_TRANSPARENT, RAW_MATERIAL_TYPE_TRANSPARENT,
RAW_MATERIAL_TYPE_SKINNED_OPAQUE, RAW_MATERIAL_TYPE_SKINNED_OPAQUE,
@ -183,30 +184,31 @@ enum RawMaterialType
}; };
struct RawMatProps { struct RawMatProps {
explicit RawMatProps(RawShadingModel shadingModel) explicit RawMatProps(RawShadingModel shadingModel) : shadingModel(shadingModel) {}
: shadingModel(shadingModel)
{}
const RawShadingModel shadingModel; const RawShadingModel shadingModel;
virtual bool operator!=(const RawMatProps &other) const { return !(*this == other); } virtual bool operator!=(const RawMatProps& other) const {
virtual bool operator==(const RawMatProps &other) const { return shadingModel == other.shadingModel; }; return !(*this == other);
}
virtual bool operator==(const RawMatProps& other) const {
return shadingModel == other.shadingModel;
};
}; };
struct RawTraditionalMatProps : RawMatProps { struct RawTraditionalMatProps : RawMatProps {
RawTraditionalMatProps( RawTraditionalMatProps(
RawShadingModel shadingModel, RawShadingModel shadingModel,
const Vec3f &&ambientFactor, const Vec3f&& ambientFactor,
const Vec4f &&diffuseFactor, const Vec4f&& diffuseFactor,
const Vec3f &&emissiveFactor, const Vec3f&& emissiveFactor,
const Vec3f &&specularFactor, const Vec3f&& specularFactor,
const float shininess const float shininess)
) : RawMatProps(shadingModel), : RawMatProps(shadingModel),
ambientFactor(ambientFactor), ambientFactor(ambientFactor),
diffuseFactor(diffuseFactor), diffuseFactor(diffuseFactor),
emissiveFactor(emissiveFactor), emissiveFactor(emissiveFactor),
specularFactor(specularFactor), specularFactor(specularFactor),
shininess(shininess) shininess(shininess) {}
{}
const Vec3f ambientFactor; const Vec3f ambientFactor;
const Vec4f diffuseFactor; const Vec4f diffuseFactor;
@ -214,13 +216,11 @@ struct RawTraditionalMatProps : RawMatProps {
const Vec3f specularFactor; const Vec3f specularFactor;
const float shininess; const float shininess;
bool operator==(const RawMatProps &other) const override { bool operator==(const RawMatProps& other) const override {
if (RawMatProps::operator==(other)) { if (RawMatProps::operator==(other)) {
const auto &typed = (RawTraditionalMatProps &) other; const auto& typed = (RawTraditionalMatProps&)other;
return ambientFactor == typed.ambientFactor && return ambientFactor == typed.ambientFactor && diffuseFactor == typed.diffuseFactor &&
diffuseFactor == typed.diffuseFactor && specularFactor == typed.specularFactor && emissiveFactor == typed.emissiveFactor &&
specularFactor == typed.specularFactor &&
emissiveFactor == typed.emissiveFactor &&
shininess == typed.shininess; shininess == typed.shininess;
} }
return false; return false;
@ -230,40 +230,35 @@ struct RawTraditionalMatProps : RawMatProps {
struct RawMetRoughMatProps : RawMatProps { struct RawMetRoughMatProps : RawMatProps {
RawMetRoughMatProps( RawMetRoughMatProps(
RawShadingModel shadingModel, RawShadingModel shadingModel,
const Vec4f &&diffuseFactor, const Vec4f&& diffuseFactor,
const Vec3f &&emissiveFactor, const Vec3f&& emissiveFactor,
float emissiveIntensity, float emissiveIntensity,
float metallic, float metallic,
float roughness float roughness)
) : RawMatProps(shadingModel), : RawMatProps(shadingModel),
diffuseFactor(diffuseFactor), diffuseFactor(diffuseFactor),
emissiveFactor(emissiveFactor), emissiveFactor(emissiveFactor),
emissiveIntensity(emissiveIntensity), emissiveIntensity(emissiveIntensity),
metallic(metallic), metallic(metallic),
roughness(roughness) roughness(roughness) {}
{}
const Vec4f diffuseFactor; const Vec4f diffuseFactor;
const Vec3f emissiveFactor; const Vec3f emissiveFactor;
const float emissiveIntensity; const float emissiveIntensity;
const float metallic; const float metallic;
const float roughness; const float roughness;
bool operator==(const RawMatProps &other) const override { bool operator==(const RawMatProps& other) const override {
if (RawMatProps::operator==(other)) { if (RawMatProps::operator==(other)) {
const auto &typed = (RawMetRoughMatProps &) other; const auto& typed = (RawMetRoughMatProps&)other;
return diffuseFactor == typed.diffuseFactor && return diffuseFactor == typed.diffuseFactor && emissiveFactor == typed.emissiveFactor &&
emissiveFactor == typed.emissiveFactor && emissiveIntensity == typed.emissiveIntensity && metallic == typed.metallic &&
emissiveIntensity == typed.emissiveIntensity &&
metallic == typed.metallic &&
roughness == typed.roughness; roughness == typed.roughness;
} }
return false; return false;
} }
}; };
struct RawMaterial {
struct RawMaterial
{
std::string name; std::string name;
RawMaterialType type; RawMaterialType type;
std::shared_ptr<RawMatProps> info; std::shared_ptr<RawMatProps> info;
@ -271,15 +266,13 @@ struct RawMaterial
std::vector<std::string> userProperties; std::vector<std::string> userProperties;
}; };
enum RawLightType enum RawLightType {
{
RAW_LIGHT_TYPE_DIRECTIONAL, RAW_LIGHT_TYPE_DIRECTIONAL,
RAW_LIGHT_TYPE_POINT, RAW_LIGHT_TYPE_POINT,
RAW_LIGHT_TYPE_SPOT, RAW_LIGHT_TYPE_SPOT,
}; };
struct RawLight struct RawLight {
{
std::string name; std::string name;
RawLightType type; RawLightType type;
Vec3f color; Vec3f color;
@ -288,16 +281,14 @@ struct RawLight
float outerConeAngle; // only meaningful for spot float outerConeAngle; // only meaningful for spot
}; };
struct RawBlendChannel struct RawBlendChannel {
{
float defaultDeform; float defaultDeform;
bool hasNormals; bool hasNormals;
bool hasTangents; bool hasTangents;
std::string name; std::string name;
}; };
struct RawSurface struct RawSurface {
{
long id; long id;
std::string name; // The name of this surface std::string name; // The name of this surface
long skeletonRootId; // The id of the root node of the skeleton. long skeletonRootId; // The id of the root node of the skeleton.
@ -310,8 +301,7 @@ struct RawSurface
bool discrete; bool discrete;
}; };
struct RawChannel struct RawChannel {
{
int nodeIndex; int nodeIndex;
std::vector<Vec3f> translations; std::vector<Vec3f> translations;
std::vector<Quatf> rotations; std::vector<Quatf> rotations;
@ -319,26 +309,19 @@ struct RawChannel
std::vector<float> weights; std::vector<float> weights;
}; };
struct RawAnimation struct RawAnimation {
{
std::string name; std::string name;
std::vector<float> times; std::vector<float> times;
std::vector<RawChannel> channels; std::vector<RawChannel> channels;
}; };
struct RawCamera struct RawCamera {
{
std::string name; std::string name;
long nodeId; long nodeId;
enum enum { CAMERA_MODE_PERSPECTIVE, CAMERA_MODE_ORTHOGRAPHIC } mode;
{
CAMERA_MODE_PERSPECTIVE,
CAMERA_MODE_ORTHOGRAPHIC
} mode;
struct struct {
{
float aspectRatio; float aspectRatio;
float fovDegreesX; float fovDegreesX;
float fovDegreesY; float fovDegreesY;
@ -346,8 +329,7 @@ struct RawCamera
float farZ; float farZ;
} perspective; } perspective;
struct struct {
{
float magX; float magX;
float magY; float magY;
float nearZ; float nearZ;
@ -355,8 +337,7 @@ struct RawCamera
} orthographic; } orthographic;
}; };
struct RawNode struct RawNode {
{
bool isJoint; bool isJoint;
long id; long id;
std::string name; std::string name;
@ -370,99 +351,176 @@ struct RawNode
std::vector<std::string> userProperties; std::vector<std::string> userProperties;
}; };
class RawModel class RawModel {
{ public:
public:
RawModel(); RawModel();
// Add geometry. // Add geometry.
void AddVertexAttribute(const RawVertexAttribute attrib); void AddVertexAttribute(const RawVertexAttribute attrib);
int AddVertex(const RawVertex &vertex); int AddVertex(const RawVertex& vertex);
int AddTriangle(const int v0, const int v1, const int v2, const int materialIndex, const int surfaceIndex); int AddTriangle(
int AddTexture(const std::string &name, const std::string &fileName, const std::string &fileLocation, RawTextureUsage usage); const int v0,
int AddMaterial(const RawMaterial &material); const int v1,
const int v2,
const int materialIndex,
const int surfaceIndex);
int AddTexture(
const std::string& name,
const std::string& fileName,
const std::string& fileLocation,
RawTextureUsage usage);
int AddMaterial(const RawMaterial& material);
int AddMaterial( int AddMaterial(
const char *name, const RawMaterialType materialType, const int textures[RAW_TEXTURE_USAGE_MAX], const char* name,
std::shared_ptr<RawMatProps> materialInfo, const std::vector<std::string>& userProperties); const RawMaterialType materialType,
int AddLight(const char *name, RawLightType lightType, Vec3f color, float intensity, const int textures[RAW_TEXTURE_USAGE_MAX],
float innerConeAngle, float outerConeAngle); std::shared_ptr<RawMatProps> materialInfo,
int AddSurface(const RawSurface &suface); const std::vector<std::string>& userProperties);
int AddSurface(const char *name, long surfaceId); int AddLight(
int AddAnimation(const RawAnimation &animation); const char* name,
RawLightType lightType,
Vec3f color,
float intensity,
float innerConeAngle,
float outerConeAngle);
int AddSurface(const RawSurface& suface);
int AddSurface(const char* name, long surfaceId);
int AddAnimation(const RawAnimation& animation);
int AddCameraPerspective( int AddCameraPerspective(
const char *name, const long nodeId, const float aspectRatio, const float fovDegreesX, const float fovDegreesY, const char* name,
const float nearZ, const float farZ); const long nodeId,
int const float aspectRatio,
AddCameraOrthographic(const char *name, const long nodeId, const float magX, const float magY, const float nearZ, const float farZ); const float fovDegreesX,
int AddNode(const RawNode &node); const float fovDegreesY,
int AddNode(const long id, const char *name, const long parentId); const float nearZ,
void SetRootNode(const long nodeId) { rootNodeId = nodeId; } const float farZ);
const long GetRootNode() const { return rootNodeId; } int AddCameraOrthographic(
const char* name,
const long nodeId,
const float magX,
const float magY,
const float nearZ,
const float farZ);
int AddNode(const RawNode& node);
int AddNode(const long id, const char* name, const long parentId);
void SetRootNode(const long nodeId) {
rootNodeId = nodeId;
}
const long GetRootNode() const {
return rootNodeId;
}
// Remove unused vertices, textures or materials after removing vertex attributes, textures, materials or surfaces. // Remove unused vertices, textures or materials after removing vertex attributes, textures,
// materials or surfaces.
void Condense(); void Condense();
void TransformGeometry(ComputeNormalsOption); void TransformGeometry(ComputeNormalsOption);
void TransformTextures(const std::vector<std::function<Vec2f(Vec2f)>> &transforms); void TransformTextures(const std::vector<std::function<Vec2f(Vec2f)>>& transforms);
size_t CalculateNormals(bool); size_t CalculateNormals(bool);
// Get the attributes stored per vertex. // Get the attributes stored per vertex.
int GetVertexAttributes() const { return vertexAttributes; } int GetVertexAttributes() const {
return vertexAttributes;
}
// Iterate over the vertices. // Iterate over the vertices.
int GetVertexCount() const { return (int) vertices.size(); } int GetVertexCount() const {
const RawVertex &GetVertex(const int index) const { return vertices[index]; } return (int)vertices.size();
}
const RawVertex& GetVertex(const int index) const {
return vertices[index];
}
// Iterate over the triangles. // Iterate over the triangles.
int GetTriangleCount() const { return (int) triangles.size(); } int GetTriangleCount() const {
const RawTriangle &GetTriangle(const int index) const { return triangles[index]; } return (int)triangles.size();
}
const RawTriangle& GetTriangle(const int index) const {
return triangles[index];
}
// Iterate over the textures. // Iterate over the textures.
int GetTextureCount() const { return (int) textures.size(); } int GetTextureCount() const {
const RawTexture &GetTexture(const int index) const { return textures[index]; } return (int)textures.size();
}
const RawTexture& GetTexture(const int index) const {
return textures[index];
}
// Iterate over the materials. // Iterate over the materials.
int GetMaterialCount() const { return (int) materials.size(); } int GetMaterialCount() const {
const RawMaterial &GetMaterial(const int index) const { return materials[index]; } return (int)materials.size();
}
const RawMaterial& GetMaterial(const int index) const {
return materials[index];
}
// Iterate over the surfaces. // Iterate over the surfaces.
int GetSurfaceCount() const { return (int) surfaces.size(); } int GetSurfaceCount() const {
const RawSurface &GetSurface(const int index) const { return surfaces[index]; } return (int)surfaces.size();
RawSurface &GetSurface(const int index) { return surfaces[index]; } }
const RawSurface& GetSurface(const int index) const {
return surfaces[index];
}
RawSurface& GetSurface(const int index) {
return surfaces[index];
}
int GetSurfaceById(const long id) const; int GetSurfaceById(const long id) const;
// Iterate over the animations. // Iterate over the animations.
int GetAnimationCount() const { return (int) animations.size(); } int GetAnimationCount() const {
const RawAnimation &GetAnimation(const int index) const { return animations[index]; } return (int)animations.size();
}
const RawAnimation& GetAnimation(const int index) const {
return animations[index];
}
// Iterate over the cameras. // Iterate over the cameras.
int GetCameraCount() const { return (int) cameras.size(); } int GetCameraCount() const {
const RawCamera &GetCamera(const int index) const { return cameras[index]; } return (int)cameras.size();
}
const RawCamera& GetCamera(const int index) const {
return cameras[index];
}
// Iterate over the lights. // Iterate over the lights.
int GetLightCount() const { return (int) lights.size(); } int GetLightCount() const {
const RawLight &GetLight(const int index) const { return lights[index]; } return (int)lights.size();
}
const RawLight& GetLight(const int index) const {
return lights[index];
}
// Iterate over the nodes. // Iterate over the nodes.
int GetNodeCount() const { return (int) nodes.size(); } int GetNodeCount() const {
const RawNode &GetNode(const int index) const { return nodes[index]; } return (int)nodes.size();
RawNode &GetNode(const int index) { return nodes[index]; } }
const RawNode& GetNode(const int index) const {
return nodes[index];
}
RawNode& GetNode(const int index) {
return nodes[index];
}
int GetNodeById(const long nodeId) const; int GetNodeById(const long nodeId) const;
// Create individual attribute arrays. // Create individual attribute arrays.
// Returns true if the vertices store the particular attribute. // Returns true if the vertices store the particular attribute.
template<typename _attrib_type_> template <typename _attrib_type_>
void GetAttributeArray(std::vector<_attrib_type_> &out, const _attrib_type_ RawVertex::* ptr) const; void GetAttributeArray(std::vector<_attrib_type_>& out, const _attrib_type_ RawVertex::*ptr)
const;
// Create an array with a raw model for each material. // Create an array with a raw model for each material.
// Multiple surfaces with the same material will turn into a single model. // Multiple surfaces with the same material will turn into a single model.
// However, surfaces that are marked as 'discrete' will turn into separate models. // However, surfaces that are marked as 'discrete' will turn into separate models.
void CreateMaterialModels( void CreateMaterialModels(
std::vector<RawModel> &materialModels, bool shortIndices, const int keepAttribs, const bool forceDiscrete) const; std::vector<RawModel>& materialModels,
bool shortIndices,
const int keepAttribs,
const bool forceDiscrete) const;
private: private:
Vec3f getFaceNormal(int verts[3]) const; Vec3f getFaceNormal(int verts[3]) const;
long rootNodeId; long rootNodeId;
@ -479,9 +537,10 @@ private:
std::vector<RawNode> nodes; std::vector<RawNode> nodes;
}; };
template<typename _attrib_type_> template <typename _attrib_type_>
void RawModel::GetAttributeArray(std::vector<_attrib_type_> &out, const _attrib_type_ RawVertex::* ptr) const void RawModel::GetAttributeArray(
{ std::vector<_attrib_type_>& out,
const _attrib_type_ RawVertex::*ptr) const {
out.resize(vertices.size()); out.resize(vertices.size());
for (size_t i = 0; i < vertices.size(); i++) { for (size_t i = 0; i < vertices.size(); i++) {
out[i] = vertices[i].*ptr; out[i] = vertices[i].*ptr;

View File

@ -9,24 +9,24 @@
#include "File_Utils.hpp" #include "File_Utils.hpp"
#include <fstream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <fstream>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#if defined( __unix__ ) || defined ( __APPLE__ ) #if defined(__unix__) || defined(__APPLE__)
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#define _getcwd getcwd #define _getcwd getcwd
#define _mkdir(a) mkdir(a, 0777) #define _mkdir(a) mkdir(a, 0777)
#elif defined( _WIN32 ) #elif defined(_WIN32)
#include <direct.h> #include <direct.h>
#include <process.h> #include <process.h>
#else #else
@ -41,8 +41,7 @@
namespace FileUtils { namespace FileUtils {
std::string GetCurrentFolder() std::string GetCurrentFolder() {
{
char cwd[StringUtils::MAX_PATH_LENGTH]; char cwd[StringUtils::MAX_PATH_LENGTH];
if (!_getcwd(cwd, sizeof(cwd))) { if (!_getcwd(cwd, sizeof(cwd))) {
return std::string(); return std::string();
@ -55,65 +54,62 @@ namespace FileUtils {
cwd[length + 1] = '\0'; cwd[length + 1] = '\0';
} }
return std::string(cwd); return std::string(cwd);
} }
bool FileExists(const std::string &filePath) bool FileExists(const std::string& filePath) {
{
std::ifstream stream(filePath); std::ifstream stream(filePath);
return stream.good(); return stream.good();
} }
bool FolderExists(const std::string &folderPath) bool FolderExists(const std::string& folderPath) {
{ #if defined(__unix__) || defined(__APPLE__)
#if defined( __unix__ ) || defined( __APPLE__ ) DIR* dir = opendir(folderPath.c_str());
DIR *dir = opendir(folderPath.c_str());
if (dir) { if (dir) {
closedir(dir); closedir(dir);
return true; return true;
} }
return false; return false;
#else #else
const DWORD ftyp = GetFileAttributesA( folderPath.c_str() ); const DWORD ftyp = GetFileAttributesA(folderPath.c_str());
if ( ftyp == INVALID_FILE_ATTRIBUTES ) if (ftyp == INVALID_FILE_ATTRIBUTES) {
{
return false; // bad path return false; // bad path
} }
return ( ftyp & FILE_ATTRIBUTE_DIRECTORY ) != 0; return (ftyp & FILE_ATTRIBUTE_DIRECTORY) != 0;
#endif #endif
} }
bool MatchExtension(const char *fileExtension, const char *matchExtensions) bool MatchExtension(const char* fileExtension, const char* matchExtensions) {
{
if (matchExtensions[0] == '\0') { if (matchExtensions[0] == '\0') {
return true; return true;
} }
if (fileExtension[0] == '.') { if (fileExtension[0] == '.') {
fileExtension++; fileExtension++;
} }
for (const char *end = matchExtensions; end[0] != '\0';) { for (const char* end = matchExtensions; end[0] != '\0';) {
for (; end[0] == ';'; end++) {} for (; end[0] == ';'; end++) {
const char *ext = end; }
for (; end[0] != ';' && end[0] != '\0'; end++) {} const char* ext = end;
#if defined( __unix__ ) || defined( __APPLE__ ) for (; end[0] != ';' && end[0] != '\0'; end++) {
}
#if defined(__unix__) || defined(__APPLE__)
if (strncasecmp(fileExtension, ext, end - ext) == 0) if (strncasecmp(fileExtension, ext, end - ext) == 0)
#else #else
if ( _strnicmp( fileExtension, ext, end - ext ) == 0 ) if (_strnicmp(fileExtension, ext, end - ext) == 0)
#endif #endif
{ {
return true; return true;
} }
} }
return false; return false;
} }
std::vector<std::string> ListFolderFiles(const char *folder, const char *matchExtensions) std::vector<std::string> ListFolderFiles(const char* folder, const char* matchExtensions) {
{
std::vector<std::string> fileList; std::vector<std::string> fileList;
#if defined( __unix__ ) || defined( __APPLE__ ) #if defined(__unix__) || defined(__APPLE__)
DIR *dir = opendir(strlen(folder) > 0 ? folder : "."); DIR* dir = opendir(strlen(folder) > 0 ? folder : ".");
if (dir != nullptr) { if (dir != nullptr) {
for (;;) { for (;;) {
struct dirent *dp = readdir(dir); struct dirent* dp = readdir(dir);
if (dp == nullptr) { if (dp == nullptr) {
break; break;
} }
@ -122,8 +118,8 @@ namespace FileUtils {
continue; continue;
} }
const char *fileName = dp->d_name; const char* fileName = dp->d_name;
const char *fileExt = strrchr(fileName, '.'); const char* fileExt = strrchr(fileName, '.');
if (!fileExt || !MatchExtension(fileExt, matchExtensions)) { if (!fileExt || !MatchExtension(fileExt, matchExtensions)) {
continue; continue;
@ -139,11 +135,9 @@ namespace FileUtils {
pathStr += "*"; pathStr += "*";
WIN32_FIND_DATA FindFileData; WIN32_FIND_DATA FindFileData;
HANDLE hFind = FindFirstFile( pathStr.c_str(), &FindFileData ); HANDLE hFind = FindFirstFile(pathStr.c_str(), &FindFileData);
if ( hFind != INVALID_HANDLE_VALUE ) if (hFind != INVALID_HANDLE_VALUE) {
{ do {
do
{
if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
std::string fileName = FindFileData.cFileName; std::string fileName = FindFileData.cFileName;
std::string::size_type extPos = fileName.rfind('.'); std::string::size_type extPos = fileName.rfind('.');
@ -152,17 +146,16 @@ namespace FileUtils {
fileList.push_back(fileName); fileList.push_back(fileName);
} }
} }
} while ( FindNextFile( hFind, &FindFileData ) ); } while (FindNextFile(hFind, &FindFileData));
FindClose( hFind ); FindClose(hFind);
} }
#endif #endif
return fileList; return fileList;
} }
bool CreatePath(const char *path) bool CreatePath(const char* path) {
{ #if defined(__unix__) || defined(__APPLE__)
#if defined( __unix__ ) || defined( __APPLE__ )
StringUtils::PathSeparator separator = StringUtils::PATH_UNIX; StringUtils::PathSeparator separator = StringUtils::PATH_UNIX;
#else #else
StringUtils::PathSeparator separator = StringUtils::PATH_WIN; StringUtils::PathSeparator separator = StringUtils::PATH_WIN;
@ -170,7 +163,7 @@ namespace FileUtils {
std::string folder = StringUtils::GetFolderString(path); std::string folder = StringUtils::GetFolderString(path);
std::string clean = StringUtils::GetCleanPathString(folder, separator); std::string clean = StringUtils::GetCleanPathString(folder, separator);
std::string build = clean; std::string build = clean;
for (int i = 0; i < clean.length(); i ++) { for (int i = 0; i < clean.length(); i++) {
if (clean[i] == separator && i > 0) { if (clean[i] == separator && i > 0) {
build[i] = '\0'; build[i] = '\0';
if (i > 1 || build[1] != ':') { if (i > 1 || build[1] != ':') {
@ -182,9 +175,9 @@ namespace FileUtils {
build[i] = clean[i]; build[i] = clean[i];
} }
return true; return true;
} }
bool CopyFile(const std::string &srcFilename, const std::string &dstFilename, bool createPath) { bool CopyFile(const std::string& srcFilename, const std::string& dstFilename, bool createPath) {
std::ifstream srcFile(srcFilename, std::ios::binary); std::ifstream srcFile(srcFilename, std::ios::binary);
if (!srcFile) { if (!srcFile) {
fmt::printf("Warning: Couldn't open file %s for reading.\n", srcFilename); fmt::printf("Warning: Couldn't open file %s for reading.\n", srcFilename);
@ -210,7 +203,12 @@ namespace FileUtils {
if (srcSize == dstSize) { if (srcSize == dstSize) {
return true; return true;
} }
fmt::printf("Warning: Only copied %lu bytes to %s, when %s is %lu bytes long.\n", dstSize, dstFilename, srcFilename, srcSize); fmt::printf(
"Warning: Only copied %lu bytes to %s, when %s is %lu bytes long.\n",
dstSize,
dstFilename,
srcFilename,
srcSize);
return false; return false;
}
} }
} // namespace FileUtils

View File

@ -14,15 +14,18 @@
namespace FileUtils { namespace FileUtils {
std::string GetCurrentFolder(); std::string GetCurrentFolder();
bool FileExists(const std::string &folderPath); bool FileExists(const std::string& folderPath);
bool FolderExists(const std::string &folderPath); bool FolderExists(const std::string& folderPath);
bool MatchExtension(const char *fileExtension, const char *matchExtensions); bool MatchExtension(const char* fileExtension, const char* matchExtensions);
std::vector<std::string> ListFolderFiles(const char *folder, const char *matchExtensions); std::vector<std::string> ListFolderFiles(const char* folder, const char* matchExtensions);
bool CreatePath(const char *path); bool CreatePath(const char* path);
bool CopyFile(const std::string &srcFilename, const std::string &dstFilename, bool createPath = false); bool CopyFile(
} const std::string& srcFilename,
const std::string& dstFilename,
bool createPath = false);
} // namespace FileUtils

View File

@ -9,8 +9,8 @@
#include "Image_Utils.hpp" #include "Image_Utils.hpp"
#include <string>
#include <algorithm> #include <algorithm>
#include <string>
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
@ -22,11 +22,10 @@
namespace ImageUtils { namespace ImageUtils {
static bool imageHasTransparentPixels(FILE *f) static bool imageHasTransparentPixels(FILE* f) {
{
int width, height, channels; int width, height, channels;
// RGBA: we have to load the pixels to figure out if the image is fully opaque // RGBA: we have to load the pixels to figure out if the image is fully opaque
uint8_t *pixels = stbi_load_from_file(f, &width, &height, &channels, 0); uint8_t* pixels = stbi_load_from_file(f, &width, &height, &channels, 0);
if (pixels != nullptr) { if (pixels != nullptr) {
int pixelCount = width * height; int pixelCount = width * height;
for (int ix = 0; ix < pixelCount; ix++) { for (int ix = 0; ix < pixelCount; ix++) {
@ -37,17 +36,16 @@ namespace ImageUtils {
} }
} }
return false; return false;
} }
ImageProperties GetImageProperties(char const *filePath) ImageProperties GetImageProperties(char const* filePath) {
{
ImageProperties result = { ImageProperties result = {
1, 1,
1, 1,
IMAGE_OPAQUE, IMAGE_OPAQUE,
}; };
FILE *f = fopen(filePath, "rb"); FILE* f = fopen(filePath, "rb");
if (f == nullptr) { if (f == nullptr) {
return result; return result;
} }
@ -59,10 +57,9 @@ namespace ImageUtils {
result.occlusion = IMAGE_TRANSPARENT; result.occlusion = IMAGE_TRANSPARENT;
} }
return result; return result;
} }
std::string suffixToMimeType(std::string suffix) std::string suffixToMimeType(std::string suffix) {
{
std::transform(suffix.begin(), suffix.end(), suffix.begin(), ::tolower); std::transform(suffix.begin(), suffix.end(), suffix.begin(), ::tolower);
if (suffix == "jpg" || suffix == "jpeg") { if (suffix == "jpg" || suffix == "jpeg") {
@ -72,6 +69,6 @@ namespace ImageUtils {
return "image/png"; return "image/png";
} }
return "image/unknown"; return "image/unknown";
}
} }
} // namespace ImageUtils

View File

@ -13,25 +13,20 @@
namespace ImageUtils { namespace ImageUtils {
enum ImageOcclusion enum ImageOcclusion { IMAGE_OPAQUE, IMAGE_TRANSPARENT };
{
IMAGE_OPAQUE,
IMAGE_TRANSPARENT
};
struct ImageProperties struct ImageProperties {
{
int width; int width;
int height; int height;
ImageOcclusion occlusion; ImageOcclusion occlusion;
}; };
ImageProperties GetImageProperties(char const *filePath); ImageProperties GetImageProperties(char const* filePath);
/** /**
* Very simple method for mapping filename suffix to mime type. The glTF 2.0 spec only accepts values * Very simple method for mapping filename suffix to mime type. The glTF 2.0 spec only accepts
* "image/jpeg" and "image/png" so we don't need to get too fancy. * values "image/jpeg" and "image/png" so we don't need to get too fancy.
*/ */
std::string suffixToMimeType(std::string suffix); std::string suffixToMimeType(std::string suffix);
} } // namespace ImageUtils

View File

@ -11,77 +11,70 @@
namespace StringUtils { namespace StringUtils {
PathSeparator operator!(const PathSeparator &s) PathSeparator operator!(const PathSeparator& s) {
{
return (s == PATH_WIN) ? PATH_UNIX : PATH_WIN; return (s == PATH_WIN) ? PATH_UNIX : PATH_WIN;
} }
PathSeparator GetPathSeparator() { PathSeparator GetPathSeparator() {
#if defined( __unix__ ) || defined( __APPLE__ ) #if defined(__unix__) || defined(__APPLE__)
return PATH_UNIX; return PATH_UNIX;
#else #else
return PATH_WIN; return PATH_WIN;
#endif #endif
} }
const std::string NormalizePath(const std::string &path) const std::string NormalizePath(const std::string& path) {
{
PathSeparator separator = GetPathSeparator(); PathSeparator separator = GetPathSeparator();
char replace; char replace;
if (separator == PATH_WIN) { if (separator == PATH_WIN) {
replace = PATH_UNIX; replace = PATH_UNIX;
} } else {
else {
replace = PATH_WIN; replace = PATH_WIN;
} }
std::string normalizedPath = path; std::string normalizedPath = path;
for (size_t s = normalizedPath.find(replace, 0); s != std::string::npos; s = normalizedPath.find(replace, s)) { for (size_t s = normalizedPath.find(replace, 0); s != std::string::npos;
s = normalizedPath.find(replace, s)) {
normalizedPath[s] = separator; normalizedPath[s] = separator;
} }
return normalizedPath; return normalizedPath;
} }
const std::string GetFolderString(const std::string &path) const std::string GetFolderString(const std::string& path) {
{
size_t s = path.rfind(PATH_WIN); size_t s = path.rfind(PATH_WIN);
s = (s != std::string::npos) ? s : path.rfind(PATH_UNIX); s = (s != std::string::npos) ? s : path.rfind(PATH_UNIX);
return path.substr(0, s + 1); return path.substr(0, s + 1);
} }
const std::string GetCleanPathString(const std::string &path, const PathSeparator separator) const std::string GetCleanPathString(const std::string& path, const PathSeparator separator) {
{
std::string cleanPath = path; std::string cleanPath = path;
for (size_t s = cleanPath.find(!separator, 0); s != std::string::npos; s = cleanPath.find(!separator, s)) { for (size_t s = cleanPath.find(!separator, 0); s != std::string::npos;
s = cleanPath.find(!separator, s)) {
cleanPath[s] = separator; cleanPath[s] = separator;
} }
return cleanPath; return cleanPath;
} }
const std::string GetFileNameString(const std::string &path) const std::string GetFileNameString(const std::string& path) {
{
size_t s = path.rfind(PATH_WIN); size_t s = path.rfind(PATH_WIN);
s = (s != std::string::npos) ? s : path.rfind(PATH_UNIX); s = (s != std::string::npos) ? s : path.rfind(PATH_UNIX);
return path.substr(s + 1, std::string::npos); return path.substr(s + 1, std::string::npos);
} }
const std::string GetFileBaseString(const std::string &path) const std::string GetFileBaseString(const std::string& path) {
{
const std::string fileName = GetFileNameString(path); const std::string fileName = GetFileNameString(path);
return fileName.substr(0, fileName.rfind('.')).c_str(); return fileName.substr(0, fileName.rfind('.')).c_str();
} }
const std::string GetFileSuffixString(const std::string &path) const std::string GetFileSuffixString(const std::string& path) {
{
const std::string fileName = GetFileNameString(path); const std::string fileName = GetFileNameString(path);
size_t pos = fileName.rfind('.'); size_t pos = fileName.rfind('.');
if (pos == std::string::npos) { if (pos == std::string::npos) {
return ""; return "";
} }
return fileName.substr(++pos); return fileName.substr(++pos);
}
int CompareNoCase(const std::string &s1, const std::string &s2)
{
return strncasecmp(s1.c_str(), s2.c_str(), MAX_PATH_LENGTH);
}
} }
int CompareNoCase(const std::string& s1, const std::string& s2) {
return strncasecmp(s1.c_str(), s2.c_str(), MAX_PATH_LENGTH);
}
} // namespace StringUtils

View File

@ -9,49 +9,46 @@
#pragma once #pragma once
#include <string> #include <cstdarg>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <cstdarg> #include <string>
#if defined( _MSC_VER ) #if defined(_MSC_VER)
#define strncasecmp _strnicmp #define strncasecmp _strnicmp
#define strcasecmp _stricmp #define strcasecmp _stricmp
#endif #endif
namespace StringUtils { namespace StringUtils {
static const unsigned int MAX_PATH_LENGTH = 1024; static const unsigned int MAX_PATH_LENGTH = 1024;
enum PathSeparator enum PathSeparator { PATH_WIN = '\\', PATH_UNIX = '/' };
{
PATH_WIN = '\\',
PATH_UNIX = '/'
};
PathSeparator operator!(const PathSeparator &s); PathSeparator operator!(const PathSeparator& s);
PathSeparator GetPathSeparator(); PathSeparator GetPathSeparator();
const std::string NormalizePath(const std::string &path); const std::string NormalizePath(const std::string& path);
const std::string GetCleanPathString(const std::string &path, const PathSeparator separator = PATH_WIN); const std::string GetCleanPathString(
const std::string& path,
const PathSeparator separator = PATH_WIN);
template<size_t size> template <size_t size>
void GetCleanPath(char (&dest)[size], const char *path, const PathSeparator separator = PATH_WIN) void GetCleanPath(char (&dest)[size], const char* path, const PathSeparator separator = PATH_WIN) {
{
size_t len = size - 1; size_t len = size - 1;
strncpy(dest, path, len); strncpy(dest, path, len);
char *destPtr = dest; char* destPtr = dest;
while ((destPtr = strchr(destPtr, !separator)) != nullptr) { while ((destPtr = strchr(destPtr, !separator)) != nullptr) {
*destPtr = separator; *destPtr = separator;
} }
}
const std::string GetFolderString(const std::string &path);
const std::string GetFileNameString(const std::string &path);
const std::string GetFileBaseString(const std::string &path);
const std::string GetFileSuffixString(const std::string &path);
int CompareNoCase(const std::string &s1, const std::string &s2);
} }
const std::string GetFolderString(const std::string& path);
const std::string GetFileNameString(const std::string& path);
const std::string GetFileBaseString(const std::string& path);
const std::string GetFileSuffixString(const std::string& path);
int CompareNoCase(const std::string& s1, const std::string& s2);
} // namespace StringUtils