Apply clang-format to all our source. (#149)

Apply clang-format to all our source.
This commit is contained in:
Pär Winzell 2018-12-18 23:30:29 -08:00 committed by GitHub
parent be1b75431d
commit 5730d1c301
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 5426 additions and 5249 deletions

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

@ -10,95 +10,95 @@
#include "FbxMaterialsAccess.hpp"
#include "Fbx2Raw.hpp"
FbxMaterialsAccess::FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<const FbxTexture *, FbxString> &textureLocations) :
mappingMode(FbxGeometryElement::eNone),
mesh(nullptr),
indices(nullptr)
{
if (pMesh->GetElementMaterialCount() <= 0) {
return;
FbxMaterialsAccess::FbxMaterialsAccess(
const FbxMesh* pMesh,
const std::map<const FbxTexture*, FbxString>& textureLocations)
: mappingMode(FbxGeometryElement::eNone), mesh(nullptr), indices(nullptr) {
if (pMesh->GetElementMaterialCount() <= 0) {
return;
}
const FbxGeometryElement::EMappingMode materialMappingMode =
pMesh->GetElementMaterial()->GetMappingMode();
if (materialMappingMode != FbxGeometryElement::eByPolygon &&
materialMappingMode != FbxGeometryElement::eAllSame) {
return;
}
const FbxGeometryElement::EReferenceMode materialReferenceMode =
pMesh->GetElementMaterial()->GetReferenceMode();
if (materialReferenceMode != FbxGeometryElement::eIndexToDirect) {
return;
}
mappingMode = materialMappingMode;
mesh = pMesh;
indices = &pMesh->GetElementMaterial()->GetIndexArray();
for (int ii = 0; ii < indices->GetCount(); ii++) {
int materialNum = indices->GetAt(ii);
if (materialNum < 0) {
continue;
}
const FbxGeometryElement::EMappingMode materialMappingMode = pMesh->GetElementMaterial()->GetMappingMode();
if (materialMappingMode != FbxGeometryElement::eByPolygon && materialMappingMode != FbxGeometryElement::eAllSame) {
return;
FbxSurfaceMaterial* surfaceMaterial =
mesh->GetNode()->GetSrcObject<FbxSurfaceMaterial>(materialNum);
if (materialNum >= summaries.size()) {
summaries.resize(materialNum + 1);
}
auto summary = summaries[materialNum];
if (summary == nullptr) {
summary = summaries[materialNum] = GetMaterialInfo(surfaceMaterial, textureLocations);
}
const FbxGeometryElement::EReferenceMode materialReferenceMode = pMesh->GetElementMaterial()->GetReferenceMode();
if (materialReferenceMode != FbxGeometryElement::eIndexToDirect) {
return;
if (materialNum >= userProperties.size()) {
userProperties.resize(materialNum + 1);
}
mappingMode = materialMappingMode;
mesh = pMesh;
indices = &pMesh->GetElementMaterial()->GetIndexArray();
for (int ii = 0; ii < indices->GetCount(); ii++) {
int materialNum = indices->GetAt(ii);
if (materialNum < 0) {
continue;
}
FbxSurfaceMaterial* surfaceMaterial = mesh->GetNode()->GetSrcObject<FbxSurfaceMaterial>(materialNum);
if (materialNum >= summaries.size()) {
summaries.resize(materialNum + 1);
}
auto summary = summaries[materialNum];
if (summary == nullptr) {
summary = summaries[materialNum] = GetMaterialInfo(
surfaceMaterial,
textureLocations);
}
if (materialNum >= userProperties.size()) {
userProperties.resize(materialNum + 1);
}
if (userProperties[materialNum].empty()) {
FbxProperty objectProperty = surfaceMaterial->GetFirstProperty();
while (objectProperty.IsValid())
{
if (objectProperty.GetFlag(FbxPropertyFlags::eUserDefined)) {
userProperties[materialNum].push_back(TranscribeProperty(objectProperty).dump());
}
objectProperty = surfaceMaterial->GetNextProperty(objectProperty);
}
if (userProperties[materialNum].empty()) {
FbxProperty objectProperty = surfaceMaterial->GetFirstProperty();
while (objectProperty.IsValid()) {
if (objectProperty.GetFlag(FbxPropertyFlags::eUserDefined)) {
userProperties[materialNum].push_back(TranscribeProperty(objectProperty).dump());
}
objectProperty = surfaceMaterial->GetNextProperty(objectProperty);
}
}
}
}
const std::shared_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterial(const int polygonIndex) const
{
if (mappingMode != FbxGeometryElement::eNone) {
const int materialNum = indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0);
if (materialNum < 0) {
return nullptr;
}
return summaries.at((unsigned long) materialNum);
const std::shared_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterial(
const int polygonIndex) const {
if (mappingMode != FbxGeometryElement::eNone) {
const int materialNum =
indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0);
if (materialNum < 0) {
return nullptr;
}
return nullptr;
return summaries.at((unsigned long)materialNum);
}
return nullptr;
}
const std::vector<std::string> FbxMaterialsAccess::GetUserProperties(const int polygonIndex) const
{
if (mappingMode != FbxGeometryElement::eNone) {
const int materialNum = indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0);
if (materialNum < 0) {
return std::vector<std::string>();
}
return userProperties.at((unsigned long)materialNum);
const std::vector<std::string> FbxMaterialsAccess::GetUserProperties(const int polygonIndex) const {
if (mappingMode != FbxGeometryElement::eNone) {
const int materialNum =
indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0);
if (materialNum < 0) {
return std::vector<std::string>();
}
return std::vector<std::string>();
return userProperties.at((unsigned long)materialNum);
}
return std::vector<std::string>();
}
std::unique_ptr<FbxMaterialInfo>
FbxMaterialsAccess::GetMaterialInfo(FbxSurfaceMaterial *material, const std::map<const FbxTexture *, FbxString> &textureLocations)
{
std::unique_ptr<FbxMaterialInfo> res;
res = FbxRoughMetMaterialInfo::From(material, textureLocations);
if (!res) {
res = FbxTraditionalMaterialInfo::From(material, textureLocations);
}
return res;
std::unique_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterialInfo(
FbxSurfaceMaterial* material,
const std::map<const FbxTexture*, FbxString>& textureLocations) {
std::unique_ptr<FbxMaterialInfo> res;
res = FbxRoughMetMaterialInfo::From(material, textureLocations);
if (!res) {
res = FbxTraditionalMaterialInfo::From(material, textureLocations);
}
return res;
}

View File

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

View File

@ -7,62 +7,67 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/
#include "FbxRoughMetMaterialInfo.hpp"
#include "FbxRoughMetMaterialInfo.hpp"
std::unique_ptr<FbxRoughMetMaterialInfo>
FbxRoughMetMaterialInfo::From(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> FbxRoughMetMaterialInfo::From(
FbxSurfaceMaterial* fbxMaterial,
const std::map<const FbxTexture*, FbxString>& textureLocations) {
std::unique_ptr<FbxRoughMetMaterialInfo> res(
new FbxRoughMetMaterialInfo(fbxMaterial->GetName(), FBX_SHADER_METROUGH));
const FbxProperty mayaProp = fbxMaterial->FindProperty("Maya");
if (mayaProp.GetPropertyDataType() != FbxCompoundDT) {
return nullptr;
}
if (!fbxMaterial->ShadingModel.Get().IsEmpty()) {
::fmt::printf("Warning: Material %s has surprising shading model: %s\n",
fbxMaterial->GetName(), fbxMaterial->ShadingModel.Get());
}
const FbxProperty mayaProp = fbxMaterial->FindProperty("Maya");
if (mayaProp.GetPropertyDataType() != FbxCompoundDT) {
return nullptr;
}
if (!fbxMaterial->ShadingModel.Get().IsEmpty()) {
::fmt::printf(
"Warning: Material %s has surprising shading model: %s\n",
fbxMaterial->GetName(),
fbxMaterial->ShadingModel.Get());
}
auto getTex = [&](std::string propName) {
const FbxFileTexture *ptr = nullptr;
auto getTex = [&](std::string propName) {
const FbxFileTexture* ptr = nullptr;
const FbxProperty useProp = mayaProp.FindHierarchical(("use_" + propName + "_map").c_str());
if (useProp.IsValid() && useProp.Get<bool>()) {
const FbxProperty texProp = mayaProp.FindHierarchical(("TEX_" + propName + "_map").c_str());
if (texProp.IsValid()) {
ptr = texProp.GetSrcObject<FbxFileTexture>();
if (ptr != nullptr && textureLocations.find(ptr) == textureLocations.end()) {
ptr = nullptr;
}
}
} else if (verboseOutput && useProp.IsValid()) {
fmt::printf("Note: Property '%s' of material '%s' exists, but is flagged as 'do not use'.\n",
propName, fbxMaterial->GetName());
const FbxProperty useProp = mayaProp.FindHierarchical(("use_" + propName + "_map").c_str());
if (useProp.IsValid() && useProp.Get<bool>()) {
const FbxProperty texProp = mayaProp.FindHierarchical(("TEX_" + propName + "_map").c_str());
if (texProp.IsValid()) {
ptr = texProp.GetSrcObject<FbxFileTexture>();
if (ptr != nullptr && textureLocations.find(ptr) == textureLocations.end()) {
ptr = nullptr;
}
return ptr;
};
}
} else if (verboseOutput && useProp.IsValid()) {
fmt::printf(
"Note: Property '%s' of material '%s' exists, but is flagged as 'do not use'.\n",
propName,
fbxMaterial->GetName());
}
return ptr;
};
auto getVec = [&](std::string propName) -> FbxDouble3 {
const FbxProperty vecProp = mayaProp.FindHierarchical(propName.c_str());
return vecProp.IsValid() ? vecProp.Get<FbxDouble3>() : FbxDouble3(1, 1, 1);
};
auto getVec = [&](std::string propName) -> FbxDouble3 {
const FbxProperty vecProp = mayaProp.FindHierarchical(propName.c_str());
return vecProp.IsValid() ? vecProp.Get<FbxDouble3>() : FbxDouble3(1, 1, 1);
};
auto getVal = [&](std::string propName) -> FbxDouble {
const FbxProperty vecProp = mayaProp.FindHierarchical(propName .c_str());
return vecProp.IsValid() ? vecProp.Get<FbxDouble>() : 0;
};
auto getVal = [&](std::string propName) -> FbxDouble {
const FbxProperty vecProp = mayaProp.FindHierarchical(propName.c_str());
return vecProp.IsValid() ? vecProp.Get<FbxDouble>() : 0;
};
res->texNormal = getTex("normal");
res->texColor = getTex("color");
res->colBase = getVec("base_color");
res->texAmbientOcclusion = getTex("ao");
res->texEmissive = getTex("emissive");
res->colEmissive = getVec("emissive");
res->emissiveIntensity = getVal("emissive_intensity");
res->texMetallic = getTex("metallic");
res->metallic = getVal("metallic");
res->texRoughness = getTex("roughness");
res->roughness = getVal("roughness");
res->texNormal = getTex("normal");
res->texColor = getTex("color");
res->colBase = getVec("base_color");
res->texAmbientOcclusion = getTex("ao");
res->texEmissive = getTex("emissive");
res->colEmissive = getVec("emissive");
res->emissiveIntensity = getVal("emissive_intensity");
res->texMetallic = getTex("metallic");
res->metallic = getVal("metallic");
res->texRoughness = getTex("roughness");
res->roughness = getVal("roughness");
return res;
return res;
}

View File

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

View File

@ -9,84 +9,89 @@
#include "FbxSkinningAccess.hpp"
FbxSkinningAccess::FbxSkinningAccess(const FbxMesh *pMesh, FbxScene *pScene, FbxNode *pNode)
: rootIndex(-1)
{
for (int deformerIndex = 0; deformerIndex < pMesh->GetDeformerCount(); deformerIndex++) {
FbxSkin *skin = reinterpret_cast< FbxSkin * >( pMesh->GetDeformer(deformerIndex, FbxDeformer::eSkin));
if (skin != nullptr) {
const int clusterCount = skin->GetClusterCount();
if (clusterCount == 0) {
continue;
}
int controlPointCount = pMesh->GetControlPointsCount();
vertexJointIndices.resize(controlPointCount, Vec4i(0, 0, 0, 0));
vertexJointWeights.resize(controlPointCount, Vec4f(0.0f, 0.0f, 0.0f, 0.0f));
for (int clusterIndex = 0; clusterIndex < clusterCount; clusterIndex++) {
FbxCluster *cluster = skin->GetCluster(clusterIndex);
const int indexCount = cluster->GetControlPointIndicesCount();
const int *clusterIndices = cluster->GetControlPointIndices();
const double *clusterWeights = cluster->GetControlPointWeights();
assert(cluster->GetLinkMode() == FbxCluster::eNormalize);
// Transform link matrix.
FbxAMatrix transformLinkMatrix;
cluster->GetTransformLinkMatrix(transformLinkMatrix);
// The transformation of the mesh at binding time
FbxAMatrix transformMatrix;
cluster->GetTransformMatrix(transformMatrix);
// Inverse bind matrix.
FbxAMatrix globalBindposeInverseMatrix = transformLinkMatrix.Inverse() * transformMatrix;
inverseBindMatrices.emplace_back(globalBindposeInverseMatrix);
jointNodes.push_back(cluster->GetLink());
jointIds.push_back(cluster->GetLink()->GetUniqueID());
const FbxAMatrix globalNodeTransform = cluster->GetLink()->EvaluateGlobalTransform();
jointSkinningTransforms.push_back(FbxMatrix(globalNodeTransform * globalBindposeInverseMatrix));
jointInverseGlobalTransforms.push_back(FbxMatrix(globalNodeTransform.Inverse()));
for (int i = 0; i < indexCount; i++) {
if (clusterIndices[i] < 0 || clusterIndices[i] >= controlPointCount) {
continue;
}
if (clusterWeights[i] <= vertexJointWeights[clusterIndices[i]][MAX_WEIGHTS - 1]) {
continue;
}
vertexJointIndices[clusterIndices[i]][MAX_WEIGHTS - 1] = clusterIndex;
vertexJointWeights[clusterIndices[i]][MAX_WEIGHTS - 1] = (float) clusterWeights[i];
for (int j = MAX_WEIGHTS - 1; j > 0; j--) {
if (vertexJointWeights[clusterIndices[i]][j - 1] >= vertexJointWeights[clusterIndices[i]][j]) {
break;
}
std::swap(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++) {
vertexJointWeights[i] = vertexJointWeights[i].Normalized();
FbxSkinningAccess::FbxSkinningAccess(const FbxMesh* pMesh, FbxScene* pScene, FbxNode* pNode)
: rootIndex(-1) {
for (int deformerIndex = 0; deformerIndex < pMesh->GetDeformerCount(); deformerIndex++) {
FbxSkin* skin =
reinterpret_cast<FbxSkin*>(pMesh->GetDeformer(deformerIndex, FbxDeformer::eSkin));
if (skin != nullptr) {
const int clusterCount = skin->GetClusterCount();
if (clusterCount == 0) {
continue;
}
int controlPointCount = pMesh->GetControlPointsCount();
vertexJointIndices.resize(controlPointCount, Vec4i(0, 0, 0, 0));
vertexJointWeights.resize(controlPointCount, Vec4f(0.0f, 0.0f, 0.0f, 0.0f));
for (int clusterIndex = 0; clusterIndex < clusterCount; clusterIndex++) {
FbxCluster* cluster = skin->GetCluster(clusterIndex);
const int indexCount = cluster->GetControlPointIndicesCount();
const int* clusterIndices = cluster->GetControlPointIndices();
const double* clusterWeights = cluster->GetControlPointWeights();
assert(cluster->GetLinkMode() == FbxCluster::eNormalize);
// Transform link matrix.
FbxAMatrix transformLinkMatrix;
cluster->GetTransformLinkMatrix(transformLinkMatrix);
// The transformation of the mesh at binding time
FbxAMatrix transformMatrix;
cluster->GetTransformMatrix(transformMatrix);
// Inverse bind matrix.
FbxAMatrix globalBindposeInverseMatrix = transformLinkMatrix.Inverse() * transformMatrix;
inverseBindMatrices.emplace_back(globalBindposeInverseMatrix);
jointNodes.push_back(cluster->GetLink());
jointIds.push_back(cluster->GetLink()->GetUniqueID());
const FbxAMatrix globalNodeTransform = cluster->GetLink()->EvaluateGlobalTransform();
jointSkinningTransforms.push_back(
FbxMatrix(globalNodeTransform * globalBindposeInverseMatrix));
jointInverseGlobalTransforms.push_back(FbxMatrix(globalNodeTransform.Inverse()));
for (int i = 0; i < indexCount; i++) {
if (clusterIndices[i] < 0 || clusterIndices[i] >= controlPointCount) {
continue;
}
if (clusterWeights[i] <= vertexJointWeights[clusterIndices[i]][MAX_WEIGHTS - 1]) {
continue;
}
vertexJointIndices[clusterIndices[i]][MAX_WEIGHTS - 1] = clusterIndex;
vertexJointWeights[clusterIndices[i]][MAX_WEIGHTS - 1] = (float)clusterWeights[i];
for (int j = MAX_WEIGHTS - 1; j > 0; j--) {
if (vertexJointWeights[clusterIndices[i]][j - 1] >=
vertexJointWeights[clusterIndices[i]][j]) {
break;
}
std::swap(
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++) {
vertexJointWeights[i] = vertexJointWeights[i].Normalized();
}
}
}
rootIndex = -1;
for (size_t i = 0; i < jointNodes.size() && rootIndex == -1; i++) {
rootIndex = (int) i;
FbxNode *parent = jointNodes[i]->GetParent();
if (parent == nullptr) {
break;
}
for (size_t j = 0; j < jointNodes.size(); j++) {
if (jointNodes[j] == parent) {
rootIndex = -1;
break;
}
}
rootIndex = -1;
for (size_t i = 0; i < jointNodes.size() && rootIndex == -1; i++) {
rootIndex = (int)i;
FbxNode* parent = jointNodes[i]->GetParent();
if (parent == nullptr) {
break;
}
for (size_t j = 0; j < jointNodes.size(); j++) {
if (jointNodes[j] == parent) {
rootIndex = -1;
break;
}
}
}
}

View File

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

View File

@ -9,116 +9,129 @@
#include "FbxTraditionalMaterialInfo.hpp"
std::unique_ptr<FbxTraditionalMaterialInfo>
FbxTraditionalMaterialInfo::From(FbxSurfaceMaterial *fbxMaterial, const std::map<const FbxTexture *, FbxString> &textureLocations)
{
auto getSurfaceScalar = [&](const char *propName) -> std::tuple<FbxDouble, FbxFileTexture *> {
const FbxProperty prop = fbxMaterial->FindProperty(propName);
std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialInfo::From(
FbxSurfaceMaterial* fbxMaterial,
const std::map<const FbxTexture*, FbxString>& textureLocations) {
auto getSurfaceScalar = [&](const char* propName) -> std::tuple<FbxDouble, FbxFileTexture*> {
const FbxProperty prop = fbxMaterial->FindProperty(propName);
FbxDouble val(0);
FbxFileTexture *tex = prop.GetSrcObject<FbxFileTexture>();
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
tex = nullptr;
}
if (tex == nullptr && prop.IsValid()) {
val = prop.Get<FbxDouble>();
}
return std::make_tuple(val, tex);
};
FbxDouble val(0);
FbxFileTexture* tex = prop.GetSrcObject<FbxFileTexture>();
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
tex = nullptr;
}
if (tex == nullptr && prop.IsValid()) {
val = prop.Get<FbxDouble>();
}
return std::make_tuple(val, tex);
};
auto getSurfaceVector = [&](const char *propName) -> std::tuple<FbxDouble3, FbxFileTexture *> {
const FbxProperty prop = fbxMaterial->FindProperty(propName);
auto getSurfaceVector = [&](const char* propName) -> std::tuple<FbxDouble3, FbxFileTexture*> {
const FbxProperty prop = fbxMaterial->FindProperty(propName);
FbxDouble3 val(1, 1, 1);
FbxFileTexture *tex = prop.GetSrcObject<FbxFileTexture>();
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
tex = nullptr;
}
if (tex == nullptr && prop.IsValid()) {
val = prop.Get<FbxDouble3>();
}
return std::make_tuple(val, tex);
};
FbxDouble3 val(1, 1, 1);
FbxFileTexture* tex = prop.GetSrcObject<FbxFileTexture>();
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
tex = nullptr;
}
if (tex == nullptr && prop.IsValid()) {
val = prop.Get<FbxDouble3>();
}
return std::make_tuple(val, tex);
};
auto getSurfaceValues = [&](const char *colName, const char *facName) -> std::tuple<FbxVector4, FbxFileTexture *, FbxFileTexture *> {
const FbxProperty colProp = fbxMaterial->FindProperty(colName);
const FbxProperty facProp = fbxMaterial->FindProperty(facName);
auto getSurfaceValues =
[&](const char* colName,
const char* facName) -> std::tuple<FbxVector4, FbxFileTexture*, FbxFileTexture*> {
const FbxProperty colProp = fbxMaterial->FindProperty(colName);
const FbxProperty facProp = fbxMaterial->FindProperty(facName);
FbxDouble3 colorVal(1, 1, 1);
FbxDouble factorVal(1);
FbxDouble3 colorVal(1, 1, 1);
FbxDouble factorVal(1);
FbxFileTexture *colTex = colProp.GetSrcObject<FbxFileTexture>();
if (colTex != nullptr && textureLocations.find(colTex) == textureLocations.end()) {
colTex = nullptr;
}
if (colTex == nullptr && colProp.IsValid()) {
colorVal = colProp.Get<FbxDouble3>();
}
FbxFileTexture *facTex = facProp.GetSrcObject<FbxFileTexture>();
if (facTex != nullptr && textureLocations.find(facTex) == textureLocations.end()) {
facTex = nullptr;
}
if (facTex == nullptr && facProp.IsValid()) {
factorVal = facProp.Get<FbxDouble>();
}
FbxFileTexture* colTex = colProp.GetSrcObject<FbxFileTexture>();
if (colTex != nullptr && textureLocations.find(colTex) == textureLocations.end()) {
colTex = nullptr;
}
if (colTex == nullptr && colProp.IsValid()) {
colorVal = colProp.Get<FbxDouble3>();
}
FbxFileTexture* facTex = facProp.GetSrcObject<FbxFileTexture>();
if (facTex != nullptr && textureLocations.find(facTex) == textureLocations.end()) {
facTex = nullptr;
}
if (facTex == nullptr && facProp.IsValid()) {
factorVal = facProp.Get<FbxDouble>();
}
auto val = FbxVector4(
colorVal[0] * factorVal,
colorVal[1] * factorVal,
colorVal[2] * factorVal,
factorVal);
return std::make_tuple(val, colTex, facTex);
};
auto val = FbxVector4(
colorVal[0] * factorVal, colorVal[1] * factorVal, colorVal[2] * factorVal, factorVal);
return std::make_tuple(val, colTex, facTex);
};
std::string name = fbxMaterial->GetName();
std::unique_ptr<FbxTraditionalMaterialInfo> res(new FbxTraditionalMaterialInfo(name.c_str(), fbxMaterial->ShadingModel.Get()));
std::string name = fbxMaterial->GetName();
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
auto handleBasicProperty = [&](const char *colName, const char *facName) -> std::tuple<FbxVector4, FbxFileTexture *>{
FbxFileTexture *colTex, *facTex;
FbxVector4 vec;
std::tie(vec, colTex, facTex) = getSurfaceValues(colName, facName);
if (colTex) {
if (facTex) {
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, facTex);
};
std::tie(res->colAmbient, res->texAmbient) =
handleBasicProperty(FbxSurfaceMaterial::sAmbient, FbxSurfaceMaterial::sAmbientFactor);
std::tie(res->colSpecular, res->texSpecular) =
handleBasicProperty(FbxSurfaceMaterial::sSpecular, FbxSurfaceMaterial::sSpecularFactor);
std::tie(res->colDiffuse, res->texDiffuse) =
handleBasicProperty(FbxSurfaceMaterial::sDiffuse, FbxSurfaceMaterial::sDiffuseFactor);
std::tie(res->colEmissive, res->texEmissive) =
handleBasicProperty(FbxSurfaceMaterial::sEmissive, FbxSurfaceMaterial::sEmissiveFactor);
// the normal map can only ever be a map, ignore everything else
tie(std::ignore, res->texNormal) = getSurfaceVector(FbxSurfaceMaterial::sNormalMap);
// shininess can be a map or a factor; afaict the map is always 'ShininessExponent' and the
// value is always found in 'Shininess' but only sometimes in 'ShininessExponent'.
tie(std::ignore, res->texShininess) = getSurfaceScalar("ShininessExponent");
tie(res->shininess, std::ignore) = getSurfaceScalar("Shininess");
// for transparency we just want a constant vector value;
FbxVector4 transparency;
// extract any existing textures only so we can warn that we're throwing them away
// four properties are on the same structure and follow the same rules
auto handleBasicProperty = [&](const char* colName,
const char* facName) -> std::tuple<FbxVector4, FbxFileTexture*> {
FbxFileTexture *colTex, *facTex;
std::tie(transparency, colTex, facTex) =
getSurfaceValues(FbxSurfaceMaterial::sTransparentColor, FbxSurfaceMaterial::sTransparencyFactor);
if (colTex) {
fmt::printf("Warning: Mat [%s]: Can't handle texture for %s; discarding.\n", name, FbxSurfaceMaterial::sTransparentColor);
}
if (facTex) {
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
res->colDiffuse[3] = 1.0 - (transparency[0] + transparency[1] + transparency[2])/3.0;
FbxVector4 vec;
return res;
std::tie(vec, colTex, facTex) = getSurfaceValues(colName, facName);
if (colTex) {
if (facTex) {
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, facTex);
};
std::tie(res->colAmbient, res->texAmbient) =
handleBasicProperty(FbxSurfaceMaterial::sAmbient, FbxSurfaceMaterial::sAmbientFactor);
std::tie(res->colSpecular, res->texSpecular) =
handleBasicProperty(FbxSurfaceMaterial::sSpecular, FbxSurfaceMaterial::sSpecularFactor);
std::tie(res->colDiffuse, res->texDiffuse) =
handleBasicProperty(FbxSurfaceMaterial::sDiffuse, FbxSurfaceMaterial::sDiffuseFactor);
std::tie(res->colEmissive, res->texEmissive) =
handleBasicProperty(FbxSurfaceMaterial::sEmissive, FbxSurfaceMaterial::sEmissiveFactor);
// the normal map can only ever be a map, ignore everything else
tie(std::ignore, res->texNormal) = getSurfaceVector(FbxSurfaceMaterial::sNormalMap);
// shininess can be a map or a factor; afaict the map is always 'ShininessExponent' and the
// value is always found in 'Shininess' but only sometimes in 'ShininessExponent'.
tie(std::ignore, res->texShininess) = getSurfaceScalar("ShininessExponent");
tie(res->shininess, std::ignore) = getSurfaceScalar("Shininess");
// for transparency we just want a constant vector value;
FbxVector4 transparency;
// extract any existing textures only so we can warn that we're throwing them away
FbxFileTexture *colTex, *facTex;
std::tie(transparency, colTex, facTex) = getSurfaceValues(
FbxSurfaceMaterial::sTransparentColor, FbxSurfaceMaterial::sTransparencyFactor);
if (colTex) {
fmt::printf(
"Warning: Mat [%s]: Can't handle texture for %s; discarding.\n",
name,
FbxSurfaceMaterial::sTransparentColor);
}
if (facTex) {
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
res->colDiffuse[3] = 1.0 - (transparency[0] + transparency[1] + transparency[2]) / 3.0;
return res;
}

View File

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

View File

@ -10,116 +10,117 @@
#include "RoughnessMetallicMaterials.hpp"
std::unique_ptr<FbxRoughMetMaterialInfo> Fbx3dsMaxPhysicalMaterialResolver::resolve() const {
const FbxProperty topProp = fbxMaterial->FindProperty("3dsMax");
if (topProp.GetPropertyDataType() != FbxCompoundDT) {
return nullptr;
}
const FbxProperty props = fbxMaterial->FindProperty("Parameters");
const FbxProperty topProp = fbxMaterial->FindProperty("3dsMax");
if (topProp.GetPropertyDataType() != FbxCompoundDT) {
return nullptr;
}
const FbxProperty props = fbxMaterial->FindProperty("Parameters");
FbxString shadingModel = fbxMaterial->ShadingModel.Get();
if (!shadingModel.IsEmpty() && shadingModel != "unknown") {
::fmt::printf("Warning: Material %s has surprising shading model: %s\n",
fbxMaterial->GetName(), shadingModel);
}
FbxString shadingModel = fbxMaterial->ShadingModel.Get();
if (!shadingModel.IsEmpty() && shadingModel != "unknown") {
::fmt::printf(
"Warning: Material %s has surprising shading model: %s\n",
fbxMaterial->GetName(),
shadingModel);
}
auto getTex = [&](std::string propName) -> const FbxFileTexture * {
const FbxFileTexture *ptr = nullptr;
auto getTex = [&](std::string propName) -> const FbxFileTexture* {
const FbxFileTexture* ptr = nullptr;
const FbxProperty useProp = props.FindHierarchical((propName + "_map_on").c_str());
if (useProp.IsValid() && useProp.Get<bool>()) {
const FbxProperty texProp = useProp.FindHierarchical((propName + "_map").c_str());
if (texProp.IsValid()) {
ptr = texProp.GetSrcObject<FbxFileTexture>();
if (ptr != nullptr && textureLocations.find(ptr) == textureLocations.end()) {
ptr = nullptr;
}
}
} else if (verboseOutput && useProp.IsValid()) {
fmt::printf("Note: property '%s' of 3dsMax Physical material '%s' exists, but is flagged as 'off'.\n",
propName, fbxMaterial->GetName());
const FbxProperty useProp = props.FindHierarchical((propName + "_map_on").c_str());
if (useProp.IsValid() && useProp.Get<bool>()) {
const FbxProperty texProp = useProp.FindHierarchical((propName + "_map").c_str());
if (texProp.IsValid()) {
ptr = texProp.GetSrcObject<FbxFileTexture>();
if (ptr != nullptr && textureLocations.find(ptr) == textureLocations.end()) {
ptr = nullptr;
}
return ptr;
};
int materialMode = getValue(props, "material_mode", 0);
fmt::printf("Note: 3dsMax Physical material has material_mode = %d.\n", materialMode);
// baseWeight && baseColor
FbxDouble baseWeight = getValue(props, "base_weight", 1.0);
const auto *baseWeightMap = getTex("base_weight");
FbxDouble4 baseCol = getValue(props, "base_color", FbxDouble4(0.5, 0.5, 0.5, 1.0));
const auto *baseTex = getTex("base_color");
double emissiveWeight = getValue(props, "emission", 0.0);
const auto *emissiveWeightMap = getTex("emission");
FbxDouble4 emissiveColor = getValue(props, "emit_color", FbxDouble4(1, 1, 1, 1));
const auto *emissiveColorMap = getTex("emit_color");
// TODO: emit_luminance, emit_kelvin?
// roughness & metalness: supported
double roughness = getValue(props, "roughness", 0.0);
const auto *roughnessMap = getTex("roughness");
double metalness = getValue(props, "metalness", 0.0);
const auto *metalnessMap = getTex("metalness");
// TODO: does invertRoughness affect roughness_map too?
bool invertRoughness = getValue(props, "inv_roughness", false);
if (invertRoughness) {
roughness = 1.0f - roughness;
}
} else if (verboseOutput && useProp.IsValid()) {
fmt::printf(
"Note: property '%s' of 3dsMax Physical material '%s' exists, but is flagged as 'off'.\n",
propName,
fbxMaterial->GetName());
}
return ptr;
};
// TODO: attempt to bake transparency > 0.0f into the alpha of baseColour?
double transparency = getValue(props, "transparency", 0.0);
const auto *transparencyMap = getTex("transparency");
int materialMode = getValue(props, "material_mode", 0);
fmt::printf("Note: 3dsMax Physical material has material_mode = %d.\n", materialMode);
// SSS: not supported
double scattering = getValue(props, "scattering", 0.0);
const auto *scatteringMap = getTex("scattering");
// baseWeight && baseColor
FbxDouble baseWeight = getValue(props, "base_weight", 1.0);
const auto* baseWeightMap = getTex("base_weight");
FbxDouble4 baseCol = getValue(props, "base_color", FbxDouble4(0.5, 0.5, 0.5, 1.0));
const auto* baseTex = getTex("base_color");
// reflectivity: not supported
double reflectivityWeight = getValue(props, "reflectivity", 1.);
const auto *reflectivityWeightMap = getTex("reflectivity");
FbxDouble4 reflectivityColor = getValue(props, "refl_color", FbxDouble4(1, 1, 1, 1));
const auto *reflectivityColorMap = getTex("refl_color");
double emissiveWeight = getValue(props, "emission", 0.0);
const auto* emissiveWeightMap = getTex("emission");
FbxDouble4 emissiveColor = getValue(props, "emit_color", FbxDouble4(1, 1, 1, 1));
const auto* emissiveColorMap = getTex("emit_color");
// TODO: emit_luminance, emit_kelvin?
// coatings: not supported
double coating = getValue(props, "coating", 0.0);
// roughness & metalness: supported
double roughness = getValue(props, "roughness", 0.0);
const auto* roughnessMap = getTex("roughness");
double metalness = getValue(props, "metalness", 0.0);
const auto* metalnessMap = getTex("metalness");
// diffuse roughness: not supported
double diffuseRoughness = getValue(props, "diff_roughness", 0.);
// TODO: does invertRoughness affect roughness_map too?
bool invertRoughness = getValue(props, "inv_roughness", false);
if (invertRoughness) {
roughness = 1.0f - roughness;
}
// explicit brdf curve control: not supported
bool isBrdfMode = getValue(props, "brdf_mode", false);
// TODO: attempt to bake transparency > 0.0f into the alpha of baseColour?
double transparency = getValue(props, "transparency", 0.0);
const auto* transparencyMap = getTex("transparency");
// anisotrophy: not supported
double anisotropy = getValue(props, "anisotropy", 1.0);
// SSS: not supported
double scattering = getValue(props, "scattering", 0.0);
const auto* scatteringMap = getTex("scattering");
// TODO: how the heck do we combine these to generate a normal map?
const auto *bumpMap = getTex("bump");
const auto *displacementMap = getTex("displacement");
// reflectivity: not supported
double reflectivityWeight = getValue(props, "reflectivity", 1.);
const auto* reflectivityWeightMap = getTex("reflectivity");
FbxDouble4 reflectivityColor = getValue(props, "refl_color", FbxDouble4(1, 1, 1, 1));
const auto* reflectivityColorMap = getTex("refl_color");
std::unique_ptr<FbxRoughMetMaterialInfo> res(
new FbxRoughMetMaterialInfo(
fbxMaterial->GetName(),
FbxRoughMetMaterialInfo::FBX_SHADER_METROUGH,
baseCol,
metalness,
roughness
)
);
res->texBaseColor = baseTex;
res->baseWeight = baseWeight;
res->texBaseWeight = baseWeightMap;
// coatings: not supported
double coating = getValue(props, "coating", 0.0);
res->texMetallic = metalnessMap;
res->texRoughness = roughnessMap;
// diffuse roughness: not supported
double diffuseRoughness = getValue(props, "diff_roughness", 0.);
res->texNormal = bumpMap; // TODO LOL NO NONO
// explicit brdf curve control: not supported
bool isBrdfMode = getValue(props, "brdf_mode", false);
res->emissive = emissiveColor;
res->emissiveIntensity = emissiveWeight;
res->texEmissive = emissiveColorMap;
res->texEmissiveWeight = emissiveWeightMap;
// anisotrophy: not supported
double anisotropy = getValue(props, "anisotropy", 1.0);
return res;
// TODO: how the heck do we combine these to generate a normal map?
const auto* bumpMap = getTex("bump");
const auto* displacementMap = getTex("displacement");
std::unique_ptr<FbxRoughMetMaterialInfo> res(new FbxRoughMetMaterialInfo(
fbxMaterial->GetName(),
FbxRoughMetMaterialInfo::FBX_SHADER_METROUGH,
baseCol,
metalness,
roughness));
res->texBaseColor = baseTex;
res->baseWeight = baseWeight;
res->texBaseWeight = baseWeightMap;
res->texMetallic = metalnessMap;
res->texRoughness = roughnessMap;
res->texNormal = bumpMap; // TODO LOL NO NONO
res->emissive = emissiveColor;
res->emissiveIntensity = emissiveWeight;
res->texEmissive = emissiveColorMap;
res->texEmissiveWeight = emissiveWeightMap;
return res;
}

View File

@ -11,68 +11,70 @@
#include "RoughnessMetallicMaterials.hpp"
#include "TraditionalMaterials.hpp"
FbxMaterialsAccess::FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<const FbxTexture *, FbxString> &textureLocations) :
mappingMode(FbxGeometryElement::eNone),
mesh(nullptr),
indices(nullptr)
{
if (pMesh->GetElementMaterialCount() <= 0) {
return;
}
FbxMaterialsAccess::FbxMaterialsAccess(
const FbxMesh* pMesh,
const std::map<const FbxTexture*, FbxString>& textureLocations)
: mappingMode(FbxGeometryElement::eNone), mesh(nullptr), indices(nullptr) {
if (pMesh->GetElementMaterialCount() <= 0) {
return;
}
const FbxGeometryElement::EMappingMode materialMappingMode = pMesh->GetElementMaterial()->GetMappingMode();
if (materialMappingMode != FbxGeometryElement::eByPolygon && materialMappingMode != FbxGeometryElement::eAllSame) {
return;
}
const FbxGeometryElement::EMappingMode materialMappingMode =
pMesh->GetElementMaterial()->GetMappingMode();
if (materialMappingMode != FbxGeometryElement::eByPolygon &&
materialMappingMode != FbxGeometryElement::eAllSame) {
return;
}
const FbxGeometryElement::EReferenceMode materialReferenceMode = pMesh->GetElementMaterial()->GetReferenceMode();
if (materialReferenceMode != FbxGeometryElement::eIndexToDirect) {
return;
}
const FbxGeometryElement::EReferenceMode materialReferenceMode =
pMesh->GetElementMaterial()->GetReferenceMode();
if (materialReferenceMode != FbxGeometryElement::eIndexToDirect) {
return;
}
mappingMode = materialMappingMode;
mesh = pMesh;
indices = &pMesh->GetElementMaterial()->GetIndexArray();
mappingMode = materialMappingMode;
mesh = pMesh;
indices = &pMesh->GetElementMaterial()->GetIndexArray();
for (int ii = 0; ii < indices->GetCount(); ii++) {
int materialNum = indices->GetAt(ii);
if (materialNum < 0) {
continue;
}
if (materialNum >= summaries.size()) {
summaries.resize(materialNum + 1);
}
auto summary = summaries[materialNum];
if (summary == nullptr) {
summary = summaries[materialNum] = GetMaterialInfo(
mesh->GetNode()->GetSrcObject<FbxSurfaceMaterial>(materialNum),
textureLocations);
}
for (int ii = 0; ii < indices->GetCount(); ii++) {
int materialNum = indices->GetAt(ii);
if (materialNum < 0) {
continue;
}
if (materialNum >= summaries.size()) {
summaries.resize(materialNum + 1);
}
auto summary = summaries[materialNum];
if (summary == nullptr) {
summary = summaries[materialNum] = GetMaterialInfo(
mesh->GetNode()->GetSrcObject<FbxSurfaceMaterial>(materialNum), textureLocations);
}
}
}
const std::shared_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterial(const int polygonIndex) const
{
if (mappingMode != FbxGeometryElement::eNone) {
const int materialNum = indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0);
if (materialNum < 0) {
return nullptr;
}
return summaries.at((unsigned long) materialNum);
const std::shared_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterial(
const int polygonIndex) const {
if (mappingMode != FbxGeometryElement::eNone) {
const int materialNum =
indices->GetAt((mappingMode == FbxGeometryElement::eByPolygon) ? polygonIndex : 0);
if (materialNum < 0) {
return nullptr;
}
return nullptr;
return summaries.at((unsigned long)materialNum);
}
return nullptr;
}
std::unique_ptr<FbxMaterialInfo>
FbxMaterialsAccess::GetMaterialInfo(FbxSurfaceMaterial *material, const std::map<const FbxTexture *, FbxString> &textureLocations)
{
std::unique_ptr<FbxMaterialInfo> res = FbxStingrayPBSMaterialResolver(material, textureLocations).resolve();
std::unique_ptr<FbxMaterialInfo> FbxMaterialsAccess::GetMaterialInfo(
FbxSurfaceMaterial* material,
const std::map<const FbxTexture*, FbxString>& textureLocations) {
std::unique_ptr<FbxMaterialInfo> res =
FbxStingrayPBSMaterialResolver(material, textureLocations).resolve();
if (res == nullptr) {
res = Fbx3dsMaxPhysicalMaterialResolver(material, textureLocations).resolve();
if (res == nullptr) {
res = Fbx3dsMaxPhysicalMaterialResolver(material, textureLocations).resolve();
if (res == nullptr) {
res = FbxTraditionalMaterialResolver(material, textureLocations).resolve();
}
res = FbxTraditionalMaterialResolver(material, textureLocations).resolve();
}
return res;
}
return res;
}

View File

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

View File

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

View File

@ -10,62 +10,63 @@
#include "RoughnessMetallicMaterials.hpp"
std::unique_ptr<FbxRoughMetMaterialInfo> FbxStingrayPBSMaterialResolver::resolve() const {
const FbxProperty mayaProp = fbxMaterial->FindProperty("Maya");
if (mayaProp.GetPropertyDataType() != FbxCompoundDT) {
return nullptr;
}
if (!fbxMaterial->ShadingModel.Get().IsEmpty()) {
::fmt::printf("Warning: Material %s has surprising shading model: %s\n",
fbxMaterial->GetName(), fbxMaterial->ShadingModel.Get());
}
const FbxProperty mayaProp = fbxMaterial->FindProperty("Maya");
if (mayaProp.GetPropertyDataType() != FbxCompoundDT) {
return nullptr;
}
if (!fbxMaterial->ShadingModel.Get().IsEmpty()) {
::fmt::printf(
"Warning: Material %s has surprising shading model: %s\n",
fbxMaterial->GetName(),
fbxMaterial->ShadingModel.Get());
}
auto getTex = [&](std::string propName) {
const FbxFileTexture *ptr = nullptr;
auto getTex = [&](std::string propName) {
const FbxFileTexture* ptr = nullptr;
const FbxProperty useProp = mayaProp.FindHierarchical(("use_" + propName + "_map").c_str());
if (useProp.IsValid() && useProp.Get<bool>()) {
const FbxProperty texProp = mayaProp.FindHierarchical(("TEX_" + propName + "_map").c_str());
if (texProp.IsValid()) {
ptr = texProp.GetSrcObject<FbxFileTexture>();
if (ptr != nullptr && textureLocations.find(ptr) == textureLocations.end()) {
ptr = nullptr;
}
}
} else if (verboseOutput && useProp.IsValid()) {
fmt::printf("Note: Property '%s' of Stingray PBS material '%s' exists, but is flagged as 'do not use'.\n",
propName, fbxMaterial->GetName());
const FbxProperty useProp = mayaProp.FindHierarchical(("use_" + propName + "_map").c_str());
if (useProp.IsValid() && useProp.Get<bool>()) {
const FbxProperty texProp = mayaProp.FindHierarchical(("TEX_" + propName + "_map").c_str());
if (texProp.IsValid()) {
ptr = texProp.GetSrcObject<FbxFileTexture>();
if (ptr != nullptr && textureLocations.find(ptr) == textureLocations.end()) {
ptr = nullptr;
}
return ptr;
};
}
} else if (verboseOutput && useProp.IsValid()) {
fmt::printf(
"Note: Property '%s' of Stingray PBS material '%s' exists, but is flagged as 'do not use'.\n",
propName,
fbxMaterial->GetName());
}
return ptr;
};
auto getVec = [&](std::string propName) -> FbxDouble3 {
const FbxProperty vecProp = mayaProp.FindHierarchical(propName.c_str());
return vecProp.IsValid() ? vecProp.Get<FbxDouble3>() : FbxDouble3(1, 1, 1);
};
auto getVec = [&](std::string propName) -> FbxDouble3 {
const FbxProperty vecProp = mayaProp.FindHierarchical(propName.c_str());
return vecProp.IsValid() ? vecProp.Get<FbxDouble3>() : FbxDouble3(1, 1, 1);
};
auto getVal = [&](std::string propName) -> FbxDouble {
const FbxProperty vecProp = mayaProp.FindHierarchical(propName .c_str());
return vecProp.IsValid() ? vecProp.Get<FbxDouble>() : 0;
};
auto getVal = [&](std::string propName) -> FbxDouble {
const FbxProperty vecProp = mayaProp.FindHierarchical(propName.c_str());
return vecProp.IsValid() ? vecProp.Get<FbxDouble>() : 0;
};
FbxDouble3 baseColor = getVec("base_color");
std::unique_ptr<FbxRoughMetMaterialInfo> res(
new FbxRoughMetMaterialInfo(
fbxMaterial->GetName(),
FbxRoughMetMaterialInfo::FBX_SHADER_METROUGH,
FbxDouble4(baseColor[0], baseColor[1], baseColor[2], 1),
getVal("metallic"),
getVal("roughness")
)
);
res->texNormal = getTex("normal");
res->texBaseColor = getTex("color");
res->texAmbientOcclusion = getTex("ao");
res->texEmissive = getTex("emissive");
res->emissive = getVec("emissive");
res->emissiveIntensity = getVal("emissive_intensity");
res->texMetallic = getTex("metallic");
res->texRoughness = getTex("roughness");
FbxDouble3 baseColor = getVec("base_color");
std::unique_ptr<FbxRoughMetMaterialInfo> res(new FbxRoughMetMaterialInfo(
fbxMaterial->GetName(),
FbxRoughMetMaterialInfo::FBX_SHADER_METROUGH,
FbxDouble4(baseColor[0], baseColor[1], baseColor[2], 1),
getVal("metallic"),
getVal("roughness")));
res->texNormal = getTex("normal");
res->texBaseColor = getTex("color");
res->texAmbientOcclusion = getTex("ao");
res->texEmissive = getTex("emissive");
res->emissive = getVec("emissive");
res->emissiveIntensity = getVal("emissive_intensity");
res->texMetallic = getTex("metallic");
res->texRoughness = getTex("roughness");
return res;
return res;
};

View File

@ -9,115 +9,127 @@
#include "TraditionalMaterials.hpp"
std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialResolver::resolve() const
{
auto getSurfaceScalar = [&](const char *propName) -> std::tuple<FbxDouble, FbxFileTexture *> {
const FbxProperty prop = fbxMaterial->FindProperty(propName);
std::unique_ptr<FbxTraditionalMaterialInfo> FbxTraditionalMaterialResolver::resolve() const {
auto getSurfaceScalar = [&](const char* propName) -> std::tuple<FbxDouble, FbxFileTexture*> {
const FbxProperty prop = fbxMaterial->FindProperty(propName);
FbxDouble val(0);
FbxFileTexture *tex = prop.GetSrcObject<FbxFileTexture>();
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
tex = nullptr;
}
if (tex == nullptr && prop.IsValid()) {
val = prop.Get<FbxDouble>();
}
return std::make_tuple(val, tex);
};
FbxDouble val(0);
FbxFileTexture* tex = prop.GetSrcObject<FbxFileTexture>();
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
tex = nullptr;
}
if (tex == nullptr && prop.IsValid()) {
val = prop.Get<FbxDouble>();
}
return std::make_tuple(val, tex);
};
auto getSurfaceVector = [&](const char *propName) -> std::tuple<FbxDouble3, FbxFileTexture *> {
const FbxProperty prop = fbxMaterial->FindProperty(propName);
auto getSurfaceVector = [&](const char* propName) -> std::tuple<FbxDouble3, FbxFileTexture*> {
const FbxProperty prop = fbxMaterial->FindProperty(propName);
FbxDouble3 val(1, 1, 1);
FbxFileTexture *tex = prop.GetSrcObject<FbxFileTexture>();
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
tex = nullptr;
}
if (tex == nullptr && prop.IsValid()) {
val = prop.Get<FbxDouble3>();
}
return std::make_tuple(val, tex);
};
FbxDouble3 val(1, 1, 1);
FbxFileTexture* tex = prop.GetSrcObject<FbxFileTexture>();
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
tex = nullptr;
}
if (tex == nullptr && prop.IsValid()) {
val = prop.Get<FbxDouble3>();
}
return std::make_tuple(val, tex);
};
auto getSurfaceValues = [&](const char *colName, const char *facName) -> std::tuple<FbxVector4, FbxFileTexture *, FbxFileTexture *> {
const FbxProperty colProp = fbxMaterial->FindProperty(colName);
const FbxProperty facProp = fbxMaterial->FindProperty(facName);
auto getSurfaceValues =
[&](const char* colName,
const char* facName) -> std::tuple<FbxVector4, FbxFileTexture*, FbxFileTexture*> {
const FbxProperty colProp = fbxMaterial->FindProperty(colName);
const FbxProperty facProp = fbxMaterial->FindProperty(facName);
FbxDouble3 colorVal(1, 1, 1);
FbxDouble factorVal(1);
FbxDouble3 colorVal(1, 1, 1);
FbxDouble factorVal(1);
FbxFileTexture *colTex = colProp.GetSrcObject<FbxFileTexture>();
if (colTex != nullptr && textureLocations.find(colTex) == textureLocations.end()) {
colTex = nullptr;
}
if (colTex == nullptr && colProp.IsValid()) {
colorVal = colProp.Get<FbxDouble3>();
}
FbxFileTexture *facTex = facProp.GetSrcObject<FbxFileTexture>();
if (facTex != nullptr && textureLocations.find(facTex) == textureLocations.end()) {
facTex = nullptr;
}
if (facTex == nullptr && facProp.IsValid()) {
factorVal = facProp.Get<FbxDouble>();
}
FbxFileTexture* colTex = colProp.GetSrcObject<FbxFileTexture>();
if (colTex != nullptr && textureLocations.find(colTex) == textureLocations.end()) {
colTex = nullptr;
}
if (colTex == nullptr && colProp.IsValid()) {
colorVal = colProp.Get<FbxDouble3>();
}
FbxFileTexture* facTex = facProp.GetSrcObject<FbxFileTexture>();
if (facTex != nullptr && textureLocations.find(facTex) == textureLocations.end()) {
facTex = nullptr;
}
if (facTex == nullptr && facProp.IsValid()) {
factorVal = facProp.Get<FbxDouble>();
}
auto val = FbxVector4(
colorVal[0] * factorVal,
colorVal[1] * factorVal,
colorVal[2] * factorVal,
factorVal);
return std::make_tuple(val, colTex, facTex);
};
auto val = FbxVector4(
colorVal[0] * factorVal, colorVal[1] * factorVal, colorVal[2] * factorVal, factorVal);
return std::make_tuple(val, colTex, facTex);
};
std::string name = fbxMaterial->GetName();
std::unique_ptr<FbxTraditionalMaterialInfo> res(new FbxTraditionalMaterialInfo(name.c_str(), fbxMaterial->ShadingModel.Get()));
std::string name = fbxMaterial->GetName();
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
auto handleBasicProperty = [&](const char *colName, const char *facName) -> std::tuple<FbxVector4, FbxFileTexture *>{
FbxFileTexture *colTex, *facTex;
FbxVector4 vec;
std::tie(vec, colTex, facTex) = getSurfaceValues(colName, facName);
if (colTex) {
if (facTex) {
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, facTex);
};
std::tie(res->colAmbient, res->texAmbient) =
handleBasicProperty(FbxSurfaceMaterial::sAmbient, FbxSurfaceMaterial::sAmbientFactor);
std::tie(res->colSpecular, res->texSpecular) =
handleBasicProperty(FbxSurfaceMaterial::sSpecular, FbxSurfaceMaterial::sSpecularFactor);
std::tie(res->colDiffuse, res->texDiffuse) =
handleBasicProperty(FbxSurfaceMaterial::sDiffuse, FbxSurfaceMaterial::sDiffuseFactor);
std::tie(res->colEmissive, res->texEmissive) =
handleBasicProperty(FbxSurfaceMaterial::sEmissive, FbxSurfaceMaterial::sEmissiveFactor);
// the normal map can only ever be a map, ignore everything else
tie(std::ignore, res->texNormal) = getSurfaceVector(FbxSurfaceMaterial::sNormalMap);
// shininess can be a map or a factor; afaict the map is always 'ShininessExponent' and the
// value is always found in 'Shininess' but only sometimes in 'ShininessExponent'.
tie(std::ignore, res->texShininess) = getSurfaceScalar("ShininessExponent");
tie(res->shininess, std::ignore) = getSurfaceScalar("Shininess");
// for transparency we just want a constant vector value;
FbxVector4 transparency;
// extract any existing textures only so we can warn that we're throwing them away
// four properties are on the same structure and follow the same rules
auto handleBasicProperty = [&](const char* colName,
const char* facName) -> std::tuple<FbxVector4, FbxFileTexture*> {
FbxFileTexture *colTex, *facTex;
std::tie(transparency, colTex, facTex) =
getSurfaceValues(FbxSurfaceMaterial::sTransparentColor, FbxSurfaceMaterial::sTransparencyFactor);
if (colTex) {
fmt::printf("Warning: Mat [%s]: Can't handle texture for %s; discarding.\n", name, FbxSurfaceMaterial::sTransparentColor);
}
if (facTex) {
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
res->colDiffuse[3] = 1.0 - (transparency[0] + transparency[1] + transparency[2])/3.0;
FbxVector4 vec;
return res;
std::tie(vec, colTex, facTex) = getSurfaceValues(colName, facName);
if (colTex) {
if (facTex) {
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, facTex);
};
std::tie(res->colAmbient, res->texAmbient) =
handleBasicProperty(FbxSurfaceMaterial::sAmbient, FbxSurfaceMaterial::sAmbientFactor);
std::tie(res->colSpecular, res->texSpecular) =
handleBasicProperty(FbxSurfaceMaterial::sSpecular, FbxSurfaceMaterial::sSpecularFactor);
std::tie(res->colDiffuse, res->texDiffuse) =
handleBasicProperty(FbxSurfaceMaterial::sDiffuse, FbxSurfaceMaterial::sDiffuseFactor);
std::tie(res->colEmissive, res->texEmissive) =
handleBasicProperty(FbxSurfaceMaterial::sEmissive, FbxSurfaceMaterial::sEmissiveFactor);
// the normal map can only ever be a map, ignore everything else
tie(std::ignore, res->texNormal) = getSurfaceVector(FbxSurfaceMaterial::sNormalMap);
// shininess can be a map or a factor; afaict the map is always 'ShininessExponent' and the
// value is always found in 'Shininess' but only sometimes in 'ShininessExponent'.
tie(std::ignore, res->texShininess) = getSurfaceScalar("ShininessExponent");
tie(res->shininess, std::ignore) = getSurfaceScalar("Shininess");
// for transparency we just want a constant vector value;
FbxVector4 transparency;
// extract any existing textures only so we can warn that we're throwing them away
FbxFileTexture *colTex, *facTex;
std::tie(transparency, colTex, facTex) = getSurfaceValues(
FbxSurfaceMaterial::sTransparentColor, FbxSurfaceMaterial::sTransparencyFactor);
if (colTex) {
fmt::printf(
"Warning: Mat [%s]: Can't handle texture for %s; discarding.\n",
name,
FbxSurfaceMaterial::sTransparentColor);
}
if (facTex) {
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
res->colDiffuse[3] = 1.0 - (transparency[0] + transparency[1] + transparency[2]) / 3.0;
return res;
}

View File

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

View File

@ -1,85 +1,86 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* 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
* of patent rights can be found in the PATENTS file in the same directory.
*/
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* 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
* of patent rights can be found in the PATENTS file in the same directory.
*/
#include "GltfModel.hpp"
std::shared_ptr<BufferViewData> GltfModel::GetAlignedBufferView(BufferData &buffer, const BufferViewData::GL_ArrayType target)
{
unsigned long bufferSize = this->binary->size();
if ((bufferSize % 4) > 0) {
bufferSize += (4 - (bufferSize % 4));
this->binary->resize(bufferSize);
}
return this->bufferViews.hold(new BufferViewData(buffer, bufferSize, target));
std::shared_ptr<BufferViewData> GltfModel::GetAlignedBufferView(
BufferData& buffer,
const BufferViewData::GL_ArrayType target) {
unsigned long bufferSize = this->binary->size();
if ((bufferSize % 4) > 0) {
bufferSize += (4 - (bufferSize % 4));
this->binary->resize(bufferSize);
}
return this->bufferViews.hold(new BufferViewData(buffer, bufferSize, target));
}
// 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)
{
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE);
bufferView->byteLength = bytes;
std::shared_ptr<BufferViewData>
GltfModel::AddRawBufferView(BufferData& buffer, const char* source, uint32_t bytes) {
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE);
bufferView->byteLength = bytes;
// make space for the new bytes (possibly moving the underlying data)
unsigned long bufferSize = this->binary->size();
this->binary->resize(bufferSize + bytes);
// make space for the new bytes (possibly moving the underlying data)
unsigned long bufferSize = this->binary->size();
this->binary->resize(bufferSize + bytes);
// and copy them into place
memcpy(&(*this->binary)[bufferSize], source, bytes);
return bufferView;
// and copy them into place
memcpy(&(*this->binary)[bufferSize], source, bytes);
return bufferView;
}
std::shared_ptr<BufferViewData> GltfModel::AddBufferViewForFile(BufferData &buffer, const std::string &filename)
{
// see if we've already created a BufferViewData for this precise file
auto iter = filenameToBufferView.find(filename);
if (iter != filenameToBufferView.end()) {
return iter->second;
}
std::shared_ptr<BufferViewData> GltfModel::AddBufferViewForFile(
BufferData& buffer,
const std::string& filename) {
// see if we've already created a BufferViewData for this precise file
auto iter = filenameToBufferView.find(filename);
if (iter != filenameToBufferView.end()) {
return iter->second;
}
std::shared_ptr<BufferViewData> result;
std::ifstream file(filename, std::ios::binary | std::ios::ate);
if (file) {
std::streamsize size = file.tellg();
file.seekg(0, std::ios::beg);
std::shared_ptr<BufferViewData> result;
std::ifstream file(filename, std::ios::binary | std::ios::ate);
if (file) {
std::streamsize size = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<char> fileBuffer(size);
if (file.read(fileBuffer.data(), size)) {
result = AddRawBufferView(buffer, fileBuffer.data(), size);
} else {
fmt::printf("Warning: Couldn't read %lu bytes from %s, skipping file.\n", size, filename);
}
std::vector<char> fileBuffer(size);
if (file.read(fileBuffer.data(), size)) {
result = AddRawBufferView(buffer, fileBuffer.data(), size);
} else {
fmt::printf("Warning: Couldn't open file %s, skipping file.\n", filename);
fmt::printf("Warning: Couldn't read %lu bytes from %s, skipping file.\n", size, filename);
}
// note that we persist here not only success, but also failure, as nullptr
filenameToBufferView[filename] = result;
return result;
} else {
fmt::printf("Warning: Couldn't open file %s, skipping file.\n", filename);
}
// note that we persist here not only success, but also failure, as nullptr
filenameToBufferView[filename] = result;
return result;
}
void GltfModel::serializeHolders(json &glTFJson)
{
serializeHolder(glTFJson, "buffers", buffers);
serializeHolder(glTFJson, "bufferViews", bufferViews);
serializeHolder(glTFJson, "scenes", scenes);
serializeHolder(glTFJson, "accessors", accessors);
serializeHolder(glTFJson, "images", images);
serializeHolder(glTFJson, "samplers", samplers);
serializeHolder(glTFJson, "textures", textures);
serializeHolder(glTFJson, "materials", materials);
serializeHolder(glTFJson, "meshes", meshes);
serializeHolder(glTFJson, "skins", skins);
serializeHolder(glTFJson, "animations", animations);
serializeHolder(glTFJson, "cameras", cameras);
serializeHolder(glTFJson, "nodes", nodes);
if (!lights.ptrs.empty()) {
json lightsJson = json::object();
serializeHolder(lightsJson, "lights", lights);
glTFJson["extensions"][KHR_LIGHTS_PUNCTUAL] = lightsJson;
}
void GltfModel::serializeHolders(json& glTFJson) {
serializeHolder(glTFJson, "buffers", buffers);
serializeHolder(glTFJson, "bufferViews", bufferViews);
serializeHolder(glTFJson, "scenes", scenes);
serializeHolder(glTFJson, "accessors", accessors);
serializeHolder(glTFJson, "images", images);
serializeHolder(glTFJson, "samplers", samplers);
serializeHolder(glTFJson, "textures", textures);
serializeHolder(glTFJson, "materials", materials);
serializeHolder(glTFJson, "meshes", meshes);
serializeHolder(glTFJson, "skins", skins);
serializeHolder(glTFJson, "animations", animations);
serializeHolder(glTFJson, "cameras", cameras);
serializeHolder(glTFJson, "nodes", nodes);
if (!lights.ptrs.empty()) {
json lightsJson = json::object();
serializeHolder(lightsJson, "lights", lights);
glTFJson["extensions"][KHR_LIGHTS_PUNCTUAL] = lightsJson;
}
}

View File

@ -1,11 +1,11 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* 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
* of patent rights can be found in the PATENTS file in the same directory.
*/
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* 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
* of patent rights can be found in the PATENTS file in the same directory.
*/
#pragma once
@ -30,139 +30,143 @@
#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
* point to the n:th buffer view, and so on. The Holder class takes a freshly 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
* are all kept in the GLTFData struct. Clients may certainly cnhoose to perpetuate the full shared_ptr<T>
* reference counting type, but generally speaking we pass around simple T& and T* 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
{
public:
std::shared_ptr<T> hold(T *ptr)
{
ptr->ix = ptrs.size();
ptrs.emplace_back(ptr);
return ptrs.back();
}
std::vector<std::shared_ptr<T>> ptrs;
* glTF 2.0 is based on the idea that data structs within a file are referenced by index; an
* accessor will point to the n:th buffer view, and so on. The Holder class takes a freshly
* 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 are all kept in the GLTFData struct. Clients may certainly cnhoose to perpetuate the full
* shared_ptr<T> reference counting type, but generally speaking we pass around simple T& and T*
* 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 {
public:
std::shared_ptr<T> hold(T* ptr) {
ptr->ix = ptrs.size();
ptrs.emplace_back(ptr);
return ptrs.back();
}
std::vector<std::shared_ptr<T>> ptrs;
};
class GltfModel
{
public:
explicit GltfModel(const GltfOptions &options)
: binary(new std::vector<uint8_t>)
, isGlb(options.outputBinary)
, defaultSampler(nullptr)
, defaultBuffer(buffers.hold(buildDefaultBuffer(options)))
{
defaultSampler = samplers.hold(buildDefaultSampler());
class GltfModel {
public:
explicit GltfModel(const GltfOptions& options)
: binary(new std::vector<uint8_t>),
isGlb(options.outputBinary),
defaultSampler(nullptr),
defaultBuffer(buffers.hold(buildDefaultBuffer(options))) {
defaultSampler = samplers.hold(buildDefaultSampler());
}
std::shared_ptr<BufferViewData> GetAlignedBufferView(
BufferData& buffer,
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>
std::shared_ptr<AccessorData> AddAccessorWithView(
BufferViewData& bufferView,
const GLType& type,
const std::vector<T>& source,
std::string name) {
auto accessor = accessors.hold(new AccessorData(bufferView, type, name));
accessor->appendAsBinaryArray(source, *binary);
bufferView.byteLength = accessor->byteLength();
return accessor;
}
template <class T>
std::shared_ptr<AccessorData>
AddAccessorAndView(BufferData& buffer, const GLType& type, const std::vector<T>& source) {
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE);
return AddAccessorWithView(*bufferView, type, source, std::string(""));
}
template <class T>
std::shared_ptr<AccessorData> AddAccessorAndView(
BufferData& buffer,
const GLType& type,
const std::vector<T>& source,
std::string name) {
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE);
return AddAccessorWithView(*bufferView, type, source, name);
}
template <class T>
std::shared_ptr<AccessorData> AddAttributeToPrimitive(
BufferData& buffer,
const RawModel& surfaceModel,
PrimitiveData& primitive,
const AttributeDefinition<T>& attrDef) {
// copy attribute data into vector
std::vector<T> attribArr;
surfaceModel.GetAttributeArray<T>(attribArr, attrDef.rawAttributeIx);
std::shared_ptr<AccessorData> accessor;
if (attrDef.dracoComponentType != draco::DT_INVALID && primitive.dracoMesh != nullptr) {
primitive.AddDracoAttrib(attrDef, attribArr);
accessor = accessors.hold(new AccessorData(attrDef.glType));
accessor->count = attribArr.size();
} else {
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER);
accessor = AddAccessorWithView(*bufferView, attrDef.glType, attribArr, std::string(""));
}
primitive.AddAttrib(attrDef.gltfName, *accessor);
return accessor;
};
std::shared_ptr<BufferViewData> GetAlignedBufferView(BufferData &buffer, 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>
std::shared_ptr<AccessorData> AddAccessorWithView(
BufferViewData &bufferView, const GLType &type, const std::vector<T> &source, std::string name)
{
auto accessor = accessors.hold(new AccessorData(bufferView, type, name));
accessor->appendAsBinaryArray(source, *binary);
bufferView.byteLength = accessor->byteLength();
return accessor;
template <class T>
void serializeHolder(json& glTFJson, std::string key, const Holder<T> holder) {
if (!holder.ptrs.empty()) {
std::vector<json> bits;
for (const auto& ptr : holder.ptrs) {
bits.push_back(ptr->serialize());
}
glTFJson[key] = bits;
}
}
template<class T>
std::shared_ptr<AccessorData> AddAccessorAndView(
BufferData &buffer, const GLType &type, const std::vector<T> &source)
{
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE);
return AddAccessorWithView(*bufferView, type, source, std::string(""));
}
void serializeHolders(json& glTFJson);
template<class T>
std::shared_ptr<AccessorData> AddAccessorAndView(
BufferData &buffer, const GLType &type, const std::vector<T> &source, std::string name)
{
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE);
return AddAccessorWithView(*bufferView, type, source, name);
}
const bool isGlb;
template<class T>
std::shared_ptr<AccessorData> AddAttributeToPrimitive(
BufferData &buffer, const RawModel &surfaceModel, PrimitiveData &primitive,
const AttributeDefinition<T> &attrDef)
{
// copy attribute data into vector
std::vector<T> attribArr;
surfaceModel.GetAttributeArray<T>(attribArr, attrDef.rawAttributeIx);
// cache BufferViewData instances that've already been created from a given filename
std::map<std::string, std::shared_ptr<BufferViewData>> filenameToBufferView;
std::shared_ptr<AccessorData> accessor;
if (attrDef.dracoComponentType != draco::DT_INVALID && primitive.dracoMesh != nullptr) {
primitive.AddDracoAttrib(attrDef, attribArr);
std::shared_ptr<std::vector<uint8_t>> binary;
accessor = accessors.hold(new AccessorData(attrDef.glType));
accessor->count = attribArr.size();
} else {
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER);
accessor = AddAccessorWithView(*bufferView, attrDef.glType, attribArr, std::string(""));
}
primitive.AddAttrib(attrDef.gltfName, *accessor);
return accessor;
};
Holder<BufferData> buffers;
Holder<BufferViewData> bufferViews;
Holder<AccessorData> accessors;
Holder<ImageData> images;
Holder<SamplerData> samplers;
Holder<TextureData> textures;
Holder<MaterialData> materials;
Holder<MeshData> meshes;
Holder<SkinData> skins;
Holder<AnimationData> animations;
Holder<CameraData> cameras;
Holder<NodeData> nodes;
Holder<SceneData> scenes;
Holder<LightData> lights;
template<class T>
void serializeHolder(json &glTFJson, std::string key, const Holder<T> holder)
{
if (!holder.ptrs.empty()) {
std::vector<json> bits;
for (const auto &ptr : holder.ptrs) {
bits.push_back(ptr->serialize());
}
glTFJson[key] = bits;
}
}
std::shared_ptr<SamplerData> defaultSampler;
std::shared_ptr<BufferData> defaultBuffer;
void serializeHolders(json &glTFJson);
const bool isGlb;
// cache BufferViewData instances that've already been created from a given filename
std::map<std::string, std::shared_ptr<BufferViewData>> filenameToBufferView;
std::shared_ptr<std::vector<uint8_t>> binary;
Holder<BufferData> buffers;
Holder<BufferViewData> bufferViews;
Holder<AccessorData> accessors;
Holder<ImageData> images;
Holder<SamplerData> samplers;
Holder<TextureData> textures;
Holder<MaterialData> materials;
Holder<MeshData> meshes;
Holder<SkinData> skins;
Holder<AnimationData> animations;
Holder<CameraData> cameras;
Holder<NodeData> nodes;
Holder<SceneData> scenes;
Holder<LightData> lights;
std::shared_ptr<SamplerData> defaultSampler;
std::shared_ptr<BufferData> defaultBuffer;
private:
SamplerData *buildDefaultSampler() {
return new SamplerData();
}
BufferData *buildDefaultBuffer(const GltfOptions &options) {
return options.outputBinary ?
new BufferData(binary) :
new BufferData(extBufferFilename, binary, options.embedResources);
}
private:
SamplerData* buildDefaultSampler() {
return new SamplerData();
}
BufferData* buildDefaultBuffer(const GltfOptions& options) {
return options.outputBinary ? new BufferData(binary)
: new BufferData(extBufferFilename, binary, options.embedResources);
}
};

File diff suppressed because it is too large Load Diff

View File

@ -19,138 +19,141 @@
#include "FBX2glTF.h"
#include "raw/RawModel.hpp"
const std::string KHR_DRACO_MESH_COMPRESSION = "KHR_draco_mesh_compression";
const std::string KHR_MATERIALS_CMN_UNLIT = "KHR_materials_unlit";
const std::string KHR_LIGHTS_PUNCTUAL = "KHR_lights_punctual";
const std::string KHR_DRACO_MESH_COMPRESSION = "KHR_draco_mesh_compression";
const std::string KHR_MATERIALS_CMN_UNLIT = "KHR_materials_unlit";
const std::string KHR_LIGHTS_PUNCTUAL = "KHR_lights_punctual";
const std::string extBufferFilename = "buffer.bin";
struct ComponentType {
// OpenGL Datatype enums
enum GL_DataType
{
GL_BYTE = 5120,
GL_UNSIGNED_BYTE,
GL_SHORT,
GL_UNSIGNED_SHORT,
GL_INT,
GL_UNSIGNED_INT,
GL_FLOAT
};
// OpenGL Datatype enums
enum GL_DataType {
GL_BYTE = 5120,
GL_UNSIGNED_BYTE,
GL_SHORT,
GL_UNSIGNED_SHORT,
GL_INT,
GL_UNSIGNED_INT,
GL_FLOAT
};
const GL_DataType glType;
const unsigned int size;
const GL_DataType glType;
const unsigned int size;
};
const ComponentType CT_USHORT = {ComponentType::GL_UNSIGNED_SHORT, 2};
const ComponentType CT_UINT = {ComponentType::GL_UNSIGNED_INT, 4};
const ComponentType CT_FLOAT = {ComponentType::GL_FLOAT, 4};
const ComponentType CT_UINT = {ComponentType::GL_UNSIGNED_INT, 4};
const ComponentType CT_FLOAT = {ComponentType::GL_FLOAT, 4};
// Map our low-level data types for glTF output
struct GLType {
GLType(const ComponentType &componentType, unsigned int count, const std::string dataType)
: componentType(componentType),
count(count),
dataType(dataType)
{}
GLType(const ComponentType& componentType, unsigned int count, const std::string dataType)
: componentType(componentType), 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 uint32_t scalar) const {
switch(componentType.size) {
case 1:
*buf = (uint8_t)scalar;
break;
case 2:
*((uint16_t *) buf) = (uint16_t)scalar;
break;
case 4:
*((uint32_t *) buf) = scalar;
break;
}
void write(uint8_t* buf, const float scalar) const {
*((float*)buf) = scalar;
}
void write(uint8_t* buf, const uint32_t scalar) const {
switch (componentType.size) {
case 1:
*buf = (uint8_t)scalar;
break;
case 2:
*((uint16_t*)buf) = (uint16_t)scalar;
break;
case 4:
*((uint32_t*)buf) = scalar;
break;
}
}
template<class T, int d>
void write(uint8_t *buf, const mathfu::Vector<T, d> &vector) const {
for (int ii = 0; ii < d; ii ++) {
((T *)buf)[ii] = vector(ii);
}
template <class T, int d>
void write(uint8_t* buf, const mathfu::Vector<T, d>& vector) const {
for (int ii = 0; ii < d; ii++) {
((T*)buf)[ii] = vector(ii);
}
template<class T, int d>
void write(uint8_t *buf, const mathfu::Matrix<T, d> &matrix) const {
// three matrix types require special alignment considerations that we don't handle
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment
assert(!(sizeof(T) == 1 && d == 2));
assert(!(sizeof(T) == 1 && d == 3));
assert(!(sizeof(T) == 2 && d == 2));
for (int col = 0; col < d; col ++) {
for (int row = 0; row < d; row ++) {
// glTF matrices are column-major
((T *)buf)[col * d + row] = matrix(row, col);
}
}
}
template <class T, int d>
void write(uint8_t* buf, const mathfu::Matrix<T, d>& matrix) const {
// three matrix types require special alignment considerations that we don't handle
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment
assert(!(sizeof(T) == 1 && d == 2));
assert(!(sizeof(T) == 1 && d == 3));
assert(!(sizeof(T) == 2 && d == 2));
for (int col = 0; col < d; col++) {
for (int row = 0; row < d; row++) {
// glTF matrices are column-major
((T*)buf)[col * d + row] = matrix(row, col);
}
}
template<class T>
void write(uint8_t *buf, const mathfu::Quaternion<T> &quaternion) const {
for (int ii = 0; ii < 3; ii++) {
((T *)buf)[ii] = quaternion.vector()(ii);
}
((T *)buf)[3] = quaternion.scalar();
}
template <class T>
void write(uint8_t* buf, const mathfu::Quaternion<T>& quaternion) const {
for (int ii = 0; ii < 3; ii++) {
((T*)buf)[ii] = quaternion.vector()(ii);
}
((T*)buf)[3] = quaternion.scalar();
}
const ComponentType componentType;
const uint8_t count;
const std::string dataType;
const ComponentType componentType;
const uint8_t count;
const std::string dataType;
};
const GLType GLT_FLOAT = {CT_FLOAT, 1, "SCALAR"};
const GLType GLT_FLOAT = {CT_FLOAT, 1, "SCALAR"};
const GLType GLT_USHORT = {CT_USHORT, 1, "SCALAR"};
const GLType GLT_UINT = {CT_UINT, 1, "SCALAR"};
const GLType GLT_VEC2F = {CT_FLOAT, 2, "VEC2"};
const GLType GLT_VEC3F = {CT_FLOAT, 3, "VEC3"};
const GLType GLT_VEC4F = {CT_FLOAT, 4, "VEC4"};
const GLType GLT_VEC4I = {CT_USHORT, 4, "VEC4"};
const GLType GLT_MAT2F = {CT_USHORT, 4, "MAT2"};
const GLType GLT_MAT3F = {CT_USHORT, 9, "MAT3"};
const GLType GLT_MAT4F = {CT_FLOAT, 16, "MAT4"};
const GLType GLT_QUATF = {CT_FLOAT, 4, "VEC4"};
const GLType GLT_UINT = {CT_UINT, 1, "SCALAR"};
const GLType GLT_VEC2F = {CT_FLOAT, 2, "VEC2"};
const GLType GLT_VEC3F = {CT_FLOAT, 3, "VEC3"};
const GLType GLT_VEC4F = {CT_FLOAT, 4, "VEC4"};
const GLType GLT_VEC4I = {CT_USHORT, 4, "VEC4"};
const GLType GLT_MAT2F = {CT_USHORT, 4, "MAT2"};
const GLType GLT_MAT3F = {CT_USHORT, 9, "MAT3"};
const GLType GLT_MAT4F = {CT_FLOAT, 16, "MAT4"};
const GLType GLT_QUATF = {CT_FLOAT, 4, "VEC4"};
/**
* The base of any indexed glTF entity.
*/
struct Holdable
{
uint32_t ix;
struct Holdable {
uint32_t ix;
virtual json serialize() const = 0;
virtual json serialize() const = 0;
};
template<class T>
struct AttributeDefinition
{
const std::string gltfName;
const T RawVertex::* rawAttributeIx;
const GLType glType;
const draco::GeometryAttribute::Type dracoAttribute;
const draco::DataType dracoComponentType;
template <class T>
struct AttributeDefinition {
const std::string gltfName;
const T RawVertex::*rawAttributeIx;
const GLType glType;
const draco::GeometryAttribute::Type dracoAttribute;
const draco::DataType dracoComponentType;
AttributeDefinition(
const std::string gltfName, const T RawVertex::*rawAttributeIx, const GLType &_glType,
const draco::GeometryAttribute::Type dracoAttribute, const draco::DataType dracoComponentType)
: gltfName(gltfName),
rawAttributeIx(rawAttributeIx),
glType(_glType),
dracoAttribute(dracoAttribute),
dracoComponentType(dracoComponentType) {}
AttributeDefinition(
const std::string gltfName,
const T RawVertex::*rawAttributeIx,
const GLType& _glType,
const draco::GeometryAttribute::Type dracoAttribute,
const draco::DataType dracoComponentType)
: gltfName(gltfName),
rawAttributeIx(rawAttributeIx),
glType(_glType),
dracoAttribute(dracoAttribute),
dracoComponentType(dracoComponentType) {}
AttributeDefinition(
const std::string gltfName, const T RawVertex::*rawAttributeIx, const GLType &_glType)
: gltfName(gltfName),
rawAttributeIx(rawAttributeIx),
glType(_glType),
dracoAttribute(draco::GeometryAttribute::INVALID),
dracoComponentType(draco::DataType::DT_INVALID) {}
AttributeDefinition(
const std::string gltfName,
const T RawVertex::*rawAttributeIx,
const GLType& _glType)
: gltfName(gltfName),
rawAttributeIx(rawAttributeIx),
glType(_glType),
dracoAttribute(draco::GeometryAttribute::INVALID),
dracoComponentType(draco::DataType::DT_INVALID) {}
};
struct AccessorData;
@ -169,19 +172,15 @@ struct SceneData;
struct SkinData;
struct TextureData;
struct ModelData
{
explicit ModelData(std::shared_ptr<const std::vector<uint8_t> > const &_binary)
: binary(_binary)
{
}
struct ModelData {
explicit ModelData(std::shared_ptr<const std::vector<uint8_t>> const& _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(
std::ofstream &gltfOutStream,
const std::string &outputFolder,
const RawModel &raw,
const GltfOptions &options
);
ModelData* Raw2Gltf(
std::ofstream& gltfOutStream,
const std::string& outputFolder,
const RawModel& raw,
const GltfOptions& options);

View File

@ -1,212 +1,219 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* 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
* of patent rights can be found in the PATENTS file in the same directory.
*/
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* 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
* of patent rights can be found in the PATENTS file in the same directory.
*/
#include "TextureBuilder.hpp"
#include <stb_image.h>
#include <stb_image_write.h>
#include <utils/File_Utils.hpp>
#include <utils/Image_Utils.hpp>
#include <utils/String_Utils.hpp>
#include <utils/File_Utils.hpp>
#include <gltf/properties/ImageData.hpp>
#include <gltf/properties/TextureData.hpp>
// keep track of some texture data as we load them
struct TexInfo {
explicit TexInfo(int rawTexIx) : rawTexIx(rawTexIx) {}
explicit TexInfo(int rawTexIx) : rawTexIx(rawTexIx) {}
const int rawTexIx;
int width {};
int height {};
int channels {};
uint8_t *pixels {};
const int rawTexIx;
int width{};
int height{};
int channels{};
uint8_t* pixels{};
};
std::shared_ptr<TextureData> TextureBuilder::combine(
const std::vector<int> &ixVec,
const std::string &tag,
const pixel_merger &computePixel,
bool includeAlphaChannel)
{
const std::string key = texIndicesKey(ixVec, tag);
auto iter = textureByIndicesKey.find(key);
if (iter != textureByIndicesKey.end()) {
return iter->second;
}
const std::vector<int>& ixVec,
const std::string& tag,
const pixel_merger& computePixel,
bool includeAlphaChannel) {
const std::string key = texIndicesKey(ixVec, tag);
auto iter = textureByIndicesKey.find(key);
if (iter != textureByIndicesKey.end()) {
return iter->second;
}
int width = -1, height = -1;
std::string mergedFilename = tag;
std::vector<TexInfo> texes { };
for (const int rawTexIx : ixVec) {
TexInfo info(rawTexIx);
if (rawTexIx >= 0) {
const RawTexture &rawTex = raw.GetTexture(rawTexIx);
const std::string &fileLoc = rawTex.fileLocation;
const std::string &name = StringUtils::GetFileBaseString(StringUtils::GetFileNameString(fileLoc));
if (!fileLoc.empty()) {
info.pixels = stbi_load(fileLoc.c_str(), &info.width, &info.height, &info.channels, 0);
if (!info.pixels) {
fmt::printf("Warning: merge texture [%d](%s) could not be loaded.\n",
rawTexIx,
name);
} else {
if (width < 0) {
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",
name,
info.width, info.height, width, height);
// this is bad enough that we abort the whole merge
return nullptr;
}
mergedFilename += "_" + name;
}
}
}
texes.push_back(info);
}
// at the moment, the best choice of filename is also the best choice of name
const std::string mergedName = mergedFilename;
if (width < 0) {
// no textures to merge; bail
return nullptr;
}
// TODO: which channel combinations make sense in input files?
// write 3 or 4 channels depending on whether or not we need transparency
int channels = includeAlphaChannel ? 4 : 3;
std::vector<uint8_t> mergedPixels(static_cast<size_t>(channels * width * height));
std::vector<pixel> pixels(texes.size());
std::vector<const pixel *> pixelPointers(texes.size());
for (int xx = 0; xx < width; xx ++) {
for (int yy = 0; yy < height; yy ++) {
pixels.clear();
for (int jj = 0; jj < texes.size(); jj ++) {
const TexInfo &tex = texes[jj];
// each texture's structure will depend on its channel count
int ii = tex.channels * (xx + yy*width);
int kk = 0;
if (tex.pixels != nullptr) {
for (; kk < tex.channels; kk ++) {
pixels[jj][kk] = tex.pixels[ii++] / 255.0f;
}
}
for (; kk < pixels[jj].size(); kk ++) {
pixels[jj][kk] = 1.0f;
}
pixelPointers[jj] = &pixels[jj];
}
const pixel merged = computePixel(pixelPointers);
int ii = channels * (xx + yy*width);
for (int jj = 0; jj < channels; jj ++) {
mergedPixels[ii + jj] = static_cast<uint8_t>(fmax(0, fmin(255.0f, merged[jj] * 255.0f)));
}
}
}
// write a .png iff we need transparency in the destination texture
bool png = includeAlphaChannel;
std::vector<char> imgBuffer;
int res;
if (png) {
res = stbi_write_png_to_func(WriteToVectorContext, &imgBuffer,
width, height, channels, mergedPixels.data(), width * channels);
} else {
res = stbi_write_jpg_to_func(WriteToVectorContext, &imgBuffer,
width, height, channels, mergedPixels.data(), 80);
}
if (!res) {
fmt::printf("Warning: failed to generate merge texture '%s'.\n", mergedFilename);
return nullptr;
}
ImageData *image;
if (options.outputBinary) {
const auto bufferView = gltf.AddRawBufferView(*gltf.defaultBuffer, imgBuffer.data(), imgBuffer.size());
image = new ImageData(mergedName, *bufferView, png ? "image/png" : "image/jpeg");
} else {
const std::string imageFilename = mergedFilename + (png ? ".png" : ".jpg");
const std::string imagePath = outputFolder + imageFilename;
FILE *fp = fopen(imagePath.c_str(), "wb");
if (fp == nullptr) {
fmt::printf("Warning:: Couldn't write file '%s' for writing.\n", imagePath);
int width = -1, height = -1;
std::string mergedFilename = tag;
std::vector<TexInfo> texes{};
for (const int rawTexIx : ixVec) {
TexInfo info(rawTexIx);
if (rawTexIx >= 0) {
const RawTexture& rawTex = raw.GetTexture(rawTexIx);
const std::string& fileLoc = rawTex.fileLocation;
const std::string& name =
StringUtils::GetFileBaseString(StringUtils::GetFileNameString(fileLoc));
if (!fileLoc.empty()) {
info.pixels = stbi_load(fileLoc.c_str(), &info.width, &info.height, &info.channels, 0);
if (!info.pixels) {
fmt::printf("Warning: merge texture [%d](%s) could not be loaded.\n", rawTexIx, name);
} else {
if (width < 0) {
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",
name,
info.width,
info.height,
width,
height);
// this is bad enough that we abort the whole merge
return nullptr;
}
mergedFilename += "_" + name;
}
if (fwrite(imgBuffer.data(), imgBuffer.size(), 1, fp) != 1) {
fmt::printf("Warning: Failed to write %lu bytes to file '%s'.\n", imgBuffer.size(), imagePath);
fclose(fp);
return nullptr;
}
fclose(fp);
if (verboseOutput) {
fmt::printf("Wrote %lu bytes to texture '%s'.\n", imgBuffer.size(), imagePath);
}
image = new ImageData(mergedName, imageFilename);
}
}
std::shared_ptr<TextureData> texDat = gltf.textures.hold(
new TextureData(mergedName, *gltf.defaultSampler, *gltf.images.hold(image)));
textureByIndicesKey.insert(std::make_pair(key, texDat));
return texDat;
texes.push_back(info);
}
// at the moment, the best choice of filename is also the best choice of name
const std::string mergedName = mergedFilename;
if (width < 0) {
// no textures to merge; bail
return nullptr;
}
// TODO: which channel combinations make sense in input files?
// write 3 or 4 channels depending on whether or not we need transparency
int channels = includeAlphaChannel ? 4 : 3;
std::vector<uint8_t> mergedPixels(static_cast<size_t>(channels * width * height));
std::vector<pixel> pixels(texes.size());
std::vector<const pixel*> pixelPointers(texes.size());
for (int xx = 0; xx < width; xx++) {
for (int yy = 0; yy < height; yy++) {
pixels.clear();
for (int jj = 0; jj < texes.size(); jj++) {
const TexInfo& tex = texes[jj];
// each texture's structure will depend on its channel count
int ii = tex.channels * (xx + yy * width);
int kk = 0;
if (tex.pixels != nullptr) {
for (; kk < tex.channels; kk++) {
pixels[jj][kk] = tex.pixels[ii++] / 255.0f;
}
}
for (; kk < pixels[jj].size(); kk++) {
pixels[jj][kk] = 1.0f;
}
pixelPointers[jj] = &pixels[jj];
}
const pixel merged = computePixel(pixelPointers);
int ii = channels * (xx + yy * width);
for (int jj = 0; jj < channels; jj++) {
mergedPixels[ii + jj] = static_cast<uint8_t>(fmax(0, fmin(255.0f, merged[jj] * 255.0f)));
}
}
}
// write a .png iff we need transparency in the destination texture
bool png = includeAlphaChannel;
std::vector<char> imgBuffer;
int res;
if (png) {
res = stbi_write_png_to_func(
WriteToVectorContext,
&imgBuffer,
width,
height,
channels,
mergedPixels.data(),
width * channels);
} else {
res = stbi_write_jpg_to_func(
WriteToVectorContext, &imgBuffer, width, height, channels, mergedPixels.data(), 80);
}
if (!res) {
fmt::printf("Warning: failed to generate merge texture '%s'.\n", mergedFilename);
return nullptr;
}
ImageData* image;
if (options.outputBinary) {
const auto bufferView =
gltf.AddRawBufferView(*gltf.defaultBuffer, imgBuffer.data(), imgBuffer.size());
image = new ImageData(mergedName, *bufferView, png ? "image/png" : "image/jpeg");
} else {
const std::string imageFilename = mergedFilename + (png ? ".png" : ".jpg");
const std::string imagePath = outputFolder + imageFilename;
FILE* fp = fopen(imagePath.c_str(), "wb");
if (fp == nullptr) {
fmt::printf("Warning:: Couldn't write file '%s' for writing.\n", imagePath);
return nullptr;
}
if (fwrite(imgBuffer.data(), imgBuffer.size(), 1, fp) != 1) {
fmt::printf(
"Warning: Failed to write %lu bytes to file '%s'.\n", imgBuffer.size(), imagePath);
fclose(fp);
return nullptr;
}
fclose(fp);
if (verboseOutput) {
fmt::printf("Wrote %lu bytes to texture '%s'.\n", imgBuffer.size(), imagePath);
}
image = new ImageData(mergedName, imageFilename);
}
std::shared_ptr<TextureData> texDat = gltf.textures.hold(
new TextureData(mergedName, *gltf.defaultSampler, *gltf.images.hold(image)));
textureByIndicesKey.insert(std::make_pair(key, texDat));
return texDat;
}
/** 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) {
const std::string key = texIndicesKey({ rawTexIndex }, tag);
auto iter = textureByIndicesKey.find(key);
if (iter != textureByIndicesKey.end()) {
return iter->second;
std::shared_ptr<TextureData> TextureBuilder::simple(int rawTexIndex, const std::string& tag) {
const std::string key = texIndicesKey({rawTexIndex}, tag);
auto iter = textureByIndicesKey.find(key);
if (iter != textureByIndicesKey.end()) {
return iter->second;
}
const RawTexture& rawTexture = raw.GetTexture(rawTexIndex);
const std::string textureName = StringUtils::GetFileBaseString(rawTexture.name);
const std::string relativeFilename = StringUtils::GetFileNameString(rawTexture.fileLocation);
ImageData* image = nullptr;
if (options.outputBinary) {
auto bufferView = gltf.AddBufferViewForFile(*gltf.defaultBuffer, rawTexture.fileLocation);
if (bufferView) {
std::string suffix = StringUtils::GetFileSuffixString(rawTexture.fileLocation);
image = new ImageData(relativeFilename, *bufferView, ImageUtils::suffixToMimeType(suffix));
}
const RawTexture &rawTexture = raw.GetTexture(rawTexIndex);
const std::string textureName = StringUtils::GetFileBaseString(rawTexture.name);
const std::string relativeFilename = StringUtils::GetFileNameString(rawTexture.fileLocation);
ImageData *image = nullptr;
if (options.outputBinary) {
auto bufferView = gltf.AddBufferViewForFile(*gltf.defaultBuffer, rawTexture.fileLocation);
if (bufferView) {
std::string suffix = StringUtils::GetFileSuffixString(rawTexture.fileLocation);
image = new ImageData(relativeFilename, *bufferView, ImageUtils::suffixToMimeType(suffix));
}
} else if (!relativeFilename.empty()) {
image = new ImageData(relativeFilename, relativeFilename);
std::string outputPath = outputFolder + StringUtils::NormalizePath(relativeFilename);
if (FileUtils::CopyFile(rawTexture.fileLocation, outputPath, true))
{
if (verboseOutput) {
fmt::printf("Copied texture '%s' to output folder: %s\n", textureName, outputPath);
}
} else {
// no point commenting further on read/write error; CopyFile() does enough of that, and we
// certainly want to to add an image struct to the glTF JSON, with the correct relative path
// reference, even if the copy failed.
}
}
if (!image) {
// fallback is tiny transparent PNG
image = new ImageData(
textureName,
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg=="
);
} else if (!relativeFilename.empty()) {
image = new ImageData(relativeFilename, relativeFilename);
std::string outputPath = outputFolder + StringUtils::NormalizePath(relativeFilename);
if (FileUtils::CopyFile(rawTexture.fileLocation, outputPath, true)) {
if (verboseOutput) {
fmt::printf("Copied texture '%s' to output folder: %s\n", textureName, outputPath);
}
} else {
// no point commenting further on read/write error; CopyFile() does enough of that, and we
// certainly want to to add an image struct to the glTF JSON, with the correct relative path
// reference, even if the copy failed.
}
}
if (!image) {
// fallback is tiny transparent PNG
image = new ImageData(
textureName,
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==");
}
std::shared_ptr<TextureData> texDat = gltf.textures.hold(
new TextureData(textureName, *gltf.defaultSampler, *gltf.images.hold(image)));
textureByIndicesKey.insert(std::make_pair(key, texDat));
return texDat;
std::shared_ptr<TextureData> texDat = gltf.textures.hold(
new TextureData(textureName, *gltf.defaultSampler, *gltf.images.hold(image)));
textureByIndicesKey.insert(std::make_pair(key, texDat));
return texDat;
}

View File

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

View File

@ -10,44 +10,32 @@
#include "AccessorData.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(),
bufferView(bufferView.ix),
type(std::move(type)),
byteOffset(0),
count(0),
name(name)
{
}
name(name) {}
AccessorData::AccessorData(GLType type)
: Holdable(),
bufferView(-1),
type(std::move(type)),
byteOffset(0),
count(0)
{
}
: Holdable(), bufferView(-1), type(std::move(type)), byteOffset(0), count(0) {}
json AccessorData::serialize() const
{
json result {
{ "componentType", type.componentType.glType },
{ "type", type.dataType },
{ "count", count }
};
if (bufferView >= 0) {
result["bufferView"] = bufferView;
result["byteOffset"] = byteOffset;
}
if (!min.empty()) {
result["min"] = min;
}
if (!max.empty()) {
result["max"] = max;
}
if (name.length() > 0) {
result["name"] = name;
}
return result;
json AccessorData::serialize() const {
json result{
{"componentType", type.componentType.glType}, {"type", type.dataType}, {"count", count}};
if (bufferView >= 0) {
result["bufferView"] = bufferView;
result["byteOffset"] = byteOffset;
}
if (!min.empty()) {
result["min"] = min;
}
if (!max.empty()) {
result["max"] = max;
}
if (name.length() > 0) {
result["name"] = name;
}
return result;
}

View File

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

View File

@ -14,57 +14,42 @@
#include "AccessorData.hpp"
#include "NodeData.hpp"
AnimationData::AnimationData(std::string name, const AccessorData &timeAccessor)
: Holdable(),
name(std::move(name)),
timeAccessor(timeAccessor.ix) {}
AnimationData::AnimationData(std::string name, const AccessorData& timeAccessor)
: Holdable(), name(std::move(name)), timeAccessor(timeAccessor.ix) {}
// 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
void AnimationData::AddNodeChannel(const NodeData &node, const AccessorData &accessor, std::string path)
{
assert(channels.size() == samplers.size());
uint32_t ix = channels.size();
channels.emplace_back(channel_t(ix, node, std::move(path)));
samplers.emplace_back(sampler_t(timeAccessor, accessor.ix));
void AnimationData::AddNodeChannel(
const NodeData& node,
const AccessorData& accessor,
std::string path) {
assert(channels.size() == samplers.size());
uint32_t ix = channels.size();
channels.emplace_back(channel_t(ix, node, std::move(path)));
samplers.emplace_back(sampler_t(timeAccessor, accessor.ix));
}
json AnimationData::serialize() const
{
return {
{ "name", name },
{ "channels", channels },
{ "samplers", samplers }
};
json AnimationData::serialize() const {
return {{"name", name}, {"channels", channels}, {"samplers", samplers}};
}
AnimationData::channel_t::channel_t(uint32_t ix, const NodeData &node, std::string path)
: ix(ix),
node(node.ix),
path(std::move(path))
{
AnimationData::channel_t::channel_t(uint32_t ix, const NodeData& node, std::string path)
: ix(ix), node(node.ix), path(std::move(path)) {}
AnimationData::sampler_t::sampler_t(uint32_t time, uint32_t output) : time(time), output(output) {}
void to_json(json& j, const AnimationData::channel_t& data) {
j = json{{"sampler", data.ix},
{
"target",
{{"node", data.node}, {"path", data.path}},
}};
}
AnimationData::sampler_t::sampler_t(uint32_t time, uint32_t output)
: time(time),
output(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 },
};
void to_json(json& j, const AnimationData::sampler_t& data) {
j = json{
{"input", data.time},
{"interpolation", "LINEAR"},
{"output", data.output},
};
}

View File

@ -11,38 +11,35 @@
#include "gltf/Raw2Gltf.hpp"
struct AnimationData : Holdable
{
AnimationData(std::string name, const AccessorData &timeAccessor);
struct AnimationData : Holdable {
AnimationData(std::string name, const AccessorData& timeAccessor);
// 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
void AddNodeChannel(const NodeData &node, const AccessorData &accessor, std::string path);
// 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
void AddNodeChannel(const NodeData& node, const AccessorData& accessor, std::string path);
json serialize() const override;
json serialize() const override;
struct channel_t
{
channel_t(uint32_t _ix, const NodeData &node, std::string path);
struct channel_t {
channel_t(uint32_t _ix, const NodeData& node, std::string path);
const uint32_t ix;
const uint32_t node;
const std::string path;
};
const uint32_t ix;
const uint32_t node;
const std::string path;
};
struct sampler_t
{
sampler_t(uint32_t time, uint32_t output);
struct sampler_t {
sampler_t(uint32_t time, uint32_t output);
const uint32_t time;
const uint32_t output;
};
const uint32_t time;
const uint32_t output;
};
const std::string name;
const uint32_t timeAccessor;
std::vector<channel_t> channels;
std::vector<sampler_t> samplers;
const std::string name;
const uint32_t timeAccessor;
std::vector<channel_t> channels;
std::vector<sampler_t> samplers;
};
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::channel_t& data);
void to_json(json& j, const AnimationData::sampler_t& data);

View File

@ -11,33 +11,24 @@
#include "BufferData.hpp"
BufferData::BufferData(const std::shared_ptr<const std::vector<uint8_t> > &binData)
: Holdable(),
isGlb(true),
binData(binData)
{
}
BufferData::BufferData(const std::shared_ptr<const std::vector<uint8_t>>& binData)
: Holdable(), isGlb(true), binData(binData) {}
BufferData::BufferData(std::string uri, const std::shared_ptr<const std::vector<uint8_t> > &binData, bool isEmbedded)
: Holdable(),
isGlb(false),
uri(isEmbedded ? "" : std::move(uri)),
binData(binData)
{
}
BufferData::BufferData(
std::string uri,
const std::shared_ptr<const std::vector<uint8_t>>& binData,
bool isEmbedded)
: Holdable(), isGlb(false), uri(isEmbedded ? "" : std::move(uri)), binData(binData) {}
json BufferData::serialize() const
{
json result{
{"byteLength", binData->size()}
};
if (!isGlb) {
if (!uri.empty()) {
result["uri"] = uri;
} else {
std::string encoded = base64::encode(*binData);
result["uri"] = "data:application/octet-stream;base64," + encoded;
}
json BufferData::serialize() const {
json result{{"byteLength", binData->size()}};
if (!isGlb) {
if (!uri.empty()) {
result["uri"] = uri;
} else {
std::string encoded = base64::encode(*binData);
result["uri"] = "data:application/octet-stream;base64," + encoded;
}
return result;
}
return result;
}

View File

@ -11,15 +11,17 @@
#include "gltf/Raw2Gltf.hpp"
struct BufferData : Holdable
{
explicit BufferData(const std::shared_ptr<const std::vector<uint8_t> > &binData);
struct BufferData : Holdable {
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 std::string uri;
const std::shared_ptr<const std::vector<uint8_t> > binData; // TODO this is just weird
const bool isGlb;
const std::string uri;
const std::shared_ptr<const std::vector<uint8_t>> binData; // TODO this is just weird
};

View File

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

View File

@ -11,22 +11,20 @@
#include "gltf/Raw2Gltf.hpp"
struct BufferViewData : Holdable
{
enum GL_ArrayType
{
GL_ARRAY_NONE = 0, // no GL buffer is being set
GL_ARRAY_BUFFER = 34962,
GL_ELEMENT_ARRAY_BUFFER = 34963
};
struct BufferViewData : Holdable {
enum GL_ArrayType {
GL_ARRAY_NONE = 0, // no GL buffer is being set
GL_ARRAY_BUFFER = 34962,
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;
const unsigned int buffer;
const unsigned int byteOffset;
const GL_ArrayType target;
const unsigned int buffer;
const unsigned int byteOffset;
const GL_ArrayType target;
unsigned int byteLength = 0;
unsigned int byteLength = 0;
};

View File

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

View File

@ -12,17 +12,16 @@
#include "gltf/Raw2Gltf.hpp"
// TODO: this class needs some work
struct CameraData : Holdable
{
CameraData();
json serialize() const override;
struct CameraData : Holdable {
CameraData();
json serialize() const override;
std::string name;
std::string type;
float aspectRatio;
float yfov;
float xmag;
float ymag;
float znear;
float zfar;
std::string name;
std::string type;
float aspectRatio;
float yfov;
float xmag;
float ymag;
float znear;
float zfar;
};

View File

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

View File

@ -11,15 +11,14 @@
#include "gltf/Raw2Gltf.hpp"
struct ImageData : Holdable
{
ImageData(std::string name, std::string uri);
ImageData(std::string name, const BufferViewData &bufferView, std::string mimeType);
struct ImageData : Holdable {
ImageData(std::string name, std::string uri);
ImageData(std::string name, const BufferViewData& bufferView, std::string mimeType);
json serialize() const override;
json serialize() const override;
const std::string name;
const std::string uri; // non-empty in gltf mode
const int32_t bufferView; // non-negative in glb mode
const std::string mimeType;
const std::string name;
const std::string uri; // non-empty in gltf mode
const int32_t bufferView; // non-negative in glb mode
const std::string mimeType;
};

View File

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

View File

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

View File

@ -11,77 +11,74 @@
#include "TextureData.hpp"
// TODO: retrieve & pass in correct UV set from FBX
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 };
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};
}
Tex::Tex(uint32_t texRef, uint32_t texCoord)
: texRef(texRef),
texCoord(texCoord) {}
Tex::Tex(uint32_t texRef, uint32_t texCoord) : texRef(texRef), texCoord(texCoord) {}
void to_json(json &j, const Tex &data) {
j = json {
{ "index", data.texRef },
{ "texCoord", data.texCoord }
};
void to_json(json& j, const Tex& data) {
j = json{{"index", data.texRef}, {"texCoord", data.texCoord}};
}
KHRCmnUnlitMaterial::KHRCmnUnlitMaterial()
{
}
KHRCmnUnlitMaterial::KHRCmnUnlitMaterial() {}
void to_json(json &j, const KHRCmnUnlitMaterial &d)
{
j = json({});
void to_json(json& j, const KHRCmnUnlitMaterial& d) {
j = json({});
}
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) {
return Vec3f::Max(bottom, Vec3f::Min(top, vec));
inline Vec3f
clamp(const Vec3f& vec, const Vec3f& bottom = VEC3F_ZERO, const Vec3f& top = VEC3F_ONE) {
return Vec3f::Max(bottom, Vec3f::Min(top, vec));
}
inline Vec4f clamp(const Vec4f &vec, const Vec4f &bottom = VEC4F_ZERO, const Vec4f &top = VEC4F_ONE) {
return Vec4f::Max(bottom, Vec4f::Min(top, vec));
inline Vec4f
clamp(const Vec4f& vec, const Vec4f& bottom = VEC4F_ZERO, const Vec4f& top = VEC4F_ONE) {
return Vec4f::Max(bottom, Vec4f::Min(top, vec));
}
PBRMetallicRoughness::PBRMetallicRoughness(
const TextureData *baseColorTexture, const TextureData *metRoughTexture,
const Vec4f &baseColorFactor, float metallic, float roughness)
const TextureData* baseColorTexture,
const TextureData* metRoughTexture,
const Vec4f& baseColorFactor,
float metallic,
float roughness)
: baseColorTexture(Tex::ref(baseColorTexture)),
metRoughTexture(Tex::ref(metRoughTexture)),
baseColorFactor(clamp(baseColorFactor)),
metallic(clamp(metallic)),
roughness(clamp(roughness))
{
}
roughness(clamp(roughness)) {}
void to_json(json &j, const PBRMetallicRoughness &d)
{
j = { };
if (d.baseColorTexture != nullptr) {
j["baseColorTexture"] = *d.baseColorTexture;
}
if (d.baseColorFactor.LengthSquared() > 0) {
j["baseColorFactor"] = toStdVec(d.baseColorFactor);
}
if (d.metRoughTexture != nullptr) {
j["metallicRoughnessTexture"] = *d.metRoughTexture;
// if a texture is provided, throw away metallic/roughness values
j["roughnessFactor"] = 1.0f;
j["metallicFactor"] = 1.0f;
} else {
// without a texture, however, use metallic/roughness as constants
j["metallicFactor"] = d.metallic;
j["roughnessFactor"] = d.roughness;
}
void to_json(json& j, const PBRMetallicRoughness& d) {
j = {};
if (d.baseColorTexture != nullptr) {
j["baseColorTexture"] = *d.baseColorTexture;
}
if (d.baseColorFactor.LengthSquared() > 0) {
j["baseColorFactor"] = toStdVec(d.baseColorFactor);
}
if (d.metRoughTexture != nullptr) {
j["metallicRoughnessTexture"] = *d.metRoughTexture;
// if a texture is provided, throw away metallic/roughness values
j["roughnessFactor"] = 1.0f;
j["metallicFactor"] = 1.0f;
} else {
// without a texture, however, use metallic/roughness as constants
j["metallicFactor"] = d.metallic;
j["roughnessFactor"] = d.roughness;
}
}
MaterialData::MaterialData(
std::string name, bool isTransparent, const RawShadingModel shadingModel,
const TextureData *normalTexture, const TextureData *occlusionTexture,
const TextureData *emissiveTexture, const Vec3f & emissiveFactor,
std::string name,
bool isTransparent,
const RawShadingModel shadingModel,
const TextureData* normalTexture,
const TextureData* occlusionTexture,
const TextureData* emissiveTexture,
const Vec3f& emissiveFactor,
std::shared_ptr<KHRCmnUnlitMaterial> const khrCmnConstantMaterial,
std::shared_ptr<PBRMetallicRoughness> const pbrMetallicRoughness)
: Holdable(),
@ -95,50 +92,43 @@ MaterialData::MaterialData(
khrCmnConstantMaterial(khrCmnConstantMaterial),
pbrMetallicRoughness(pbrMetallicRoughness) {}
json MaterialData::serialize() const
{
json result = {
{ "name", name },
{ "alphaMode", isTransparent ? "BLEND" : "OPAQUE" },
{ "extras", {
{ "fromFBX", {
{ "shadingModel", Describe(shadingModel) },
{ "isTruePBR", shadingModel == RAW_SHADING_MODEL_PBR_MET_ROUGH }
}}
}}
};
json MaterialData::serialize() const {
json result = {{"name", name},
{"alphaMode", isTransparent ? "BLEND" : "OPAQUE"},
{"extras",
{{"fromFBX",
{{"shadingModel", Describe(shadingModel)},
{"isTruePBR", shadingModel == RAW_SHADING_MODEL_PBR_MET_ROUGH}}}}}};
if (normalTexture != nullptr) {
result["normalTexture"] = *normalTexture;
}
if (occlusionTexture != nullptr) {
result["occlusionTexture"] = *occlusionTexture;
}
if (emissiveTexture != nullptr) {
result["emissiveTexture"] = *emissiveTexture;
}
if (emissiveFactor.LengthSquared() > 0) {
result["emissiveFactor"] = toStdVec(emissiveFactor);
}
if (pbrMetallicRoughness != nullptr) {
result["pbrMetallicRoughness"] = *pbrMetallicRoughness;
}
if (khrCmnConstantMaterial != nullptr) {
json extensions = { };
extensions[KHR_MATERIALS_CMN_UNLIT] = *khrCmnConstantMaterial;
result["extensions"] = extensions;
}
if (normalTexture != nullptr) {
result["normalTexture"] = *normalTexture;
}
if (occlusionTexture != nullptr) {
result["occlusionTexture"] = *occlusionTexture;
}
if (emissiveTexture != nullptr) {
result["emissiveTexture"] = *emissiveTexture;
}
if (emissiveFactor.LengthSquared() > 0) {
result["emissiveFactor"] = toStdVec(emissiveFactor);
}
if (pbrMetallicRoughness != nullptr) {
result["pbrMetallicRoughness"] = *pbrMetallicRoughness;
}
if (khrCmnConstantMaterial != nullptr) {
json extensions = {};
extensions[KHR_MATERIALS_CMN_UNLIT] = *khrCmnConstantMaterial;
result["extensions"] = extensions;
}
for (const auto& i : userProperties)
{
auto& prop_map = result["extras"]["fromFBX"]["userProperties"];
for (const auto& i : userProperties) {
auto& prop_map = result["extras"]["fromFBX"]["userProperties"];
json j = json::parse(i);
for (const auto& k : json::iterator_wrapper(j))
{
prop_map[k.key()] = k.value();
}
json j = json::parse(i);
for (const auto& k : json::iterator_wrapper(j)) {
prop_map[k.key()] = k.value();
}
}
return result;
return result;
}

View File

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

View File

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

View File

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

View File

@ -10,8 +10,11 @@
#include "NodeData.hpp"
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)
: Holdable(),
name(std::move(name)),
isJoint(isJoint),
@ -22,90 +25,80 @@ NodeData::NodeData(
mesh(-1),
camera(-1),
light(-1),
skin(-1)
{
skin(-1) {}
void NodeData::AddChildNode(uint32_t childIx) {
children.push_back(childIx);
}
void NodeData::AddChildNode(uint32_t childIx)
{
children.push_back(childIx);
void NodeData::SetMesh(uint32_t meshIx) {
assert(mesh < 0);
assert(!isJoint);
mesh = meshIx;
}
void NodeData::SetMesh(uint32_t meshIx)
{
assert(mesh < 0);
assert(!isJoint);
mesh = meshIx;
void NodeData::SetSkin(uint32_t skinIx) {
assert(skin < 0);
assert(!isJoint);
skin = skinIx;
}
void NodeData::SetSkin(uint32_t skinIx)
{
assert(skin < 0);
assert(!isJoint);
skin = skinIx;
void NodeData::SetCamera(uint32_t cameraIndex) {
assert(!isJoint);
camera = cameraIndex;
}
void NodeData::SetCamera(uint32_t cameraIndex)
{
assert(!isJoint);
camera = cameraIndex;
void NodeData::SetLight(uint32_t lightIndex) {
assert(!isJoint);
light = lightIndex;
}
void NodeData::SetLight(uint32_t lightIndex)
{
assert(!isJoint);
light = lightIndex;
}
json NodeData::serialize() const {
json result = {{"name", name}};
json NodeData::serialize() const
{
json result = { { "name", name } };
// 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 {
if (std::none_of(vec.begin(), vec.end(), [&](float n) { return std::isnan(n); })) {
result[key] = vec;
}
};
maybeAdd("translation", toStdVec(translation));
maybeAdd("rotation", toStdVec(rotation));
maybeAdd("scale", toStdVec(scale));
if (!children.empty()) {
result["children"] = children;
// 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 {
if (std::none_of(vec.begin(), vec.end(), [&](float n) { return std::isnan(n); })) {
result[key] = vec;
}
if (isJoint) {
// sanity-check joint node
assert(mesh < 0 && skin < 0);
} else {
// non-joint node
if (mesh >= 0) {
result["mesh"] = mesh;
}
if (!skeletons.empty()) {
result["skeletons"] = skeletons;
}
if (skin >= 0) {
result["skin"] = skin;
}
if (camera >= 0) {
result["camera"] = camera;
}
if (light >= 0) {
result["extensions"][KHR_LIGHTS_PUNCTUAL]["light"] = light;
}
};
maybeAdd("translation", toStdVec(translation));
maybeAdd("rotation", toStdVec(rotation));
maybeAdd("scale", toStdVec(scale));
if (!children.empty()) {
result["children"] = children;
}
if (isJoint) {
// sanity-check joint node
assert(mesh < 0 && skin < 0);
} else {
// non-joint node
if (mesh >= 0) {
result["mesh"] = mesh;
}
for (const auto& i : userProperties)
{
auto& prop_map = result["extras"]["fromFBX"]["userProperties"];
json j = json::parse(i);
for (const auto& k : json::iterator_wrapper(j))
{
prop_map[k.key()] = k.value();
}
if (!skeletons.empty()) {
result["skeletons"] = skeletons;
}
if (skin >= 0) {
result["skin"] = skin;
}
if (camera >= 0) {
result["camera"] = camera;
}
if (light >= 0) {
result["extensions"][KHR_LIGHTS_PUNCTUAL]["light"] = light;
}
}
return result;
for (const auto& i : userProperties) {
auto& prop_map = result["extras"]["fromFBX"]["userProperties"];
json j = json::parse(i);
for (const auto& k : json::iterator_wrapper(j)) {
prop_map[k.key()] = k.value();
}
}
return result;
}

View File

@ -11,28 +11,32 @@
#include "gltf/Raw2Gltf.hpp"
struct NodeData : Holdable
{
NodeData(std::string name, const Vec3f &translation, const Quatf &rotation, const Vec3f &scale, bool isJoint);
struct NodeData : Holdable {
NodeData(
std::string name,
const Vec3f& translation,
const Quatf& rotation,
const Vec3f& scale,
bool isJoint);
void AddChildNode(uint32_t childIx);
void SetMesh(uint32_t meshIx);
void SetSkin(uint32_t skinIx);
void SetCamera(uint32_t camera);
void SetLight(uint32_t light);
void AddChildNode(uint32_t childIx);
void SetMesh(uint32_t meshIx);
void SetSkin(uint32_t skinIx);
void SetCamera(uint32_t camera);
void SetLight(uint32_t light);
json serialize() const override;
json serialize() const override;
const std::string name;
const bool isJoint;
Vec3f translation;
Quatf rotation;
Vec3f scale;
std::vector<uint32_t> children;
int32_t mesh;
int32_t camera;
int32_t light;
int32_t skin;
std::vector<std::string> skeletons;
std::vector<std::string> userProperties;
const std::string name;
const bool isJoint;
Vec3f translation;
Quatf rotation;
Vec3f scale;
std::vector<uint32_t> children;
int32_t mesh;
int32_t camera;
int32_t light;
int32_t skin;
std::vector<std::string> skeletons;
std::vector<std::string> userProperties;
};

View File

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

View File

@ -11,62 +11,70 @@
#include "gltf/Raw2Gltf.hpp"
struct PrimitiveData
{
enum MeshMode
{
POINTS = 0,
LINES,
LINE_LOOP,
LINE_STRIP,
TRIANGLES,
TRIANGLE_STRIP,
TRIANGLE_FAN
};
struct PrimitiveData {
enum MeshMode {
POINTS = 0,
LINES,
LINE_LOOP,
LINE_STRIP,
TRIANGLES,
TRIANGLE_STRIP,
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>
void AddDracoAttrib(const AttributeDefinition<T> attribute, const std::vector<T> &attribArr)
{
draco::PointAttribute att;
int8_t componentCount = attribute.glType.count;
att.Init(
attribute.dracoAttribute, nullptr, componentCount, attribute.dracoComponentType,
false, componentCount * draco::DataTypeLength(attribute.dracoComponentType), 0);
template <class T>
void AddDracoAttrib(const AttributeDefinition<T> attribute, const std::vector<T>& attribArr) {
draco::PointAttribute att;
int8_t componentCount = attribute.glType.count;
att.Init(
attribute.dracoAttribute,
nullptr,
componentCount,
attribute.dracoComponentType,
false,
componentCount * draco::DataTypeLength(attribute.dracoComponentType),
0);
const int dracoAttId = dracoMesh->AddAttribute(att, true, attribArr.size());
draco::PointAttribute *attPtr = dracoMesh->attribute(dracoAttId);
const int dracoAttId = dracoMesh->AddAttribute(att, true, attribArr.size());
draco::PointAttribute* attPtr = dracoMesh->attribute(dracoAttId);
std::vector<uint8_t> buf(sizeof(T));
for (uint32_t ii = 0; ii < attribArr.size(); ii++) {
uint8_t *ptr = &buf[0];
attribute.glType.write(ptr, attribArr[ii]);
attPtr->SetAttributeValue(attPtr->mapped_index(draco::PointIndex(ii)), ptr);
}
dracoAttributes[attribute.gltfName] = dracoAttId;
std::vector<uint8_t> buf(sizeof(T));
for (uint32_t ii = 0; ii < attribArr.size(); ii++) {
uint8_t* ptr = &buf[0];
attribute.glType.write(ptr, attribArr[ii]);
attPtr->SetAttributeValue(attPtr->mapped_index(draco::PointIndex(ii)), ptr);
}
void NoteDracoBuffer(const BufferViewData &data);
dracoAttributes[attribute.gltfName] = dracoAttId;
}
const int indices;
const unsigned int material;
const MeshMode mode;
void NoteDracoBuffer(const BufferViewData& data);
std::vector<std::tuple<int, int, int>> targetAccessors {};
const int indices;
const unsigned int material;
const MeshMode mode;
std::map<std::string, int> attributes;
std::map<std::string, int> dracoAttributes;
std::vector<std::tuple<int, int, int>> targetAccessors{};
std::shared_ptr<draco::Mesh> dracoMesh;
int dracoBufferView;
std::map<std::string, int> attributes;
std::map<std::string, int> dracoAttributes;
std::shared_ptr<draco::Mesh> dracoMesh;
int dracoBufferView;
};
void to_json(json &j, const PrimitiveData &d);
void to_json(json& j, const PrimitiveData& d);

View File

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

View File

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

View File

@ -11,12 +11,11 @@
#include "gltf/Raw2Gltf.hpp"
struct SceneData : Holdable
{
SceneData(std::string name, const NodeData &rootNode);
struct SceneData : Holdable {
SceneData(std::string name, const NodeData& rootNode);
json serialize() const override;
json serialize() const override;
const std::string name;
std::vector<uint32_t> nodes;
const std::string name;
std::vector<uint32_t> nodes;
};

View File

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

View File

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

View File

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

View File

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

View File

@ -11,93 +11,93 @@
#include <fbxsdk.h>
#include <mathfu/vector.h>
#include <mathfu/matrix.h>
#include <mathfu/quaternion.h>
#include <mathfu/rect.h>
#include <mathfu/vector.h>
/**
* All the mathfu:: implementations of our core data types.
*/
template<class T, int d>
struct Bounds
{
mathfu::Vector<T, d> min;
mathfu::Vector<T, d> max;
bool initialized = false;
template <class T, int d>
struct Bounds {
mathfu::Vector<T, d> min;
mathfu::Vector<T, d> max;
bool initialized = false;
void Clear() {
min = mathfu::Vector<T, d>();
max = mathfu::Vector<T, d>();
initialized = false;
}
void Clear() {
min = mathfu::Vector<T, d>();
max = mathfu::Vector<T, d>();
initialized = false;
}
void AddPoint(const mathfu::Vector<T, d> &p) {
if (initialized) {
for (int ii = 0; ii < d; ii ++) {
min(ii) = std::min(min(ii), p(ii));
max(ii) = std::max(max(ii), p(ii));
}
} else {
min = p;
max = p;
initialized = true;
}
void AddPoint(const mathfu::Vector<T, d>& p) {
if (initialized) {
for (int ii = 0; ii < d; ii++) {
min(ii) = std::min(min(ii), p(ii));
max(ii) = std::max(max(ii), p(ii));
}
} else {
min = p;
max = p;
initialized = true;
}
}
};
typedef mathfu::Vector<uint16_t, 4> Vec4i;
typedef mathfu::Matrix<uint16_t, 4> Mat4i;
typedef mathfu::Vector<float, 2> Vec2f;
typedef mathfu::Vector<float, 3> Vec3f;
typedef mathfu::Vector<float, 4> Vec4f;
typedef mathfu::Matrix<float, 2> Mat2f;
typedef mathfu::Matrix<float, 3> Mat3f;
typedef mathfu::Matrix<float, 4> Mat4f;
typedef mathfu::Quaternion<float> Quatf;
typedef Bounds<float, 3> Boundsf;
typedef mathfu::Vector<float, 2> Vec2f;
typedef mathfu::Vector<float, 3> Vec3f;
typedef mathfu::Vector<float, 4> Vec4f;
typedef mathfu::Matrix<float, 2> Mat2f;
typedef mathfu::Matrix<float, 3> Mat3f;
typedef mathfu::Matrix<float, 4> Mat4f;
typedef mathfu::Quaternion<float> Quatf;
typedef Bounds<float, 3> Boundsf;
#define VEC3F_ONE (Vec3f {1.0f})
#define VEC3F_ZERO (Vec3f {0.0f})
#define VEC4F_ONE (Vec4f {1.0f})
#define VEC4F_ZERO (Vec4f {0.0f})
#define VEC3F_ONE (Vec3f{1.0f})
#define VEC3F_ZERO (Vec3f{0.0f})
#define VEC4F_ONE (Vec4f{1.0f})
#define VEC4F_ZERO (Vec4f{0.0f})
template<class T, int d> inline std::vector<T> toStdVec(const mathfu::Vector <T, d> &vec)
{
std::vector<T> result(d);
for (int ii = 0; ii < d; ii ++) {
result[ii] = vec[ii];
template <class T, int d>
inline std::vector<T> toStdVec(const mathfu::Vector<T, d>& vec) {
std::vector<T> result(d);
for (int ii = 0; ii < d; ii++) {
result[ii] = vec[ii];
}
return result;
}
template <class T>
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) {
return Vec3f((float)v[0], (float)v[1], (float)v[2]);
}
inline Vec3f toVec3f(const FbxVector4& v) {
return Vec3f((float)v[0], (float)v[1], (float)v[2]);
}
inline Vec4f toVec4f(const FbxVector4& v) {
return Vec4f((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
}
inline Mat4f toMat4f(const FbxAMatrix& m) {
auto result = Mat4f();
for (int row = 0; row < 4; row++) {
for (int col = 0; col < 4; col++) {
result(row, col) = (float)m[row][col];
}
return result;
}
return result;
}
template<class T> 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) {
return Vec3f((float) v[0], (float) v[1], (float) v[2]);
}
inline Vec3f toVec3f(const FbxVector4 &v) {
return Vec3f((float) v[0], (float) v[1], (float) v[2]);
}
inline Vec4f toVec4f(const FbxVector4 &v) {
return Vec4f((float) v[0], (float) v[1], (float) v[2], (float) v[3]);
}
inline Mat4f toMat4f(const FbxAMatrix &m) {
auto result = Mat4f();
for (int row = 0; row < 4; row ++) {
for (int col = 0; col < 4; col ++) {
result(row, col) = (float) m[row][col];
}
}
return result;
}
inline Quatf toQuatf(const FbxQuaternion &q) {
return Quatf((float) q[3], (float) q[0], (float) q[1], (float) q[2]);
inline Quatf toQuatf(const FbxQuaternion& q) {
return Quatf((float)q[3], (float)q[0], (float)q[1], (float)q[2]);
}

File diff suppressed because it is too large Load Diff

View File

@ -9,481 +9,540 @@
#pragma once
#include <unordered_map>
#include <functional>
#include <set>
#include <unordered_map>
#include "FBX2glTF.h"
enum RawVertexAttribute {
RAW_VERTEX_ATTRIBUTE_POSITION = 1 << 0,
RAW_VERTEX_ATTRIBUTE_NORMAL = 1 << 1,
RAW_VERTEX_ATTRIBUTE_TANGENT = 1 << 2,
RAW_VERTEX_ATTRIBUTE_BINORMAL = 1 << 3,
RAW_VERTEX_ATTRIBUTE_COLOR = 1 << 4,
RAW_VERTEX_ATTRIBUTE_UV0 = 1 << 5,
RAW_VERTEX_ATTRIBUTE_UV1 = 1 << 6,
RAW_VERTEX_ATTRIBUTE_JOINT_INDICES = 1 << 7,
RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS = 1 << 8,
enum RawVertexAttribute
{
RAW_VERTEX_ATTRIBUTE_POSITION = 1 << 0,
RAW_VERTEX_ATTRIBUTE_NORMAL = 1 << 1,
RAW_VERTEX_ATTRIBUTE_TANGENT = 1 << 2,
RAW_VERTEX_ATTRIBUTE_BINORMAL = 1 << 3,
RAW_VERTEX_ATTRIBUTE_COLOR = 1 << 4,
RAW_VERTEX_ATTRIBUTE_UV0 = 1 << 5,
RAW_VERTEX_ATTRIBUTE_UV1 = 1 << 6,
RAW_VERTEX_ATTRIBUTE_JOINT_INDICES = 1 << 7,
RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS = 1 << 8,
RAW_VERTEX_ATTRIBUTE_AUTO = 1 << 31
RAW_VERTEX_ATTRIBUTE_AUTO = 1 << 31
};
struct RawBlendVertex
{
Vec3f position {};
Vec3f normal {};
Vec4f tangent {};
struct RawBlendVertex {
Vec3f position{};
Vec3f normal{};
Vec4f tangent{};
bool operator==(const RawBlendVertex &other) const {
return position == other.position &&
normal == other.normal &&
tangent == other.tangent;
}
bool operator==(const RawBlendVertex& other) const {
return position == other.position && normal == other.normal && tangent == other.tangent;
}
};
struct RawVertex
{
RawVertex() :
polarityUv0(false),
pad1(false),
pad2(false),
pad3(false) {}
struct RawVertex {
RawVertex() : polarityUv0(false), pad1(false), pad2(false), pad3(false) {}
Vec3f position { 0.0f };
Vec3f normal { 0.0f };
Vec3f binormal { 0.0f };
Vec4f tangent { 0.0f };
Vec4f color { 0.0f };
Vec2f uv0 { 0.0f };
Vec2f uv1 { 0.0f };
Vec4i jointIndices { 0, 0, 0, 0 };
Vec4f jointWeights { 0.0f };
// end of members that directly correspond to vertex attributes
Vec3f position{0.0f};
Vec3f normal{0.0f};
Vec3f binormal{0.0f};
Vec4f tangent{0.0f};
Vec4f color{0.0f};
Vec2f uv0{0.0f};
Vec2f uv1{0.0f};
Vec4i jointIndices{0, 0, 0, 0};
Vec4f jointWeights{0.0f};
// 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
int blendSurfaceIx = -1;
// the size of this vector is always identical to the size of the corresponding RawSurface.blendChannels
std::vector<RawBlendVertex> blends { };
// if this vertex participates in a blend shape setup, the surfaceIx of its dedicated mesh;
// otherwise, -1
int blendSurfaceIx = -1;
// the size of this vector is always identical to the size of the corresponding
// RawSurface.blendChannels
std::vector<RawBlendVertex> blends{};
bool polarityUv0;
bool pad1;
bool pad2;
bool pad3;
bool polarityUv0;
bool pad1;
bool pad2;
bool pad3;
bool operator==(const RawVertex &other) const;
size_t Difference(const RawVertex &other) const;
bool operator==(const RawVertex& other) const;
size_t Difference(const RawVertex& other) const;
};
class VertexHasher
{
public:
size_t operator()(const RawVertex &v) const
{
size_t seed = 5381;
const auto hasher = std::hash<float>{};
seed ^= hasher(v.position[0]) + 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);
return seed;
}
class VertexHasher {
public:
size_t operator()(const RawVertex& v) const {
size_t seed = 5381;
const auto hasher = std::hash<float>{};
seed ^= hasher(v.position[0]) + 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);
return seed;
}
};
struct RawTriangle
{
int verts[3];
int materialIndex;
int surfaceIndex;
struct RawTriangle {
int verts[3];
int materialIndex;
int surfaceIndex;
};
enum RawShadingModel
{
RAW_SHADING_MODEL_UNKNOWN = -1,
RAW_SHADING_MODEL_CONSTANT,
RAW_SHADING_MODEL_LAMBERT,
RAW_SHADING_MODEL_BLINN,
RAW_SHADING_MODEL_PHONG,
RAW_SHADING_MODEL_PBR_MET_ROUGH,
RAW_SHADING_MODEL_MAX
enum RawShadingModel {
RAW_SHADING_MODEL_UNKNOWN = -1,
RAW_SHADING_MODEL_CONSTANT,
RAW_SHADING_MODEL_LAMBERT,
RAW_SHADING_MODEL_BLINN,
RAW_SHADING_MODEL_PHONG,
RAW_SHADING_MODEL_PBR_MET_ROUGH,
RAW_SHADING_MODEL_MAX
};
inline std::string Describe(RawShadingModel model) {
switch(model) {
case RAW_SHADING_MODEL_UNKNOWN: return "<unknown>";
case RAW_SHADING_MODEL_CONSTANT: return "Constant";
case RAW_SHADING_MODEL_LAMBERT: return "Lambert";
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>";
}
switch (model) {
case RAW_SHADING_MODEL_UNKNOWN:
return "<unknown>";
case RAW_SHADING_MODEL_CONSTANT:
return "Constant";
case RAW_SHADING_MODEL_LAMBERT:
return "Lambert";
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
{
RAW_TEXTURE_USAGE_NONE = -1,
RAW_TEXTURE_USAGE_AMBIENT,
RAW_TEXTURE_USAGE_DIFFUSE,
RAW_TEXTURE_USAGE_NORMAL,
RAW_TEXTURE_USAGE_SPECULAR,
RAW_TEXTURE_USAGE_SHININESS,
RAW_TEXTURE_USAGE_EMISSIVE,
RAW_TEXTURE_USAGE_REFLECTION,
RAW_TEXTURE_USAGE_ALBEDO,
RAW_TEXTURE_USAGE_OCCLUSION,
RAW_TEXTURE_USAGE_ROUGHNESS,
RAW_TEXTURE_USAGE_METALLIC,
RAW_TEXTURE_USAGE_MAX
enum RawTextureUsage {
RAW_TEXTURE_USAGE_NONE = -1,
RAW_TEXTURE_USAGE_AMBIENT,
RAW_TEXTURE_USAGE_DIFFUSE,
RAW_TEXTURE_USAGE_NORMAL,
RAW_TEXTURE_USAGE_SPECULAR,
RAW_TEXTURE_USAGE_SHININESS,
RAW_TEXTURE_USAGE_EMISSIVE,
RAW_TEXTURE_USAGE_REFLECTION,
RAW_TEXTURE_USAGE_ALBEDO,
RAW_TEXTURE_USAGE_OCCLUSION,
RAW_TEXTURE_USAGE_ROUGHNESS,
RAW_TEXTURE_USAGE_METALLIC,
RAW_TEXTURE_USAGE_MAX
};
inline std::string Describe(RawTextureUsage usage)
{
switch (usage) {
case RAW_TEXTURE_USAGE_NONE: return "<none>";
case RAW_TEXTURE_USAGE_AMBIENT: return "ambient";
case RAW_TEXTURE_USAGE_DIFFUSE: return "diffuse";
case RAW_TEXTURE_USAGE_NORMAL: return "normal";
case RAW_TEXTURE_USAGE_SPECULAR: return "specular";
case RAW_TEXTURE_USAGE_SHININESS: 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";
}
inline std::string Describe(RawTextureUsage usage) {
switch (usage) {
case RAW_TEXTURE_USAGE_NONE:
return "<none>";
case RAW_TEXTURE_USAGE_AMBIENT:
return "ambient";
case RAW_TEXTURE_USAGE_DIFFUSE:
return "diffuse";
case RAW_TEXTURE_USAGE_NORMAL:
return "normal";
case RAW_TEXTURE_USAGE_SPECULAR:
return "specular";
case RAW_TEXTURE_USAGE_SHININESS:
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
{
RAW_TEXTURE_OCCLUSION_OPAQUE,
RAW_TEXTURE_OCCLUSION_TRANSPARENT
enum RawTextureOcclusion { RAW_TEXTURE_OCCLUSION_OPAQUE, RAW_TEXTURE_OCCLUSION_TRANSPARENT };
struct RawTexture {
std::string name; // logical name in FBX file
int width;
int height;
int mipLevels;
RawTextureUsage usage;
RawTextureOcclusion occlusion;
std::string fileName; // original filename in FBX file
std::string fileLocation; // inferred path in local filesystem, or ""
};
struct RawTexture
{
std::string name; // logical name in FBX file
int width;
int height;
int mipLevels;
RawTextureUsage usage;
RawTextureOcclusion occlusion;
std::string fileName; // original filename in FBX file
std::string fileLocation; // inferred path in local filesystem, or ""
};
enum RawMaterialType
{
RAW_MATERIAL_TYPE_OPAQUE,
RAW_MATERIAL_TYPE_TRANSPARENT,
RAW_MATERIAL_TYPE_SKINNED_OPAQUE,
RAW_MATERIAL_TYPE_SKINNED_TRANSPARENT,
enum RawMaterialType {
RAW_MATERIAL_TYPE_OPAQUE,
RAW_MATERIAL_TYPE_TRANSPARENT,
RAW_MATERIAL_TYPE_SKINNED_OPAQUE,
RAW_MATERIAL_TYPE_SKINNED_TRANSPARENT,
};
struct RawMatProps {
explicit RawMatProps(RawShadingModel shadingModel)
: shadingModel(shadingModel)
{}
const RawShadingModel shadingModel;
explicit RawMatProps(RawShadingModel shadingModel) : shadingModel(shadingModel) {}
const RawShadingModel shadingModel;
virtual bool operator!=(const RawMatProps &other) const { return !(*this == other); }
virtual bool operator==(const RawMatProps &other) const { return shadingModel == other.shadingModel; };
virtual bool operator!=(const RawMatProps& other) const {
return !(*this == other);
}
virtual bool operator==(const RawMatProps& other) const {
return shadingModel == other.shadingModel;
};
};
struct RawTraditionalMatProps : RawMatProps {
RawTraditionalMatProps(
RawShadingModel shadingModel,
const Vec3f &&ambientFactor,
const Vec4f &&diffuseFactor,
const Vec3f &&emissiveFactor,
const Vec3f &&specularFactor,
const float shininess
) : RawMatProps(shadingModel),
ambientFactor(ambientFactor),
diffuseFactor(diffuseFactor),
emissiveFactor(emissiveFactor),
specularFactor(specularFactor),
shininess(shininess)
{}
RawTraditionalMatProps(
RawShadingModel shadingModel,
const Vec3f&& ambientFactor,
const Vec4f&& diffuseFactor,
const Vec3f&& emissiveFactor,
const Vec3f&& specularFactor,
const float shininess)
: RawMatProps(shadingModel),
ambientFactor(ambientFactor),
diffuseFactor(diffuseFactor),
emissiveFactor(emissiveFactor),
specularFactor(specularFactor),
shininess(shininess) {}
const Vec3f ambientFactor;
const Vec4f diffuseFactor;
const Vec3f emissiveFactor;
const Vec3f specularFactor;
const float shininess;
const Vec3f ambientFactor;
const Vec4f diffuseFactor;
const Vec3f emissiveFactor;
const Vec3f specularFactor;
const float shininess;
bool operator==(const RawMatProps &other) const override {
if (RawMatProps::operator==(other)) {
const auto &typed = (RawTraditionalMatProps &) other;
return ambientFactor == typed.ambientFactor &&
diffuseFactor == typed.diffuseFactor &&
specularFactor == typed.specularFactor &&
emissiveFactor == typed.emissiveFactor &&
shininess == typed.shininess;
}
return false;
bool operator==(const RawMatProps& other) const override {
if (RawMatProps::operator==(other)) {
const auto& typed = (RawTraditionalMatProps&)other;
return ambientFactor == typed.ambientFactor && diffuseFactor == typed.diffuseFactor &&
specularFactor == typed.specularFactor && emissiveFactor == typed.emissiveFactor &&
shininess == typed.shininess;
}
return false;
}
};
struct RawMetRoughMatProps : RawMatProps {
RawMetRoughMatProps(
RawShadingModel shadingModel,
const Vec4f &&diffuseFactor,
const Vec3f &&emissiveFactor,
float emissiveIntensity,
float metallic,
float roughness
) : RawMatProps(shadingModel),
diffuseFactor(diffuseFactor),
emissiveFactor(emissiveFactor),
emissiveIntensity(emissiveIntensity),
metallic(metallic),
roughness(roughness)
{}
const Vec4f diffuseFactor;
const Vec3f emissiveFactor;
const float emissiveIntensity;
const float metallic;
const float roughness;
RawMetRoughMatProps(
RawShadingModel shadingModel,
const Vec4f&& diffuseFactor,
const Vec3f&& emissiveFactor,
float emissiveIntensity,
float metallic,
float roughness)
: RawMatProps(shadingModel),
diffuseFactor(diffuseFactor),
emissiveFactor(emissiveFactor),
emissiveIntensity(emissiveIntensity),
metallic(metallic),
roughness(roughness) {}
const Vec4f diffuseFactor;
const Vec3f emissiveFactor;
const float emissiveIntensity;
const float metallic;
const float roughness;
bool operator==(const RawMatProps &other) const override {
if (RawMatProps::operator==(other)) {
const auto &typed = (RawMetRoughMatProps &) other;
return diffuseFactor == typed.diffuseFactor &&
emissiveFactor == typed.emissiveFactor &&
emissiveIntensity == typed.emissiveIntensity &&
metallic == typed.metallic &&
roughness == typed.roughness;
}
return false;
bool operator==(const RawMatProps& other) const override {
if (RawMatProps::operator==(other)) {
const auto& typed = (RawMetRoughMatProps&)other;
return diffuseFactor == typed.diffuseFactor && emissiveFactor == typed.emissiveFactor &&
emissiveIntensity == typed.emissiveIntensity && metallic == typed.metallic &&
roughness == typed.roughness;
}
return false;
}
};
struct RawMaterial
{
std::string name;
RawMaterialType type;
std::shared_ptr<RawMatProps> info;
int textures[RAW_TEXTURE_USAGE_MAX];
std::vector<std::string> userProperties;
struct RawMaterial {
std::string name;
RawMaterialType type;
std::shared_ptr<RawMatProps> info;
int textures[RAW_TEXTURE_USAGE_MAX];
std::vector<std::string> userProperties;
};
enum RawLightType
{
RAW_LIGHT_TYPE_DIRECTIONAL,
RAW_LIGHT_TYPE_POINT,
RAW_LIGHT_TYPE_SPOT,
enum RawLightType {
RAW_LIGHT_TYPE_DIRECTIONAL,
RAW_LIGHT_TYPE_POINT,
RAW_LIGHT_TYPE_SPOT,
};
struct RawLight
{
std::string name;
RawLightType type;
Vec3f color;
float intensity;
float innerConeAngle; // only meaningful for spot
float outerConeAngle; // only meaningful for spot
struct RawLight {
std::string name;
RawLightType type;
Vec3f color;
float intensity;
float innerConeAngle; // only meaningful for spot
float outerConeAngle; // only meaningful for spot
};
struct RawBlendChannel
{
float defaultDeform;
bool hasNormals;
bool hasTangents;
std::string name;
struct RawBlendChannel {
float defaultDeform;
bool hasNormals;
bool hasTangents;
std::string name;
};
struct RawSurface
{
long id;
std::string name; // The name of this surface
long skeletonRootId; // The id of the root node of the skeleton.
Bounds<float, 3> bounds;
std::vector<long> jointIds;
std::vector<Vec3f> jointGeometryMins;
std::vector<Vec3f> jointGeometryMaxs;
std::vector<Mat4f> inverseBindMatrices;
std::vector<RawBlendChannel> blendChannels;
bool discrete;
struct RawSurface {
long id;
std::string name; // The name of this surface
long skeletonRootId; // The id of the root node of the skeleton.
Bounds<float, 3> bounds;
std::vector<long> jointIds;
std::vector<Vec3f> jointGeometryMins;
std::vector<Vec3f> jointGeometryMaxs;
std::vector<Mat4f> inverseBindMatrices;
std::vector<RawBlendChannel> blendChannels;
bool discrete;
};
struct RawChannel
{
int nodeIndex;
std::vector<Vec3f> translations;
std::vector<Quatf> rotations;
std::vector<Vec3f> scales;
std::vector<float> weights;
struct RawChannel {
int nodeIndex;
std::vector<Vec3f> translations;
std::vector<Quatf> rotations;
std::vector<Vec3f> scales;
std::vector<float> weights;
};
struct RawAnimation
{
std::string name;
std::vector<float> times;
std::vector<RawChannel> channels;
struct RawAnimation {
std::string name;
std::vector<float> times;
std::vector<RawChannel> channels;
};
struct RawCamera
{
std::string name;
long nodeId;
struct RawCamera {
std::string name;
long nodeId;
enum
{
CAMERA_MODE_PERSPECTIVE,
CAMERA_MODE_ORTHOGRAPHIC
} mode;
enum { CAMERA_MODE_PERSPECTIVE, CAMERA_MODE_ORTHOGRAPHIC } mode;
struct
{
float aspectRatio;
float fovDegreesX;
float fovDegreesY;
float nearZ;
float farZ;
} perspective;
struct {
float aspectRatio;
float fovDegreesX;
float fovDegreesY;
float nearZ;
float farZ;
} perspective;
struct
{
float magX;
float magY;
float nearZ;
float farZ;
} orthographic;
struct {
float magX;
float magY;
float nearZ;
float farZ;
} orthographic;
};
struct RawNode
{
bool isJoint;
long id;
std::string name;
long parentId;
std::vector<long> childIds;
Vec3f translation;
Quatf rotation;
Vec3f scale;
long surfaceId;
long lightIx;
std::vector<std::string> userProperties;
struct RawNode {
bool isJoint;
long id;
std::string name;
long parentId;
std::vector<long> childIds;
Vec3f translation;
Quatf rotation;
Vec3f scale;
long surfaceId;
long lightIx;
std::vector<std::string> userProperties;
};
class RawModel
{
public:
RawModel();
class RawModel {
public:
RawModel();
// Add geometry.
void AddVertexAttribute(const RawVertexAttribute attrib);
int AddVertex(const RawVertex &vertex);
int AddTriangle(const int v0, 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(
const char *name, const RawMaterialType materialType, const int textures[RAW_TEXTURE_USAGE_MAX],
std::shared_ptr<RawMatProps> materialInfo, const std::vector<std::string>& userProperties);
int AddLight(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(
const char *name, const long nodeId, const float aspectRatio, const float fovDegreesX, const float fovDegreesY,
const float nearZ, const float farZ);
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; }
// Add geometry.
void AddVertexAttribute(const RawVertexAttribute attrib);
int AddVertex(const RawVertex& vertex);
int AddTriangle(
const int v0,
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(
const char* name,
const RawMaterialType materialType,
const int textures[RAW_TEXTURE_USAGE_MAX],
std::shared_ptr<RawMatProps> materialInfo,
const std::vector<std::string>& userProperties);
int AddLight(
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(
const char* name,
const long nodeId,
const float aspectRatio,
const float fovDegreesX,
const float fovDegreesY,
const float nearZ,
const float farZ);
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.
void Condense();
// Remove unused vertices, textures or materials after removing vertex attributes, textures,
// materials or surfaces.
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.
int GetVertexAttributes() const { return vertexAttributes; }
// Get the attributes stored per vertex.
int GetVertexAttributes() const {
return vertexAttributes;
}
// Iterate over the vertices.
int GetVertexCount() const { return (int) vertices.size(); }
const RawVertex &GetVertex(const int index) const { return vertices[index]; }
// Iterate over the vertices.
int GetVertexCount() const {
return (int)vertices.size();
}
const RawVertex& GetVertex(const int index) const {
return vertices[index];
}
// Iterate over the triangles.
int GetTriangleCount() const { return (int) triangles.size(); }
const RawTriangle &GetTriangle(const int index) const { return triangles[index]; }
// Iterate over the triangles.
int GetTriangleCount() const {
return (int)triangles.size();
}
const RawTriangle& GetTriangle(const int index) const {
return triangles[index];
}
// Iterate over the textures.
int GetTextureCount() const { return (int) textures.size(); }
const RawTexture &GetTexture(const int index) const { return textures[index]; }
// Iterate over the textures.
int GetTextureCount() const {
return (int)textures.size();
}
const RawTexture& GetTexture(const int index) const {
return textures[index];
}
// Iterate over the materials.
int GetMaterialCount() const { return (int) materials.size(); }
const RawMaterial &GetMaterial(const int index) const { return materials[index]; }
// Iterate over the materials.
int GetMaterialCount() const {
return (int)materials.size();
}
const RawMaterial& GetMaterial(const int index) const {
return materials[index];
}
// Iterate over the surfaces.
int GetSurfaceCount() const { return (int) surfaces.size(); }
const RawSurface &GetSurface(const int index) const { return surfaces[index]; }
RawSurface &GetSurface(const int index) { return surfaces[index]; }
int GetSurfaceById(const long id) const;
// Iterate over the surfaces.
int GetSurfaceCount() const {
return (int)surfaces.size();
}
const RawSurface& GetSurface(const int index) const {
return surfaces[index];
}
RawSurface& GetSurface(const int index) {
return surfaces[index];
}
int GetSurfaceById(const long id) const;
// Iterate over the animations.
int GetAnimationCount() const { return (int) animations.size(); }
const RawAnimation &GetAnimation(const int index) const { return animations[index]; }
// Iterate over the animations.
int GetAnimationCount() const {
return (int)animations.size();
}
const RawAnimation& GetAnimation(const int index) const {
return animations[index];
}
// Iterate over the cameras.
int GetCameraCount() const { return (int) cameras.size(); }
const RawCamera &GetCamera(const int index) const { return cameras[index]; }
// Iterate over the cameras.
int GetCameraCount() const {
return (int)cameras.size();
}
const RawCamera& GetCamera(const int index) const {
return cameras[index];
}
// Iterate over the lights.
int GetLightCount() const { return (int) lights.size(); }
const RawLight &GetLight(const int index) const { return lights[index]; }
// Iterate over the lights.
int GetLightCount() const {
return (int)lights.size();
}
const RawLight& GetLight(const int index) const {
return lights[index];
}
// Iterate over the nodes.
int GetNodeCount() const { return (int) nodes.size(); }
const RawNode &GetNode(const int index) const { return nodes[index]; }
RawNode &GetNode(const int index) { return nodes[index]; }
int GetNodeById(const long nodeId) const;
// Iterate over the nodes.
int GetNodeCount() const {
return (int)nodes.size();
}
const RawNode& GetNode(const int index) const {
return nodes[index];
}
RawNode& GetNode(const int index) {
return nodes[index];
}
int GetNodeById(const long nodeId) const;
// Create individual attribute arrays.
// Returns true if the vertices store the particular attribute.
template<typename _attrib_type_>
void GetAttributeArray(std::vector<_attrib_type_> &out, const _attrib_type_ RawVertex::* ptr) const;
// Create individual attribute arrays.
// Returns true if the vertices store the particular attribute.
template <typename _attrib_type_>
void GetAttributeArray(std::vector<_attrib_type_>& out, const _attrib_type_ RawVertex::*ptr)
const;
// Create an array with a raw model for each material.
// Multiple surfaces with the same material will turn into a single model.
// However, surfaces that are marked as 'discrete' will turn into separate models.
void CreateMaterialModels(
std::vector<RawModel> &materialModels, bool shortIndices, const int keepAttribs, const bool forceDiscrete) const;
// Create an array with a raw model for each material.
// Multiple surfaces with the same material will turn into a single model.
// However, surfaces that are marked as 'discrete' will turn into separate models.
void CreateMaterialModels(
std::vector<RawModel>& materialModels,
bool shortIndices,
const int keepAttribs,
const bool forceDiscrete) const;
private:
Vec3f getFaceNormal(int verts[3]) const;
private:
Vec3f getFaceNormal(int verts[3]) const;
long rootNodeId;
int vertexAttributes;
std::unordered_map<RawVertex, int, VertexHasher> vertexHash;
std::vector<RawVertex> vertices;
std::vector<RawTriangle> triangles;
std::vector<RawTexture> textures;
std::vector<RawMaterial> materials;
std::vector<RawLight> lights;
std::vector<RawSurface> surfaces;
std::vector<RawAnimation> animations;
std::vector<RawCamera> cameras;
std::vector<RawNode> nodes;
long rootNodeId;
int vertexAttributes;
std::unordered_map<RawVertex, int, VertexHasher> vertexHash;
std::vector<RawVertex> vertices;
std::vector<RawTriangle> triangles;
std::vector<RawTexture> textures;
std::vector<RawMaterial> materials;
std::vector<RawLight> lights;
std::vector<RawSurface> surfaces;
std::vector<RawAnimation> animations;
std::vector<RawCamera> cameras;
std::vector<RawNode> nodes;
};
template<typename _attrib_type_>
void RawModel::GetAttributeArray(std::vector<_attrib_type_> &out, const _attrib_type_ RawVertex::* ptr) const
{
out.resize(vertices.size());
for (size_t i = 0; i < vertices.size(); i++) {
out[i] = vertices[i].*ptr;
}
template <typename _attrib_type_>
void RawModel::GetAttributeArray(
std::vector<_attrib_type_>& out,
const _attrib_type_ RawVertex::*ptr) const {
out.resize(vertices.size());
for (size_t i = 0; i < vertices.size(); i++) {
out[i] = vertices[i].*ptr;
}
}

View File

@ -9,24 +9,24 @@
#include "File_Utils.hpp"
#include <fstream>
#include <string>
#include <vector>
#include <fstream>
#include <stdint.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 <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#define _getcwd getcwd
#define _mkdir(a) mkdir(a, 0777)
#elif defined( _WIN32 )
#elif defined(_WIN32)
#include <direct.h>
#include <process.h>
#else
@ -41,176 +41,174 @@
namespace FileUtils {
std::string GetCurrentFolder()
{
char cwd[StringUtils::MAX_PATH_LENGTH];
if (!_getcwd(cwd, sizeof(cwd))) {
return std::string();
}
cwd[sizeof(cwd) - 1] = '\0';
StringUtils::GetCleanPath(cwd, cwd, StringUtils::PATH_UNIX);
const size_t length = strlen(cwd);
if (cwd[length - 1] != '/' && length < StringUtils::MAX_PATH_LENGTH - 1) {
cwd[length + 0] = '/';
cwd[length + 1] = '\0';
}
return std::string(cwd);
}
bool FileExists(const std::string &filePath)
{
std::ifstream stream(filePath);
return stream.good();
}
bool FolderExists(const std::string &folderPath)
{
#if defined( __unix__ ) || defined( __APPLE__ )
DIR *dir = opendir(folderPath.c_str());
if (dir) {
closedir(dir);
return true;
}
return false;
#else
const DWORD ftyp = GetFileAttributesA( folderPath.c_str() );
if ( ftyp == INVALID_FILE_ATTRIBUTES )
{
return false; // bad path
}
return ( ftyp & FILE_ATTRIBUTE_DIRECTORY ) != 0;
#endif
}
bool MatchExtension(const char *fileExtension, const char *matchExtensions)
{
if (matchExtensions[0] == '\0') {
return true;
}
if (fileExtension[0] == '.') {
fileExtension++;
}
for (const char *end = matchExtensions; end[0] != '\0';) {
for (; end[0] == ';'; end++) {}
const char *ext = end;
for (; end[0] != ';' && end[0] != '\0'; end++) {}
#if defined( __unix__ ) || defined( __APPLE__ )
if (strncasecmp(fileExtension, ext, end - ext) == 0)
#else
if ( _strnicmp( fileExtension, ext, end - ext ) == 0 )
#endif
{
return true;
}
}
return false;
}
std::vector<std::string> ListFolderFiles(const char *folder, const char *matchExtensions)
{
std::vector<std::string> fileList;
#if defined( __unix__ ) || defined( __APPLE__ )
DIR *dir = opendir(strlen(folder) > 0 ? folder : ".");
if (dir != nullptr) {
for (;;) {
struct dirent *dp = readdir(dir);
if (dp == nullptr) {
break;
}
if (dp->d_type == DT_DIR) {
continue;
}
const char *fileName = dp->d_name;
const char *fileExt = strrchr(fileName, '.');
if (!fileExt || !MatchExtension(fileExt, matchExtensions)) {
continue;
}
fileList.emplace_back(fileName);
}
closedir(dir);
}
#else
std::string pathStr = folder;
pathStr += "*";
WIN32_FIND_DATA FindFileData;
HANDLE hFind = FindFirstFile( pathStr.c_str(), &FindFileData );
if ( hFind != INVALID_HANDLE_VALUE )
{
do
{
if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
std::string fileName = FindFileData.cFileName;
std::string::size_type extPos = fileName.rfind('.');
if (extPos != std::string::npos &&
MatchExtension(fileName.substr(extPos + 1).c_str(), matchExtensions)) {
fileList.push_back(fileName);
}
}
} while ( FindNextFile( hFind, &FindFileData ) );
FindClose( hFind );
}
#endif
return fileList;
}
bool CreatePath(const char *path)
{
#if defined( __unix__ ) || defined( __APPLE__ )
StringUtils::PathSeparator separator = StringUtils::PATH_UNIX;
#else
StringUtils::PathSeparator separator = StringUtils::PATH_WIN;
#endif
std::string folder = StringUtils::GetFolderString(path);
std::string clean = StringUtils::GetCleanPathString(folder, separator);
std::string build = clean;
for (int i = 0; i < clean.length(); i ++) {
if (clean[i] == separator && i > 0) {
build[i] = '\0';
if (i > 1 || build[1] != ':') {
if (_mkdir(build.c_str()) != 0 && errno != EEXIST) {
return false;
}
}
}
build[i] = clean[i];
}
return true;
}
bool CopyFile(const std::string &srcFilename, const std::string &dstFilename, bool createPath) {
std::ifstream srcFile(srcFilename, std::ios::binary);
if (!srcFile) {
fmt::printf("Warning: Couldn't open file %s for reading.\n", srcFilename);
return false;
}
// find source file length
srcFile.seekg(0, std::ios::end);
std::streamsize srcSize = srcFile.tellg();
srcFile.seekg(0, std::ios::beg);
if (createPath && !CreatePath(dstFilename.c_str())) {
fmt::printf("Warning: Couldn't create directory %s.\n", dstFilename);
return false;
}
std::ofstream dstFile(dstFilename, std::ios::binary | std::ios::trunc);
if (!dstFile) {
fmt::printf("Warning: Couldn't open file %s for writing.\n", dstFilename);
return false;
}
dstFile << srcFile.rdbuf();
std::streamsize dstSize = dstFile.tellp();
if (srcSize == dstSize) {
return true;
}
fmt::printf("Warning: Only copied %lu bytes to %s, when %s is %lu bytes long.\n", dstSize, dstFilename, srcFilename, srcSize);
return false;
}
std::string GetCurrentFolder() {
char cwd[StringUtils::MAX_PATH_LENGTH];
if (!_getcwd(cwd, sizeof(cwd))) {
return std::string();
}
cwd[sizeof(cwd) - 1] = '\0';
StringUtils::GetCleanPath(cwd, cwd, StringUtils::PATH_UNIX);
const size_t length = strlen(cwd);
if (cwd[length - 1] != '/' && length < StringUtils::MAX_PATH_LENGTH - 1) {
cwd[length + 0] = '/';
cwd[length + 1] = '\0';
}
return std::string(cwd);
}
bool FileExists(const std::string& filePath) {
std::ifstream stream(filePath);
return stream.good();
}
bool FolderExists(const std::string& folderPath) {
#if defined(__unix__) || defined(__APPLE__)
DIR* dir = opendir(folderPath.c_str());
if (dir) {
closedir(dir);
return true;
}
return false;
#else
const DWORD ftyp = GetFileAttributesA(folderPath.c_str());
if (ftyp == INVALID_FILE_ATTRIBUTES) {
return false; // bad path
}
return (ftyp & FILE_ATTRIBUTE_DIRECTORY) != 0;
#endif
}
bool MatchExtension(const char* fileExtension, const char* matchExtensions) {
if (matchExtensions[0] == '\0') {
return true;
}
if (fileExtension[0] == '.') {
fileExtension++;
}
for (const char* end = matchExtensions; end[0] != '\0';) {
for (; end[0] == ';'; end++) {
}
const char* ext = end;
for (; end[0] != ';' && end[0] != '\0'; end++) {
}
#if defined(__unix__) || defined(__APPLE__)
if (strncasecmp(fileExtension, ext, end - ext) == 0)
#else
if (_strnicmp(fileExtension, ext, end - ext) == 0)
#endif
{
return true;
}
}
return false;
}
std::vector<std::string> ListFolderFiles(const char* folder, const char* matchExtensions) {
std::vector<std::string> fileList;
#if defined(__unix__) || defined(__APPLE__)
DIR* dir = opendir(strlen(folder) > 0 ? folder : ".");
if (dir != nullptr) {
for (;;) {
struct dirent* dp = readdir(dir);
if (dp == nullptr) {
break;
}
if (dp->d_type == DT_DIR) {
continue;
}
const char* fileName = dp->d_name;
const char* fileExt = strrchr(fileName, '.');
if (!fileExt || !MatchExtension(fileExt, matchExtensions)) {
continue;
}
fileList.emplace_back(fileName);
}
closedir(dir);
}
#else
std::string pathStr = folder;
pathStr += "*";
WIN32_FIND_DATA FindFileData;
HANDLE hFind = FindFirstFile(pathStr.c_str(), &FindFileData);
if (hFind != INVALID_HANDLE_VALUE) {
do {
if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
std::string fileName = FindFileData.cFileName;
std::string::size_type extPos = fileName.rfind('.');
if (extPos != std::string::npos &&
MatchExtension(fileName.substr(extPos + 1).c_str(), matchExtensions)) {
fileList.push_back(fileName);
}
}
} while (FindNextFile(hFind, &FindFileData));
FindClose(hFind);
}
#endif
return fileList;
}
bool CreatePath(const char* path) {
#if defined(__unix__) || defined(__APPLE__)
StringUtils::PathSeparator separator = StringUtils::PATH_UNIX;
#else
StringUtils::PathSeparator separator = StringUtils::PATH_WIN;
#endif
std::string folder = StringUtils::GetFolderString(path);
std::string clean = StringUtils::GetCleanPathString(folder, separator);
std::string build = clean;
for (int i = 0; i < clean.length(); i++) {
if (clean[i] == separator && i > 0) {
build[i] = '\0';
if (i > 1 || build[1] != ':') {
if (_mkdir(build.c_str()) != 0 && errno != EEXIST) {
return false;
}
}
}
build[i] = clean[i];
}
return true;
}
bool CopyFile(const std::string& srcFilename, const std::string& dstFilename, bool createPath) {
std::ifstream srcFile(srcFilename, std::ios::binary);
if (!srcFile) {
fmt::printf("Warning: Couldn't open file %s for reading.\n", srcFilename);
return false;
}
// find source file length
srcFile.seekg(0, std::ios::end);
std::streamsize srcSize = srcFile.tellg();
srcFile.seekg(0, std::ios::beg);
if (createPath && !CreatePath(dstFilename.c_str())) {
fmt::printf("Warning: Couldn't create directory %s.\n", dstFilename);
return false;
}
std::ofstream dstFile(dstFilename, std::ios::binary | std::ios::trunc);
if (!dstFile) {
fmt::printf("Warning: Couldn't open file %s for writing.\n", dstFilename);
return false;
}
dstFile << srcFile.rdbuf();
std::streamsize dstSize = dstFile.tellp();
if (srcSize == dstSize) {
return true;
}
fmt::printf(
"Warning: Only copied %lu bytes to %s, when %s is %lu bytes long.\n",
dstSize,
dstFilename,
srcFilename,
srcSize);
return false;
}
} // namespace FileUtils

View File

@ -14,15 +14,18 @@
namespace FileUtils {
std::string GetCurrentFolder();
std::string GetCurrentFolder();
bool FileExists(const std::string &folderPath);
bool FolderExists(const std::string &folderPath);
bool FileExists(const std::string& folderPath);
bool FolderExists(const std::string& folderPath);
bool MatchExtension(const char *fileExtension, const char *matchExtensions);
std::vector<std::string> ListFolderFiles(const char *folder, const char *matchExtensions);
bool MatchExtension(const char* fileExtension, 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 <string>
#include <algorithm>
#include <string>
#define STB_IMAGE_IMPLEMENTATION
@ -22,56 +22,53 @@
namespace ImageUtils {
static bool imageHasTransparentPixels(FILE *f)
{
int width, height, channels;
// 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);
if (pixels != nullptr) {
int pixelCount = width * height;
for (int ix = 0; ix < pixelCount; ix++) {
// test fourth byte (alpha); 255 is 1.0
if (pixels[4 * ix + 3] != 255) {
return true;
}
}
}
return false;
static bool imageHasTransparentPixels(FILE* f) {
int width, height, channels;
// 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);
if (pixels != nullptr) {
int pixelCount = width * height;
for (int ix = 0; ix < pixelCount; ix++) {
// test fourth byte (alpha); 255 is 1.0
if (pixels[4 * ix + 3] != 255) {
return true;
}
}
ImageProperties GetImageProperties(char const *filePath)
{
ImageProperties result = {
1,
1,
IMAGE_OPAQUE,
};
FILE *f = fopen(filePath, "rb");
if (f == nullptr) {
return result;
}
int channels;
int success = stbi_info_from_file(f, &result.width, &result.height, &channels);
if (success && channels == 4 && imageHasTransparentPixels(f)) {
result.occlusion = IMAGE_TRANSPARENT;
}
return result;
}
std::string suffixToMimeType(std::string suffix)
{
std::transform(suffix.begin(), suffix.end(), suffix.begin(), ::tolower);
if (suffix == "jpg" || suffix == "jpeg") {
return "image/jpeg";
}
if (suffix == "png") {
return "image/png";
}
return "image/unknown";
}
}
return false;
}
ImageProperties GetImageProperties(char const* filePath) {
ImageProperties result = {
1,
1,
IMAGE_OPAQUE,
};
FILE* f = fopen(filePath, "rb");
if (f == nullptr) {
return result;
}
int channels;
int success = stbi_info_from_file(f, &result.width, &result.height, &channels);
if (success && channels == 4 && imageHasTransparentPixels(f)) {
result.occlusion = IMAGE_TRANSPARENT;
}
return result;
}
std::string suffixToMimeType(std::string suffix) {
std::transform(suffix.begin(), suffix.end(), suffix.begin(), ::tolower);
if (suffix == "jpg" || suffix == "jpeg") {
return "image/jpeg";
}
if (suffix == "png") {
return "image/png";
}
return "image/unknown";
}
} // namespace ImageUtils

View File

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

View File

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

View File

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