mirror of
https://github.com/godotengine/godot.git
synced 2024-11-10 14:12:51 +00:00
Remove ad-hoc FBX importer
This importer was the fruit of a lot of amazing reverse engineering work by RevoluPowered, based on the original Assimp importer that was introduced by fire. While promising and well tuned for a specific type of FBX scenes, it was found to have many flaws to support the many FBX exporters and legacy models that Godot users want to use. As we currently lack a maintainer to improve it, those issues are left unresolved and FBX import is still sub-par in the current Godot releases. After some experimentation, we're instead adding a new importer that relies on Facebook's `fbx2gltf` command line tool to convert FBX to glTF, so that we can then use our well-maintained glTF importer. See #59653 and https://github.com/facebookincubator/FBX2glTF for details.
This commit is contained in:
parent
60f8df380d
commit
33d477498e
@ -63,13 +63,6 @@ Copyright: 2011, Ole Kniemeyer, MAXON, www.maxon.net
|
||||
2014-2022, Godot Engine contributors.
|
||||
License: Expat and Zlib
|
||||
|
||||
Files: ./modules/fbx/fbx_parser/
|
||||
Comment: Open Asset Import Library (FBX parser)
|
||||
Copyright: 2006-2020, assimp team
|
||||
2007-2022, Juan Linietsky, Ariel Manzur.
|
||||
2014-2022, Godot Engine contributors.
|
||||
License: BSD-3-clause
|
||||
|
||||
Files: ./platform/android/java/lib/aidl/com/android/*
|
||||
./platform/android/java/lib/res/layout/status_bar_ongoing_event_progress_bar.xml
|
||||
./platform/android/java/lib/src/com/google/android/*
|
||||
|
@ -1,32 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="EditorSceneFormatImporterFBX" inherits="EditorSceneFormatImporter" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||
<brief_description>
|
||||
FBX 3D asset importer.
|
||||
</brief_description>
|
||||
<description>
|
||||
This is an FBX 3D asset importer with full support for most FBX features.
|
||||
If exporting a FBX scene from Autodesk Maya, use these FBX export settings:
|
||||
[codeblock]
|
||||
- Smoothing Groups
|
||||
- Smooth Mesh
|
||||
- Triangluate (for meshes with blend shapes)
|
||||
- Bake Animation
|
||||
- Resample All
|
||||
- Deformed Models
|
||||
- Skins
|
||||
- Blend Shapes
|
||||
- Curve Filters
|
||||
- Constant Key Reducer
|
||||
- Auto Tangents Only
|
||||
- *Do not check* Constraints (as it will break the file)
|
||||
- Can check Embed Media (embeds textures into the exported FBX file)
|
||||
- Note that when importing embedded media, the texture and mesh will be a single immutable file.
|
||||
- You will have to re-export then re-import the FBX if the texture has changed.
|
||||
- Units: Centimeters
|
||||
- Up Axis: Y
|
||||
- Binary format in FBX 2017
|
||||
[/codeblock]
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
</class>
|
@ -1,196 +0,0 @@
|
||||
# Open Source FBX Specification for the Importer
|
||||
|
||||
The goal of this document is to make everything in FBX clearly stated, any errors will be corrected over time this
|
||||
is a first draft.
|
||||
|
||||
## fbx parser - originally from assimp
|
||||
|
||||
- Folder: /modules/fbx/fbx_parser
|
||||
- Upstream: assimp
|
||||
- Original Version: git (308db73d0b3c2d1870cd3e465eaa283692a4cf23, 2019)
|
||||
- License: BSD-3-Clause
|
||||
|
||||
This can never be updated from upstream, we have heavily modified the parser to provide memory safety and add some
|
||||
functionality. If anything we should give this parser back to assimp at some point as it has a lot of new features.
|
||||
|
||||
# Updating assimp fbx parser
|
||||
|
||||
Don't. It's not possible the code is rewritten in many areas to remove thirdparty deps and various bugs are fixed.
|
||||
|
||||
Many days were put into rewriting the parser to use safe code and safe memory accessors.
|
||||
|
||||
# File Headers
|
||||
|
||||
FBX Binaries start with the header "Kaydara FBX Binary"
|
||||
|
||||
FBX ASCII documents contain a larger header, sometimes with copyright information for a file.
|
||||
|
||||
Detecting these is pretty simple.
|
||||
|
||||
# What is an OP link?
|
||||
It's an object to property link. It lists the properties for that object in some cases. Source and destination based by
|
||||
ID.
|
||||
|
||||
# What is a OO link?
|
||||
Its an object to object link, it contains the ID source and destination ID.
|
||||
|
||||
# FBX Node connections
|
||||
|
||||
Nodes in FBX are connected using OO links, This means Object to Object.
|
||||
|
||||
FBX has a single other kind of link which is Object Property, this is used for Object to Property Links, this can be
|
||||
extra attributes, defaults, or even some simple settings.
|
||||
|
||||
# Bones / Joints / Locators
|
||||
|
||||
Bones in FBX are nodes, they initially have the Model:: Type, then have links to SubDeformer the sub deformer
|
||||
is part of the skin there is also an explicit Skin link, which then links to the geometry using OO links in the
|
||||
document.
|
||||
|
||||
# Rotation Order in FBX compared to Godot
|
||||
|
||||
**Godot uses the rotation order:** YXZ
|
||||
|
||||
**FBX has dynamic rotation order to prevent gimbal lock with complex animations**
|
||||
|
||||
```cpp
|
||||
enum RotOrder {
|
||||
RotOrder_EulerXYZ = 0
|
||||
RotOrder_EulerXZY,
|
||||
RotOrder_EulerYZX,
|
||||
RotOrder_EulerYXZ,
|
||||
RotOrder_EulerZXY,
|
||||
RotOrder_EulerZYX,
|
||||
RotOrder_SphericXYZ // nobody uses this - as far as we can tell
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
# Pivot transforms
|
||||
|
||||
### Pivot description:
|
||||
- Maya and 3DS max consider everything to be in node space (bones joints, skins, lights, cameras, etc)
|
||||
- Everything is a node, this means essentially nodes are auto or variants
|
||||
- They are local to the node in the tree.
|
||||
- They are used to calculate where a node is in space
|
||||
```c++
|
||||
// For a better reference you can check editor_scene_importer_fbx.h
|
||||
// references: GenFBXTransform / read the data in
|
||||
// references: ComputePivotTransform / run the calculation
|
||||
// This is the local pivot transform for the node, not the global transforms
|
||||
Transform ComputePivotTransform(
|
||||
Transform3D chain[TransformationComp_MAXIMUM],
|
||||
Transform3D &geometric_transform) {
|
||||
// Maya pivots
|
||||
Transform3D T = chain[TransformationComp_Translation];
|
||||
Transform3D Roff = chain[TransformationComp_RotationOffset];
|
||||
Transform3D Rp = chain[TransformationComp_RotationPivot];
|
||||
Transform3D Rpre = chain[TransformationComp_PreRotation];
|
||||
Transform3D R = chain[TransformationComp_Rotation];
|
||||
Transform3D Rpost = chain[TransformationComp_PostRotation];
|
||||
Transform3D Soff = chain[TransformationComp_ScalingOffset];
|
||||
Transform3D Sp = chain[TransformationComp_ScalingPivot];
|
||||
Transform3D S = chain[TransformationComp_Scaling];
|
||||
|
||||
// 3DS Max Pivots
|
||||
Transform3D OT = chain[TransformationComp_GeometricTranslation];
|
||||
Transform3D OR = chain[TransformationComp_GeometricRotation];
|
||||
Transform3D OS = chain[TransformationComp_GeometricScaling];
|
||||
|
||||
// Calculate 3DS max pivot transform - use geometric space (e.g doesn't effect children nodes only the current node)
|
||||
geometric_transform = OT * OR * OS;
|
||||
// Calculate standard maya pivots
|
||||
return T * Roff * Rp * Rpre * R * Rpost.inverse() * Rp.inverse() * Soff * Sp * S * Sp.inverse();
|
||||
}
|
||||
```
|
||||
|
||||
# Transform inheritance for FBX Nodes
|
||||
|
||||
The goal of below is to explain why they implement this in the first place.
|
||||
|
||||
The use case is to make nodes have an option to override their local scaling or to make scaling influenced by orientation, which i would imagine would be useful for when you need to rotate a node and the child to scale based on the orientation rather than setting on the rotation matrix planes.
|
||||
```cpp
|
||||
// not modified the formatting here since this code must remain clear
|
||||
enum TransformInheritance {
|
||||
Transform_RrSs = 0,
|
||||
// Parent Rotation * Local Rotation * Parent Scale * Local Scale -- Parent Rotation Offset * Parent ScalingOffset (Local scaling is offset by rotation of parent node)
|
||||
Transform_RSrs = 1, // Parent Rotation * Parent Scale * Local Rotation * Local Scale -- Parent * Local (normal mode)
|
||||
Transform_Rrs = 2, // Parent Rotation * Local Rotation * Local Scale -- Node transform scale is the only relevant component
|
||||
TransformInheritance_MAX // end-of-enum sentinel
|
||||
};
|
||||
|
||||
enum TransformInheritance {
|
||||
Transform_RrSs = 0,
|
||||
// Local scaling is offset by rotation of parent node
|
||||
Transform_RSrs = 1,
|
||||
// Parent * Local (normal mode)
|
||||
Transform_Rrs = 2,
|
||||
// Node transform scale is the only relevant component
|
||||
TransformInheritance_MAX // end-of-enum sentinel
|
||||
};
|
||||
```
|
||||
|
||||
# Axis in FBX
|
||||
|
||||
Godot has one format for the declared axis
|
||||
|
||||
AXIS X, AXIS Y, -AXIS Z
|
||||
|
||||
FBX supports any format you can think of. As it has to support Maya and 3DS Max.
|
||||
|
||||
#### FBX File Header
|
||||
```json
|
||||
GlobalSettings: {
|
||||
Version: 1000
|
||||
Properties70: {
|
||||
P: "UpAxis", "int", "Integer", "",1
|
||||
P: "UpAxisSign", "int", "Integer", "",1
|
||||
P: "FrontAxis", "int", "Integer", "",2
|
||||
P: "FrontAxisSign", "int", "Integer", "",1
|
||||
P: "CoordAxis", "int", "Integer", "",0
|
||||
P: "CoordAxisSign", "int", "Integer", "",1
|
||||
P: "OriginalUpAxis", "int", "Integer", "",1
|
||||
P: "OriginalUpAxisSign", "int", "Integer", "",1
|
||||
P: "UnitScaleFactor", "double", "Number", "",1
|
||||
P: "OriginalUnitScaleFactor", "double", "Number", "",1
|
||||
P: "AmbientColor", "ColorRGB", "Color", "",0,0,0
|
||||
P: "DefaultCamera", "KString", "", "", "Producer Perspective"
|
||||
P: "TimeMode", "enum", "", "",6
|
||||
P: "TimeProtocol", "enum", "", "",2
|
||||
P: "SnapOnFrameMode", "enum", "", "",0
|
||||
P: "TimeSpanStart", "KTime", "Time", "",0
|
||||
P: "TimeSpanStop", "KTime", "Time", "",92372316000
|
||||
P: "CustomFrameRate", "double", "Number", "",-1
|
||||
P: "TimeMarker", "Compound", "", ""
|
||||
P: "CurrentTimeMarker", "int", "Integer", "",-1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### FBX FILE declares axis dynamically using FBX header
|
||||
Coord is X
|
||||
Up is Y
|
||||
Front is Z
|
||||
|
||||
#### GODOT - constant reference point
|
||||
Coord is X positive,
|
||||
Y is up positive,
|
||||
Front is -Z negative
|
||||
|
||||
### Explaining MeshGeometry indexing
|
||||
|
||||
Reference type declared:
|
||||
- Direct (directly related to the mapping information type)
|
||||
- IndexToDirect (Map with key value, meaning depends on the MappingInformationType)
|
||||
|
||||
ControlPoint is a vertex
|
||||
* None The mapping is undetermined.
|
||||
* ByVertex There will be one mapping coordinate for each surface control point/vertex.
|
||||
* If you have direct reference type vertices [x]
|
||||
* If you have IndexToDirect reference type the UV
|
||||
* ByPolygonVertex There will be one mapping coordinate for each vertex, for every polygon of which it is a part. This means that a vertex will have as many mapping coordinates as polygons of which it is a part. (Sorted by polygon, referencing vertex)
|
||||
* ByPolygon There can be only one mapping coordinate for the whole polygon.
|
||||
* One mapping per polygon polygon x has this normal x
|
||||
* For each vertex of the polygon then set the normal to x
|
||||
* ByEdge There will be one mapping coordinate for each unique edge in the mesh. This is meant to be used with smoothing layer elements. (Mapping is referencing the edge id)
|
||||
* AllSame There can be only one mapping coordinate for the whole surface.
|
@ -1,18 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env")
|
||||
Import("env_modules")
|
||||
|
||||
env_fbx = env_modules.Clone()
|
||||
|
||||
# Make includes relative to the folder path specified here so our includes are clean
|
||||
env_fbx.Prepend(CPPPATH=["#modules/fbx/"])
|
||||
|
||||
if env["builtin_zlib"]:
|
||||
env_fbx.Prepend(CPPPATH=["#thirdparty/zlib/"])
|
||||
|
||||
# Godot's own source files
|
||||
env_fbx.add_source_files(env.modules_sources, "tools/*.cpp")
|
||||
env_fbx.add_source_files(env.modules_sources, "data/*.cpp")
|
||||
env_fbx.add_source_files(env.modules_sources, "fbx_parser/*.cpp")
|
||||
env_fbx.add_source_files(env.modules_sources, "*.cpp")
|
@ -1,16 +0,0 @@
|
||||
def can_build(env, platform):
|
||||
return env["tools"]
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
||||
|
||||
|
||||
def get_doc_classes():
|
||||
return [
|
||||
"EditorSceneImporterFBX",
|
||||
]
|
||||
|
||||
|
||||
def get_doc_path():
|
||||
return "doc_classes"
|
@ -1,46 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_anim_container.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_ANIM_CONTAINER_H
|
||||
#define FBX_ANIM_CONTAINER_H
|
||||
|
||||
#include "core/math/vector3.h"
|
||||
|
||||
// Generic keyframes 99.99 percent of files will be vector3, except if quat interp is used, or visibility tracks
|
||||
// FBXTrack is used in a map in the implementation in fbx/editor_scene_importer_fbx.cpp
|
||||
// to avoid having to rewrite the entire logic I refactored this into the code instead.
|
||||
// once it works I can rewrite so we can add the fun misc features / small features
|
||||
struct FBXTrack {
|
||||
bool has_default = false;
|
||||
Vector3 default_value;
|
||||
std::map<int64_t, Vector3> keyframes;
|
||||
};
|
||||
|
||||
#endif //MODEL_ABSTRACTION_ANIM_CONTAINER_H
|
@ -1,56 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_bone.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "fbx_bone.h"
|
||||
|
||||
#include "fbx_node.h"
|
||||
#include "import_state.h"
|
||||
|
||||
Ref<FBXNode> FBXSkinDeformer::get_link(const ImportState &state) const {
|
||||
print_verbose("bone name: " + bone->bone_name);
|
||||
|
||||
// safe for when deformers must be polyfilled when skin has different count of binds to bones in the scene ;)
|
||||
if (!cluster) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V_MSG(cluster->TargetNode() == nullptr, nullptr, "bone has invalid target node");
|
||||
|
||||
Ref<FBXNode> link_node;
|
||||
uint64_t id = cluster->TargetNode()->ID();
|
||||
if (state.fbx_target_map.has(id)) {
|
||||
link_node = state.fbx_target_map[id];
|
||||
} else {
|
||||
print_error("link node not found for " + itos(id));
|
||||
}
|
||||
|
||||
// the node in space this is for, like if it's FOR a target.
|
||||
return link_node;
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_bone.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_BONE_H
|
||||
#define FBX_BONE_H
|
||||
|
||||
#include "fbx_node.h"
|
||||
#include "import_state.h"
|
||||
|
||||
#include "fbx_parser/FBXDocument.h"
|
||||
|
||||
struct PivotTransform;
|
||||
|
||||
struct FBXBone : public RefCounted {
|
||||
uint64_t parent_bone_id = 0;
|
||||
uint64_t bone_id = 0;
|
||||
|
||||
bool valid_parent = false; // if the parent bone id is set up.
|
||||
String bone_name = String(); // bone name
|
||||
|
||||
bool is_root_bone() const {
|
||||
return !valid_parent;
|
||||
}
|
||||
|
||||
// Godot specific data
|
||||
int godot_bone_id = -2; // godot internal bone id assigned after import
|
||||
|
||||
// if a bone / armature is the root then FBX skeleton will contain the bone not any other skeleton.
|
||||
// this is to support joints by themselves in scenes
|
||||
bool valid_armature_id = false;
|
||||
uint64_t armature_id = 0;
|
||||
|
||||
/* link node is the parent bone */
|
||||
mutable const FBXDocParser::Geometry *geometry = nullptr;
|
||||
mutable const FBXDocParser::ModelLimbNode *limb_node = nullptr;
|
||||
|
||||
void set_node(Ref<FBXNode> p_node) {
|
||||
node = p_node;
|
||||
}
|
||||
|
||||
// Stores the pivot xform for this bone
|
||||
|
||||
Ref<FBXNode> node = nullptr;
|
||||
Ref<FBXBone> parent_bone = nullptr;
|
||||
Ref<FBXSkeleton> fbx_skeleton = nullptr;
|
||||
};
|
||||
|
||||
struct FBXSkinDeformer {
|
||||
FBXSkinDeformer(Ref<FBXBone> p_bone, const FBXDocParser::Cluster *p_cluster) :
|
||||
cluster(p_cluster), bone(p_bone) {}
|
||||
~FBXSkinDeformer() {}
|
||||
const FBXDocParser::Cluster *cluster;
|
||||
Ref<FBXBone> bone;
|
||||
|
||||
/* get associate model - the model can be invalid sometimes */
|
||||
Ref<FBXBone> get_associate_model() const {
|
||||
return bone->parent_bone;
|
||||
}
|
||||
|
||||
Ref<FBXNode> get_link(const ImportState &state) const;
|
||||
};
|
||||
|
||||
#endif // FBX_BONE_H
|
@ -1,468 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_material.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "fbx_material.h"
|
||||
|
||||
// FIXME: Shouldn't depend on core_bind.h! Use DirAccessRef like the rest of
|
||||
// the engine instead of core_bind::Directory.
|
||||
#include "core/core_bind.h"
|
||||
#include "scene/resources/material.h"
|
||||
#include "scene/resources/texture.h"
|
||||
#include "tools/validation_tools.h"
|
||||
|
||||
String FBXMaterial::get_material_name() const {
|
||||
return material_name;
|
||||
}
|
||||
|
||||
void FBXMaterial::set_imported_material(FBXDocParser::Material *p_material) {
|
||||
material = p_material;
|
||||
}
|
||||
|
||||
void FBXMaterial::add_search_string(String p_filename, String p_current_directory, String search_directory, Vector<String> &texture_search_paths) {
|
||||
if (search_directory.is_empty()) {
|
||||
texture_search_paths.push_back(p_current_directory.get_base_dir().plus_file(p_filename));
|
||||
} else {
|
||||
texture_search_paths.push_back(p_current_directory.get_base_dir().plus_file(search_directory + "/" + p_filename));
|
||||
texture_search_paths.push_back(p_current_directory.get_base_dir().plus_file("../" + search_directory + "/" + p_filename));
|
||||
}
|
||||
}
|
||||
|
||||
String find_file(const String &p_base, const String &p_file_to_find) {
|
||||
core_bind::Directory dir;
|
||||
dir.open(p_base);
|
||||
|
||||
dir.list_dir_begin();
|
||||
String n = dir.get_next();
|
||||
while (!n.is_empty()) {
|
||||
if (n == "." || n == "..") {
|
||||
n = dir.get_next();
|
||||
continue;
|
||||
}
|
||||
if (dir.current_is_dir()) {
|
||||
// Don't use `path_to` or the returned path will be wrong.
|
||||
const String f = find_file(p_base + "/" + n, p_file_to_find);
|
||||
if (!f.is_empty()) {
|
||||
return f;
|
||||
}
|
||||
} else if (n == p_file_to_find) {
|
||||
return p_base + "/" + n;
|
||||
}
|
||||
n = dir.get_next();
|
||||
}
|
||||
dir.list_dir_end();
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
// fbx will not give us good path information and let's not regex them to fix them
|
||||
// no relative paths are in fbx generally they have a rel field but it's populated incorrectly by the SDK.
|
||||
String FBXMaterial::find_texture_path_by_filename(const String p_filename, const String p_current_directory) {
|
||||
core_bind::Directory dir;
|
||||
Vector<String> paths;
|
||||
add_search_string(p_filename, p_current_directory, "", paths);
|
||||
add_search_string(p_filename, p_current_directory, "texture", paths);
|
||||
add_search_string(p_filename, p_current_directory, "textures", paths);
|
||||
add_search_string(p_filename, p_current_directory, "Textures", paths);
|
||||
add_search_string(p_filename, p_current_directory, "materials", paths);
|
||||
add_search_string(p_filename, p_current_directory, "mats", paths);
|
||||
add_search_string(p_filename, p_current_directory, "pictures", paths);
|
||||
add_search_string(p_filename, p_current_directory, "images", paths);
|
||||
|
||||
for (int i = 0; i < paths.size(); i++) {
|
||||
if (dir.file_exists(paths[i])) {
|
||||
return paths[i];
|
||||
}
|
||||
}
|
||||
|
||||
// We were not able to find the texture in the common locations,
|
||||
// try to find it into the project globally.
|
||||
// The common textures can be stored into one of those folders:
|
||||
// res://asset
|
||||
// res://texture
|
||||
// res://material
|
||||
// res://mat
|
||||
// res://image
|
||||
// res://picture
|
||||
//
|
||||
// Note the folders can also be called with custom names, like:
|
||||
// res://my_assets
|
||||
// since the keyword `asset` is into the directory name the textures will be
|
||||
// searched there too.
|
||||
|
||||
dir.open("res://");
|
||||
dir.list_dir_begin();
|
||||
String n = dir.get_next();
|
||||
while (!n.is_empty()) {
|
||||
if (n == "." || n == "..") {
|
||||
n = dir.get_next();
|
||||
continue;
|
||||
}
|
||||
if (dir.current_is_dir()) {
|
||||
const String lower_n = n.to_lower();
|
||||
if (
|
||||
// Don't need to use plural.
|
||||
lower_n.find("asset") >= 0 ||
|
||||
lower_n.find("texture") >= 0 ||
|
||||
lower_n.find("material") >= 0 ||
|
||||
lower_n.find("mat") >= 0 ||
|
||||
lower_n.find("image") >= 0 ||
|
||||
lower_n.find("picture") >= 0) {
|
||||
// Don't use `path_to` or the returned path will be wrong.
|
||||
const String f = find_file(String("res://") + n, p_filename);
|
||||
if (!f.is_empty()) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
}
|
||||
n = dir.get_next();
|
||||
}
|
||||
dir.list_dir_end();
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T extract_from_prop(FBXDocParser::PropertyPtr prop, const T &p_default, const std::string &p_name, const String &p_type) {
|
||||
ERR_FAIL_COND_V_MSG(prop == nullptr, p_default, "invalid property passed to extractor");
|
||||
const FBXDocParser::TypedProperty<T> *val = dynamic_cast<const FBXDocParser::TypedProperty<T> *>(prop);
|
||||
|
||||
ERR_FAIL_COND_V_MSG(val == nullptr, p_default, "The FBX is corrupted, the property `" + String(p_name.c_str()) + "` is a `" + String(typeid(*prop).name()) + "` but should be a " + p_type);
|
||||
// Make sure to not lost any eventual opacity.
|
||||
return val->Value();
|
||||
}
|
||||
|
||||
Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) {
|
||||
ERR_FAIL_COND_V(material == nullptr, nullptr);
|
||||
|
||||
const String p_fbx_current_directory = state.path;
|
||||
|
||||
Ref<StandardMaterial3D> spatial_material;
|
||||
spatial_material.instantiate();
|
||||
|
||||
// read the material file
|
||||
// is material two sided
|
||||
// read material name
|
||||
print_verbose("[material] material name: " + ImportUtils::FBXNodeToName(material->Name()));
|
||||
|
||||
material_name = ImportUtils::FBXNodeToName(material->Name());
|
||||
|
||||
for (const std::pair<std::string, const FBXDocParser::Texture *> iter : material->Textures()) {
|
||||
const uint64_t texture_id = iter.second->ID();
|
||||
const std::string &fbx_mapping_name = iter.first;
|
||||
const FBXDocParser::Texture *fbx_texture_data = iter.second;
|
||||
const String absolute_texture_path = iter.second->FileName().c_str();
|
||||
const String texture_name = absolute_texture_path.get_file();
|
||||
const String file_extension = absolute_texture_path.get_extension().to_upper();
|
||||
|
||||
const String debug_string = "texture id: " + itos(texture_id) + " texture name: " + String(iter.second->Name().c_str()) + " mapping name: " + String(fbx_mapping_name.c_str());
|
||||
// remember errors STILL need this string at the end for when you aren't in verbose debug mode :) they need context for when you're not verbose-ing.
|
||||
print_verbose(debug_string);
|
||||
|
||||
const String file_extension_uppercase = file_extension.to_upper();
|
||||
|
||||
if (fbx_transparency_flags.count(fbx_mapping_name) > 0) {
|
||||
// just enable it later let's make this fine-tuned.
|
||||
spatial_material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA);
|
||||
}
|
||||
|
||||
ERR_CONTINUE_MSG(file_extension.is_empty(), "your texture has no file extension so we had to ignore it, let us know if you think this is wrong file an issue on github! " + debug_string);
|
||||
ERR_CONTINUE_MSG(fbx_texture_map.count(fbx_mapping_name) <= 0, "This material has a texture with mapping name: " + String(fbx_mapping_name.c_str()) + " which is not yet supported by this importer. Consider opening an issue so we can support it.");
|
||||
ERR_CONTINUE_MSG(
|
||||
file_extension_uppercase != "PNG" &&
|
||||
file_extension_uppercase != "JPEG" &&
|
||||
file_extension_uppercase != "JPG" &&
|
||||
file_extension_uppercase != "TGA" &&
|
||||
file_extension_uppercase != "WEBP" &&
|
||||
file_extension_uppercase != "DDS",
|
||||
"The FBX file contains a texture with an unrecognized extension: " + file_extension_uppercase);
|
||||
|
||||
print_verbose("Getting FBX mapping mode for " + String(fbx_mapping_name.c_str()));
|
||||
// get the texture map type
|
||||
const StandardMaterial3D::TextureParam mapping_mode = fbx_texture_map.at(fbx_mapping_name);
|
||||
print_verbose("Set FBX mapping mode to " + get_texture_param_name(mapping_mode));
|
||||
|
||||
Ref<Texture> texture;
|
||||
print_verbose("texture mapping name: " + texture_name);
|
||||
|
||||
if (state.cached_image_searches.has(texture_name)) {
|
||||
texture = state.cached_image_searches[texture_name];
|
||||
} else {
|
||||
String path = find_texture_path_by_filename(texture_name, p_fbx_current_directory);
|
||||
if (!path.is_empty()) {
|
||||
Ref<Texture2D> image_texture = ResourceLoader::load(path);
|
||||
|
||||
ERR_CONTINUE(image_texture.is_null());
|
||||
|
||||
texture = image_texture;
|
||||
state.cached_image_searches.insert(texture_name, texture);
|
||||
print_verbose("Created texture from loaded image file.");
|
||||
|
||||
} else if (fbx_texture_data != nullptr && fbx_texture_data->Media() != nullptr && fbx_texture_data->Media()->IsEmbedded()) {
|
||||
// This is an embedded texture. Extract it.
|
||||
Ref<Image> image;
|
||||
//image.instantiate(); // oooo double instance bug? why make Image::_png_blah call
|
||||
|
||||
const String extension = texture_name.get_extension().to_upper();
|
||||
if (extension == "PNG") {
|
||||
// The stored file is a PNG.
|
||||
image = Image::_png_mem_loader_func(fbx_texture_data->Media()->Content(), fbx_texture_data->Media()->ContentLength());
|
||||
ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded PNG image load fail.");
|
||||
|
||||
} else if (
|
||||
extension == "JPEG" ||
|
||||
extension == "JPG") {
|
||||
// The stored file is a JPEG.
|
||||
image = Image::_jpg_mem_loader_func(fbx_texture_data->Media()->Content(), fbx_texture_data->Media()->ContentLength());
|
||||
ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded JPEG image load fail.");
|
||||
|
||||
} else if (extension == "TGA") {
|
||||
// The stored file is a TGA.
|
||||
image = Image::_tga_mem_loader_func(fbx_texture_data->Media()->Content(), fbx_texture_data->Media()->ContentLength());
|
||||
ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded TGA image load fail.");
|
||||
|
||||
} else if (extension == "WEBP") {
|
||||
// The stored file is a WEBP.
|
||||
image = Image::_webp_mem_loader_func(fbx_texture_data->Media()->Content(), fbx_texture_data->Media()->ContentLength());
|
||||
ERR_CONTINUE_MSG(image.is_valid() == false, "FBX Embedded WEBP image load fail.");
|
||||
|
||||
// } else if (extension == "DDS") {
|
||||
// // In this moment is not possible to extract a DDS from a buffer, TODO consider add it to godot. See `textureloader_dds.cpp::load().
|
||||
// // The stored file is a DDS.
|
||||
} else {
|
||||
ERR_CONTINUE_MSG(true, "The embedded image with extension: " + extension + " is not yet supported. Open an issue please.");
|
||||
}
|
||||
|
||||
Ref<ImageTexture> image_texture;
|
||||
image_texture.instantiate();
|
||||
image_texture->create_from_image(image);
|
||||
|
||||
texture = image_texture;
|
||||
|
||||
// TODO: this is potentially making something with the same name have a match incorrectly USE FBX ID as Hash. #fuck it later.
|
||||
state.cached_image_searches[texture_name] = texture;
|
||||
print_verbose("Created texture from embedded image.");
|
||||
} else {
|
||||
ERR_CONTINUE_MSG(true, "The FBX texture, with name: `" + texture_name + "`, is not found into the project nor is stored as embedded file. Make sure to insert the texture as embedded file or into the project, then reimport.");
|
||||
}
|
||||
}
|
||||
|
||||
spatial_material->set_texture(mapping_mode, texture);
|
||||
}
|
||||
|
||||
if (spatial_material.is_valid()) {
|
||||
spatial_material->set_name(material_name);
|
||||
}
|
||||
|
||||
/// ALL below is related to properties
|
||||
for (FBXDocParser::LazyPropertyMap::value_type iter : material->GetLazyProperties()) {
|
||||
const std::string name = iter.first;
|
||||
|
||||
if (name.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PropertyDesc desc = PROPERTY_DESC_NOT_FOUND;
|
||||
if (fbx_properties_desc.count(name) > 0) {
|
||||
desc = fbx_properties_desc.at(name);
|
||||
}
|
||||
|
||||
// check if we can ignore this it will be done at the next phase
|
||||
if (desc == PROPERTY_DESC_NOT_FOUND || desc == PROPERTY_DESC_IGNORE) {
|
||||
// count the texture mapping references. Skip this one if it's found and we can't look up a property value.
|
||||
if (fbx_texture_map.count(name) > 0) {
|
||||
continue; // safe to ignore it's a texture mapping.
|
||||
}
|
||||
}
|
||||
|
||||
if (desc == PROPERTY_DESC_IGNORE) {
|
||||
//WARN_PRINT("[Ignored] The FBX material parameter: `" + String(name.c_str()) + "` is ignored.");
|
||||
continue;
|
||||
} else {
|
||||
print_verbose("FBX Material parameter: " + String(name.c_str()));
|
||||
|
||||
// Check for Diffuse material system / lambert materials / legacy basically
|
||||
if (name == "Diffuse" && !warning_non_pbr_material) {
|
||||
ValidationTracker::get_singleton()->add_validation_error(state.path, "Invalid material settings change to Ai Standard Surface shader, mat name: " + material_name.c_escape());
|
||||
warning_non_pbr_material = true;
|
||||
}
|
||||
}
|
||||
|
||||
// DISABLE when adding support for all weird and wonderful material formats
|
||||
if (desc == PROPERTY_DESC_NOT_FOUND) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ERR_CONTINUE_MSG(desc == PROPERTY_DESC_NOT_FOUND, "The FBX material parameter: `" + String(name.c_str()) + "` was not recognized. Please open an issue so we can add the support to it.");
|
||||
|
||||
const FBXDocParser::PropertyTable *tbl = material;
|
||||
FBXDocParser::PropertyPtr prop = tbl->Get(name);
|
||||
|
||||
ERR_CONTINUE_MSG(prop == nullptr, "This file may be corrupted because is not possible to extract the material parameter: " + String(name.c_str()));
|
||||
|
||||
if (spatial_material.is_null()) {
|
||||
// Done here so if no data no material is created.
|
||||
spatial_material.instantiate();
|
||||
}
|
||||
|
||||
const FBXDocParser::TypedProperty<real_t> *real_value = dynamic_cast<const FBXDocParser::TypedProperty<real_t> *>(prop);
|
||||
const FBXDocParser::TypedProperty<Vector3> *vector_value = dynamic_cast<const FBXDocParser::TypedProperty<Vector3> *>(prop);
|
||||
|
||||
if (!real_value && !vector_value) {
|
||||
//WARN_PRINT("unsupported datatype in property: " + String(name.c_str()));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vector_value && !real_value) {
|
||||
if (vector_value->Value() == Vector3(0, 0, 0) && !real_value) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch (desc) {
|
||||
case PROPERTY_DESC_ALBEDO_COLOR: {
|
||||
if (vector_value) {
|
||||
const Vector3 &color = vector_value->Value();
|
||||
// Make sure to not lost any eventual opacity.
|
||||
if (color != Vector3(0, 0, 0)) {
|
||||
Color c = Color();
|
||||
c[0] = color[0];
|
||||
c[1] = color[1];
|
||||
c[2] = color[2];
|
||||
spatial_material->set_albedo(c);
|
||||
}
|
||||
|
||||
} else if (real_value) {
|
||||
print_error("albedo is unsupported format?");
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_TRANSPARENT: {
|
||||
if (real_value) {
|
||||
const real_t opacity = real_value->Value();
|
||||
if (opacity < (1.0 - CMP_EPSILON)) {
|
||||
Color c = spatial_material->get_albedo();
|
||||
c.a = opacity;
|
||||
spatial_material->set_albedo(c);
|
||||
|
||||
spatial_material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA);
|
||||
spatial_material->set_depth_draw_mode(BaseMaterial3D::DEPTH_DRAW_OPAQUE_ONLY);
|
||||
}
|
||||
} else if (vector_value) {
|
||||
print_error("unsupported transparent desc type vector!");
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_SPECULAR: {
|
||||
if (real_value) {
|
||||
print_verbose("specular real value: " + rtos(real_value->Value()));
|
||||
spatial_material->set_specular(MIN(1.0, real_value->Value()));
|
||||
}
|
||||
|
||||
if (vector_value) {
|
||||
print_error("unsupported specular vector value: " + vector_value->Value());
|
||||
}
|
||||
} break;
|
||||
|
||||
case PROPERTY_DESC_SPECULAR_COLOR: {
|
||||
if (vector_value) {
|
||||
print_error("unsupported specular color: " + vector_value->Value());
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_SHINYNESS: {
|
||||
if (real_value) {
|
||||
print_error("unsupported shinyness:" + rtos(real_value->Value()));
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_METALLIC: {
|
||||
if (real_value) {
|
||||
print_verbose("metallic real value: " + rtos(real_value->Value()));
|
||||
spatial_material->set_metallic(MIN(1.0f, real_value->Value()));
|
||||
} else {
|
||||
print_error("unsupported value type for metallic");
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_ROUGHNESS: {
|
||||
if (real_value) {
|
||||
print_verbose("roughness real value: " + rtos(real_value->Value()));
|
||||
spatial_material->set_roughness(MIN(1.0f, real_value->Value()));
|
||||
} else {
|
||||
print_error("unsupported value type for roughness");
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_COAT: {
|
||||
if (real_value) {
|
||||
print_verbose("clearcoat real value: " + rtos(real_value->Value()));
|
||||
spatial_material->set_clearcoat(MIN(1.0f, real_value->Value()));
|
||||
} else {
|
||||
print_error("unsupported value type for clearcoat");
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_COAT_ROUGHNESS: {
|
||||
// meaning is that approx equal to zero is disabled not actually zero. ;)
|
||||
if (real_value && Math::is_zero_approx(real_value->Value())) {
|
||||
print_verbose("clearcoat real value: " + rtos(real_value->Value()));
|
||||
spatial_material->set_clearcoat_roughness(real_value->Value());
|
||||
} else {
|
||||
print_error("unsupported value type for clearcoat gloss");
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_EMISSIVE: {
|
||||
if (real_value && Math::is_zero_approx(real_value->Value())) {
|
||||
print_verbose("Emissive real value: " + rtos(real_value->Value()));
|
||||
spatial_material->set_emission_energy(real_value->Value());
|
||||
} else if (vector_value && !vector_value->Value().is_equal_approx(Vector3(0, 0, 0))) {
|
||||
const Vector3 &color = vector_value->Value();
|
||||
Color c;
|
||||
c[0] = color[0];
|
||||
c[1] = color[1];
|
||||
c[2] = color[2];
|
||||
spatial_material->set_emission(c);
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_EMISSIVE_COLOR: {
|
||||
if (vector_value && !vector_value->Value().is_equal_approx(Vector3(0, 0, 0))) {
|
||||
const Vector3 &color = vector_value->Value();
|
||||
Color c;
|
||||
c[0] = color[0];
|
||||
c[1] = color[1];
|
||||
c[2] = color[2];
|
||||
spatial_material->set_emission(c);
|
||||
} else {
|
||||
print_error("unsupported value type for emissive color");
|
||||
}
|
||||
} break;
|
||||
case PROPERTY_DESC_NOT_FOUND:
|
||||
case PROPERTY_DESC_IGNORE:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return spatial_material;
|
||||
}
|
@ -1,285 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_material.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_MATERIAL_H
|
||||
#define FBX_MATERIAL_H
|
||||
|
||||
#include "tools/import_utils.h"
|
||||
|
||||
#include "core/object/ref_counted.h"
|
||||
#include "core/string/ustring.h"
|
||||
|
||||
struct FBXMaterial : public RefCounted {
|
||||
String material_name = String();
|
||||
bool warning_non_pbr_material = false;
|
||||
FBXDocParser::Material *material = nullptr;
|
||||
|
||||
/* Godot materials
|
||||
*** Texture Maps:
|
||||
* Albedo - color, texture
|
||||
* Metallic - specular, metallic, texture
|
||||
* Roughness - roughness, texture
|
||||
* Emission - color, texture
|
||||
* Normal Map - scale, texture
|
||||
* Ambient Occlusion - texture
|
||||
* Refraction - scale, texture
|
||||
*** Has Settings for:
|
||||
* UV1 - SCALE, OFFSET
|
||||
* UV2 - SCALE, OFFSET
|
||||
*** Flags for
|
||||
* Transparent
|
||||
* Cull Mode
|
||||
*/
|
||||
|
||||
enum class MapMode {
|
||||
AlbedoM = 0,
|
||||
MetallicM,
|
||||
SpecularM,
|
||||
EmissionM,
|
||||
RoughnessM,
|
||||
NormalM,
|
||||
AmbientOcclusionM,
|
||||
RefractionM,
|
||||
ReflectionM,
|
||||
};
|
||||
|
||||
/* Returns the string representation of the TextureParam enum */
|
||||
static String get_texture_param_name(StandardMaterial3D::TextureParam param) {
|
||||
switch (param) {
|
||||
case StandardMaterial3D::TEXTURE_ALBEDO:
|
||||
return "TEXTURE_ALBEDO";
|
||||
case StandardMaterial3D::TEXTURE_METALLIC:
|
||||
return "TEXTURE_METALLIC";
|
||||
case StandardMaterial3D::TEXTURE_ROUGHNESS:
|
||||
return "TEXTURE_ROUGHNESS";
|
||||
case StandardMaterial3D::TEXTURE_EMISSION:
|
||||
return "TEXTURE_EMISSION";
|
||||
case StandardMaterial3D::TEXTURE_NORMAL:
|
||||
return "TEXTURE_NORMAL";
|
||||
case StandardMaterial3D::TEXTURE_RIM:
|
||||
return "TEXTURE_RIM";
|
||||
case StandardMaterial3D::TEXTURE_CLEARCOAT:
|
||||
return "TEXTURE_CLEARCOAT";
|
||||
case StandardMaterial3D::TEXTURE_FLOWMAP:
|
||||
return "TEXTURE_FLOWMAP";
|
||||
case StandardMaterial3D::TEXTURE_AMBIENT_OCCLUSION:
|
||||
return "TEXTURE_AMBIENT_OCCLUSION";
|
||||
// case StandardMaterial3D::TEXTURE_DEPTH: // TODO: work out how to make this function again!
|
||||
// return "TEXTURE_DEPTH";
|
||||
case StandardMaterial3D::TEXTURE_SUBSURFACE_SCATTERING:
|
||||
return "TEXTURE_SUBSURFACE_SCATTERING";
|
||||
// case StandardMaterial3D::TEXTURE_TRANSMISSION: // TODO: work out how to make this function again!
|
||||
// return "TEXTURE_TRANSMISSION";
|
||||
case StandardMaterial3D::TEXTURE_REFRACTION:
|
||||
return "TEXTURE_REFRACTION";
|
||||
case StandardMaterial3D::TEXTURE_DETAIL_MASK:
|
||||
return "TEXTURE_DETAIL_MASK";
|
||||
case StandardMaterial3D::TEXTURE_DETAIL_ALBEDO:
|
||||
return "TEXTURE_DETAIL_ALBEDO";
|
||||
case StandardMaterial3D::TEXTURE_DETAIL_NORMAL:
|
||||
return "TEXTURE_DETAIL_NORMAL";
|
||||
case StandardMaterial3D::TEXTURE_MAX:
|
||||
return "TEXTURE_MAX";
|
||||
default:
|
||||
return "broken horribly";
|
||||
}
|
||||
};
|
||||
|
||||
// TODO make this static?
|
||||
const std::map<std::string, bool> fbx_transparency_flags = {
|
||||
/* Transparent */
|
||||
{ "TransparentColor", true },
|
||||
{ "Maya|opacity", true }
|
||||
};
|
||||
|
||||
// TODO make this static?
|
||||
const std::map<std::string, StandardMaterial3D::TextureParam> fbx_texture_map = {
|
||||
/* Diffuse */
|
||||
{ "Maya|base", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "DiffuseColor", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "Maya|DiffuseTexture", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "Maya|baseColor", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "Maya|baseColor|file", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "3dsMax|Parameters|base_color_map", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "Maya|TEX_color_map|file", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO },
|
||||
{ "Maya|TEX_color_map", StandardMaterial3D::TextureParam::TEXTURE_ALBEDO },
|
||||
/* Emission */
|
||||
{ "EmissiveColor", StandardMaterial3D::TextureParam::TEXTURE_EMISSION },
|
||||
{ "EmissiveFactor", StandardMaterial3D::TextureParam::TEXTURE_EMISSION },
|
||||
{ "Maya|emissionColor", StandardMaterial3D::TextureParam::TEXTURE_EMISSION },
|
||||
{ "Maya|emissionColor|file", StandardMaterial3D::TextureParam::TEXTURE_EMISSION },
|
||||
{ "3dsMax|Parameters|emission_map", StandardMaterial3D::TextureParam::TEXTURE_EMISSION },
|
||||
{ "Maya|TEX_emissive_map", StandardMaterial3D::TextureParam::TEXTURE_EMISSION },
|
||||
{ "Maya|TEX_emissive_map|file", StandardMaterial3D::TextureParam::TEXTURE_EMISSION },
|
||||
/* Metallic */
|
||||
{ "Maya|metalness", StandardMaterial3D::TextureParam::TEXTURE_METALLIC },
|
||||
{ "Maya|metalness|file", StandardMaterial3D::TextureParam::TEXTURE_METALLIC },
|
||||
{ "3dsMax|Parameters|metalness_map", StandardMaterial3D::TextureParam::TEXTURE_METALLIC },
|
||||
{ "Maya|TEX_metallic_map", StandardMaterial3D::TextureParam::TEXTURE_METALLIC },
|
||||
{ "Maya|TEX_metallic_map|file", StandardMaterial3D::TextureParam::TEXTURE_METALLIC },
|
||||
|
||||
/* Roughness */
|
||||
// Arnold Roughness Map
|
||||
{ "Maya|specularRoughness", StandardMaterial3D::TextureParam::TEXTURE_ROUGHNESS },
|
||||
|
||||
{ "3dsMax|Parameters|roughness_map", StandardMaterial3D::TextureParam::TEXTURE_ROUGHNESS },
|
||||
{ "Maya|TEX_roughness_map", StandardMaterial3D::TextureParam::TEXTURE_ROUGHNESS },
|
||||
{ "Maya|TEX_roughness_map|file", StandardMaterial3D::TextureParam::TEXTURE_ROUGHNESS },
|
||||
|
||||
/* Normal */
|
||||
{ "NormalMap", StandardMaterial3D::TextureParam::TEXTURE_NORMAL },
|
||||
//{ "Bump", Material::TextureParam::TEXTURE_NORMAL },
|
||||
//{ "3dsMax|Parameters|bump_map", Material::TextureParam::TEXTURE_NORMAL },
|
||||
{ "Maya|NormalTexture", StandardMaterial3D::TextureParam::TEXTURE_NORMAL },
|
||||
//{ "Maya|normalCamera", Material::TextureParam::TEXTURE_NORMAL },
|
||||
//{ "Maya|normalCamera|file", Material::TextureParam::TEXTURE_NORMAL },
|
||||
{ "Maya|TEX_normal_map", StandardMaterial3D::TextureParam::TEXTURE_NORMAL },
|
||||
{ "Maya|TEX_normal_map|file", StandardMaterial3D::TextureParam::TEXTURE_NORMAL },
|
||||
/* AO */
|
||||
{ "Maya|TEX_ao_map", StandardMaterial3D::TextureParam::TEXTURE_AMBIENT_OCCLUSION },
|
||||
{ "Maya|TEX_ao_map|file", StandardMaterial3D::TextureParam::TEXTURE_AMBIENT_OCCLUSION },
|
||||
|
||||
// TODO: specular workflow conversion
|
||||
// { "SpecularColor", StandardMaterial3D::TextureParam::TEXTURE_METALLIC },
|
||||
// { "Maya|specularColor", StandardMaterial3D::TextureParam::TEXTURE_METALLIC },
|
||||
// { "Maya|SpecularTexture", StandardMaterial3D::TextureParam::TEXTURE_METALLIC },
|
||||
// { "Maya|SpecularTexture|file", StandardMaterial3D::TextureParam::TEXTURE_METALLIC },
|
||||
// { "ShininessExponent", SpatialMaterial::TextureParam::UNSUPPORTED },
|
||||
// { "ReflectionFactor", SpatialMaterial::TextureParam::UNSUPPORTED },
|
||||
|
||||
//{ "TransparentColor",SpatialMaterial::TextureParam::TEXTURE_CHANNEL_ALPHA },
|
||||
//{ "TransparencyFactor",SpatialMaterial::TextureParam::TEXTURE_CHANNEL_ALPHA }
|
||||
|
||||
// TODO: diffuse roughness
|
||||
//{ "Maya|diffuseRoughness", SpatialMaterial::TextureParam::UNSUPPORTED },
|
||||
//{ "Maya|diffuseRoughness|file", SpatialMaterial::TextureParam::UNSUPPORTED },
|
||||
|
||||
};
|
||||
|
||||
// TODO make this static?
|
||||
enum PropertyDesc {
|
||||
PROPERTY_DESC_NOT_FOUND,
|
||||
PROPERTY_DESC_ALBEDO_COLOR,
|
||||
PROPERTY_DESC_TRANSPARENT,
|
||||
PROPERTY_DESC_METALLIC,
|
||||
PROPERTY_DESC_ROUGHNESS,
|
||||
PROPERTY_DESC_SPECULAR,
|
||||
PROPERTY_DESC_SPECULAR_COLOR,
|
||||
PROPERTY_DESC_SHINYNESS,
|
||||
PROPERTY_DESC_COAT,
|
||||
PROPERTY_DESC_COAT_ROUGHNESS,
|
||||
PROPERTY_DESC_EMISSIVE,
|
||||
PROPERTY_DESC_EMISSIVE_COLOR,
|
||||
PROPERTY_DESC_IGNORE
|
||||
};
|
||||
|
||||
const std::map<std::string, PropertyDesc> fbx_properties_desc = {
|
||||
/* Albedo */
|
||||
{ "DiffuseColor", PROPERTY_DESC_ALBEDO_COLOR },
|
||||
{ "Maya|baseColor", PROPERTY_DESC_ALBEDO_COLOR },
|
||||
|
||||
/* Specular */
|
||||
{ "Maya|specular", PROPERTY_DESC_SPECULAR },
|
||||
{ "Maya|specularColor", PROPERTY_DESC_SPECULAR_COLOR },
|
||||
|
||||
/* Specular roughness - arnold roughness map */
|
||||
{ "Maya|specularRoughness", PROPERTY_DESC_ROUGHNESS },
|
||||
|
||||
/* Transparent */
|
||||
{ "Opacity", PROPERTY_DESC_TRANSPARENT },
|
||||
{ "TransparencyFactor", PROPERTY_DESC_TRANSPARENT },
|
||||
{ "Maya|opacity", PROPERTY_DESC_TRANSPARENT },
|
||||
|
||||
{ "Maya|metalness", PROPERTY_DESC_METALLIC },
|
||||
{ "Maya|metallic", PROPERTY_DESC_METALLIC },
|
||||
|
||||
/* Roughness */
|
||||
{ "Maya|roughness", PROPERTY_DESC_ROUGHNESS },
|
||||
|
||||
/* Coat */
|
||||
//{ "Maya|coat", PROPERTY_DESC_COAT },
|
||||
|
||||
/* Coat roughness */
|
||||
//{ "Maya|coatRoughness", PROPERTY_DESC_COAT_ROUGHNESS },
|
||||
|
||||
/* Emissive */
|
||||
{ "Maya|emission", PROPERTY_DESC_EMISSIVE },
|
||||
{ "Maya|emissive", PROPERTY_DESC_EMISSIVE },
|
||||
|
||||
/* Emissive color */
|
||||
{ "EmissiveColor", PROPERTY_DESC_EMISSIVE_COLOR },
|
||||
{ "Maya|emissionColor", PROPERTY_DESC_EMISSIVE_COLOR },
|
||||
|
||||
/* Ignore */
|
||||
{ "Shininess", PROPERTY_DESC_IGNORE },
|
||||
{ "Reflectivity", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|diffuseRoughness", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya", PROPERTY_DESC_IGNORE },
|
||||
{ "Diffuse", PROPERTY_DESC_ALBEDO_COLOR },
|
||||
{ "Maya|TypeId", PROPERTY_DESC_IGNORE },
|
||||
{ "Ambient", PROPERTY_DESC_IGNORE },
|
||||
{ "AmbientColor", PROPERTY_DESC_IGNORE },
|
||||
{ "ShininessExponent", PROPERTY_DESC_IGNORE },
|
||||
{ "Specular", PROPERTY_DESC_IGNORE },
|
||||
{ "SpecularColor", PROPERTY_DESC_IGNORE },
|
||||
{ "SpecularFactor", PROPERTY_DESC_IGNORE },
|
||||
//{ "BumpFactor", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|exitToBackground", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|indirectDiffuse", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|indirectSpecular", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|internalReflections", PROPERTY_DESC_IGNORE },
|
||||
{ "DiffuseFactor", PROPERTY_DESC_IGNORE },
|
||||
{ "AmbientFactor", PROPERTY_DESC_IGNORE },
|
||||
{ "ReflectionColor", PROPERTY_DESC_IGNORE },
|
||||
{ "Emissive", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|coatColor", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|coatNormal", PROPERTY_DESC_IGNORE },
|
||||
{ "Maya|coatIOR", PROPERTY_DESC_IGNORE },
|
||||
};
|
||||
|
||||
/* storing the texture properties like color */
|
||||
template <class T>
|
||||
struct TexturePropertyMapping : RefCounted {
|
||||
StandardMaterial3D::TextureParam map_mode = StandardMaterial3D::TextureParam::TEXTURE_ALBEDO;
|
||||
const T property = T();
|
||||
};
|
||||
|
||||
static void add_search_string(String p_filename, String p_current_directory, String search_directory, Vector<String> &texture_search_paths);
|
||||
|
||||
static String find_texture_path_by_filename(const String p_filename, const String p_current_directory);
|
||||
|
||||
String get_material_name() const;
|
||||
|
||||
void set_imported_material(FBXDocParser::Material *p_material);
|
||||
|
||||
Ref<StandardMaterial3D> import_material(ImportState &state);
|
||||
};
|
||||
|
||||
#endif // FBX_MATERIAL_H
|
File diff suppressed because it is too large
Load Diff
@ -1,200 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_mesh_data.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_MESH_DATA_H
|
||||
#define FBX_MESH_DATA_H
|
||||
|
||||
#include "core/templates/hash_map.h"
|
||||
#include "core/templates/local_vector.h"
|
||||
#include "core/templates/ordered_hash_map.h"
|
||||
#include "editor/import/resource_importer_scene.h"
|
||||
#include "scene/3d/importer_mesh_instance_3d.h"
|
||||
#include "scene/3d/mesh_instance_3d.h"
|
||||
#include "scene/resources/surface_tool.h"
|
||||
|
||||
#include "fbx_bone.h"
|
||||
#include "fbx_parser/FBXMeshGeometry.h"
|
||||
#include "import_state.h"
|
||||
#include "tools/import_utils.h"
|
||||
|
||||
struct FBXNode;
|
||||
struct FBXMeshData;
|
||||
struct FBXBone;
|
||||
struct ImportState;
|
||||
|
||||
typedef int Vertex;
|
||||
typedef int SurfaceId;
|
||||
typedef int PolygonId;
|
||||
typedef int DataIndex;
|
||||
|
||||
struct SurfaceData {
|
||||
Ref<SurfaceTool> surface_tool;
|
||||
OrderedHashMap<Vertex, int> lookup_table; // proposed fix is to replace lookup_table[vertex_id] to give the position of the vertices_map[int] index.
|
||||
LocalVector<Vertex> vertices_map; // this must be ordered the same as insertion <-- slow to do find() operation.
|
||||
Ref<Material> material;
|
||||
HashMap<PolygonId, Vector<DataIndex>> surface_polygon_vertex;
|
||||
Array morphs;
|
||||
};
|
||||
|
||||
struct VertexWeightMapping {
|
||||
Vector<float> weights;
|
||||
Vector<int> bones;
|
||||
// This extra vector is used because the bone id is computed in a second step.
|
||||
// TODO Get rid of this extra step is a good idea.
|
||||
Vector<Ref<FBXBone>> bones_ref;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct VertexData {
|
||||
int polygon_index;
|
||||
T data;
|
||||
};
|
||||
|
||||
// Caches mesh information and instantiates meshes for you using helper functions.
|
||||
struct FBXMeshData : RefCounted {
|
||||
struct MorphVertexData {
|
||||
// TODO we have only these??
|
||||
/// Each element is a vertex. Not supposed to be void.
|
||||
Vector<Vector3> vertices;
|
||||
/// Each element is a vertex. Not supposed to be void.
|
||||
Vector<Vector3> normals;
|
||||
};
|
||||
|
||||
// FIXME: remove this is a hack for testing only
|
||||
mutable const FBXDocParser::MeshGeometry *mesh_geometry = nullptr;
|
||||
|
||||
Ref<FBXNode> mesh_node = nullptr;
|
||||
/// vertex id, Weight Info
|
||||
/// later: perf we can use array here
|
||||
HashMap<int, VertexWeightMapping> vertex_weights;
|
||||
|
||||
// translate fbx mesh data from document context to FBX Mesh Geometry Context
|
||||
bool valid_weight_indexes = false;
|
||||
|
||||
ImporterMeshInstance3D *create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression);
|
||||
|
||||
void gen_weight_info(Ref<SurfaceTool> st, int vertex_id) const;
|
||||
|
||||
/* mesh maximum weight count */
|
||||
bool valid_weight_count = false;
|
||||
int max_weight_count = 0;
|
||||
uint64_t armature_id = 0;
|
||||
bool valid_armature_id = false;
|
||||
ImporterMeshInstance3D *godot_mesh_instance = nullptr;
|
||||
|
||||
private:
|
||||
void sanitize_vertex_weights(const ImportState &state);
|
||||
|
||||
/// Make sure to reorganize the vertices so that the correct UV is taken.
|
||||
/// This step is needed because differently from the normal, that can be
|
||||
/// combined, the UV may need its own triangle because sometimes they have
|
||||
/// really different UV for the same vertex but different polygon.
|
||||
/// This function make sure to add another vertex for those UVS.
|
||||
void reorganize_vertices(
|
||||
std::vector<int> &r_polygon_indices,
|
||||
std::vector<Vector3> &r_vertices,
|
||||
HashMap<int, Vector3> &r_normals,
|
||||
HashMap<int, Vector2> &r_uv_1,
|
||||
HashMap<int, Vector2> &r_uv_2,
|
||||
HashMap<int, Color> &r_color,
|
||||
HashMap<String, MorphVertexData> &r_morphs,
|
||||
HashMap<int, HashMap<int, Vector3>> &r_normals_raw,
|
||||
HashMap<int, HashMap<int, Color>> &r_colors_raw,
|
||||
HashMap<int, HashMap<int, Vector2>> &r_uv_1_raw,
|
||||
HashMap<int, HashMap<int, Vector2>> &r_uv_2_raw);
|
||||
|
||||
void add_vertex(
|
||||
const ImportState &state,
|
||||
Ref<SurfaceTool> p_surface_tool,
|
||||
real_t p_scale,
|
||||
int p_vertex,
|
||||
const std::vector<Vector3> &p_vertices_position,
|
||||
const HashMap<int, Vector3> &p_normals,
|
||||
const HashMap<int, Vector2> &p_uvs_0,
|
||||
const HashMap<int, Vector2> &p_uvs_1,
|
||||
const HashMap<int, Color> &p_colors,
|
||||
const Vector3 &p_morph_value = Vector3(),
|
||||
const Vector3 &p_morph_normal = Vector3());
|
||||
|
||||
void triangulate_polygon(SurfaceData *surface, const Vector<int> &p_polygon_vertex, const std::vector<Vector3> &p_vertices) const;
|
||||
|
||||
/// This function is responsible to convert the FBX polygon vertex to
|
||||
/// vertex index.
|
||||
/// The polygon vertices are stored in an array with some negative
|
||||
/// values. The negative values define the last face index.
|
||||
/// For example the following `face_array` contains two faces, the former
|
||||
/// with 3 vertices and the latter with a line:
|
||||
/// [0,2,-2,3,-5]
|
||||
/// Parsed as:
|
||||
/// [0, 2, 1, 3, 4]
|
||||
/// The negative values are computed using this formula: `(-value) - 1`
|
||||
///
|
||||
/// Returns the vertex index from the polygon vertex.
|
||||
/// Returns -1 if `p_index` is invalid.
|
||||
int get_vertex_from_polygon_vertex(const std::vector<int> &p_face_indices, int p_index) const;
|
||||
|
||||
/// Returns true if this polygon_vertex_index is the end of a new polygon.
|
||||
bool is_end_of_polygon(const std::vector<int> &p_face_indices, int p_index) const;
|
||||
|
||||
/// Returns true if this polygon_vertex_index is the begin of a new polygon.
|
||||
bool is_start_of_polygon(const std::vector<int> &p_face_indices, int p_index) const;
|
||||
|
||||
/// Returns the number of polygons.
|
||||
int count_polygons(const std::vector<int> &p_face_indices) const;
|
||||
|
||||
/// Used to extract data from the `MappingData` aligned with vertex.
|
||||
/// Useful to extract normal/uvs/colors/tangents/etc...
|
||||
/// If the function fails somehow, it returns an hollow vector and print an error.
|
||||
template <class R, class T>
|
||||
HashMap<int, R> extract_per_vertex_data(
|
||||
int p_vertex_count,
|
||||
const std::vector<FBXDocParser::MeshGeometry::Edge> &p_edges,
|
||||
const std::vector<int> &p_mesh_indices,
|
||||
const FBXDocParser::MeshGeometry::MappingData<T> &p_mapping_data,
|
||||
R (*collector_function)(const Vector<VertexData<T>> *p_vertex_data, R p_fall_back),
|
||||
R p_fall_back) const;
|
||||
|
||||
/// Used to extract data from the `MappingData` organized per polygon.
|
||||
/// Useful to extract the material
|
||||
/// If the function fails somehow, it returns an hollow vector and print an error.
|
||||
template <class T>
|
||||
HashMap<int, T> extract_per_polygon(
|
||||
int p_vertex_count,
|
||||
const std::vector<int> &p_face_indices,
|
||||
const FBXDocParser::MeshGeometry::MappingData<T> &p_fbx_data,
|
||||
T p_fallback_value) const;
|
||||
|
||||
/// Extracts the morph data and organizes it per vertices.
|
||||
/// The returned `MorphVertexData` arrays are never something different
|
||||
/// then the `vertex_count`.
|
||||
void extract_morphs(const FBXDocParser::MeshGeometry *mesh_geometry, HashMap<String, MorphVertexData> &r_data);
|
||||
};
|
||||
|
||||
#endif // FBX_MESH_DATA_H
|
@ -1,63 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_node.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_NODE_H
|
||||
#define FBX_NODE_H
|
||||
|
||||
#include "fbx_skeleton.h"
|
||||
#include "model_abstraction.h"
|
||||
#include "pivot_transform.h"
|
||||
|
||||
#include "fbx_parser/FBXDocument.h"
|
||||
|
||||
class Node3D;
|
||||
struct PivotTransform;
|
||||
|
||||
struct FBXNode : RefCounted, ModelAbstraction {
|
||||
uint64_t current_node_id = 0;
|
||||
String node_name = String();
|
||||
Node3D *godot_node = nullptr;
|
||||
|
||||
// used to parent the skeleton once the tree is built.
|
||||
Ref<FBXSkeleton> skeleton_node = Ref<FBXSkeleton>();
|
||||
|
||||
void set_parent(Ref<FBXNode> p_parent) {
|
||||
fbx_parent = p_parent;
|
||||
}
|
||||
|
||||
void set_pivot_transform(Ref<PivotTransform> p_pivot_transform) {
|
||||
pivot_transform = p_pivot_transform;
|
||||
}
|
||||
|
||||
Ref<PivotTransform> pivot_transform = Ref<PivotTransform>(); // local and global xform data
|
||||
Ref<FBXNode> fbx_parent = Ref<FBXNode>(); // parent node
|
||||
};
|
||||
|
||||
#endif // FBX_NODE_H
|
@ -1,130 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_skeleton.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "fbx_skeleton.h"
|
||||
|
||||
#include "import_state.h"
|
||||
|
||||
#include "tools/import_utils.h"
|
||||
|
||||
void FBXSkeleton::init_skeleton(const ImportState &state) {
|
||||
int skeleton_bone_count = skeleton_bones.size();
|
||||
|
||||
if (skeleton == nullptr && skeleton_bone_count > 0) {
|
||||
skeleton = memnew(Skeleton3D);
|
||||
|
||||
if (fbx_node.is_valid()) {
|
||||
// cache skeleton attachment for later during node creation
|
||||
// can't be done until after node hierarchy is built
|
||||
if (fbx_node->godot_node != state.root) {
|
||||
fbx_node->skeleton_node = Ref<FBXSkeleton>(this);
|
||||
print_verbose("cached armature skeleton attachment for node " + fbx_node->node_name);
|
||||
} else {
|
||||
// root node must never be a skeleton to prevent cyclic skeletons from being allowed (skeleton in a skeleton)
|
||||
fbx_node->godot_node->add_child(skeleton);
|
||||
skeleton->set_owner(state.root_owner);
|
||||
skeleton->set_name("Skeleton3D");
|
||||
print_verbose("created armature skeleton for root");
|
||||
}
|
||||
} else {
|
||||
memfree(skeleton);
|
||||
skeleton = nullptr;
|
||||
print_error("[doc] skeleton has no valid node to parent nodes to - erasing");
|
||||
skeleton_bones.clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Make the bone name uniques.
|
||||
for (int x = 0; x < skeleton_bone_count; x++) {
|
||||
Ref<FBXBone> bone = skeleton_bones[x];
|
||||
if (bone.is_valid()) {
|
||||
// Make sure the bone name is unique.
|
||||
const String bone_name = bone->bone_name;
|
||||
int same_name_count = 0;
|
||||
for (int y = x + 1; y < skeleton_bone_count; y++) {
|
||||
Ref<FBXBone> other_bone = skeleton_bones[y];
|
||||
if (other_bone.is_valid()) {
|
||||
if (other_bone->bone_name == bone_name) {
|
||||
same_name_count += 1;
|
||||
other_bone->bone_name += "_" + itos(same_name_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<int, Ref<FBXBone>> bone_map;
|
||||
// implement fbx cluster skin logic here this is where it goes
|
||||
int bone_count = 0;
|
||||
for (int x = 0; x < skeleton_bone_count; x++) {
|
||||
Ref<FBXBone> bone = skeleton_bones[x];
|
||||
if (bone.is_valid()) {
|
||||
skeleton->add_bone(bone->bone_name);
|
||||
bone->godot_bone_id = bone_count;
|
||||
bone->fbx_skeleton = Ref<FBXSkeleton>(this);
|
||||
bone_map.insert(bone_count, bone);
|
||||
print_verbose("added bone " + itos(bone->bone_id) + " " + bone->bone_name);
|
||||
bone_count++;
|
||||
}
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_MSG(skeleton->get_bone_count() != bone_count, "Not all bones got added, is the file corrupted?");
|
||||
|
||||
for (const KeyValue<int, Ref<FBXBone>> &bone_element : bone_map) {
|
||||
const Ref<FBXBone> bone = bone_element.value;
|
||||
int bone_index = bone_element.key;
|
||||
print_verbose("working on bone: " + itos(bone_index) + " bone name:" + bone->bone_name);
|
||||
|
||||
skeleton->set_bone_rest(bone->godot_bone_id, get_unscaled_transform(bone->node->pivot_transform->LocalTransform, state.scale));
|
||||
{
|
||||
Transform3D base_xform = bone->node->pivot_transform->LocalTransform;
|
||||
|
||||
skeleton->set_bone_pose_position(bone_index, base_xform.origin);
|
||||
skeleton->set_bone_pose_rotation(bone_index, base_xform.basis.get_rotation_quaternion());
|
||||
skeleton->set_bone_pose_scale(bone_index, base_xform.basis.get_scale());
|
||||
}
|
||||
|
||||
// lookup parent ID
|
||||
if (bone->valid_parent && state.fbx_bone_map.has(bone->parent_bone_id)) {
|
||||
Ref<FBXBone> parent_bone = state.fbx_bone_map[bone->parent_bone_id];
|
||||
int bone_id = skeleton->find_bone(parent_bone->bone_name);
|
||||
if (bone_id != -1) {
|
||||
skeleton->set_bone_parent(bone_index, bone_id);
|
||||
} else {
|
||||
print_error("invalid bone parent: " + parent_bone->bone_name);
|
||||
}
|
||||
} else {
|
||||
if (bone->godot_bone_id != -1) {
|
||||
skeleton->set_bone_parent(bone_index, -1); // no parent for this bone
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* fbx_skeleton.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_SKELETON_H
|
||||
#define FBX_SKELETON_H
|
||||
|
||||
#include "fbx_bone.h"
|
||||
#include "fbx_node.h"
|
||||
#include "model_abstraction.h"
|
||||
|
||||
#include "core/object/ref_counted.h"
|
||||
#include "scene/3d/skeleton_3d.h"
|
||||
|
||||
struct FBXNode;
|
||||
struct ImportState;
|
||||
struct FBXBone;
|
||||
|
||||
struct FBXSkeleton : RefCounted {
|
||||
Ref<FBXNode> fbx_node = Ref<FBXNode>();
|
||||
Vector<Ref<FBXBone>> skeleton_bones = Vector<Ref<FBXBone>>();
|
||||
Skeleton3D *skeleton = nullptr;
|
||||
|
||||
void init_skeleton(const ImportState &state);
|
||||
};
|
||||
|
||||
#endif // FBX_SKELETON_H
|
@ -1,112 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* import_state.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef IMPORT_STATE_H
|
||||
#define IMPORT_STATE_H
|
||||
|
||||
#include "fbx_mesh_data.h"
|
||||
#include "tools/import_utils.h"
|
||||
#include "tools/validation_tools.h"
|
||||
|
||||
#include "pivot_transform.h"
|
||||
|
||||
#include "core/io/resource_importer.h"
|
||||
#include "core/templates/vector.h"
|
||||
#include "editor/import/resource_importer_scene.h"
|
||||
#include "editor/project_settings_editor.h"
|
||||
#include "scene/3d/mesh_instance_3d.h"
|
||||
#include "scene/3d/node_3d.h"
|
||||
#include "scene/3d/skeleton_3d.h"
|
||||
#include "scene/animation/animation_player.h"
|
||||
#include "scene/resources/animation.h"
|
||||
#include "scene/resources/surface_tool.h"
|
||||
|
||||
#include "modules/fbx/fbx_parser/FBXDocument.h"
|
||||
#include "modules/fbx/fbx_parser/FBXImportSettings.h"
|
||||
#include "modules/fbx/fbx_parser/FBXMeshGeometry.h"
|
||||
#include "modules/fbx/fbx_parser/FBXParser.h"
|
||||
#include "modules/fbx/fbx_parser/FBXTokenizer.h"
|
||||
#include "modules/fbx/fbx_parser/FBXUtil.h"
|
||||
|
||||
struct FBXBone;
|
||||
struct FBXMeshData;
|
||||
struct FBXNode;
|
||||
struct FBXSkeleton;
|
||||
|
||||
struct ImportState {
|
||||
bool enable_material_import = true;
|
||||
bool enable_animation_import = true;
|
||||
bool is_blender_fbx = false;
|
||||
|
||||
Map<StringName, Ref<Texture>> cached_image_searches;
|
||||
Map<uint64_t, Ref<Material>> cached_materials;
|
||||
|
||||
String path = String();
|
||||
Node3D *root_owner = nullptr;
|
||||
Node3D *root = nullptr;
|
||||
real_t scale = 0.01;
|
||||
Ref<FBXNode> fbx_root_node = Ref<FBXNode>();
|
||||
// skeleton map - merged automatically when they are on the same x node in the tree so we can merge them automatically.
|
||||
Map<uint64_t, Ref<FBXSkeleton>> skeleton_map = Map<uint64_t, Ref<FBXSkeleton>>();
|
||||
|
||||
// nodes on the same level get merged automatically.
|
||||
//Map<uint64_t, Skeleton3D *> armature_map;
|
||||
AnimationPlayer *animation_player = nullptr;
|
||||
|
||||
// Generation 4 - Raw document accessing for bone/skin/joint/kLocators
|
||||
// joints are not necessarily bones but must be merged into the skeleton
|
||||
// (bone id), bone
|
||||
Map<uint64_t, Ref<FBXBone>> fbx_bone_map = Map<uint64_t, Ref<FBXBone>>(); // this is the bone name and setup information required for joints
|
||||
// this will never contain joints only bones attached to a mesh.
|
||||
|
||||
// Generation 4 - Raw document for creating the nodes transforms in the scene
|
||||
// this is a list of the nodes in the scene
|
||||
// (id, node)
|
||||
List<Ref<FBXNode>> fbx_node_list = List<Ref<FBXNode>>();
|
||||
|
||||
// All nodes which have been created in the scene
|
||||
// this will not contain the root node of the scene
|
||||
Map<uint64_t, Ref<FBXNode>> fbx_target_map = Map<uint64_t, Ref<FBXNode>>();
|
||||
|
||||
// mesh nodes which are created in node / mesh step - used for populating skin poses in MeshSkins
|
||||
Map<uint64_t, Ref<FBXNode>> MeshNodes = Map<uint64_t, Ref<FBXNode>>();
|
||||
// mesh skin map
|
||||
Map<uint64_t, Ref<Skin>> MeshSkins = Map<uint64_t, Ref<Skin>>();
|
||||
|
||||
// this is the container for the mesh weight information and eventually
|
||||
// any mesh data
|
||||
// but not the skin, just stuff important for rendering
|
||||
// skin is applied to mesh instance so not really required to be in here yet.
|
||||
// maybe later
|
||||
// fbx mesh id, FBXMeshData
|
||||
Map<uint64_t, Ref<FBXMeshData>> renderer_mesh_data = Map<uint64_t, Ref<FBXMeshData>>();
|
||||
};
|
||||
|
||||
#endif // IMPORT_STATE_H
|
@ -1,52 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* model_abstraction.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef MODEL_ABSTRACTION_H
|
||||
#define MODEL_ABSTRACTION_H
|
||||
|
||||
#include "modules/fbx/fbx_parser/FBXDocument.h"
|
||||
|
||||
struct ModelAbstraction {
|
||||
mutable const FBXDocParser::Model *fbx_model = nullptr;
|
||||
|
||||
void set_model(const FBXDocParser::Model *p_model) {
|
||||
fbx_model = p_model;
|
||||
}
|
||||
|
||||
bool has_model() const {
|
||||
return fbx_model != nullptr;
|
||||
}
|
||||
|
||||
const FBXDocParser::Model *get_model() const {
|
||||
return fbx_model;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // MODEL_ABSTRACTION_H
|
@ -1,307 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* pivot_transform.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "pivot_transform.h"
|
||||
|
||||
#include "tools/import_utils.h"
|
||||
|
||||
void PivotTransform::ReadTransformChain() {
|
||||
const FBXDocParser::PropertyTable *props = fbx_model;
|
||||
const FBXDocParser::Model::RotOrder &rot = fbx_model->RotationOrder();
|
||||
const FBXDocParser::TransformInheritance &inheritType = fbx_model->InheritType();
|
||||
inherit_type = inheritType; // copy the inherit type we need it in the second step.
|
||||
print_verbose("Model: " + String(fbx_model->Name().c_str()) + " Has inherit type: " + itos(fbx_model->InheritType()));
|
||||
bool ok = false;
|
||||
raw_pre_rotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "PreRotation", ok));
|
||||
if (ok) {
|
||||
pre_rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(raw_pre_rotation));
|
||||
print_verbose("valid pre_rotation: " + raw_pre_rotation + " euler conversion: " + (pre_rotation.get_euler() * (180 / Math_PI)));
|
||||
}
|
||||
raw_post_rotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "PostRotation", ok));
|
||||
if (ok) {
|
||||
post_rotation = ImportUtils::EulerToQuaternion(FBXDocParser::Model::RotOrder_EulerXYZ, ImportUtils::deg2rad(raw_post_rotation));
|
||||
print_verbose("valid post_rotation: " + raw_post_rotation + " euler conversion: " + (pre_rotation.get_euler() * (180 / Math_PI)));
|
||||
}
|
||||
const Vector3 &RotationPivot = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "RotationPivot", ok));
|
||||
if (ok) {
|
||||
rotation_pivot = ImportUtils::FixAxisConversions(RotationPivot);
|
||||
}
|
||||
const Vector3 &RotationOffset = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "RotationOffset", ok));
|
||||
if (ok) {
|
||||
rotation_offset = ImportUtils::FixAxisConversions(RotationOffset);
|
||||
}
|
||||
const Vector3 &ScalingOffset = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "ScalingOffset", ok));
|
||||
if (ok) {
|
||||
scaling_offset = ImportUtils::FixAxisConversions(ScalingOffset);
|
||||
}
|
||||
const Vector3 &ScalingPivot = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "ScalingPivot", ok));
|
||||
if (ok) {
|
||||
scaling_pivot = ImportUtils::FixAxisConversions(ScalingPivot);
|
||||
}
|
||||
const Vector3 &Translation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "Lcl Translation", ok));
|
||||
if (ok) {
|
||||
translation = ImportUtils::FixAxisConversions(Translation);
|
||||
}
|
||||
raw_rotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "Lcl Rotation", ok));
|
||||
if (ok) {
|
||||
rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(raw_rotation));
|
||||
}
|
||||
const Vector3 &Scaling = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "Lcl Scaling", ok));
|
||||
if (ok) {
|
||||
scaling = Scaling;
|
||||
} else {
|
||||
scaling = Vector3(1, 1, 1);
|
||||
}
|
||||
const Vector3 &GeometricScaling = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricScaling", ok));
|
||||
if (ok) {
|
||||
geometric_scaling = GeometricScaling;
|
||||
} else {
|
||||
geometric_scaling = Vector3(1, 1, 1);
|
||||
}
|
||||
|
||||
const Vector3 &GeometricRotation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricRotation", ok));
|
||||
if (ok) {
|
||||
geometric_rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(GeometricRotation));
|
||||
} else {
|
||||
geometric_rotation = Quaternion();
|
||||
}
|
||||
|
||||
const Vector3 &GeometricTranslation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricTranslation", ok));
|
||||
if (ok) {
|
||||
geometric_translation = ImportUtils::FixAxisConversions(GeometricTranslation);
|
||||
} else {
|
||||
geometric_translation = Vector3(0, 0, 0);
|
||||
}
|
||||
|
||||
if (geometric_rotation != Quaternion()) {
|
||||
print_error("geometric rotation is unsupported!");
|
||||
//CRASH_COND(true);
|
||||
}
|
||||
|
||||
if (!geometric_scaling.is_equal_approx(Vector3(1, 1, 1))) {
|
||||
print_error("geometric scaling is unsupported!");
|
||||
//CRASH_COND(true);
|
||||
}
|
||||
|
||||
if (!geometric_translation.is_equal_approx(Vector3(0, 0, 0))) {
|
||||
print_error("geometric translation is unsupported.");
|
||||
//CRASH_COND(true);
|
||||
}
|
||||
}
|
||||
|
||||
Transform3D PivotTransform::ComputeLocalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const {
|
||||
Transform3D T, Roff, Rp, Soff, Sp, S;
|
||||
|
||||
// Here I assume this is the operation which needs done.
|
||||
// Its WorldTransform * V
|
||||
|
||||
// Origin pivots
|
||||
T.set_origin(p_translation);
|
||||
Roff.set_origin(rotation_offset);
|
||||
Rp.set_origin(rotation_pivot);
|
||||
Soff.set_origin(scaling_offset);
|
||||
Sp.set_origin(scaling_pivot);
|
||||
|
||||
// Scaling node
|
||||
S.scale(p_scaling);
|
||||
// Rotation pivots
|
||||
Transform3D Rpre = Transform3D(pre_rotation);
|
||||
Transform3D R = Transform3D(p_rotation);
|
||||
Transform3D Rpost = Transform3D(post_rotation);
|
||||
|
||||
return T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
|
||||
}
|
||||
|
||||
Transform3D PivotTransform::ComputeGlobalTransform(Transform3D t) const {
|
||||
Vector3 pos = t.origin;
|
||||
Vector3 scale = t.basis.get_scale();
|
||||
Quaternion rot = t.basis.get_rotation_quaternion();
|
||||
return ComputeGlobalTransform(pos, rot, scale);
|
||||
}
|
||||
|
||||
Transform3D PivotTransform::ComputeLocalTransform(Transform3D t) const {
|
||||
Vector3 pos = t.origin;
|
||||
Vector3 scale = t.basis.get_scale();
|
||||
Quaternion rot = t.basis.get_rotation_quaternion();
|
||||
return ComputeLocalTransform(pos, rot, scale);
|
||||
}
|
||||
|
||||
Transform3D PivotTransform::ComputeGlobalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const {
|
||||
Transform3D T, Roff, Rp, Soff, Sp, S;
|
||||
|
||||
// Here I assume this is the operation which needs done.
|
||||
// Its WorldTransform * V
|
||||
|
||||
// Origin pivots
|
||||
T.set_origin(p_translation);
|
||||
Roff.set_origin(rotation_offset);
|
||||
Rp.set_origin(rotation_pivot);
|
||||
Soff.set_origin(scaling_offset);
|
||||
Sp.set_origin(scaling_pivot);
|
||||
|
||||
// Scaling node
|
||||
S.scale(p_scaling);
|
||||
|
||||
// Rotation pivots
|
||||
Transform3D Rpre = Transform3D(pre_rotation);
|
||||
Transform3D R = Transform3D(p_rotation);
|
||||
Transform3D Rpost = Transform3D(post_rotation);
|
||||
|
||||
Transform3D parent_global_xform;
|
||||
Transform3D parent_local_scaling_m;
|
||||
|
||||
if (parent_transform.is_valid()) {
|
||||
parent_global_xform = parent_transform->GlobalTransform;
|
||||
parent_local_scaling_m = parent_transform->Local_Scaling_Matrix;
|
||||
}
|
||||
|
||||
Transform3D local_rotation_m, parent_global_rotation_m;
|
||||
Quaternion parent_global_rotation = parent_global_xform.basis.get_rotation_quaternion();
|
||||
parent_global_rotation_m.basis.set_quaternion(parent_global_rotation);
|
||||
local_rotation_m = Rpre * R * Rpost;
|
||||
|
||||
//Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quaternion().normalized());
|
||||
|
||||
Transform3D local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation;
|
||||
Vector3 parent_translation = parent_global_xform.get_origin();
|
||||
parent_shear_translation.origin = parent_translation;
|
||||
parent_shear_rotation = parent_shear_translation.affine_inverse() * parent_global_xform;
|
||||
parent_shear_scaling = parent_global_rotation_m.affine_inverse() * parent_shear_rotation;
|
||||
local_shear_scaling = S;
|
||||
|
||||
// Inherit type handler - we don't care about T here, just reordering RSrs etc.
|
||||
Transform3D global_rotation_scale;
|
||||
if (inherit_type == FBXDocParser::Transform_RrSs) {
|
||||
global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling;
|
||||
} else if (inherit_type == FBXDocParser::Transform_RSrs) {
|
||||
global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling;
|
||||
} else if (inherit_type == FBXDocParser::Transform_Rrs) {
|
||||
Transform3D parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.affine_inverse();
|
||||
global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_global_shear_m_noLocal * local_shear_scaling;
|
||||
}
|
||||
Transform3D local_transform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
|
||||
//Transform3D local_translation_pivoted = Transform3D(Basis(), LocalTransform.origin);
|
||||
|
||||
ERR_FAIL_COND_V_MSG(local_transform.basis.determinant() == 0, Transform3D(), "Det == 0 prevented in scene file");
|
||||
|
||||
// manual hack to force SSC not to be compensated for - until we can handle it properly with tests
|
||||
return parent_global_xform * local_transform;
|
||||
}
|
||||
|
||||
void PivotTransform::ComputePivotTransform() {
|
||||
Transform3D T, Roff, Rp, Soff, Sp, S;
|
||||
|
||||
// Here I assume this is the operation which needs done.
|
||||
// Its WorldTransform * V
|
||||
|
||||
// Origin pivots
|
||||
T.set_origin(translation);
|
||||
Roff.set_origin(rotation_offset);
|
||||
Rp.set_origin(rotation_pivot);
|
||||
Soff.set_origin(scaling_offset);
|
||||
Sp.set_origin(scaling_pivot);
|
||||
|
||||
// Scaling node
|
||||
if (!scaling.is_equal_approx(Vector3())) {
|
||||
S.scale(scaling);
|
||||
} else {
|
||||
S.scale(Vector3(1, 1, 1));
|
||||
}
|
||||
Local_Scaling_Matrix = S; // copy for when node / child is looking for the value of this.
|
||||
|
||||
// Rotation pivots
|
||||
Transform3D Rpre = Transform3D(pre_rotation);
|
||||
Transform3D R = Transform3D(rotation);
|
||||
Transform3D Rpost = Transform3D(post_rotation);
|
||||
|
||||
Transform3D parent_global_xform;
|
||||
Transform3D parent_local_scaling_m;
|
||||
|
||||
if (parent_transform.is_valid()) {
|
||||
parent_global_xform = parent_transform->GlobalTransform;
|
||||
parent_local_scaling_m = parent_transform->Local_Scaling_Matrix;
|
||||
}
|
||||
|
||||
Transform3D local_rotation_m, parent_global_rotation_m;
|
||||
Quaternion parent_global_rotation = parent_global_xform.basis.get_rotation_quaternion();
|
||||
parent_global_rotation_m.basis.set_quaternion(parent_global_rotation);
|
||||
local_rotation_m = Rpre * R * Rpost;
|
||||
|
||||
//Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quaternion().normalized());
|
||||
|
||||
Transform3D local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation;
|
||||
Vector3 parent_translation = parent_global_xform.get_origin();
|
||||
parent_shear_translation.origin = parent_translation;
|
||||
parent_shear_rotation = parent_shear_translation.affine_inverse() * parent_global_xform;
|
||||
parent_shear_scaling = parent_global_rotation_m.affine_inverse() * parent_shear_rotation;
|
||||
local_shear_scaling = S;
|
||||
|
||||
// Inherit type handler - we don't care about T here, just reordering RSrs etc.
|
||||
Transform3D global_rotation_scale;
|
||||
if (inherit_type == FBXDocParser::Transform_RrSs) {
|
||||
global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling;
|
||||
} else if (inherit_type == FBXDocParser::Transform_RSrs) {
|
||||
global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling;
|
||||
} else if (inherit_type == FBXDocParser::Transform_Rrs) {
|
||||
Transform3D parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.inverse();
|
||||
global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_global_shear_m_noLocal * local_shear_scaling;
|
||||
}
|
||||
LocalTransform = Transform3D();
|
||||
LocalTransform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
|
||||
|
||||
ERR_FAIL_COND_MSG(LocalTransform.basis.determinant() == 0, "invalid scale reset");
|
||||
|
||||
Transform3D local_translation_pivoted = Transform3D(Basis(), LocalTransform.origin);
|
||||
GlobalTransform = Transform3D();
|
||||
//GlobalTransform = parent_global_xform * LocalTransform;
|
||||
Transform3D global_origin = Transform3D(Basis(), parent_translation);
|
||||
GlobalTransform = (global_origin * local_translation_pivoted) * global_rotation_scale;
|
||||
|
||||
ImportUtils::debug_xform("local xform calculation", LocalTransform);
|
||||
print_verbose("scale of node: " + S.basis.get_scale_local());
|
||||
print_verbose("---------------------------------------------------------------");
|
||||
}
|
||||
|
||||
void PivotTransform::Execute() {
|
||||
ReadTransformChain();
|
||||
ComputePivotTransform();
|
||||
|
||||
ImportUtils::debug_xform("global xform: ", GlobalTransform);
|
||||
|
||||
if (LocalTransform.basis.determinant() == 0) {
|
||||
print_error("Serious det == 0!");
|
||||
}
|
||||
|
||||
if (GlobalTransform.basis.determinant() == 0) {
|
||||
print_error("Serious! node has det == 0!");
|
||||
}
|
||||
|
||||
computed_global_xform = true;
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* pivot_transform.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef PIVOT_TRANSFORM_H
|
||||
#define PIVOT_TRANSFORM_H
|
||||
|
||||
#include "core/math/transform_3d.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
|
||||
#include "model_abstraction.h"
|
||||
|
||||
#include "fbx_parser/FBXDocument.h"
|
||||
#include "tools/import_utils.h"
|
||||
|
||||
enum TransformationComp {
|
||||
TransformationComp_Translation,
|
||||
TransformationComp_Scaling,
|
||||
TransformationComp_Rotation,
|
||||
TransformationComp_RotationOffset,
|
||||
TransformationComp_RotationPivot,
|
||||
TransformationComp_PreRotation,
|
||||
TransformationComp_PostRotation,
|
||||
TransformationComp_ScalingOffset,
|
||||
TransformationComp_ScalingPivot,
|
||||
TransformationComp_GeometricTranslation,
|
||||
TransformationComp_GeometricRotation,
|
||||
TransformationComp_GeometricScaling,
|
||||
TransformationComp_MAXIMUM
|
||||
};
|
||||
// Abstract away pivot data so its simpler to handle
|
||||
struct PivotTransform : RefCounted, ModelAbstraction {
|
||||
// at the end we want to keep geometric_ everything, post and pre rotation
|
||||
// these are used during animation data processing / keyframe ingestion the rest can be simplified down / out.
|
||||
Quaternion pre_rotation = Quaternion();
|
||||
Quaternion post_rotation = Quaternion();
|
||||
Quaternion rotation = Quaternion();
|
||||
Quaternion geometric_rotation = Quaternion();
|
||||
Vector3 rotation_pivot = Vector3();
|
||||
Vector3 rotation_offset = Vector3();
|
||||
Vector3 scaling_offset = Vector3(1.0, 1.0, 1.0);
|
||||
Vector3 scaling_pivot = Vector3(1.0, 1.0, 1.0);
|
||||
Vector3 translation = Vector3();
|
||||
Vector3 scaling = Vector3(1.0, 1.0, 1.0);
|
||||
Vector3 geometric_scaling = Vector3(1.0, 1.0, 1.0);
|
||||
Vector3 geometric_translation = Vector3();
|
||||
|
||||
Vector3 raw_rotation = Vector3();
|
||||
Vector3 raw_post_rotation = Vector3();
|
||||
Vector3 raw_pre_rotation = Vector3();
|
||||
|
||||
/* Read pivots from the document */
|
||||
void ReadTransformChain();
|
||||
|
||||
void debug_pivot_xform(String p_name) {
|
||||
print_verbose("debugging node name: " + p_name);
|
||||
print_verbose("raw rotation: " + raw_rotation * (180 / Math_PI));
|
||||
print_verbose("raw pre_rotation " + raw_pre_rotation * (180 / Math_PI));
|
||||
print_verbose("raw post_rotation " + raw_post_rotation * (180 / Math_PI));
|
||||
}
|
||||
|
||||
Transform3D ComputeGlobalTransform(Transform3D t) const;
|
||||
Transform3D ComputeLocalTransform(Transform3D t) const;
|
||||
Transform3D ComputeGlobalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const;
|
||||
Transform3D ComputeLocalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const;
|
||||
|
||||
/* Extract into xforms and calculate once */
|
||||
void ComputePivotTransform();
|
||||
|
||||
/* Execute the command for the pivot generation */
|
||||
void Execute();
|
||||
|
||||
void set_parent(Ref<PivotTransform> p_parent) {
|
||||
parent_transform = p_parent;
|
||||
}
|
||||
|
||||
bool computed_global_xform = false;
|
||||
Ref<PivotTransform> parent_transform = Ref<PivotTransform>();
|
||||
//Transform chain[TransformationComp_MAXIMUM];
|
||||
|
||||
// cached for later use
|
||||
Transform3D GlobalTransform = Transform3D();
|
||||
Transform3D LocalTransform = Transform3D();
|
||||
Transform3D Local_Scaling_Matrix = Transform3D(); // used for inherit type.
|
||||
Transform3D GeometricTransform = Transform3D(); // 3DS max only
|
||||
FBXDocParser::TransformInheritance inherit_type = FBXDocParser::TransformInheritance_MAX; // maya fbx requires this - sorry <3
|
||||
};
|
||||
|
||||
#endif // PIVOT_TRANSFORM_H
|
File diff suppressed because it is too large
Load Diff
@ -1,136 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* editor_scene_importer_fbx.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef EDITOR_SCENE_IMPORTER_FBX_H
|
||||
#define EDITOR_SCENE_IMPORTER_FBX_H
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
#include "data/import_state.h"
|
||||
#include "tools/import_utils.h"
|
||||
|
||||
#include "core/io/resource_importer.h"
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/local_vector.h"
|
||||
#include "core/templates/vector.h"
|
||||
#include "core/variant/dictionary.h"
|
||||
#include "editor/import/resource_importer_scene.h"
|
||||
#include "editor/project_settings_editor.h"
|
||||
#include "scene/3d/mesh_instance_3d.h"
|
||||
#include "scene/3d/node_3d.h"
|
||||
#include "scene/3d/skeleton_3d.h"
|
||||
#include "scene/animation/animation_player.h"
|
||||
#include "scene/resources/animation.h"
|
||||
#include "scene/resources/surface_tool.h"
|
||||
|
||||
#include "fbx_parser/FBXDocument.h"
|
||||
#include "fbx_parser/FBXImportSettings.h"
|
||||
#include "fbx_parser/FBXMeshGeometry.h"
|
||||
#include "fbx_parser/FBXUtil.h"
|
||||
|
||||
#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
|
||||
|
||||
class EditorSceneFormatImporterFBX : public EditorSceneFormatImporter {
|
||||
private:
|
||||
GDCLASS(EditorSceneFormatImporterFBX, EditorSceneFormatImporter);
|
||||
|
||||
struct AssetImportAnimation {
|
||||
enum Interpolation {
|
||||
INTERP_LINEAR,
|
||||
INTERP_STEP,
|
||||
INTERP_CATMULLROMSPLINE,
|
||||
INTERP_CUBIC_SPLINE
|
||||
};
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
const T *ProcessDOMConnection(
|
||||
const FBXDocParser::Document *doc,
|
||||
uint64_t current_element,
|
||||
bool reverse_lookup = false) {
|
||||
const std::vector<const FBXDocParser::Connection *> &conns = reverse_lookup ? doc->GetConnectionsByDestinationSequenced(current_element) : doc->GetConnectionsBySourceSequenced(current_element);
|
||||
//print_verbose("[doc] looking for " + String(element_to_find));
|
||||
// using the temp pattern here so we can debug before it returns
|
||||
// in some cases we return too early, with 'deformer object base class' in wrong place
|
||||
// in assimp this means we can accidentally return too early...
|
||||
const T *return_obj = nullptr;
|
||||
|
||||
for (const FBXDocParser::Connection *con : conns) {
|
||||
const FBXDocParser::Object *source_object = con->SourceObject();
|
||||
const FBXDocParser::Object *dest_object = con->DestinationObject();
|
||||
if (source_object && dest_object != nullptr) {
|
||||
//print_verbose("[doc] connection name: " + String(source_object->Name().c_str()) + ", dest: " + String(dest_object->Name().c_str()));
|
||||
const T *temp = dynamic_cast<const T *>(reverse_lookup ? source_object : dest_object);
|
||||
if (temp) {
|
||||
return_obj = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (return_obj != nullptr) {
|
||||
//print_verbose("[doc] returned valid element");
|
||||
//print_verbose("Found object for bone");
|
||||
return return_obj;
|
||||
}
|
||||
|
||||
// safe to return nothing, need to use nullptr here as nullptr is used internally for FBX document.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void BuildDocumentBones(Ref<FBXBone> p_parent_bone,
|
||||
ImportState &state, const FBXDocParser::Document *p_doc,
|
||||
uint64_t p_id);
|
||||
|
||||
void BuildDocumentNodes(Ref<PivotTransform> parent_transform, ImportState &state, const FBXDocParser::Document *doc, uint64_t id, Ref<FBXNode> fbx_parent);
|
||||
|
||||
Node3D *_generate_scene(const String &p_path, const FBXDocParser::Document *p_document,
|
||||
const uint32_t p_flags,
|
||||
int p_bake_fps,
|
||||
const int32_t p_max_bone_weights,
|
||||
bool p_is_blender_fbx);
|
||||
|
||||
template <class T>
|
||||
T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, float p_time, AssetImportAnimation::Interpolation p_interp);
|
||||
|
||||
public:
|
||||
EditorSceneFormatImporterFBX();
|
||||
~EditorSceneFormatImporterFBX() {}
|
||||
|
||||
virtual void get_extensions(List<String> *r_extensions) const override;
|
||||
virtual uint32_t get_import_flags() const override;
|
||||
virtual Node3D *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override;
|
||||
virtual Ref<Animation> import_animation(const String &p_path,
|
||||
uint32_t p_flags, const Map<StringName, Variant> &p_options,
|
||||
int p_bake_fps) override;
|
||||
};
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
#endif // EDITOR_SCENE_IMPORTER_FBX_H
|
@ -1,283 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* ByteSwapper.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file Helper class tp perform various byte order swappings
|
||||
(e.g. little to big endian) */
|
||||
#ifndef BYTE_SWAPPER_H
|
||||
#define BYTE_SWAPPER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <algorithm>
|
||||
#include <locale>
|
||||
|
||||
namespace FBXDocParser {
|
||||
// --------------------------------------------------------------------------------------
|
||||
/** Defines some useful byte order swap routines.
|
||||
*
|
||||
* This is required to read big-endian model formats on little-endian machines,
|
||||
* and vice versa. Direct use of this class is DEPRECATED. Use #StreamReader instead. */
|
||||
// --------------------------------------------------------------------------------------
|
||||
class ByteSwap {
|
||||
ByteSwap() {}
|
||||
|
||||
public:
|
||||
// ----------------------------------------------------------------------
|
||||
/** Swap two bytes of data
|
||||
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
|
||||
static inline void Swap2(void *_szOut) {
|
||||
uint8_t *const szOut = reinterpret_cast<uint8_t *>(_szOut);
|
||||
std::swap(szOut[0], szOut[1]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** Swap four bytes of data
|
||||
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
|
||||
static inline void Swap4(void *_szOut) {
|
||||
uint8_t *const szOut = reinterpret_cast<uint8_t *>(_szOut);
|
||||
std::swap(szOut[0], szOut[3]);
|
||||
std::swap(szOut[1], szOut[2]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** Swap eight bytes of data
|
||||
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
|
||||
static inline void Swap8(void *_szOut) {
|
||||
uint8_t *const szOut = reinterpret_cast<uint8_t *>(_szOut);
|
||||
std::swap(szOut[0], szOut[7]);
|
||||
std::swap(szOut[1], szOut[6]);
|
||||
std::swap(szOut[2], szOut[5]);
|
||||
std::swap(szOut[3], szOut[4]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap a float. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(float *fOut) {
|
||||
Swap4(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap a double. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(double *fOut) {
|
||||
Swap8(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap an int16t. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(int16_t *fOut) {
|
||||
Swap2(fOut);
|
||||
}
|
||||
|
||||
static inline void Swap(uint16_t *fOut) {
|
||||
Swap2(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap an int32t. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(int32_t *fOut) {
|
||||
Swap4(fOut);
|
||||
}
|
||||
|
||||
static inline void Swap(uint32_t *fOut) {
|
||||
Swap4(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap an int64t. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(int64_t *fOut) {
|
||||
Swap8(fOut);
|
||||
}
|
||||
|
||||
static inline void Swap(uint64_t *fOut) {
|
||||
Swap8(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
//! Templatized ByteSwap
|
||||
//! \returns param tOut as swapped
|
||||
template <typename Type>
|
||||
static inline Type Swapped(Type tOut) {
|
||||
return _swapper<Type, sizeof(Type)>()(tOut);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T, size_t size>
|
||||
struct _swapper;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ByteSwap::_swapper<T, 2> {
|
||||
T operator()(T tOut) {
|
||||
Swap2(&tOut);
|
||||
return tOut;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ByteSwap::_swapper<T, 4> {
|
||||
T operator()(T tOut) {
|
||||
Swap4(&tOut);
|
||||
return tOut;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ByteSwap::_swapper<T, 8> {
|
||||
T operator()(T tOut) {
|
||||
Swap8(&tOut);
|
||||
return tOut;
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ByteSwap macros for BigEndian/LittleEndian support
|
||||
// --------------------------------------------------------------------------------------
|
||||
#if (defined AI_BUILD_BIG_ENDIAN)
|
||||
#define AI_LE(t) (t)
|
||||
#define AI_BE(t) ByteSwap::Swapped(t)
|
||||
#define AI_LSWAP2(p)
|
||||
#define AI_LSWAP4(p)
|
||||
#define AI_LSWAP8(p)
|
||||
#define AI_LSWAP2P(p)
|
||||
#define AI_LSWAP4P(p)
|
||||
#define AI_LSWAP8P(p)
|
||||
#define LE_NCONST const
|
||||
#define AI_SWAP2(p) ByteSwap::Swap2(&(p))
|
||||
#define AI_SWAP4(p) ByteSwap::Swap4(&(p))
|
||||
#define AI_SWAP8(p) ByteSwap::Swap8(&(p))
|
||||
#define AI_SWAP2P(p) ByteSwap::Swap2((p))
|
||||
#define AI_SWAP4P(p) ByteSwap::Swap4((p))
|
||||
#define AI_SWAP8P(p) ByteSwap::Swap8((p))
|
||||
#define BE_NCONST
|
||||
#else
|
||||
#define AI_BE(t) (t)
|
||||
#define AI_LE(t) ByteSwap::Swapped(t)
|
||||
#define AI_SWAP2(p)
|
||||
#define AI_SWAP4(p)
|
||||
#define AI_SWAP8(p)
|
||||
#define AI_SWAP2P(p)
|
||||
#define AI_SWAP4P(p)
|
||||
#define AI_SWAP8P(p)
|
||||
#define BE_NCONST const
|
||||
#define AI_LSWAP2(p) ByteSwap::Swap2(&(p))
|
||||
#define AI_LSWAP4(p) ByteSwap::Swap4(&(p))
|
||||
#define AI_LSWAP8(p) ByteSwap::Swap8(&(p))
|
||||
#define AI_LSWAP2P(p) ByteSwap::Swap2((p))
|
||||
#define AI_LSWAP4P(p) ByteSwap::Swap4((p))
|
||||
#define AI_LSWAP8P(p) ByteSwap::Swap8((p))
|
||||
#define LE_NCONST
|
||||
#endif
|
||||
|
||||
namespace Intern {
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
template <typename T, bool doit>
|
||||
struct ByteSwapper {
|
||||
void operator()(T *inout) {
|
||||
ByteSwap::Swap(inout);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ByteSwapper<T, false> {
|
||||
void operator()(T *) {
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
template <bool SwapEndianess, typename T, bool RuntimeSwitch>
|
||||
struct Getter {
|
||||
void operator()(T *inout, bool le) {
|
||||
le = !le;
|
||||
if (le) {
|
||||
ByteSwapper<T, (sizeof(T) > 1 ? true : false)>()(inout);
|
||||
} else {
|
||||
ByteSwapper<T, false>()(inout);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <bool SwapEndianess, typename T>
|
||||
struct Getter<SwapEndianess, T, false> {
|
||||
void operator()(T *inout, bool /*le*/) {
|
||||
// static branch
|
||||
ByteSwapper<T, (SwapEndianess && sizeof(T) > 1)>()(inout);
|
||||
}
|
||||
};
|
||||
} // namespace Intern
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // BYTE_SWAPPER_H
|
@ -1,183 +0,0 @@
|
||||
===============================================================
|
||||
Open Asset Import Library (Assimp)
|
||||
Developers and Contributors
|
||||
===============================================================
|
||||
|
||||
The following is a non-exhaustive list of all constributors over the years.
|
||||
If you think your name should be listed here, drop us a line and we'll add you.
|
||||
|
||||
- Alexander Gessler,
|
||||
3DS-, BLEND-, ASE-, DXF-, HMP-, MDL-, MD2-, MD3-, MD5-, MDC-, NFF-, PLY-, STL-, RAW-, OFF-, MS3D-, Q3D- and LWO-Loader, Assimp-Viewer, assimp-cmd, -noboost, Website (Design).
|
||||
|
||||
- Thomas Schulze,
|
||||
X-, Collada-, BVH-Loader, Postprocessing framework. Data structure & Interface design, documentation.
|
||||
|
||||
- Kim Kulling,
|
||||
Obj-, Q3BSD-, OpenGEX-Loader, Logging system, CMake-build-environment, Linux-build, Website ( Admin ), Coverity ( Admin ), Glitter ( Admin ).
|
||||
|
||||
- R.Schmidt,
|
||||
Linux build, eclipse support.
|
||||
|
||||
- Matthias Gubisch,
|
||||
Assimp.net
|
||||
Visual Studio 9 support, bugfixes.
|
||||
|
||||
- Mark Sibly
|
||||
B3D-Loader, Assimp testing
|
||||
|
||||
- Jonathan Klein
|
||||
Ogre Loader, VC2010 fixes and CMake fixes.
|
||||
|
||||
- Sebastian Hempel,
|
||||
PyAssimp (first version)
|
||||
Compile-Bugfixes for mingw, add environment for static library support in make.
|
||||
|
||||
- Jonathan Pokrass
|
||||
Supplied a bugfix concerning the scaling in the md3 loader.
|
||||
|
||||
- Andrew Galante,
|
||||
Submitted patches to make Assimp compile with GCC-4, a makefile and the xcode3 workspace.
|
||||
|
||||
- Andreas Nagel
|
||||
First Assimp testing & verification under Windows Vista 64 Bit.
|
||||
|
||||
- Marius Schr<68>der
|
||||
Allowed us to use many of his models for screenshots and testing.
|
||||
|
||||
- Christian Schubert
|
||||
Supplied various XFiles for testing purposes.
|
||||
|
||||
- Tizian Wieland
|
||||
Searched the web for hundreds of test models for internal use
|
||||
|
||||
- John Connors
|
||||
Supplied patches for linux and SCons.
|
||||
|
||||
- T. R.
|
||||
The GUY who performed some of the CSM mocaps.
|
||||
|
||||
- Andy Maloney
|
||||
Contributed fixes for the documentation and the doxygen markup
|
||||
|
||||
- Zhao Lei
|
||||
Contributed several bugfixes fixing memory leaks and improving float parsing
|
||||
|
||||
- sueastside
|
||||
Updated PyAssimp to the latest Assimp data structures and provided a script to keep the Python binding up-to-date.
|
||||
|
||||
- Tobias Rittig
|
||||
Collada testing with Cinema 4D
|
||||
|
||||
- Brad Grantham
|
||||
Improvements in OpenGL-Sample.
|
||||
|
||||
- Robert Ramirez
|
||||
Add group loading feature to Obj-Loader.
|
||||
|
||||
- Chris Maiwald
|
||||
Many bugreports, improving Assimp's portability, regular testing & feedback.
|
||||
|
||||
- Stepan Hrbek
|
||||
Bugreport and fix for a obj-materialloader crash.
|
||||
|
||||
- David Nadlinger
|
||||
D bindings, CMake install support.
|
||||
|
||||
- Dario Accornero
|
||||
Contributed several patches regarding Mac OS/XCode targets, bug reports.
|
||||
|
||||
- Martin Walser (Samhayne)
|
||||
Contributed the 'SimpleTexturedOpenGl' sample.
|
||||
|
||||
- Matthias Fauconneau
|
||||
Contributed a fix for the Q3-BSP loader.
|
||||
|
||||
- Jørgen P. Tjernø
|
||||
Contributed updated and improved xcode workspaces
|
||||
|
||||
- drparallax
|
||||
Contributed the /samples/SimpleAssimpViewX sample
|
||||
|
||||
- Carsten Fuchs
|
||||
Contributed a fix for the Normalize method in aiQuaternion.
|
||||
|
||||
- dbburgess
|
||||
Contributes a Android-specific build issue: log the hardware architecture for ARM.
|
||||
|
||||
- alfiereinre7
|
||||
Contributes a obj-fileparser fix: missing tokens in the obj-token list.
|
||||
|
||||
- Roman Kharitonov
|
||||
Contributes a fix for the configure script environment.
|
||||
|
||||
- Ed Diana
|
||||
Contributed AssimpDelphi (/port/AssimpDelphi).
|
||||
|
||||
- rdb
|
||||
Contributes a bundle of fixes and improvements for the bsp-importer.
|
||||
|
||||
- Mick P
|
||||
For contributing the De-bone postprocessing step and filing various bug reports.
|
||||
|
||||
- Rosen Diankov
|
||||
Contributed patches to build assimp debian packages using cmake.
|
||||
|
||||
- Mark Page
|
||||
Contributed a patch to fix the VertexTriangleAdjacency postprocessing step.
|
||||
|
||||
- IOhannes
|
||||
Contributed the Debian build fixes ( architecture macro ).
|
||||
|
||||
- gellule
|
||||
Several LWO and LWS fixes (pivoting).
|
||||
|
||||
- Marcel Metz
|
||||
GCC/Linux fixes for the SimpleOpenGL sample.
|
||||
|
||||
- Brian Miller
|
||||
Bugfix for a compiler fix for iOS on arm.
|
||||
|
||||
- Séverin Lemaignan
|
||||
Rewrite of PyAssimp, distutils and Python3 support
|
||||
|
||||
- albert-wang
|
||||
Bugfixes for the collada parser
|
||||
|
||||
- Ya ping Jin
|
||||
Bugfixes for uv-tanget calculation.
|
||||
|
||||
- Jonne Nauha
|
||||
Ogre Binary format support
|
||||
|
||||
- Filip Wasil, Tieto Poland Sp. z o.o.
|
||||
Android JNI asset extraction support
|
||||
|
||||
- Richard Steffen
|
||||
Contributed ExportProperties interface
|
||||
Contributed X File exporter
|
||||
Contributed Step (stp) exporter
|
||||
|
||||
- Thomas Iorns (mesilliac)
|
||||
Initial FBX Export support
|
||||
|
||||
For a more detailed list just check: https://github.com/assimp/assimp/network/members
|
||||
|
||||
|
||||
========
|
||||
Patreons
|
||||
========
|
||||
|
||||
Huge thanks to our Patreons!
|
||||
|
||||
- migenius
|
||||
- Marcus
|
||||
- Cort
|
||||
- elect
|
||||
- Steffen
|
||||
|
||||
|
||||
===================
|
||||
Commercial Sponsors
|
||||
===================
|
||||
|
||||
- MyDidimo (mydidimo.com): Sponsored development of FBX Export support
|
@ -1,273 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXAnimation.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXAnimation.cpp
|
||||
* @brief Assimp::FBX::AnimationCurve, Assimp::FBX::AnimationCurveNode,
|
||||
* Assimp::FBX::AnimationLayer, Assimp::FBX::AnimationStack
|
||||
*/
|
||||
|
||||
#include "FBXCommon.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXParser.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurve::AnimationCurve(uint64_t id, const ElementPtr element, const std::string &name, const Document & /*doc*/) :
|
||||
Object(id, element, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
const ElementPtr KeyTime = GetRequiredElement(sc, "KeyTime");
|
||||
const ElementPtr KeyValueFloat = GetRequiredElement(sc, "KeyValueFloat");
|
||||
|
||||
// note preserved keys and values for legacy FBXConverter.cpp
|
||||
// we can remove this once the animation system is written
|
||||
// and clean up this code so we do not have copies everywhere.
|
||||
ParseVectorDataArray(keys, KeyTime);
|
||||
ParseVectorDataArray(values, KeyValueFloat);
|
||||
|
||||
if (keys.size() != values.size()) {
|
||||
DOMError("the number of key times does not match the number of keyframe values", KeyTime);
|
||||
}
|
||||
|
||||
// put the two lists into the map, underlying container is really just a dictionary
|
||||
// these will always match, if not an error will throw and the file will not import
|
||||
// this is useful because we then can report something and fix this later if it becomes an issue
|
||||
// at this point we do not need a different count of these elements so this makes the
|
||||
// most sense to do.
|
||||
for (size_t x = 0; x < keys.size(); x++) {
|
||||
keyvalues[keys[x]] = values[x];
|
||||
}
|
||||
|
||||
const ElementPtr KeyAttrDataFloat = sc->GetElement("KeyAttrDataFloat");
|
||||
if (KeyAttrDataFloat) {
|
||||
ParseVectorDataArray(attributes, KeyAttrDataFloat);
|
||||
}
|
||||
|
||||
const ElementPtr KeyAttrFlags = sc->GetElement("KeyAttrFlags");
|
||||
if (KeyAttrFlags) {
|
||||
ParseVectorDataArray(flags, KeyAttrFlags);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurve::~AnimationCurve() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurveNode::AnimationCurveNode(uint64_t id, const ElementPtr element, const std::string &name,
|
||||
const Document &doc, const char *const *target_prop_whitelist /*= nullptr*/,
|
||||
size_t whitelist_size /*= 0*/) :
|
||||
Object(id, element, name), doc(doc) {
|
||||
// find target node
|
||||
const char *whitelist[] = { "Model", "NodeAttribute", "Deformer" };
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsBySourceSequenced(ID(), whitelist, 3);
|
||||
|
||||
for (const Connection *con : conns) {
|
||||
// link should go for a property
|
||||
if (!con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object *object = con->DestinationObject();
|
||||
|
||||
if (!object) {
|
||||
DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
target = object;
|
||||
prop = con->PropertyName();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurveNode::~AnimationCurveNode() {
|
||||
curves.clear();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const AnimationMap &AnimationCurveNode::Curves() const {
|
||||
/* Lazy loaded animation curves, will only load if required */
|
||||
if (curves.empty()) {
|
||||
// resolve attached animation curves
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurve");
|
||||
|
||||
for (const Connection *con : conns) {
|
||||
// So the advantage of having this STL boilerplate is that it's dead simple once you get it.
|
||||
// The other advantage is casting is guaranteed to be safe and nullptr will be returned in the last step if it fails.
|
||||
Object *ob = con->SourceObject();
|
||||
AnimationCurve *anim_curve = dynamic_cast<AnimationCurve *>(ob);
|
||||
ERR_CONTINUE_MSG(!anim_curve, "Failed to convert animation curve from object");
|
||||
|
||||
curves.insert(std::make_pair(con->PropertyName(), anim_curve));
|
||||
}
|
||||
}
|
||||
|
||||
return curves;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationLayer::AnimationLayer(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
|
||||
Object(id, element, name), doc(doc) {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationLayer::~AnimationLayer() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_prop_whitelist,
|
||||
size_t whitelist_size /*= 0*/) const {
|
||||
AnimationCurveNodeList nodes;
|
||||
|
||||
// resolve attached animation nodes
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurveNode");
|
||||
nodes.reserve(conns.size());
|
||||
|
||||
for (const Connection *con : conns) {
|
||||
// link should not go to a property
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object *ob = con->SourceObject();
|
||||
|
||||
if (!ob) {
|
||||
DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const AnimationCurveNode *anim = dynamic_cast<AnimationCurveNode *>(ob);
|
||||
if (!anim) {
|
||||
DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (target_prop_whitelist) {
|
||||
const char *s = anim->TargetProperty().c_str();
|
||||
bool ok = false;
|
||||
for (size_t i = 0; i < whitelist_size; ++i) {
|
||||
if (!strcmp(s, target_prop_whitelist[i])) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
nodes.push_back(anim);
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationStack::AnimationStack(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
|
||||
Object(id, element, name) {
|
||||
// resolve attached animation layers
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationLayer");
|
||||
layers.reserve(conns.size());
|
||||
|
||||
for (const Connection *con : conns) {
|
||||
// link should not go to a property
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object *ob = con->SourceObject();
|
||||
if (!ob) {
|
||||
DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const AnimationLayer *anim = dynamic_cast<const AnimationLayer *>(ob);
|
||||
|
||||
if (!anim) {
|
||||
DOMWarning("source object for ->AnimationStack link is not an AnimationLayer", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
layers.push_back(anim);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationStack::~AnimationStack() {
|
||||
}
|
||||
} // namespace FBXDocParser
|
@ -1,442 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXBinaryTokenizer.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
/** @file FBXBinaryTokenizer.cpp
|
||||
* @brief Implementation of a fake lexer for binary fbx files -
|
||||
* we emit tokens so the parser needs almost no special handling
|
||||
* for binary files.
|
||||
*/
|
||||
|
||||
#include "ByteSwapper.h"
|
||||
#include "FBXTokenizer.h"
|
||||
#include "core/string/print_string.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace FBXDocParser {
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Token::Token(const char *sbegin, const char *send, TokenType type, size_t offset) :
|
||||
sbegin(sbegin),
|
||||
send(send),
|
||||
type(type),
|
||||
line(offset),
|
||||
column(BINARY_MARKER) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
// contents is bad.. :/
|
||||
contents = std::string(sbegin, static_cast<size_t>(send - sbegin));
|
||||
#endif
|
||||
// calc length
|
||||
// measure from sBegin to sEnd and validate?
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// signal tokenization error
|
||||
void TokenizeError(const std::string &message, size_t offset) {
|
||||
print_error("[FBX-Tokenize] " + String(message.c_str()) + ", offset " + itos(offset));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
size_t Offset(const char *begin, const char *cursor) {
|
||||
//ai_assert(begin <= cursor);
|
||||
|
||||
return cursor - begin;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TokenizeError(const std::string &message, const char *begin, const char *cursor) {
|
||||
TokenizeError(message, Offset(begin, cursor));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint32_t ReadWord(const char *input, const char *&cursor, const char *end) {
|
||||
const size_t k_to_read = sizeof(uint32_t);
|
||||
if (Offset(cursor, end) < k_to_read) {
|
||||
TokenizeError("cannot ReadWord, out of bounds", input, cursor);
|
||||
}
|
||||
|
||||
uint32_t word;
|
||||
::memcpy(&word, cursor, 4);
|
||||
AI_SWAP4(word);
|
||||
|
||||
cursor += k_to_read;
|
||||
|
||||
return word;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint64_t ReadDoubleWord(const char *input, const char *&cursor, const char *end) {
|
||||
const size_t k_to_read = sizeof(uint64_t);
|
||||
if (Offset(cursor, end) < k_to_read) {
|
||||
TokenizeError("cannot ReadDoubleWord, out of bounds", input, cursor);
|
||||
}
|
||||
|
||||
uint64_t dword /*= *reinterpret_cast<const uint64_t*>(cursor)*/;
|
||||
::memcpy(&dword, cursor, sizeof(uint64_t));
|
||||
AI_SWAP8(dword);
|
||||
|
||||
cursor += k_to_read;
|
||||
|
||||
return dword;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint8_t ReadByte(const char *input, const char *&cursor, const char *end) {
|
||||
if (Offset(cursor, end) < sizeof(uint8_t)) {
|
||||
TokenizeError("cannot ReadByte, out of bounds", input, cursor);
|
||||
}
|
||||
|
||||
uint8_t word; /* = *reinterpret_cast< const uint8_t* >( cursor )*/
|
||||
::memcpy(&word, cursor, sizeof(uint8_t));
|
||||
++cursor;
|
||||
|
||||
return word;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int ReadString(const char *&sbegin_out, const char *&send_out, const char *input,
|
||||
const char *&cursor, const char *end, bool long_length = false, bool allow_null = false) {
|
||||
const uint32_t len_len = long_length ? 4 : 1;
|
||||
if (Offset(cursor, end) < len_len) {
|
||||
TokenizeError("cannot ReadString, out of bounds reading length", input, cursor);
|
||||
}
|
||||
|
||||
const uint32_t length = long_length ? ReadWord(input, cursor, end) : ReadByte(input, cursor, end);
|
||||
|
||||
if (Offset(cursor, end) < length) {
|
||||
TokenizeError("cannot ReadString, length is out of bounds", input, cursor);
|
||||
}
|
||||
|
||||
sbegin_out = cursor;
|
||||
cursor += length;
|
||||
|
||||
send_out = cursor;
|
||||
|
||||
if (!allow_null) {
|
||||
for (unsigned int i = 0; i < length; ++i) {
|
||||
if (sbegin_out[i] == '\0') {
|
||||
TokenizeError("failed ReadString, unexpected NUL character in string", input, cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, const char *&cursor, const char *end, bool &corrupt) {
|
||||
if (Offset(cursor, end) < 1) {
|
||||
TokenizeError("cannot ReadData, out of bounds reading length", input, cursor);
|
||||
corrupt = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const char type = *cursor;
|
||||
sbegin_out = cursor++;
|
||||
|
||||
switch (type) {
|
||||
// 16 bit int
|
||||
case 'Y':
|
||||
cursor += 2;
|
||||
break;
|
||||
|
||||
// 1 bit bool flag (yes/no)
|
||||
case 'C':
|
||||
cursor += 1;
|
||||
break;
|
||||
|
||||
// 32 bit int
|
||||
case 'I':
|
||||
// <- fall through
|
||||
|
||||
// float
|
||||
case 'F':
|
||||
cursor += 4;
|
||||
break;
|
||||
|
||||
// double
|
||||
case 'D':
|
||||
cursor += 8;
|
||||
break;
|
||||
|
||||
// 64 bit int
|
||||
case 'L':
|
||||
cursor += 8;
|
||||
break;
|
||||
|
||||
// note: do not write cursor += ReadWord(...cursor) as this would be UB
|
||||
|
||||
// raw binary data
|
||||
case 'R': {
|
||||
const uint32_t length = ReadWord(input, cursor, end);
|
||||
cursor += length;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'b':
|
||||
// TODO: what is the 'b' type code? Right now we just skip over it /
|
||||
// take the full range we could get
|
||||
cursor = end;
|
||||
break;
|
||||
|
||||
// array of *
|
||||
case 'f':
|
||||
case 'd':
|
||||
case 'l':
|
||||
case 'i':
|
||||
case 'c': {
|
||||
const uint32_t length = ReadWord(input, cursor, end);
|
||||
const uint32_t encoding = ReadWord(input, cursor, end);
|
||||
|
||||
const uint32_t comp_len = ReadWord(input, cursor, end);
|
||||
|
||||
// compute length based on type and check against the stored value
|
||||
if (encoding == 0) {
|
||||
uint32_t stride = 0;
|
||||
switch (type) {
|
||||
case 'f':
|
||||
case 'i':
|
||||
stride = 4;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'l':
|
||||
stride = 8;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
stride = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
};
|
||||
//ai_assert(stride > 0);
|
||||
if (length * stride != comp_len) {
|
||||
TokenizeError("cannot ReadData, calculated data stride differs from what the file claims", input, cursor);
|
||||
}
|
||||
}
|
||||
// zip/deflate algorithm (encoding==1)? take given length. anything else? die
|
||||
else if (encoding != 1) {
|
||||
TokenizeError("cannot ReadData, unknown encoding", input, cursor);
|
||||
}
|
||||
cursor += comp_len;
|
||||
break;
|
||||
} // string
|
||||
case 'S': {
|
||||
const char *sb, *se;
|
||||
// 0 characters can legally happen in such strings
|
||||
ReadString(sb, se, input, cursor, end, true, true);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
corrupt = true; // must exit
|
||||
TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1), input, cursor);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cursor > end) {
|
||||
corrupt = true; // must exit
|
||||
TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1), input, cursor);
|
||||
return;
|
||||
}
|
||||
|
||||
// the type code is contained in the returned range
|
||||
send_out = cursor;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, const char *end, bool const is64bits, bool &corrupt) {
|
||||
// the first word contains the offset at which this block ends
|
||||
const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
|
||||
|
||||
// we may get 0 if reading reached the end of the file -
|
||||
// fbx files have a mysterious extra footer which I don't know
|
||||
// how to extract any information from, but at least it always
|
||||
// starts with a 0.
|
||||
if (!end_offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (end_offset > Offset(input, end)) {
|
||||
TokenizeError("block offset is out of range", input, cursor);
|
||||
corrupt = true;
|
||||
return false;
|
||||
} else if (end_offset < Offset(input, cursor)) {
|
||||
TokenizeError("block offset is negative out of range", input, cursor);
|
||||
corrupt = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// the second data word contains the number of properties in the scope
|
||||
const uint64_t prop_count = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
|
||||
|
||||
// the third data word contains the length of the property list
|
||||
const uint64_t prop_length = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
|
||||
|
||||
// now comes the name of the scope/key
|
||||
const char *sbeg = nullptr, *send = nullptr;
|
||||
ReadString(sbeg, send, input, cursor, end);
|
||||
|
||||
output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, cursor)));
|
||||
|
||||
// now come the individual properties
|
||||
const char *begin_cursor = cursor;
|
||||
for (unsigned int i = 0; i < prop_count; ++i) {
|
||||
ReadData(sbeg, send, input, cursor, begin_cursor + prop_length, corrupt);
|
||||
if (corrupt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor)));
|
||||
|
||||
if (i != prop_count - 1) {
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_COMMA, Offset(input, cursor)));
|
||||
}
|
||||
}
|
||||
|
||||
if (Offset(begin_cursor, cursor) != prop_length) {
|
||||
TokenizeError("property length not reached, something is wrong", input, cursor);
|
||||
corrupt = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// at the end of each nested block, there is a NUL record to indicate
|
||||
// that the sub-scope exists (i.e. to distinguish between P: and P : {})
|
||||
// this NUL record is 13 bytes long on 32 bit version and 25 bytes long on 64 bit.
|
||||
const size_t sentinel_block_length = is64bits ? (sizeof(uint64_t) * 3 + 1) : (sizeof(uint32_t) * 3 + 1);
|
||||
|
||||
if (Offset(input, cursor) < end_offset) {
|
||||
if (end_offset - Offset(input, cursor) < sentinel_block_length) {
|
||||
TokenizeError("insufficient padding bytes at block end", input, cursor);
|
||||
}
|
||||
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_OPEN_BRACKET, Offset(input, cursor)));
|
||||
|
||||
// XXX this is vulnerable to stack overflowing ..
|
||||
while (Offset(input, cursor) < end_offset - sentinel_block_length) {
|
||||
ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits, corrupt);
|
||||
if (corrupt) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor)));
|
||||
|
||||
for (unsigned int i = 0; i < sentinel_block_length; ++i) {
|
||||
if (cursor[i] != '\0') {
|
||||
TokenizeError("failed to read nested block sentinel, expected all bytes to be 0", input, cursor);
|
||||
corrupt = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
cursor += sentinel_block_length;
|
||||
}
|
||||
|
||||
if (Offset(input, cursor) != end_offset) {
|
||||
TokenizeError("scope length not reached, something is wrong", input, cursor);
|
||||
corrupt = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
|
||||
void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, bool &corrupt) {
|
||||
if (length < 0x1b) {
|
||||
//TokenizeError("file is too short",0);
|
||||
}
|
||||
|
||||
if (strncmp(input, "Kaydara FBX Binary", 18)) {
|
||||
TokenizeError("magic bytes not found", 0);
|
||||
}
|
||||
|
||||
const char *cursor = input + 18;
|
||||
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
||||
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
||||
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
||||
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
||||
/*Result ignored*/ ReadByte(input, cursor, input + length);
|
||||
const uint32_t version = ReadWord(input, cursor, input + length);
|
||||
print_verbose("FBX Version: " + itos(version));
|
||||
//ASSIMP_LOG_DEBUG_F("FBX version: ", version);
|
||||
const bool is64bits = version >= 7500;
|
||||
const char *end = input + length;
|
||||
while (cursor < end) {
|
||||
if (!ReadScope(output_tokens, input, cursor, input + length, is64bits, corrupt)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace FBXDocParser
|
@ -1,110 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXCommon.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXCommon.h
|
||||
* Some useful constants and enums for dealing with FBX files.
|
||||
*/
|
||||
#ifndef FBX_COMMON_H
|
||||
#define FBX_COMMON_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace FBXDocParser {
|
||||
const std::string NULL_RECORD = { // 13 null bytes
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
|
||||
}; // who knows why
|
||||
const std::string SEPARATOR = { '\x00', '\x01' }; // for use inside strings
|
||||
const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import
|
||||
const int64_t SECOND = 46186158000; // FBX's kTime unit
|
||||
|
||||
// rotation order. We'll probably use EulerXYZ for everything
|
||||
enum RotOrder {
|
||||
RotOrder_EulerXYZ = 0,
|
||||
RotOrder_EulerXZY,
|
||||
RotOrder_EulerYZX,
|
||||
RotOrder_EulerYXZ,
|
||||
RotOrder_EulerZXY,
|
||||
RotOrder_EulerZYX,
|
||||
|
||||
RotOrder_SphericXYZ,
|
||||
|
||||
RotOrder_MAX // end-of-enum sentinel
|
||||
};
|
||||
|
||||
enum TransformInheritance {
|
||||
Transform_RrSs = 0,
|
||||
Transform_RSrs = 1,
|
||||
Transform_Rrs = 2,
|
||||
TransformInheritance_MAX // end-of-enum sentinel
|
||||
};
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_COMMON_H
|
@ -1,271 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXDeformer.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXNoteAttribute.cpp
|
||||
* @brief Assimp::FBX::NodeAttribute (and subclasses) implementation
|
||||
*/
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXMeshGeometry.h"
|
||||
#include "FBXParser.h"
|
||||
#include "core/math/math_funcs.h"
|
||||
#include "core/math/transform_3d.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Deformer::Deformer(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name) {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Deformer::~Deformer() {
|
||||
}
|
||||
|
||||
Constraint::Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name) {
|
||||
}
|
||||
|
||||
Constraint::~Constraint() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Cluster::Cluster(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Deformer(id, element, doc, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
// for( auto element : sc.Elements())
|
||||
// {
|
||||
// std::cout << "cluster element: " << element.first << std::endl;
|
||||
// }
|
||||
//
|
||||
// element: Indexes
|
||||
// element: Transform
|
||||
// element: TransformAssociateModel
|
||||
// element: TransformLink
|
||||
// element: UserData
|
||||
// element: Version
|
||||
// element: Weights
|
||||
|
||||
const ElementPtr Indexes = sc->GetElement("Indexes");
|
||||
const ElementPtr Weights = sc->GetElement("Weights");
|
||||
|
||||
const ElementPtr TransformAssociateModel = sc->GetElement("TransformAssociateModel");
|
||||
if (TransformAssociateModel != nullptr) {
|
||||
//Transform t = ReadMatrix(*TransformAssociateModel);
|
||||
link_mode = SkinLinkMode_Additive;
|
||||
valid_transformAssociateModel = true;
|
||||
} else {
|
||||
link_mode = SkinLinkMode_Normalized;
|
||||
valid_transformAssociateModel = false;
|
||||
}
|
||||
|
||||
const ElementPtr Transform = GetRequiredElement(sc, "Transform", element);
|
||||
const ElementPtr TransformLink = GetRequiredElement(sc, "TransformLink", element);
|
||||
|
||||
// todo: check if we need this
|
||||
//const Element& TransformAssociateModel = GetRequiredElement(sc, "TransformAssociateModel", &element);
|
||||
|
||||
transform = ReadMatrix(Transform);
|
||||
transformLink = ReadMatrix(TransformLink);
|
||||
|
||||
// it is actually possible that there be Deformer's with no weights
|
||||
if (!!Indexes != !!Weights) {
|
||||
DOMError("either Indexes or Weights are missing from Cluster", element);
|
||||
}
|
||||
|
||||
if (Indexes) {
|
||||
ParseVectorDataArray(indices, Indexes);
|
||||
ParseVectorDataArray(weights, Weights);
|
||||
}
|
||||
|
||||
if (indices.size() != weights.size()) {
|
||||
DOMError("sizes of index and weight array don't match up", element);
|
||||
}
|
||||
|
||||
// read assigned node
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Model");
|
||||
for (const Connection *con : conns) {
|
||||
const Model *mod = ProcessSimpleConnection<Model>(*con, false, "Model -> Cluster", element);
|
||||
if (mod) {
|
||||
node = mod;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
DOMError("failed to read target Node for Cluster", element);
|
||||
node = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Cluster::~Cluster() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Skin::Skin(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Deformer(id, element, doc, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
// keep this it is used for debugging and any FBX format changes
|
||||
// for (auto element : sc.Elements()) {
|
||||
// std::cout << "skin element: " << element.first << std::endl;
|
||||
// }
|
||||
|
||||
const ElementPtr Link_DeformAcuracy = sc->GetElement("Link_DeformAcuracy");
|
||||
if (Link_DeformAcuracy) {
|
||||
accuracy = ParseTokenAsFloat(GetRequiredToken(Link_DeformAcuracy, 0));
|
||||
}
|
||||
|
||||
const ElementPtr SkinType = sc->GetElement("SkinningType");
|
||||
|
||||
if (SkinType) {
|
||||
std::string skin_type = ParseTokenAsString(GetRequiredToken(SkinType, 0));
|
||||
|
||||
if (skin_type == "Linear") {
|
||||
skinType = Skin_Linear;
|
||||
} else if (skin_type == "Rigid") {
|
||||
skinType = Skin_Rigid;
|
||||
} else if (skin_type == "DualQuaternion") {
|
||||
skinType = Skin_DualQuaternion;
|
||||
} else if (skin_type == "Blend") {
|
||||
skinType = Skin_Blend;
|
||||
} else {
|
||||
print_error("[doc:skin] could not find valid skin type: " + String(skin_type.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
// resolve assigned clusters
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
|
||||
|
||||
//
|
||||
|
||||
clusters.reserve(conns.size());
|
||||
for (const Connection *con : conns) {
|
||||
const Cluster *cluster = ProcessSimpleConnection<Cluster>(*con, false, "Cluster -> Skin", element);
|
||||
if (cluster) {
|
||||
clusters.push_back(cluster);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Skin::~Skin() {
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlendShape::BlendShape(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Deformer(id, element, doc, name) {
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
|
||||
blendShapeChannels.reserve(conns.size());
|
||||
for (const Connection *con : conns) {
|
||||
const BlendShapeChannel *bspc = ProcessSimpleConnection<BlendShapeChannel>(*con, false, "BlendShapeChannel -> BlendShape", element);
|
||||
if (bspc) {
|
||||
blendShapeChannels.push_back(bspc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlendShape::~BlendShape() {
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlendShapeChannel::BlendShapeChannel(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Deformer(id, element, doc, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
const ElementPtr DeformPercent = sc->GetElement("DeformPercent");
|
||||
if (DeformPercent) {
|
||||
percent = ParseTokenAsFloat(GetRequiredToken(DeformPercent, 0));
|
||||
}
|
||||
const ElementPtr FullWeights = sc->GetElement("FullWeights");
|
||||
if (FullWeights) {
|
||||
ParseVectorDataArray(fullWeights, FullWeights);
|
||||
}
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Geometry");
|
||||
shapeGeometries.reserve(conns.size());
|
||||
for (const Connection *con : conns) {
|
||||
const ShapeGeometry *const sg = ProcessSimpleConnection<ShapeGeometry>(*con, false, "Shape -> BlendShapeChannel", element);
|
||||
if (sg) {
|
||||
shapeGeometries.push_back(sg);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlendShapeChannel::~BlendShapeChannel() {
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
} // namespace FBXDocParser
|
@ -1,636 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXDocument.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the*
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXDocument.cpp
|
||||
* @brief Implementation of the FBX DOM classes
|
||||
*/
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXImportSettings.h"
|
||||
#include "FBXMeshGeometry.h"
|
||||
#include "FBXParser.h"
|
||||
#include "FBXProperties.h"
|
||||
#include "FBXUtil.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject::LazyObject(uint64_t id, const ElementPtr element, const Document &doc) :
|
||||
doc(doc), element(element), id(id) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject::~LazyObject() {
|
||||
object.reset();
|
||||
}
|
||||
|
||||
ObjectPtr LazyObject::LoadObject() {
|
||||
if (IsBeingConstructed() || FailedToConstruct()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (object) {
|
||||
return object.get();
|
||||
}
|
||||
|
||||
TokenPtr key = element->KeyToken();
|
||||
ERR_FAIL_COND_V(!key, nullptr);
|
||||
const TokenList &tokens = element->Tokens();
|
||||
|
||||
if (tokens.size() < 3) {
|
||||
//DOMError("expected at least 3 tokens: id, name and class tag",&element);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *err = nullptr;
|
||||
std::string name = ParseTokenAsString(tokens[1], err);
|
||||
if (err) {
|
||||
DOMError(err, element);
|
||||
}
|
||||
|
||||
// small fix for binary reading: binary fbx files don't use
|
||||
// prefixes such as Model:: in front of their names. The
|
||||
// loading code expects this at many places, though!
|
||||
// so convert the binary representation (a 0x0001) to the
|
||||
// double colon notation.
|
||||
if (tokens[1]->IsBinary()) {
|
||||
for (size_t i = 0; i < name.length(); ++i) {
|
||||
if (name[i] == 0x0 && name[i + 1] == 0x1) {
|
||||
name = name.substr(i + 2) + "::" + name.substr(0, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::string classtag = ParseTokenAsString(tokens[2], err);
|
||||
if (err) {
|
||||
DOMError(err, element);
|
||||
}
|
||||
|
||||
// prevent recursive calls
|
||||
flags |= BEING_CONSTRUCTED;
|
||||
|
||||
// this needs to be relatively fast since it happens a lot,
|
||||
// so avoid constructing strings all the time.
|
||||
const char *obtype = key->begin();
|
||||
const size_t length = static_cast<size_t>(key->end() - key->begin());
|
||||
|
||||
if (!strncmp(obtype, "Pose", length)) {
|
||||
object.reset(new FbxPose(id, element, doc, name));
|
||||
} else if (!strncmp(obtype, "Geometry", length)) {
|
||||
if (!strcmp(classtag.c_str(), "Mesh")) {
|
||||
object.reset(new MeshGeometry(id, element, name, doc));
|
||||
}
|
||||
if (!strcmp(classtag.c_str(), "Shape")) {
|
||||
object.reset(new ShapeGeometry(id, element, name, doc));
|
||||
}
|
||||
if (!strcmp(classtag.c_str(), "Line")) {
|
||||
object.reset(new LineGeometry(id, element, name, doc));
|
||||
}
|
||||
} else if (!strncmp(obtype, "NodeAttribute", length)) {
|
||||
if (!strcmp(classtag.c_str(), "Camera")) {
|
||||
object.reset(new Camera(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "CameraSwitcher")) {
|
||||
object.reset(new CameraSwitcher(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "Light")) {
|
||||
object.reset(new Light(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "Null")) {
|
||||
object.reset(new Null(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "LimbNode")) {
|
||||
// This is an older format for bones
|
||||
// this is what blender uses I believe
|
||||
object.reset(new LimbNode(id, element, doc, name));
|
||||
}
|
||||
} else if (!strncmp(obtype, "Constraint", length)) {
|
||||
object.reset(new Constraint(id, element, doc, name));
|
||||
} else if (!strncmp(obtype, "Deformer", length)) {
|
||||
if (!strcmp(classtag.c_str(), "Cluster")) {
|
||||
object.reset(new Cluster(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "Skin")) {
|
||||
object.reset(new Skin(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "BlendShape")) {
|
||||
object.reset(new BlendShape(id, element, doc, name));
|
||||
} else if (!strcmp(classtag.c_str(), "BlendShapeChannel")) {
|
||||
object.reset(new BlendShapeChannel(id, element, doc, name));
|
||||
}
|
||||
} else if (!strncmp(obtype, "Model", length)) {
|
||||
// Model is normal node
|
||||
|
||||
// LimbNode model is a 'bone' node.
|
||||
if (!strcmp(classtag.c_str(), "LimbNode")) {
|
||||
object.reset(new ModelLimbNode(id, element, doc, name));
|
||||
|
||||
} else if (strcmp(classtag.c_str(), "IKEffector") && strcmp(classtag.c_str(), "FKEffector")) {
|
||||
// FK and IK effectors are not supported.
|
||||
object.reset(new Model(id, element, doc, name));
|
||||
}
|
||||
} else if (!strncmp(obtype, "Material", length)) {
|
||||
object.reset(new Material(id, element, doc, name));
|
||||
} else if (!strncmp(obtype, "Texture", length)) {
|
||||
object.reset(new Texture(id, element, doc, name));
|
||||
} else if (!strncmp(obtype, "LayeredTexture", length)) {
|
||||
object.reset(new LayeredTexture(id, element, doc, name));
|
||||
} else if (!strncmp(obtype, "Video", length)) {
|
||||
object.reset(new Video(id, element, doc, name));
|
||||
} else if (!strncmp(obtype, "AnimationStack", length)) {
|
||||
object.reset(new AnimationStack(id, element, name, doc));
|
||||
} else if (!strncmp(obtype, "AnimationLayer", length)) {
|
||||
object.reset(new AnimationLayer(id, element, name, doc));
|
||||
} else if (!strncmp(obtype, "AnimationCurve", length)) {
|
||||
object.reset(new AnimationCurve(id, element, name, doc));
|
||||
} else if (!strncmp(obtype, "AnimationCurveNode", length)) {
|
||||
object.reset(new AnimationCurveNode(id, element, name, doc));
|
||||
} else {
|
||||
ERR_FAIL_V_MSG(nullptr, "FBX contains unsupported object: " + String(obtype));
|
||||
}
|
||||
|
||||
flags &= ~BEING_CONSTRUCTED;
|
||||
|
||||
return object.get();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object::Object(uint64_t id, const ElementPtr element, const std::string &name) :
|
||||
PropertyTable(element), element(element), name(name), id(id) {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object::~Object() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
FileGlobalSettings::FileGlobalSettings(const Document &doc) :
|
||||
PropertyTable(), doc(doc) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
FileGlobalSettings::~FileGlobalSettings() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Document::Document(const Parser &parser, const ImportSettings &settings) :
|
||||
settings(settings), parser(parser) {
|
||||
// Cannot use array default initialization syntax because vc8 fails on it
|
||||
for (unsigned int &timeStamp : creationTimeStamp) {
|
||||
timeStamp = 0;
|
||||
}
|
||||
|
||||
// we must check if we can read the header version safely, if its outdated then drop it.
|
||||
if (ReadHeader()) {
|
||||
SafeToImport = true;
|
||||
ReadPropertyTemplates();
|
||||
|
||||
ReadGlobalSettings();
|
||||
|
||||
// This order is important, connections need parsed objects to check
|
||||
// whether connections are ok or not. Objects may not be evaluated yet,
|
||||
// though, since this may require valid connections.
|
||||
ReadObjects();
|
||||
ReadConnections();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Document::~Document() {
|
||||
for (PropertyTemplateMap::value_type v : templates) {
|
||||
delete v.second;
|
||||
}
|
||||
|
||||
for (ObjectMap::value_type &v : objects) {
|
||||
delete v.second;
|
||||
}
|
||||
|
||||
for (ConnectionMap::value_type &v : src_connections) {
|
||||
delete v.second;
|
||||
}
|
||||
|
||||
// clear globals import pointer
|
||||
globals.reset();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static const unsigned int LowerSupportedVersion = 7100;
|
||||
static const unsigned int UpperSupportedVersion = 7700;
|
||||
|
||||
bool Document::ReadHeader() {
|
||||
// Read ID objects from "Objects" section
|
||||
ScopePtr sc = parser.GetRootScope();
|
||||
ElementPtr ehead = sc->GetElement("FBXHeaderExtension");
|
||||
if (!ehead || !ehead->Compound()) {
|
||||
DOMError("no FBXHeaderExtension dictionary found");
|
||||
}
|
||||
|
||||
if (parser.IsCorrupt()) {
|
||||
DOMError("File is corrupt");
|
||||
return false;
|
||||
}
|
||||
|
||||
const ScopePtr shead = ehead->Compound();
|
||||
fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead, "FBXVersion", ehead), 0));
|
||||
|
||||
// While we may have some success with newer files, we don't support
|
||||
// the older 6.n fbx format
|
||||
if (fbxVersion < LowerSupportedVersion) {
|
||||
DOMWarning("unsupported, old format version, FBX 2015-2020, you must re-export in a more modern version of your original modelling application");
|
||||
return false;
|
||||
}
|
||||
if (fbxVersion > UpperSupportedVersion) {
|
||||
DOMWarning("unsupported, newer format version, supported are only FBX 2015, up to FBX 2020"
|
||||
" trying to read it nevertheless");
|
||||
}
|
||||
|
||||
const ElementPtr ecreator = shead->GetElement("Creator");
|
||||
if (ecreator) {
|
||||
creator = ParseTokenAsString(GetRequiredToken(ecreator, 0));
|
||||
}
|
||||
|
||||
// Scene Info
|
||||
const ElementPtr scene_info = shead->GetElement("SceneInfo");
|
||||
|
||||
if (scene_info) {
|
||||
metadata_properties.Setup(scene_info);
|
||||
}
|
||||
|
||||
const ElementPtr etimestamp = shead->GetElement("CreationTimeStamp");
|
||||
if (etimestamp && etimestamp->Compound()) {
|
||||
const ScopePtr stimestamp = etimestamp->Compound();
|
||||
creationTimeStamp[0] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Year"), 0));
|
||||
creationTimeStamp[1] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Month"), 0));
|
||||
creationTimeStamp[2] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Day"), 0));
|
||||
creationTimeStamp[3] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Hour"), 0));
|
||||
creationTimeStamp[4] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Minute"), 0));
|
||||
creationTimeStamp[5] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Second"), 0));
|
||||
creationTimeStamp[6] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp, "Millisecond"), 0));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadGlobalSettings() {
|
||||
ERR_FAIL_COND_MSG(globals != nullptr, "Global settings is already setup this is a serious error and should be reported");
|
||||
|
||||
globals = std::make_shared<FileGlobalSettings>(*this);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadObjects() {
|
||||
// read ID objects from "Objects" section
|
||||
const ScopePtr sc = parser.GetRootScope();
|
||||
const ElementPtr eobjects = sc->GetElement("Objects");
|
||||
if (!eobjects || !eobjects->Compound()) {
|
||||
DOMError("no Objects dictionary found");
|
||||
}
|
||||
|
||||
// add a dummy entry to represent the Model::RootNode object (id 0),
|
||||
// which is only indirectly defined in the input file
|
||||
objects[0] = new LazyObject(0L, eobjects, *this);
|
||||
|
||||
const ScopePtr sobjects = eobjects->Compound();
|
||||
for (const ElementMap::value_type &iter : sobjects->Elements()) {
|
||||
// extract ID
|
||||
const TokenList &tok = iter.second->Tokens();
|
||||
|
||||
if (tok.empty()) {
|
||||
DOMError("expected ID after object key", iter.second);
|
||||
}
|
||||
|
||||
const char *err;
|
||||
const uint64_t id = ParseTokenAsID(tok[0], err);
|
||||
if (err) {
|
||||
DOMError(err, iter.second);
|
||||
}
|
||||
|
||||
// id=0 is normally implicit
|
||||
if (id == 0L) {
|
||||
DOMError("encountered object with implicitly defined id 0", iter.second);
|
||||
}
|
||||
|
||||
if (objects.find(id) != objects.end()) {
|
||||
DOMWarning("encountered duplicate object id, ignoring first occurrence", iter.second);
|
||||
}
|
||||
|
||||
objects[id] = new LazyObject(id, iter.second, *this);
|
||||
|
||||
// grab all animation stacks upfront since there is no listing of them
|
||||
if (!strcmp(iter.first.c_str(), "AnimationStack")) {
|
||||
animationStacks.push_back(id);
|
||||
} else if (!strcmp(iter.first.c_str(), "Constraint")) {
|
||||
constraints.push_back(id);
|
||||
} else if (!strcmp(iter.first.c_str(), "Pose")) {
|
||||
bind_poses.push_back(id);
|
||||
} else if (!strcmp(iter.first.c_str(), "Material")) {
|
||||
materials.push_back(id);
|
||||
} else if (!strcmp(iter.first.c_str(), "Deformer")) {
|
||||
TokenPtr key = iter.second->KeyToken();
|
||||
ERR_CONTINUE_MSG(!key, "[parser bug] invalid token key for deformer");
|
||||
const TokenList &tokens = iter.second->Tokens();
|
||||
const std::string class_tag = ParseTokenAsString(tokens[2], err);
|
||||
|
||||
if (err) {
|
||||
DOMError(err, iter.second);
|
||||
}
|
||||
|
||||
if (class_tag == "Skin") {
|
||||
//print_verbose("registered skin:" + itos(id));
|
||||
skins.push_back(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadPropertyTemplates() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadConnections() {
|
||||
const ScopePtr sc = parser.GetRootScope();
|
||||
|
||||
// read property templates from "Definitions" section
|
||||
const ElementPtr econns = sc->GetElement("Connections");
|
||||
if (!econns || !econns->Compound()) {
|
||||
DOMError("no Connections dictionary found");
|
||||
}
|
||||
|
||||
uint64_t insertionOrder = 0l;
|
||||
const ScopePtr sconns = econns->Compound();
|
||||
const ElementCollection conns = sconns->GetCollection("C");
|
||||
for (ElementMap::const_iterator it = conns.first; it != conns.second; ++it) {
|
||||
const ElementPtr el = (*it).second;
|
||||
const std::string &type = ParseTokenAsString(GetRequiredToken(el, 0));
|
||||
|
||||
// PP = property-property connection, ignored for now
|
||||
// (tokens: "PP", ID1, "Property1", ID2, "Property2")
|
||||
if (type == "PP") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint64_t src = ParseTokenAsID(GetRequiredToken(el, 1));
|
||||
const uint64_t dest = ParseTokenAsID(GetRequiredToken(el, 2));
|
||||
|
||||
// OO = object-object connection
|
||||
// OP = object-property connection, in which case the destination property follows the object ID
|
||||
const std::string &prop = (type == "OP" ? ParseTokenAsString(GetRequiredToken(el, 3)) : "");
|
||||
|
||||
if (objects.find(src) == objects.end()) {
|
||||
DOMWarning("source object for connection does not exist", el);
|
||||
continue;
|
||||
}
|
||||
|
||||
// dest may be 0 (root node) but we added a dummy object before
|
||||
if (objects.find(dest) == objects.end()) {
|
||||
DOMWarning("destination object for connection does not exist", el);
|
||||
continue;
|
||||
}
|
||||
|
||||
// add new connection
|
||||
const Connection *const c = new Connection(insertionOrder++, src, dest, prop, *this);
|
||||
src_connections.insert(ConnectionMap::value_type(src, c));
|
||||
dest_connections.insert(ConnectionMap::value_type(dest, c));
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<const AnimationStack *> &Document::AnimationStacks() const {
|
||||
if (!animationStacksResolved.empty() || animationStacks.empty()) {
|
||||
return animationStacksResolved;
|
||||
}
|
||||
|
||||
animationStacksResolved.reserve(animationStacks.size());
|
||||
for (uint64_t id : animationStacks) {
|
||||
LazyObject *lazy = GetObject(id);
|
||||
|
||||
// Two things happen here:
|
||||
// We cast internally an Object PTR to an Animation Stack PTR
|
||||
// We return invalid weak_ptrs for objects which are invalid
|
||||
|
||||
const AnimationStack *stack = lazy->Get<AnimationStack>();
|
||||
ERR_CONTINUE_MSG(!stack, "invalid ptr to AnimationStack - conversion failure");
|
||||
|
||||
// We push back the weak reference :) to keep things simple, as ownership is on the parser side so it won't be cleaned up.
|
||||
animationStacksResolved.push_back(stack);
|
||||
}
|
||||
|
||||
return animationStacksResolved;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject *Document::GetObject(uint64_t id) const {
|
||||
ObjectMap::const_iterator it = objects.find(id);
|
||||
return it == objects.end() ? nullptr : (*it).second;
|
||||
}
|
||||
|
||||
#define MAX_CLASSNAMES 6
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsSequenced(uint64_t id, const ConnectionMap &conns) const {
|
||||
std::vector<const Connection *> temp;
|
||||
|
||||
const std::pair<ConnectionMap::const_iterator, ConnectionMap::const_iterator> range =
|
||||
conns.equal_range(id);
|
||||
|
||||
temp.reserve(std::distance(range.first, range.second));
|
||||
for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
|
||||
temp.push_back((*it).second);
|
||||
}
|
||||
|
||||
std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
|
||||
|
||||
return temp; // NRVO should handle this
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsSequenced(uint64_t id, bool is_src,
|
||||
const ConnectionMap &conns,
|
||||
const char *const *classnames,
|
||||
size_t count) const
|
||||
|
||||
{
|
||||
size_t lengths[MAX_CLASSNAMES];
|
||||
|
||||
const size_t c = count;
|
||||
for (size_t i = 0; i < c; ++i) {
|
||||
lengths[i] = strlen(classnames[i]);
|
||||
}
|
||||
|
||||
std::vector<const Connection *> temp;
|
||||
const std::pair<ConnectionMap::const_iterator, ConnectionMap::const_iterator> range =
|
||||
conns.equal_range(id);
|
||||
|
||||
temp.reserve(std::distance(range.first, range.second));
|
||||
for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
|
||||
TokenPtr key = (is_src ? (*it).second->LazyDestinationObject() : (*it).second->LazySourceObject())->GetElement()->KeyToken();
|
||||
|
||||
const char *obtype = key->begin();
|
||||
|
||||
for (size_t i = 0; i < c; ++i) {
|
||||
//ai_assert(classnames[i]);
|
||||
if (static_cast<size_t>(std::distance(key->begin(), key->end())) == lengths[i] && !strncmp(classnames[i], obtype, lengths[i])) {
|
||||
obtype = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (obtype) {
|
||||
continue;
|
||||
}
|
||||
|
||||
temp.push_back((*it).second);
|
||||
}
|
||||
|
||||
std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
|
||||
return temp; // NRVO should handle this
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsBySourceSequenced(uint64_t source) const {
|
||||
return GetConnectionsSequenced(source, ConnectionsBySource());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsBySourceSequenced(uint64_t src, const char *classname) const {
|
||||
const char *arr[] = { classname };
|
||||
return GetConnectionsBySourceSequenced(src, arr, 1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsBySourceSequenced(uint64_t source,
|
||||
const char *const *classnames, size_t count) const {
|
||||
return GetConnectionsSequenced(source, true, ConnectionsBySource(), classnames, count);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
|
||||
const char *classname) const {
|
||||
const char *arr[] = { classname };
|
||||
return GetConnectionsByDestinationSequenced(dest, arr, 1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsByDestinationSequenced(uint64_t dest) const {
|
||||
return GetConnectionsSequenced(dest, ConnectionsByDestination());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection *> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
|
||||
const char *const *classnames, size_t count) const {
|
||||
return GetConnectionsSequenced(dest, false, ConnectionsByDestination(), classnames, count);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Connection::Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string &prop,
|
||||
const Document &doc) :
|
||||
insertionOrder(insertionOrder), prop(prop), src(src), dest(dest), doc(doc) {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Connection::~Connection() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject *Connection::LazySourceObject() const {
|
||||
LazyObject *const lazy = doc.GetObject(src);
|
||||
return lazy;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject *Connection::LazyDestinationObject() const {
|
||||
LazyObject *const lazy = doc.GetObject(dest);
|
||||
return lazy;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object *Connection::SourceObject() const {
|
||||
LazyObject *lazy = doc.GetObject(src);
|
||||
//ai_assert(lazy);
|
||||
return lazy->LoadObject();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object *Connection::DestinationObject() const {
|
||||
LazyObject *lazy = doc.GetObject(dest);
|
||||
//ai_assert(lazy);
|
||||
return lazy->LoadObject();
|
||||
}
|
||||
} // namespace FBXDocParser
|
File diff suppressed because it is too large
Load Diff
@ -1,141 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXDocumentUtil.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXDocumentUtil.cpp
|
||||
* @brief Implementation of the FBX DOM utility functions declared in FBXDocumentUtil.h
|
||||
*/
|
||||
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXParser.h"
|
||||
#include "FBXProperties.h"
|
||||
#include "FBXUtil.h"
|
||||
#include "core/string/print_string.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
namespace Util {
|
||||
|
||||
void DOMError(const std::string &message) {
|
||||
print_error("[FBX-DOM]" + String(message.c_str()));
|
||||
}
|
||||
|
||||
void DOMError(const std::string &message, const Token *token) {
|
||||
print_error("[FBX-DOM]" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
|
||||
}
|
||||
|
||||
void DOMError(const std::string &message, const std::shared_ptr<Token> token) {
|
||||
print_error("[FBX-DOM]" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
|
||||
}
|
||||
|
||||
void DOMError(const std::string &message, const Element *element /*= nullptr*/) {
|
||||
if (element) {
|
||||
DOMError(message, element->KeyToken());
|
||||
}
|
||||
print_error("[FBX-DOM] " + String(message.c_str()));
|
||||
}
|
||||
|
||||
void DOMError(const std::string &message, const std::shared_ptr<Element> element /*= nullptr*/) {
|
||||
if (element) {
|
||||
DOMError(message, element->KeyToken());
|
||||
}
|
||||
print_error("[FBX-DOM] " + String(message.c_str()));
|
||||
}
|
||||
|
||||
void DOMWarning(const std::string &message) {
|
||||
print_verbose("[FBX-DOM] warning:" + String(message.c_str()));
|
||||
}
|
||||
|
||||
void DOMWarning(const std::string &message, const Token *token) {
|
||||
print_verbose("[FBX-DOM] warning:" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
|
||||
}
|
||||
|
||||
void DOMWarning(const std::string &message, const Element *element /*= nullptr*/) {
|
||||
if (element) {
|
||||
DOMWarning(message, element->KeyToken());
|
||||
return;
|
||||
}
|
||||
print_verbose("[FBX-DOM] warning:" + String(message.c_str()));
|
||||
}
|
||||
|
||||
void DOMWarning(const std::string &message, const std::shared_ptr<Token> token) {
|
||||
print_verbose("[FBX-DOM] warning:" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
|
||||
}
|
||||
|
||||
void DOMWarning(const std::string &message, const std::shared_ptr<Element> element /*= nullptr*/) {
|
||||
if (element) {
|
||||
DOMWarning(message, element->KeyToken());
|
||||
return;
|
||||
}
|
||||
print_verbose("[FBX-DOM] warning:" + String(message.c_str()));
|
||||
}
|
||||
|
||||
} // namespace Util
|
||||
} // namespace FBXDocParser
|
@ -1,134 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXDocumentUtil.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2012, assimp team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXDocumentUtil.h
|
||||
* @brief FBX internal utilities used by the DOM reading code
|
||||
*/
|
||||
#ifndef FBX_DOCUMENT_UTIL_H
|
||||
#define FBX_DOCUMENT_UTIL_H
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
struct Token;
|
||||
struct Element;
|
||||
|
||||
namespace FBXDocParser {
|
||||
namespace Util {
|
||||
|
||||
// Parser errors
|
||||
void DOMError(const std::string &message);
|
||||
void DOMError(const std::string &message, const Token *token);
|
||||
void DOMError(const std::string &message, const Element *element);
|
||||
void DOMError(const std::string &message, const std::shared_ptr<Element> element);
|
||||
void DOMError(const std::string &message, const std::shared_ptr<Token> token);
|
||||
|
||||
// Parser warnings
|
||||
void DOMWarning(const std::string &message);
|
||||
void DOMWarning(const std::string &message, const Token *token);
|
||||
void DOMWarning(const std::string &message, const Element *element);
|
||||
void DOMWarning(const std::string &message, const std::shared_ptr<Token> token);
|
||||
void DOMWarning(const std::string &message, const std::shared_ptr<Element> element);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
const T *ProcessSimpleConnection(const Connection &con,
|
||||
bool is_object_property_conn,
|
||||
const char *name,
|
||||
const ElementPtr element,
|
||||
const char **propNameOut = nullptr) {
|
||||
if (is_object_property_conn && !con.PropertyName().length()) {
|
||||
DOMWarning("expected incoming " + std::string(name) +
|
||||
" link to be an object-object connection, ignoring",
|
||||
element);
|
||||
return nullptr;
|
||||
} else if (!is_object_property_conn && con.PropertyName().length()) {
|
||||
DOMWarning("expected incoming " + std::string(name) +
|
||||
" link to be an object-property connection, ignoring",
|
||||
element);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (is_object_property_conn && propNameOut) {
|
||||
// note: this is ok, the return value of PropertyValue() is guaranteed to
|
||||
// remain valid and unchanged as long as the document exists.
|
||||
*propNameOut = con.PropertyName().c_str();
|
||||
}
|
||||
|
||||
// Cast Object to AnimationPlayer for example using safe functions, which return nullptr etc
|
||||
Object *ob = con.SourceObject();
|
||||
ERR_FAIL_COND_V_MSG(!ob, nullptr, "Failed to load object from SourceObject ptr");
|
||||
return dynamic_cast<const T *>(ob);
|
||||
}
|
||||
} // namespace Util
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_DOCUMENT_UTIL_H
|
@ -1,162 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXImportSettings.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXImportSettings.h
|
||||
* @brief FBX importer runtime configuration
|
||||
*/
|
||||
#ifndef FBX_IMPORT_SETTINGS_H
|
||||
#define FBX_IMPORT_SETTINGS_H
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
/** FBX import settings, parts of which are publicly accessible via their corresponding AI_CONFIG constants */
|
||||
struct ImportSettings {
|
||||
/** enable strict mode:
|
||||
* - only accept fbx 2012, 2013 files
|
||||
* - on the slightest error, give up.
|
||||
*
|
||||
* Basically, strict mode means that the fbx file will actually
|
||||
* be validated.*/
|
||||
bool strictMode = true;
|
||||
|
||||
/** specifies whether all geometry layers are read and scanned for
|
||||
* usable data channels. The FBX spec indicates that many readers
|
||||
* will only read the first channel and that this is in some way
|
||||
* the recommended way- in reality, however, it happens a lot that
|
||||
* vertex data is spread among multiple layers.*/
|
||||
bool readAllLayers = true;
|
||||
|
||||
/** specifies whether all materials are read, or only those that
|
||||
* are referenced by at least one mesh. Reading all materials
|
||||
* may make FBX reading a lot slower since all objects
|
||||
* need to be processed.
|
||||
* This bit is ignored unless readMaterials=true.*/
|
||||
bool readAllMaterials = true;
|
||||
|
||||
/** import materials (true) or skip them and assign a default
|
||||
* material.*/
|
||||
bool readMaterials = true;
|
||||
|
||||
/** import embedded textures?*/
|
||||
bool readTextures = true;
|
||||
|
||||
/** import cameras?*/
|
||||
bool readCameras = true;
|
||||
|
||||
/** import light sources?*/
|
||||
bool readLights = true;
|
||||
|
||||
/** import animations (i.e. animation curves, the node
|
||||
* skeleton is always imported).*/
|
||||
bool readAnimations = true;
|
||||
|
||||
/** read bones (vertex weights and deform info).*/
|
||||
bool readWeights = true;
|
||||
|
||||
/** preserve transformation pivots and offsets. Since these can
|
||||
* not directly be represented in assimp, additional dummy
|
||||
* nodes will be generated. Note that settings this to false
|
||||
* can make animation import a lot slower.
|
||||
*
|
||||
* The naming scheme for the generated nodes is:
|
||||
* <OriginalName>_$AssimpFbx$_<TransformName>
|
||||
*
|
||||
* where <TransformName> is one of
|
||||
* RotationPivot
|
||||
* RotationOffset
|
||||
* PreRotation
|
||||
* PostRotation
|
||||
* ScalingPivot
|
||||
* ScalingOffset
|
||||
* Translation
|
||||
* Scaling
|
||||
* Rotation
|
||||
**/
|
||||
bool preservePivots = true;
|
||||
|
||||
/** do not import animation curves that specify a constant
|
||||
* values matching the corresponding node transformation.*/
|
||||
bool optimizeEmptyAnimationCurves = true;
|
||||
|
||||
/** use legacy naming for embedded textures eg: (*0, *1, *2).*/
|
||||
bool useLegacyEmbeddedTextureNaming = false;
|
||||
|
||||
/** Empty bones shall be removed.*/
|
||||
bool removeEmptyBones = true;
|
||||
|
||||
/** Set to true to perform a conversion from cm to meter after
|
||||
* the import.*/
|
||||
bool convertToMeters = false;
|
||||
};
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_IMPORT_SETTINGS_H
|
@ -1,388 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXMaterial.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXMaterial.cpp
|
||||
* @brief Assimp::FBX::Material and Assimp::FBX::Texture implementation
|
||||
*/
|
||||
|
||||
#include "ByteSwapper.h"
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXImportSettings.h"
|
||||
#include "FBXParser.h"
|
||||
#include "FBXProperties.h"
|
||||
|
||||
#include "FBXUtil.h"
|
||||
#include <algorithm> // std::transform
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Material::Material(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
const ElementPtr ShadingModel = sc->GetElement("ShadingModel");
|
||||
const ElementPtr MultiLayer = sc->GetElement("MultiLayer");
|
||||
|
||||
if (MultiLayer) {
|
||||
multilayer = !!ParseTokenAsInt(GetRequiredToken(MultiLayer, 0));
|
||||
}
|
||||
|
||||
if (ShadingModel) {
|
||||
shading = ParseTokenAsString(GetRequiredToken(ShadingModel, 0));
|
||||
} else {
|
||||
DOMWarning("shading mode not specified, assuming phong", element);
|
||||
shading = "phong";
|
||||
}
|
||||
|
||||
std::string templateName;
|
||||
|
||||
if (shading == "phong") {
|
||||
templateName = "Material.Phong";
|
||||
} else if (shading == "lambert") {
|
||||
templateName = "Material.Lambert";
|
||||
} else if (shading == "unknown") {
|
||||
templateName = "Material.StingRay";
|
||||
} else {
|
||||
DOMWarning("shading mode not recognized: " + shading, element);
|
||||
}
|
||||
|
||||
// resolve texture links
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID());
|
||||
for (const Connection *con : conns) {
|
||||
// texture link to properties, not objects
|
||||
if (!con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object *ob = con->SourceObject();
|
||||
if (!ob) {
|
||||
DOMWarning("failed to read source object for texture link, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Texture *tex = dynamic_cast<const Texture *>(ob);
|
||||
if (!tex) {
|
||||
LayeredTexture *layeredTexture = dynamic_cast<LayeredTexture *>(ob);
|
||||
|
||||
if (!layeredTexture) {
|
||||
DOMWarning("source object for texture link is not a texture or layered texture, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string &prop = con->PropertyName();
|
||||
if (layeredTextures.find(prop) != layeredTextures.end()) {
|
||||
DOMWarning("duplicate layered texture link: " + prop, element);
|
||||
}
|
||||
|
||||
layeredTextures[prop] = layeredTexture;
|
||||
layeredTexture->fillTexture(doc);
|
||||
} else {
|
||||
const std::string &prop = con->PropertyName();
|
||||
if (textures.find(prop) != textures.end()) {
|
||||
DOMWarning("duplicate texture link: " + prop, element);
|
||||
}
|
||||
|
||||
textures[prop] = tex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Material::~Material() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name), uvScaling(1.0f, 1.0f) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
const ElementPtr Type = sc->GetElement("Type");
|
||||
const ElementPtr FileName = sc->GetElement("FileName");
|
||||
const ElementPtr RelativeFilename = sc->GetElement("RelativeFilename");
|
||||
const ElementPtr ModelUVTranslation = sc->GetElement("ModelUVTranslation");
|
||||
const ElementPtr ModelUVScaling = sc->GetElement("ModelUVScaling");
|
||||
const ElementPtr Texture_Alpha_Source = sc->GetElement("Texture_Alpha_Source");
|
||||
const ElementPtr Cropping = sc->GetElement("Cropping");
|
||||
|
||||
if (Type) {
|
||||
type = ParseTokenAsString(GetRequiredToken(Type, 0));
|
||||
}
|
||||
|
||||
if (FileName) {
|
||||
fileName = ParseTokenAsString(GetRequiredToken(FileName, 0));
|
||||
}
|
||||
|
||||
if (RelativeFilename) {
|
||||
relativeFileName = ParseTokenAsString(GetRequiredToken(RelativeFilename, 0));
|
||||
}
|
||||
|
||||
if (ModelUVTranslation) {
|
||||
uvTrans = Vector2(ParseTokenAsFloat(GetRequiredToken(ModelUVTranslation, 0)),
|
||||
ParseTokenAsFloat(GetRequiredToken(ModelUVTranslation, 1)));
|
||||
}
|
||||
|
||||
if (ModelUVScaling) {
|
||||
uvScaling = Vector2(ParseTokenAsFloat(GetRequiredToken(ModelUVScaling, 0)),
|
||||
ParseTokenAsFloat(GetRequiredToken(ModelUVScaling, 1)));
|
||||
}
|
||||
|
||||
if (Cropping) {
|
||||
crop[0] = ParseTokenAsInt(GetRequiredToken(Cropping, 0));
|
||||
crop[1] = ParseTokenAsInt(GetRequiredToken(Cropping, 1));
|
||||
crop[2] = ParseTokenAsInt(GetRequiredToken(Cropping, 2));
|
||||
crop[3] = ParseTokenAsInt(GetRequiredToken(Cropping, 3));
|
||||
} else {
|
||||
// vc8 doesn't support the crop() syntax in initialization lists
|
||||
// (and vc9 WARNS about the new (i.e. compliant) behaviour).
|
||||
crop[0] = crop[1] = crop[2] = crop[3] = 0;
|
||||
}
|
||||
|
||||
if (Texture_Alpha_Source) {
|
||||
alphaSource = ParseTokenAsString(GetRequiredToken(Texture_Alpha_Source, 0));
|
||||
}
|
||||
|
||||
// 3DS Max and FBX SDK use "Scaling" and "Translation" instead of "ModelUVScaling" and "ModelUVTranslation". Use these properties if available.
|
||||
bool ok = true;
|
||||
const Vector3 &scaling = PropertyGet<Vector3>(this, "Scaling", ok);
|
||||
if (ok) {
|
||||
uvScaling.x = scaling.x;
|
||||
uvScaling.y = scaling.y;
|
||||
}
|
||||
|
||||
const Vector3 &trans = PropertyGet<Vector3>(this, "Translation", ok);
|
||||
if (ok) {
|
||||
uvTrans.x = trans.x;
|
||||
uvTrans.y = trans.y;
|
||||
}
|
||||
|
||||
// resolve video links
|
||||
if (doc.Settings().readTextures) {
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID());
|
||||
for (const Connection *con : conns) {
|
||||
const Object *const ob = con->SourceObject();
|
||||
if (!ob) {
|
||||
DOMWarning("failed to read source object for texture link, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Video *const video = dynamic_cast<const Video *>(ob);
|
||||
if (video) {
|
||||
media = video;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Texture::~Texture() {
|
||||
}
|
||||
|
||||
LayeredTexture::LayeredTexture(uint64_t id, const ElementPtr element, const Document & /*doc*/, const std::string &name) :
|
||||
Object(id, element, name), blendMode(BlendMode_Modulate), alpha(1) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
ElementPtr BlendModes = sc->GetElement("BlendModes");
|
||||
ElementPtr Alphas = sc->GetElement("Alphas");
|
||||
|
||||
if (BlendModes != nullptr) {
|
||||
blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(BlendModes, 0));
|
||||
}
|
||||
if (Alphas != nullptr) {
|
||||
alpha = ParseTokenAsFloat(GetRequiredToken(Alphas, 0));
|
||||
}
|
||||
}
|
||||
|
||||
LayeredTexture::~LayeredTexture() {
|
||||
}
|
||||
|
||||
void LayeredTexture::fillTexture(const Document &doc) {
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID());
|
||||
for (size_t i = 0; i < conns.size(); ++i) {
|
||||
const Connection *con = conns.at(i);
|
||||
|
||||
const Object *const ob = con->SourceObject();
|
||||
if (!ob) {
|
||||
DOMWarning("failed to read source object for texture link, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Texture *const tex = dynamic_cast<const Texture *>(ob);
|
||||
|
||||
textures.push_back(tex);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
|
||||
const ElementPtr Type = sc->GetElement("Type");
|
||||
// File Version 7500 Crashes if this is not checked fully.
|
||||
// As of writing this comment 7700 exists, in August 2020
|
||||
ElementPtr FileName = nullptr;
|
||||
if (HasElement(sc, "Filename")) {
|
||||
FileName = (ElementPtr)sc->GetElement("Filename");
|
||||
} else if (HasElement(sc, "FileName")) {
|
||||
FileName = (ElementPtr)sc->GetElement("FileName");
|
||||
} else {
|
||||
print_error("file has invalid video material returning...");
|
||||
return;
|
||||
}
|
||||
const ElementPtr RelativeFilename = sc->GetElement("RelativeFilename");
|
||||
const ElementPtr Content = sc->GetElement("Content");
|
||||
|
||||
if (Type) {
|
||||
type = ParseTokenAsString(GetRequiredToken(Type, 0));
|
||||
}
|
||||
|
||||
if (FileName) {
|
||||
fileName = ParseTokenAsString(GetRequiredToken(FileName, 0));
|
||||
}
|
||||
|
||||
if (RelativeFilename) {
|
||||
relativeFileName = ParseTokenAsString(GetRequiredToken(RelativeFilename, 0));
|
||||
}
|
||||
|
||||
if (Content && !Content->Tokens().empty()) {
|
||||
//this field is omitted when the embedded texture is already loaded, let's ignore if it's not found
|
||||
try {
|
||||
const Token *token = GetRequiredToken(Content, 0);
|
||||
const char *data = token->begin();
|
||||
if (!token->IsBinary()) {
|
||||
if (*data != '"') {
|
||||
DOMError("embedded content is not surrounded by quotation marks", element);
|
||||
} else {
|
||||
size_t targetLength = 0;
|
||||
const size_t numTokens = Content->Tokens().size();
|
||||
// First time compute size (it could be large like 64Gb and it is good to allocate it once)
|
||||
for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) {
|
||||
const Token *dataToken = GetRequiredToken(Content, tokenIdx);
|
||||
size_t tokenLength = dataToken->end() - dataToken->begin() - 2; // ignore double quotes
|
||||
const char *base64data = dataToken->begin() + 1;
|
||||
const size_t outLength = Util::ComputeDecodedSizeBase64(base64data, tokenLength);
|
||||
if (outLength == 0) {
|
||||
DOMError("Corrupted embedded content found", element);
|
||||
}
|
||||
targetLength += outLength;
|
||||
}
|
||||
if (targetLength == 0) {
|
||||
DOMError("Corrupted embedded content found", element);
|
||||
} else {
|
||||
content = new uint8_t[targetLength];
|
||||
contentLength = static_cast<uint64_t>(targetLength);
|
||||
size_t dst_offset = 0;
|
||||
for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) {
|
||||
const Token *dataToken = GetRequiredToken(Content, tokenIdx);
|
||||
ERR_FAIL_COND(!dataToken);
|
||||
size_t tokenLength = dataToken->end() - dataToken->begin() - 2; // ignore double quotes
|
||||
const char *base64data = dataToken->begin() + 1;
|
||||
dst_offset += Util::DecodeBase64(base64data, tokenLength, content + dst_offset, targetLength - dst_offset);
|
||||
}
|
||||
if (targetLength != dst_offset) {
|
||||
delete[] content;
|
||||
contentLength = 0;
|
||||
DOMError("Corrupted embedded content found", element);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (static_cast<size_t>(token->end() - data) < 5) {
|
||||
DOMError("binary data array is too short, need five (5) bytes for type signature and element count", element);
|
||||
} else if (*data != 'R') {
|
||||
DOMWarning("video content is not raw binary data, ignoring", element);
|
||||
} else {
|
||||
// read number of elements
|
||||
uint32_t len = 0;
|
||||
::memcpy(&len, data + 1, sizeof(len));
|
||||
AI_SWAP4(len);
|
||||
|
||||
contentLength = len;
|
||||
|
||||
content = new uint8_t[len];
|
||||
::memcpy(content, data + 5, len);
|
||||
}
|
||||
} catch (...) {
|
||||
// //we don't need the content data for contents that has already been loaded
|
||||
// ASSIMP_LOG_VERBOSE_DEBUG_F("Caught exception in FBXMaterial (likely because content was already loaded): ",
|
||||
// runtimeError.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Video::~Video() {
|
||||
if (content) {
|
||||
delete[] content;
|
||||
}
|
||||
}
|
||||
} // namespace FBXDocParser
|
@ -1,459 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXMeshGeometry.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXMeshGeometry.cpp
|
||||
* @brief Assimp::FBX::MeshGeometry implementation
|
||||
*/
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXImportSettings.h"
|
||||
#include "FBXMeshGeometry.h"
|
||||
#include "core/math/vector3.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Geometry::Geometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
|
||||
Object(id, element, name) {
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
|
||||
for (const Connection *con : conns) {
|
||||
const Skin *sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
|
||||
if (sk) {
|
||||
skin = sk;
|
||||
}
|
||||
const BlendShape *bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry",
|
||||
element);
|
||||
if (bsp) {
|
||||
blendShapes.push_back(bsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Geometry::~Geometry() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<const BlendShape *> &Geometry::get_blend_shapes() const {
|
||||
return blendShapes;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Skin *Geometry::DeformerSkin() const {
|
||||
return skin;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
MeshGeometry::MeshGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
|
||||
Geometry(id, element, name, doc) {
|
||||
print_verbose("mesh name: " + String(name.c_str()));
|
||||
|
||||
ScopePtr sc = element->Compound();
|
||||
ERR_FAIL_COND_MSG(sc == nullptr, "failed to read geometry, prevented crash");
|
||||
ERR_FAIL_COND_MSG(!HasElement(sc, "Vertices"), "Detected mesh with no vertices, didn't populate the mesh");
|
||||
|
||||
// must have Mesh elements:
|
||||
const ElementPtr Vertices = GetRequiredElement(sc, "Vertices", element);
|
||||
const ElementPtr PolygonVertexIndex = GetRequiredElement(sc, "PolygonVertexIndex", element);
|
||||
|
||||
if (HasElement(sc, "Edges")) {
|
||||
const ElementPtr element_edges = GetRequiredElement(sc, "Edges", element);
|
||||
ParseVectorDataArray(m_edges, element_edges);
|
||||
}
|
||||
|
||||
// read mesh data into arrays
|
||||
ParseVectorDataArray(m_vertices, Vertices);
|
||||
ParseVectorDataArray(m_face_indices, PolygonVertexIndex);
|
||||
|
||||
ERR_FAIL_COND_MSG(m_vertices.empty(), "mesh with no vertices in FBX file, did you mean to delete it?");
|
||||
ERR_FAIL_COND_MSG(m_face_indices.empty(), "mesh has no faces, was this intended?");
|
||||
|
||||
// Retrieve layer elements, for all of the mesh
|
||||
const ElementCollection &Layer = sc->GetCollection("Layer");
|
||||
|
||||
// Store all layers
|
||||
std::vector<std::tuple<int, std::string>> valid_layers;
|
||||
|
||||
// now read the sub mesh information from the geometry (normals, uvs, etc)
|
||||
for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) {
|
||||
const ScopePtr layer = GetRequiredScope(it->second);
|
||||
const ElementCollection &LayerElement = layer->GetCollection("LayerElement");
|
||||
for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) {
|
||||
std::string layer_name = eit->first;
|
||||
ElementPtr element_layer = eit->second;
|
||||
const ScopePtr layer_element = GetRequiredScope(element_layer);
|
||||
|
||||
// Actual usable 'type' LayerElementUV, LayerElementNormal, etc
|
||||
const ElementPtr Type = GetRequiredElement(layer_element, "Type");
|
||||
const ElementPtr TypedIndex = GetRequiredElement(layer_element, "TypedIndex");
|
||||
const std::string &type = ParseTokenAsString(GetRequiredToken(Type, 0));
|
||||
const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex, 0));
|
||||
|
||||
// we only need the layer name and the typed index.
|
||||
valid_layers.push_back(std::tuple<int, std::string>(typedIndex, type));
|
||||
}
|
||||
}
|
||||
|
||||
// get object / mesh directly from the FBX by the element ID.
|
||||
const ScopePtr top = GetRequiredScope(element);
|
||||
|
||||
// iterate over all layers for the mesh (uvs, normals, smoothing groups, colors, etc)
|
||||
for (size_t x = 0; x < valid_layers.size(); x++) {
|
||||
const int layer_id = std::get<0>(valid_layers[x]);
|
||||
const std::string &layer_type_name = std::get<1>(valid_layers[x]);
|
||||
|
||||
// Get collection of elements from the XLayerMap (example: LayerElementUV)
|
||||
// this must contain our proper elements.
|
||||
|
||||
// This is stupid, because it means we select them ALL not just the one we want.
|
||||
// but it's fine we can match by id.
|
||||
|
||||
const ElementCollection &candidates = top->GetCollection(layer_type_name);
|
||||
|
||||
ElementMap::const_iterator iter;
|
||||
for (iter = candidates.first; iter != candidates.second; ++iter) {
|
||||
const ScopePtr layer_scope = GetRequiredScope(iter->second);
|
||||
TokenPtr layer_token = GetRequiredToken(iter->second, 0);
|
||||
const int index = ParseTokenAsInt(layer_token);
|
||||
|
||||
ERR_FAIL_COND_MSG(layer_scope == nullptr, "prevented crash, layer scope is invalid");
|
||||
|
||||
if (index == layer_id) {
|
||||
const std::string &MappingInformationType = ParseTokenAsString(GetRequiredToken(
|
||||
GetRequiredElement(layer_scope, "MappingInformationType"), 0));
|
||||
|
||||
const std::string &ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
|
||||
GetRequiredElement(layer_scope, "ReferenceInformationType"), 0));
|
||||
|
||||
if (layer_type_name == "LayerElementUV") {
|
||||
if (index == 0) {
|
||||
m_uv_0 = resolve_vertex_data_array<Vector2>(layer_scope, MappingInformationType, ReferenceInformationType, "UV");
|
||||
} else if (index == 1) {
|
||||
m_uv_1 = resolve_vertex_data_array<Vector2>(layer_scope, MappingInformationType, ReferenceInformationType, "UV");
|
||||
}
|
||||
} else if (layer_type_name == "LayerElementMaterial") {
|
||||
m_material_allocation_ids = resolve_vertex_data_array<int>(layer_scope, MappingInformationType, ReferenceInformationType, "Materials");
|
||||
} else if (layer_type_name == "LayerElementNormal") {
|
||||
m_normals = resolve_vertex_data_array<Vector3>(layer_scope, MappingInformationType, ReferenceInformationType, "Normals");
|
||||
} else if (layer_type_name == "LayerElementColor") {
|
||||
m_colors = resolve_vertex_data_array<Color>(layer_scope, MappingInformationType, ReferenceInformationType, "Colors", "ColorIndex");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print_verbose("Mesh statistics \nuv_0: " + m_uv_0.debug_info() + "\nuv_1: " + m_uv_1.debug_info() + "\nvertices: " + itos(m_vertices.size()));
|
||||
|
||||
// Compose the edge of the mesh.
|
||||
// You can see how the edges are stored into the FBX here: https://gist.github.com/AndreaCatania/da81840f5aa3b2feedf189e26c5a87e6
|
||||
for (size_t i = 0; i < m_edges.size(); i += 1) {
|
||||
ERR_FAIL_INDEX_MSG((size_t)m_edges[i], m_face_indices.size(), "The edge is pointing to a weird location in the face indices. The FBX is corrupted.");
|
||||
int polygon_vertex_0 = m_face_indices[m_edges[i]];
|
||||
int polygon_vertex_1;
|
||||
if (polygon_vertex_0 < 0) {
|
||||
// The polygon_vertex_0 points to the end of a polygon, so it's
|
||||
// connected with the beginning of polygon in the edge list.
|
||||
|
||||
// Fist invert the vertex.
|
||||
polygon_vertex_0 = ~polygon_vertex_0;
|
||||
|
||||
// Search the start vertex of the polygon.
|
||||
// Iterate from the polygon_vertex_index backward till the start of
|
||||
// the polygon is found.
|
||||
ERR_FAIL_COND_MSG(m_edges[i] - 1 < 0, "The polygon is not yet started and we already need the final vertex. This FBX is corrupted.");
|
||||
bool found_it = false;
|
||||
for (int x = m_edges[i] - 1; x >= 0; x -= 1) {
|
||||
if (x == 0) {
|
||||
// This for sure is the start.
|
||||
polygon_vertex_1 = m_face_indices[x];
|
||||
found_it = true;
|
||||
break;
|
||||
} else if (m_face_indices[x] < 0) {
|
||||
// This is the end of the previous polygon, so the next is
|
||||
// the start of the polygon we need.
|
||||
polygon_vertex_1 = m_face_indices[x + 1];
|
||||
found_it = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// As the algorithm above, this check is useless. Because the first
|
||||
// ever vertex is always considered the beginning of a polygon.
|
||||
ERR_FAIL_COND_MSG(found_it == false, "Was not possible to find the first vertex of this polygon. FBX file is corrupted.");
|
||||
|
||||
} else {
|
||||
ERR_FAIL_INDEX_MSG((size_t)(m_edges[i] + 1), m_face_indices.size(), "FBX The other FBX edge seems to point to an invalid vertices. This FBX file is corrupted.");
|
||||
// Take the next vertex
|
||||
polygon_vertex_1 = m_face_indices[m_edges[i] + 1];
|
||||
}
|
||||
|
||||
if (polygon_vertex_1 < 0) {
|
||||
// We don't care if the `polygon_vertex_1` is the end of the polygon,
|
||||
// for `polygon_vertex_1` so we can just invert it.
|
||||
polygon_vertex_1 = ~polygon_vertex_1;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_MSG(polygon_vertex_0 == polygon_vertex_1, "The vertices of this edge can't be the same, Is this a point???. This FBX file is corrupted.");
|
||||
|
||||
// Just create the edge.
|
||||
edge_map.push_back({ polygon_vertex_0, polygon_vertex_1 });
|
||||
}
|
||||
}
|
||||
|
||||
MeshGeometry::~MeshGeometry() {
|
||||
// empty
|
||||
}
|
||||
|
||||
const std::vector<Vector3> &MeshGeometry::get_vertices() const {
|
||||
return m_vertices;
|
||||
}
|
||||
|
||||
const std::vector<MeshGeometry::Edge> &MeshGeometry::get_edge_map() const {
|
||||
return edge_map;
|
||||
}
|
||||
|
||||
const std::vector<int> &MeshGeometry::get_polygon_indices() const {
|
||||
return m_face_indices;
|
||||
}
|
||||
|
||||
const std::vector<int> &MeshGeometry::get_edges() const {
|
||||
return m_edges;
|
||||
}
|
||||
|
||||
const MeshGeometry::MappingData<Vector3> &MeshGeometry::get_normals() const {
|
||||
return m_normals;
|
||||
}
|
||||
|
||||
const MeshGeometry::MappingData<Vector2> &MeshGeometry::get_uv_0() const {
|
||||
//print_verbose("get uv_0 " + m_uv_0.debug_info() );
|
||||
return m_uv_0;
|
||||
}
|
||||
|
||||
const MeshGeometry::MappingData<Vector2> &MeshGeometry::get_uv_1() const {
|
||||
//print_verbose("get uv_1 " + m_uv_1.debug_info() );
|
||||
return m_uv_1;
|
||||
}
|
||||
|
||||
const MeshGeometry::MappingData<Color> &MeshGeometry::get_colors() const {
|
||||
return m_colors;
|
||||
}
|
||||
|
||||
const MeshGeometry::MappingData<int> &MeshGeometry::get_material_allocation_id() const {
|
||||
return m_material_allocation_ids;
|
||||
}
|
||||
|
||||
int MeshGeometry::get_edge_id(const std::vector<Edge> &p_map, int p_vertex_a, int p_vertex_b) {
|
||||
for (size_t i = 0; i < p_map.size(); i += 1) {
|
||||
if ((p_map[i].vertex_0 == p_vertex_a && p_map[i].vertex_1 == p_vertex_b) || (p_map[i].vertex_1 == p_vertex_a && p_map[i].vertex_0 == p_vertex_b)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
MeshGeometry::Edge MeshGeometry::get_edge(const std::vector<Edge> &p_map, int p_id) {
|
||||
ERR_FAIL_INDEX_V_MSG((size_t)p_id, p_map.size(), Edge({ -1, -1 }), "ID not found.");
|
||||
return p_map[p_id];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
MeshGeometry::MappingData<T> MeshGeometry::resolve_vertex_data_array(
|
||||
const ScopePtr source,
|
||||
const std::string &MappingInformationType,
|
||||
const std::string &ReferenceInformationType,
|
||||
const std::string &dataElementName,
|
||||
const std::string &indexOverride) {
|
||||
ERR_FAIL_COND_V_MSG(source == nullptr, MappingData<T>(), "Invalid scope operator preventing memory corruption");
|
||||
|
||||
// UVIndex, MaterialIndex, NormalIndex, etc..
|
||||
std::string indexDataElementName;
|
||||
|
||||
if (!indexOverride.empty()) {
|
||||
// Colors should become ColorIndex
|
||||
indexDataElementName = indexOverride;
|
||||
} else {
|
||||
// Some indexes will exist.
|
||||
indexDataElementName = dataElementName + "Index";
|
||||
}
|
||||
|
||||
// goal: expand everything to be per vertex
|
||||
|
||||
ReferenceType l_ref_type = ReferenceType::direct;
|
||||
|
||||
// Read the reference type into the enumeration
|
||||
if (ReferenceInformationType == "IndexToDirect") {
|
||||
l_ref_type = ReferenceType::index_to_direct;
|
||||
} else if (ReferenceInformationType == "Index") {
|
||||
// set non legacy index to direct mapping
|
||||
l_ref_type = ReferenceType::index;
|
||||
} else if (ReferenceInformationType == "Direct") {
|
||||
l_ref_type = ReferenceType::direct;
|
||||
} else {
|
||||
ERR_FAIL_V_MSG(MappingData<T>(), "invalid reference type has the FBX format changed?");
|
||||
}
|
||||
|
||||
MapType l_map_type = MapType::none;
|
||||
|
||||
if (MappingInformationType == "None") {
|
||||
l_map_type = MapType::none;
|
||||
} else if (MappingInformationType == "ByVertice") {
|
||||
l_map_type = MapType::vertex;
|
||||
} else if (MappingInformationType == "ByPolygonVertex") {
|
||||
l_map_type = MapType::polygon_vertex;
|
||||
} else if (MappingInformationType == "ByPolygon") {
|
||||
l_map_type = MapType::polygon;
|
||||
} else if (MappingInformationType == "ByEdge") {
|
||||
l_map_type = MapType::edge;
|
||||
} else if (MappingInformationType == "AllSame") {
|
||||
l_map_type = MapType::all_the_same;
|
||||
} else {
|
||||
print_error("invalid mapping type: " + String(MappingInformationType.c_str()));
|
||||
}
|
||||
|
||||
// create mapping data
|
||||
MeshGeometry::MappingData<T> tempData;
|
||||
tempData.map_type = l_map_type;
|
||||
tempData.ref_type = l_ref_type;
|
||||
|
||||
// parse data into array
|
||||
ParseVectorDataArray(tempData.data, GetRequiredElement(source, dataElementName));
|
||||
|
||||
// index array won't always exist
|
||||
const ElementPtr element = GetOptionalElement(source, indexDataElementName);
|
||||
if (element) {
|
||||
ParseVectorDataArray(tempData.index, element);
|
||||
}
|
||||
|
||||
return tempData;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ShapeGeometry::ShapeGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
|
||||
Geometry(id, element, name, doc) {
|
||||
const ScopePtr sc = element->Compound();
|
||||
if (nullptr == sc) {
|
||||
DOMError("failed to read Geometry object (class: Shape), no data scope found");
|
||||
}
|
||||
const ElementPtr Indexes = GetRequiredElement(sc, "Indexes", element);
|
||||
const ElementPtr Normals = GetRequiredElement(sc, "Normals", element);
|
||||
const ElementPtr Vertices = GetRequiredElement(sc, "Vertices", element);
|
||||
ParseVectorDataArray(m_indices, Indexes);
|
||||
ParseVectorDataArray(m_vertices, Vertices);
|
||||
ParseVectorDataArray(m_normals, Normals);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ShapeGeometry::~ShapeGeometry() {
|
||||
// empty
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<Vector3> &ShapeGeometry::GetVertices() const {
|
||||
return m_vertices;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<Vector3> &ShapeGeometry::GetNormals() const {
|
||||
return m_normals;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<unsigned int> &ShapeGeometry::GetIndices() const {
|
||||
return m_indices;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LineGeometry::LineGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
|
||||
Geometry(id, element, name, doc) {
|
||||
const ScopePtr sc = element->Compound();
|
||||
if (!sc) {
|
||||
DOMError("failed to read Geometry object (class: Line), no data scope found");
|
||||
}
|
||||
const ElementPtr Points = GetRequiredElement(sc, "Points", element);
|
||||
const ElementPtr PointsIndex = GetRequiredElement(sc, "PointsIndex", element);
|
||||
ParseVectorDataArray(m_vertices, Points);
|
||||
ParseVectorDataArray(m_indices, PointsIndex);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LineGeometry::~LineGeometry() {
|
||||
// empty
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<Vector3> &LineGeometry::GetVertices() const {
|
||||
return m_vertices;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<int> &LineGeometry::GetIndices() const {
|
||||
return m_indices;
|
||||
}
|
||||
} // namespace FBXDocParser
|
@ -1,263 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXMeshGeometry.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef FBX_MESH_GEOMETRY_H
|
||||
#define FBX_MESH_GEOMETRY_H
|
||||
|
||||
#include "core/math/color.h"
|
||||
#include "core/math/vector2.h"
|
||||
#include "core/math/vector3.h"
|
||||
#include "core/templates/vector.h"
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXParser.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#define AI_MAX_NUMBER_OF_TEXTURECOORDS 4
|
||||
#define AI_MAX_NUMBER_OF_COLOR_SETS 8
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
/*
|
||||
* DOM base class for all kinds of FBX geometry
|
||||
*/
|
||||
class Geometry : public Object {
|
||||
public:
|
||||
Geometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
|
||||
virtual ~Geometry();
|
||||
|
||||
/** Get the Skin attached to this geometry or nullptr */
|
||||
const Skin *DeformerSkin() const;
|
||||
|
||||
const std::vector<const BlendShape *> &get_blend_shapes() const;
|
||||
|
||||
size_t get_blend_shape_count() const {
|
||||
return blendShapes.size();
|
||||
}
|
||||
|
||||
private:
|
||||
const Skin *skin = nullptr;
|
||||
std::vector<const BlendShape *> blendShapes;
|
||||
};
|
||||
|
||||
typedef std::vector<int> MatIndexArray;
|
||||
|
||||
/// Map Geometry stores the FBX file information.
|
||||
///
|
||||
/// # FBX doc.
|
||||
/// ## Reference type declared:
|
||||
/// - Direct (directly related to the mapping information type)
|
||||
/// - IndexToDirect (Map with key value, meaning depends on the MappingInformationType)
|
||||
///
|
||||
/// ## Map Type:
|
||||
/// * None The mapping is undetermined.
|
||||
/// * ByVertex There will be one mapping coordinate for each surface control point/vertex (ControlPoint is a vertex).
|
||||
/// * If you have direct reference type vertices[x]
|
||||
/// * If you have IndexToDirect reference type the UV
|
||||
/// * ByPolygonVertex There will be one mapping coordinate for each vertex, for every polygon of which it is a part. This means that a vertex will have as many mapping coordinates as polygons of which it is a part. (Sorted by polygon, referencing vertex)
|
||||
/// * ByPolygon There can be only one mapping coordinate for the whole polygon.
|
||||
/// * One mapping per polygon polygon x has this normal x
|
||||
/// * For each vertex of the polygon then set the normal to x
|
||||
/// * ByEdge There will be one mapping coordinate for each unique edge in the mesh. This is meant to be used with smoothing layer elements. (Mapping is referencing the edge id)
|
||||
/// * AllSame There can be only one mapping coordinate for the whole surface.
|
||||
class MeshGeometry : public Geometry {
|
||||
public:
|
||||
enum class MapType {
|
||||
none = 0, // No mapping type. Stored as "None".
|
||||
vertex, // Maps per vertex. Stored as "ByVertice".
|
||||
polygon_vertex, // Maps per polygon vertex. Stored as "ByPolygonVertex".
|
||||
polygon, // Maps per polygon. Stored as "ByPolygon".
|
||||
edge, // Maps per edge. Stored as "ByEdge".
|
||||
all_the_same // Uaps to everything. Stored as "AllSame".
|
||||
};
|
||||
|
||||
enum class ReferenceType {
|
||||
direct = 0,
|
||||
index = 1,
|
||||
index_to_direct = 2
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct MappingData {
|
||||
MapType map_type = MapType::none;
|
||||
ReferenceType ref_type = ReferenceType::direct;
|
||||
std::vector<T> data;
|
||||
/// The meaning of the indices depends from the `MapType`.
|
||||
/// If `ref_type` is `direct` this map is hollow.
|
||||
std::vector<int> index;
|
||||
|
||||
String debug_info() const {
|
||||
return "indexes: " + itos(index.size()) + " data: " + itos(data.size());
|
||||
}
|
||||
};
|
||||
|
||||
struct Edge {
|
||||
int vertex_0 = 0, vertex_1 = 0;
|
||||
Edge(int v0, int v1) :
|
||||
vertex_0(v0), vertex_1(v1) {}
|
||||
Edge() {}
|
||||
};
|
||||
|
||||
public:
|
||||
MeshGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
|
||||
|
||||
virtual ~MeshGeometry();
|
||||
|
||||
const std::vector<Vector3> &get_vertices() const;
|
||||
const std::vector<Edge> &get_edge_map() const;
|
||||
const std::vector<int> &get_polygon_indices() const;
|
||||
const std::vector<int> &get_edges() const;
|
||||
const MappingData<Vector3> &get_normals() const;
|
||||
const MappingData<Vector2> &get_uv_0() const;
|
||||
const MappingData<Vector2> &get_uv_1() const;
|
||||
const MappingData<Color> &get_colors() const;
|
||||
const MappingData<int> &get_material_allocation_id() const;
|
||||
|
||||
/// Returns -1 if the vertices doesn't form an edge. Vertex order, doesn't
|
||||
// matter.
|
||||
static int get_edge_id(const std::vector<Edge> &p_map, int p_vertex_a, int p_vertex_b);
|
||||
// Returns the edge point bu that ID, or the edge with -1 vertices if the
|
||||
// id is not valid.
|
||||
static Edge get_edge(const std::vector<Edge> &p_map, int p_id);
|
||||
|
||||
private:
|
||||
// Read directly from the FBX file.
|
||||
std::vector<Vector3> m_vertices;
|
||||
std::vector<Edge> edge_map;
|
||||
std::vector<int> m_face_indices;
|
||||
std::vector<int> m_edges;
|
||||
MappingData<Vector3> m_normals;
|
||||
MappingData<Vector2> m_uv_0; // first uv coordinates
|
||||
MappingData<Vector2> m_uv_1; // second uv coordinates
|
||||
MappingData<Color> m_colors; // colors for the mesh
|
||||
MappingData<int> m_material_allocation_ids; // slot of material used
|
||||
|
||||
template <class T>
|
||||
MappingData<T> resolve_vertex_data_array(
|
||||
const ScopePtr source,
|
||||
const std::string &MappingInformationType,
|
||||
const std::string &ReferenceInformationType,
|
||||
const std::string &dataElementName,
|
||||
const std::string &indexOverride = "");
|
||||
};
|
||||
|
||||
/*
|
||||
* DOM class for FBX geometry of type "Shape"
|
||||
*/
|
||||
class ShapeGeometry : public Geometry {
|
||||
public:
|
||||
/** The class constructor */
|
||||
ShapeGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
|
||||
|
||||
/** The class destructor */
|
||||
virtual ~ShapeGeometry();
|
||||
|
||||
/** Get a list of all vertex points, non-unique*/
|
||||
const std::vector<Vector3> &GetVertices() const;
|
||||
|
||||
/** Get a list of all vertex normals or an empty array if
|
||||
* no normals are specified. */
|
||||
const std::vector<Vector3> &GetNormals() const;
|
||||
|
||||
/** Return list of vertex indices. */
|
||||
const std::vector<unsigned int> &GetIndices() const;
|
||||
|
||||
private:
|
||||
std::vector<Vector3> m_vertices;
|
||||
std::vector<Vector3> m_normals;
|
||||
std::vector<unsigned int> m_indices;
|
||||
};
|
||||
/**
|
||||
* DOM class for FBX geometry of type "Line"
|
||||
*/
|
||||
class LineGeometry : public Geometry {
|
||||
public:
|
||||
/** The class constructor */
|
||||
LineGeometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
|
||||
|
||||
/** The class destructor */
|
||||
virtual ~LineGeometry();
|
||||
|
||||
/** Get a list of all vertex points, non-unique*/
|
||||
const std::vector<Vector3> &GetVertices() const;
|
||||
|
||||
/** Return list of vertex indices. */
|
||||
const std::vector<int> &GetIndices() const;
|
||||
|
||||
private:
|
||||
std::vector<Vector3> m_vertices;
|
||||
std::vector<int> m_indices;
|
||||
};
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_MESH_GEOMETRY_H
|
@ -1,171 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXModel.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXModel.cpp
|
||||
* @brief Assimp::FBX::Model implementation
|
||||
*/
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXMeshGeometry.h"
|
||||
#include "FBXParser.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Model::Model(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name), shading("Y") {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
const ElementPtr Shading = sc->GetElement("Shading");
|
||||
const ElementPtr Culling = sc->GetElement("Culling");
|
||||
|
||||
if (Shading) {
|
||||
shading = GetRequiredToken(Shading, 0)->StringContents();
|
||||
}
|
||||
|
||||
if (Culling) {
|
||||
culling = ParseTokenAsString(GetRequiredToken(Culling, 0));
|
||||
}
|
||||
|
||||
ResolveLinks(element, doc);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Model::~Model() {
|
||||
}
|
||||
|
||||
ModelLimbNode::ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Model(id, element, doc, name){};
|
||||
|
||||
ModelLimbNode::~ModelLimbNode() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Model::ResolveLinks(const ElementPtr element, const Document &doc) {
|
||||
const char *const arr[] = { "Geometry", "Material", "NodeAttribute" };
|
||||
|
||||
// resolve material
|
||||
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), arr, 3);
|
||||
|
||||
materials.reserve(conns.size());
|
||||
geometry.reserve(conns.size());
|
||||
attributes.reserve(conns.size());
|
||||
for (const Connection *con : conns) {
|
||||
// material and geometry links should be Object-Object connections
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Object *const ob = con->SourceObject();
|
||||
if (!ob) {
|
||||
//DOMWarning("failed to read source object for incoming Model link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Material *const mat = dynamic_cast<const Material *>(ob);
|
||||
if (mat) {
|
||||
materials.push_back(mat);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Geometry *const geo = dynamic_cast<const Geometry *>(ob);
|
||||
if (geo) {
|
||||
geometry.push_back(geo);
|
||||
continue;
|
||||
}
|
||||
|
||||
const NodeAttribute *const att = dynamic_cast<const NodeAttribute *>(ob);
|
||||
if (att) {
|
||||
attributes.push_back(att);
|
||||
continue;
|
||||
}
|
||||
|
||||
DOMWarning("source object for model link is neither Material, NodeAttribute nor Geometry, ignoring", element);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Model::IsNull() const {
|
||||
const std::vector<const NodeAttribute *> &attrs = GetAttributes();
|
||||
for (const NodeAttribute *att : attrs) {
|
||||
const Null *null_tag = dynamic_cast<const Null *>(att);
|
||||
if (null_tag) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace FBXDocParser
|
@ -1,174 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXNodeAttribute.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXNoteAttribute.cpp
|
||||
* @brief Assimp::FBX::NodeAttribute (and subclasses) implementation
|
||||
*/
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXParser.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace FBXDocParser {
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
NodeAttribute::NodeAttribute(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name) {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
NodeAttribute::~NodeAttribute() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CameraSwitcher::CameraSwitcher(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
NodeAttribute(id, element, doc, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
const ElementPtr CameraId = sc->GetElement("CameraId");
|
||||
const ElementPtr CameraName = sc->GetElement("CameraName");
|
||||
const ElementPtr CameraIndexName = sc->GetElement("CameraIndexName");
|
||||
|
||||
if (CameraId) {
|
||||
cameraId = ParseTokenAsInt(GetRequiredToken(CameraId, 0));
|
||||
}
|
||||
|
||||
if (CameraName) {
|
||||
cameraName = GetRequiredToken(CameraName, 0)->StringContents();
|
||||
}
|
||||
|
||||
if (CameraIndexName && CameraIndexName->Tokens().size()) {
|
||||
cameraIndexName = GetRequiredToken(CameraIndexName, 0)->StringContents();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CameraSwitcher::~CameraSwitcher() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Camera::Camera(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
NodeAttribute(id, element, doc, name) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Camera::~Camera() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Light::Light(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
NodeAttribute(id, element, doc, name) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Light::~Light() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Null::Null(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
NodeAttribute(id, element, doc, name) {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Null::~Null() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LimbNode::LimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
NodeAttribute(id, element, doc, name) {
|
||||
//std::cout << "limb node: " << name << std::endl;
|
||||
//const Scope &sc = GetRequiredScope(element);
|
||||
|
||||
//const ElementPtr const TypeFlag = sc["TypeFlags"];
|
||||
|
||||
// keep this it can dump new properties for you
|
||||
// for( auto element : sc.Elements())
|
||||
// {
|
||||
// std::cout << "limbnode element: " << element.first << std::endl;
|
||||
// }
|
||||
|
||||
// if(TypeFlag)
|
||||
// {
|
||||
// // std::cout << "type flag: " << GetRequiredToken(*TypeFlag, 0).StringContents() << std::endl;
|
||||
// }
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LimbNode::~LimbNode() {
|
||||
}
|
||||
} // namespace FBXDocParser
|
@ -1,111 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXParseTools.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_PARSE_TOOLS_H
|
||||
#define FBX_PARSE_TOOLS_H
|
||||
|
||||
#include "core/error/error_macros.h"
|
||||
#include "core/string/ustring.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <algorithm>
|
||||
#include <locale>
|
||||
|
||||
template <class char_t>
|
||||
inline bool IsNewLine(char_t c) {
|
||||
return c == '\n' || c == '\r';
|
||||
}
|
||||
template <class char_t>
|
||||
inline bool IsSpace(char_t c) {
|
||||
return (c == (char_t)' ' || c == (char_t)'\t');
|
||||
}
|
||||
|
||||
template <class char_t>
|
||||
inline bool IsSpaceOrNewLine(char_t c) {
|
||||
return IsNewLine(c) || IsSpace(c);
|
||||
}
|
||||
|
||||
template <class char_t>
|
||||
inline bool IsLineEnd(char_t c) {
|
||||
return (c == (char_t)'\r' || c == (char_t)'\n' || c == (char_t)'\0' || c == (char_t)'\f');
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
// Special version of the function, providing higher accuracy and safety
|
||||
// It is mainly used by fast_atof to prevent ugly and unwanted integer overflows.
|
||||
// ------------------------------------------------------------------------------------
|
||||
inline uint64_t strtoul10_64(const char *in, bool &errored, const char **out = nullptr, unsigned int *max_inout = nullptr) {
|
||||
unsigned int cur = 0;
|
||||
uint64_t value = 0;
|
||||
|
||||
errored = *in < '0' || *in > '9';
|
||||
ERR_FAIL_COND_V_MSG(errored, 0, "The string cannot be converted parser error");
|
||||
|
||||
for (;;) {
|
||||
if (*in < '0' || *in > '9') {
|
||||
break;
|
||||
}
|
||||
|
||||
const uint64_t new_value = (value * (uint64_t)10) + ((uint64_t)(*in - '0'));
|
||||
|
||||
// numeric overflow, we rely on you
|
||||
if (new_value < value) {
|
||||
//WARN_PRINT( "Converting the string \" " + in + " \" into a value resulted in overflow." );
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = new_value;
|
||||
|
||||
++in;
|
||||
++cur;
|
||||
|
||||
if (max_inout && *max_inout == cur) {
|
||||
if (out) { /* skip to end */
|
||||
while (*in >= '0' && *in <= '9') {
|
||||
++in;
|
||||
}
|
||||
*out = in;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
if (out) {
|
||||
*out = in;
|
||||
}
|
||||
|
||||
if (max_inout) {
|
||||
*max_inout = cur;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
#endif // FBX_PARSE_TOOLS_H
|
File diff suppressed because it is too large
Load Diff
@ -1,270 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXParser.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXParser.h
|
||||
* @brief FBX parsing code
|
||||
*/
|
||||
#ifndef FBX_PARSER_H
|
||||
#define FBX_PARSER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "core/math/color.h"
|
||||
#include "core/math/transform_3d.h"
|
||||
#include "core/math/vector2.h"
|
||||
#include "core/math/vector3.h"
|
||||
|
||||
#include "FBXTokenizer.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
class Scope;
|
||||
class Parser;
|
||||
class Element;
|
||||
|
||||
typedef Element *ElementPtr;
|
||||
typedef Scope *ScopePtr;
|
||||
|
||||
typedef std::vector<ScopePtr> ScopeList;
|
||||
typedef std::multimap<std::string, ElementPtr> ElementMap;
|
||||
typedef std::pair<ElementMap::const_iterator, ElementMap::const_iterator> ElementCollection;
|
||||
|
||||
#define new_Scope new Scope
|
||||
#define new_Element new Element
|
||||
|
||||
/** FBX data entity that consists of a key:value tuple.
|
||||
*
|
||||
* Example:
|
||||
* @verbatim
|
||||
* AnimationCurve: 23, "AnimCurve::", "" {
|
||||
* [..]
|
||||
* }
|
||||
* @endverbatim
|
||||
*
|
||||
* As can be seen in this sample, elements can contain nested #Scope
|
||||
* as their trailing member. **/
|
||||
class Element {
|
||||
public:
|
||||
Element(TokenPtr key_token, Parser &parser);
|
||||
~Element();
|
||||
|
||||
ScopePtr Compound() const {
|
||||
return compound;
|
||||
}
|
||||
|
||||
TokenPtr KeyToken() const {
|
||||
return key_token;
|
||||
}
|
||||
|
||||
const TokenList &Tokens() const {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private:
|
||||
TokenList tokens;
|
||||
ScopePtr compound = nullptr;
|
||||
std::vector<ScopePtr> compound_scope;
|
||||
TokenPtr key_token = nullptr;
|
||||
};
|
||||
|
||||
/** FBX data entity that consists of a 'scope', a collection
|
||||
* of not necessarily unique #Element instances.
|
||||
*
|
||||
* Example:
|
||||
* @verbatim
|
||||
* GlobalSettings: {
|
||||
* Version: 1000
|
||||
* Properties70:
|
||||
* [...]
|
||||
* }
|
||||
* @endverbatim */
|
||||
class Scope {
|
||||
public:
|
||||
Scope(Parser &parser, bool topLevel = false);
|
||||
~Scope();
|
||||
|
||||
ElementPtr GetElement(const std::string &index) const {
|
||||
ElementMap::const_iterator it = elements.find(index);
|
||||
return it == elements.end() ? nullptr : (*it).second;
|
||||
}
|
||||
|
||||
ElementPtr FindElementCaseInsensitive(const std::string &elementName) const {
|
||||
for (FBXDocParser::ElementMap::const_iterator element = elements.begin(); element != elements.end(); ++element) {
|
||||
if (element->first.compare(elementName)) {
|
||||
return element->second;
|
||||
}
|
||||
}
|
||||
|
||||
// nothing to reference / expired.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ElementCollection GetCollection(const std::string &index) const {
|
||||
return elements.equal_range(index);
|
||||
}
|
||||
|
||||
const ElementMap &Elements() const {
|
||||
return elements;
|
||||
}
|
||||
|
||||
private:
|
||||
ElementMap elements;
|
||||
};
|
||||
|
||||
/** FBX parsing class, takes a list of input tokens and generates a hierarchy
|
||||
* of nested #Scope instances, representing the fbx DOM.*/
|
||||
class Parser {
|
||||
public:
|
||||
/** Parse given a token list. Does not take ownership of the tokens -
|
||||
* the objects must persist during the entire parser lifetime */
|
||||
Parser(const TokenList &tokens, bool is_binary);
|
||||
~Parser();
|
||||
|
||||
ScopePtr GetRootScope() const {
|
||||
return root;
|
||||
}
|
||||
|
||||
bool IsBinary() const {
|
||||
return is_binary;
|
||||
}
|
||||
|
||||
bool IsCorrupt() const {
|
||||
return corrupt;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Scope;
|
||||
friend class Element;
|
||||
|
||||
TokenPtr AdvanceToNextToken();
|
||||
TokenPtr LastToken() const;
|
||||
TokenPtr CurrentToken() const;
|
||||
|
||||
private:
|
||||
bool corrupt = false;
|
||||
ScopeList scopes;
|
||||
const TokenList &tokens;
|
||||
|
||||
TokenPtr last = nullptr, current = nullptr;
|
||||
TokenList::const_iterator cursor;
|
||||
ScopePtr root = nullptr;
|
||||
|
||||
const bool is_binary;
|
||||
};
|
||||
|
||||
/* token parsing - this happens when building the DOM out of the parse-tree*/
|
||||
uint64_t ParseTokenAsID(const TokenPtr t, const char *&err_out);
|
||||
size_t ParseTokenAsDim(const TokenPtr t, const char *&err_out);
|
||||
float ParseTokenAsFloat(const TokenPtr t, const char *&err_out);
|
||||
int ParseTokenAsInt(const TokenPtr t, const char *&err_out);
|
||||
int64_t ParseTokenAsInt64(const TokenPtr t, const char *&err_out);
|
||||
std::string ParseTokenAsString(const TokenPtr t, const char *&err_out);
|
||||
|
||||
/* wrapper around ParseTokenAsXXX() with DOMError handling */
|
||||
uint64_t ParseTokenAsID(const TokenPtr t);
|
||||
size_t ParseTokenAsDim(const TokenPtr t);
|
||||
float ParseTokenAsFloat(const TokenPtr t);
|
||||
int ParseTokenAsInt(const TokenPtr t);
|
||||
int64_t ParseTokenAsInt64(const TokenPtr t);
|
||||
std::string ParseTokenAsString(const TokenPtr t);
|
||||
|
||||
/* read data arrays */
|
||||
void ParseVectorDataArray(std::vector<Vector3> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<Color> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<Vector2> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<int> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<float> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<float> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<unsigned int> &out, const ElementPtr el);
|
||||
void ParseVectorDataArray(std::vector<uint64_t> &out, const ElementPtr ep);
|
||||
void ParseVectorDataArray(std::vector<int64_t> &out, const ElementPtr el);
|
||||
bool HasElement(const ScopePtr sc, const std::string &index);
|
||||
|
||||
// extract a required element from a scope, abort if the element cannot be found
|
||||
ElementPtr GetRequiredElement(const ScopePtr sc, const std::string &index, const ElementPtr element = nullptr);
|
||||
ScopePtr GetRequiredScope(const ElementPtr el); // New in 2020. (less likely to destroy application)
|
||||
ScopePtr GetOptionalScope(const ElementPtr el); // New in 2021. (even LESS likely to destroy application now)
|
||||
|
||||
ElementPtr GetOptionalElement(const ScopePtr sc, const std::string &index, const ElementPtr element = nullptr);
|
||||
// extract required compound scope
|
||||
ScopePtr GetRequiredScope(const ElementPtr el);
|
||||
// get token at a particular index
|
||||
TokenPtr GetRequiredToken(const ElementPtr el, unsigned int index);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a 4x4 matrix from an array of 16 floats
|
||||
Transform3D ReadMatrix(const ElementPtr element);
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_PARSER_H
|
@ -1,104 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXPose.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXNoteAttribute.cpp
|
||||
* @brief Assimp::FBX::NodeAttribute (and subclasses) implementation
|
||||
*/
|
||||
|
||||
#include "FBXDocument.h"
|
||||
#include "FBXParser.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
class FbxPoseNode;
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
FbxPose::FbxPose(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
|
||||
Object(id, element, name) {
|
||||
const ScopePtr sc = GetRequiredScope(element);
|
||||
//const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
|
||||
|
||||
const ElementCollection &PoseNodes = sc->GetCollection("PoseNode");
|
||||
for (ElementMap::const_iterator it = PoseNodes.first; it != PoseNodes.second; ++it) {
|
||||
std::string entry_name = (*it).first;
|
||||
ElementPtr some_element = (*it).second;
|
||||
FbxPoseNode *pose_node = new FbxPoseNode(some_element, doc, entry_name);
|
||||
pose_nodes.push_back(pose_node);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
FbxPose::~FbxPose() {
|
||||
pose_nodes.clear();
|
||||
// empty
|
||||
}
|
||||
} // namespace FBXDocParser
|
@ -1,245 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXProperties.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXProperties.cpp
|
||||
* @brief Implementation of the FBX dynamic properties system
|
||||
*/
|
||||
|
||||
#include "FBXProperties.h"
|
||||
#include "FBXDocumentUtil.h"
|
||||
#include "FBXParser.h"
|
||||
#include "FBXTokenizer.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Property::Property() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Property::~Property() {
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read a typed property out of a FBX element. The return value is nullptr if the property cannot be read.
|
||||
PropertyPtr ReadTypedProperty(const ElementPtr element) {
|
||||
//ai_assert(element.KeyToken().StringContents() == "P");
|
||||
|
||||
const TokenList &tok = element->Tokens();
|
||||
//ai_assert(tok.size() >= 5);
|
||||
|
||||
const std::string &s = ParseTokenAsString(tok[1]);
|
||||
const char *const cs = s.c_str();
|
||||
if (!strcmp(cs, "KString")) {
|
||||
return new TypedProperty<std::string>(ParseTokenAsString(tok[4]));
|
||||
} else if (!strcmp(cs, "bool") || !strcmp(cs, "Bool")) {
|
||||
return new TypedProperty<bool>(ParseTokenAsInt(tok[4]) != 0);
|
||||
} else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) {
|
||||
return new TypedProperty<int>(ParseTokenAsInt(tok[4]));
|
||||
} else if (!strcmp(cs, "ULongLong")) {
|
||||
return new TypedProperty<uint64_t>(ParseTokenAsID(tok[4]));
|
||||
} else if (!strcmp(cs, "KTime")) {
|
||||
return new TypedProperty<int64_t>(ParseTokenAsInt64(tok[4]));
|
||||
} else if (!strcmp(cs, "Vector3D") ||
|
||||
!strcmp(cs, "ColorRGB") ||
|
||||
!strcmp(cs, "Vector") ||
|
||||
!strcmp(cs, "Color") ||
|
||||
!strcmp(cs, "Lcl Translation") ||
|
||||
!strcmp(cs, "Lcl Rotation") ||
|
||||
!strcmp(cs, "Lcl Scaling")) {
|
||||
return new TypedProperty<Vector3>(Vector3(
|
||||
ParseTokenAsFloat(tok[4]),
|
||||
ParseTokenAsFloat(tok[5]),
|
||||
ParseTokenAsFloat(tok[6])));
|
||||
} else if (!strcmp(cs, "double") || !strcmp(cs, "Number") || !strcmp(cs, "Float") || !strcmp(cs, "float") || !strcmp(cs, "FieldOfView") || !strcmp(cs, "UnitScaleFactor")) {
|
||||
return new TypedProperty<float>(ParseTokenAsFloat(tok[4]));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// peek into an element and check if it contains a FBX property, if so return its name.
|
||||
std::string PeekPropertyName(const Element &element) {
|
||||
//ai_assert(element.KeyToken().StringContents() == "P");
|
||||
const TokenList &tok = element.Tokens();
|
||||
if (tok.size() < 4) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return ParseTokenAsString(tok[0]);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PropertyTable::PropertyTable() {
|
||||
}
|
||||
|
||||
// Is used when dealing with FBX Objects not metadata.
|
||||
PropertyTable::PropertyTable(const ElementPtr element) :
|
||||
element(element) {
|
||||
Setup(element);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PropertyTable::~PropertyTable() {
|
||||
for (PropertyMap::value_type &v : props) {
|
||||
delete v.second;
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyTable::Setup(ElementPtr ptr) {
|
||||
const ScopePtr sc = GetRequiredScope(ptr);
|
||||
const ElementPtr Properties70 = sc->GetElement("Properties70");
|
||||
const ScopePtr scope = GetOptionalScope(Properties70);
|
||||
|
||||
// no scope, no care.
|
||||
if (!scope) {
|
||||
return; // NOTE: this is not an error this is actually a Object, without properties, here we will nullptr it.
|
||||
}
|
||||
|
||||
for (const ElementMap::value_type &v : scope->Elements()) {
|
||||
if (v.first != "P") {
|
||||
DOMWarning("expected only P elements in property table", v.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string &name = PeekPropertyName(*v.second);
|
||||
if (!name.length()) {
|
||||
DOMWarning("could not read property name", v.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
LazyPropertyMap::const_iterator it = lazyProps.find(name);
|
||||
if (it != lazyProps.end()) {
|
||||
DOMWarning("duplicate property name, will hide previous value: " + name, v.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
// since the above checks for duplicates we can be sure to insert the only match here.
|
||||
lazyProps[name] = v.second;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PropertyPtr PropertyTable::Get(const std::string &name) const {
|
||||
PropertyMap::const_iterator it = props.find(name);
|
||||
if (it == props.end()) {
|
||||
// hasn't been parsed yet?
|
||||
LazyPropertyMap::const_iterator lit = lazyProps.find(name);
|
||||
if (lit != lazyProps.end()) {
|
||||
props[name] = ReadTypedProperty(lit->second);
|
||||
it = props.find(name);
|
||||
|
||||
//ai_assert(it != props.end());
|
||||
}
|
||||
|
||||
if (it == props.end()) {
|
||||
// check property template
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
DirectPropertyMap PropertyTable::GetUnparsedProperties() const {
|
||||
DirectPropertyMap result;
|
||||
|
||||
// Loop through all the lazy properties (which is all the properties)
|
||||
for (const LazyPropertyMap::value_type &element : lazyProps) {
|
||||
// Skip parsed properties
|
||||
if (props.end() != props.find(element.first)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read the element's value.
|
||||
// Wrap the naked pointer (since the call site is required to acquire ownership)
|
||||
// std::unique_ptr from C++11 would be preferred both as a wrapper and a return value.
|
||||
Property *prop = ReadTypedProperty(element.second);
|
||||
|
||||
// Element could not be read. Skip it.
|
||||
if (!prop) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add to result
|
||||
result[element.first] = prop;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
} // namespace FBXDocParser
|
@ -1,212 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXProperties.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXProperties.h
|
||||
* @brief FBX dynamic properties
|
||||
*/
|
||||
#ifndef FBX_PROPERTIES_H
|
||||
#define FBX_PROPERTIES_H
|
||||
|
||||
#include "FBXParser.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
// Forward declarations
|
||||
class Element;
|
||||
|
||||
/** Represents a dynamic property. Type info added by deriving classes,
|
||||
* see #TypedProperty.
|
||||
Example:
|
||||
@verbatim
|
||||
P: "ShininessExponent", "double", "Number", "",0.5
|
||||
@endvebatim
|
||||
*/
|
||||
class Property {
|
||||
protected:
|
||||
Property();
|
||||
|
||||
public:
|
||||
virtual ~Property();
|
||||
|
||||
public:
|
||||
template <typename T>
|
||||
const T *As() const {
|
||||
return dynamic_cast<const T *>(this);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TypedProperty : public Property {
|
||||
public:
|
||||
explicit TypedProperty(const T &value) :
|
||||
value(value) {
|
||||
// empty
|
||||
}
|
||||
|
||||
const T &Value() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
T value;
|
||||
};
|
||||
|
||||
#define new_Property new Property
|
||||
typedef Property *PropertyPtr;
|
||||
typedef std::map<std::string, PropertyPtr> DirectPropertyMap;
|
||||
typedef std::map<std::string, PropertyPtr> PropertyMap;
|
||||
typedef std::map<std::string, ElementPtr> LazyPropertyMap;
|
||||
|
||||
/**
|
||||
* Represents a property table as can be found in the newer FBX files (Properties60, Properties70)
|
||||
*/
|
||||
class PropertyTable {
|
||||
public:
|
||||
// in-memory property table with no source element
|
||||
PropertyTable();
|
||||
PropertyTable(const ElementPtr element);
|
||||
virtual ~PropertyTable();
|
||||
|
||||
PropertyPtr Get(const std::string &name) const;
|
||||
void Setup(ElementPtr ptr);
|
||||
|
||||
// PropertyTable's need not be coupled with FBX elements so this can be NULL
|
||||
ElementPtr GetElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
PropertyMap &GetProperties() {
|
||||
return props;
|
||||
}
|
||||
|
||||
const LazyPropertyMap &GetLazyProperties() {
|
||||
return lazyProps;
|
||||
}
|
||||
|
||||
DirectPropertyMap GetUnparsedProperties() const;
|
||||
|
||||
private:
|
||||
LazyPropertyMap lazyProps;
|
||||
mutable PropertyMap props;
|
||||
ElementPtr element = nullptr;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline T PropertyGet(const PropertyTable *in, const std::string &name, const T &defaultValue) {
|
||||
PropertyPtr prop = in->Get(name);
|
||||
if (nullptr == prop) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// strong typing, no need to be lenient
|
||||
const TypedProperty<T> *const tprop = prop->As<TypedProperty<T>>();
|
||||
if (nullptr == tprop) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return tprop->Value();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline T PropertyGet(const PropertyTable *in, const std::string &name, bool &result, bool useTemplate = false) {
|
||||
PropertyPtr prop = in->Get(name);
|
||||
if (nullptr == prop) {
|
||||
if (nullptr == in) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
prop = in->Get(name);
|
||||
if (nullptr == prop) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
}
|
||||
|
||||
// strong typing, no need to be lenient
|
||||
const TypedProperty<T> *const tprop = prop->As<TypedProperty<T>>();
|
||||
if (nullptr == tprop) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
|
||||
result = true;
|
||||
return tprop->Value();
|
||||
}
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_PROPERTIES_H
|
@ -1,253 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXTokenizer.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXTokenizer.cpp
|
||||
* @brief Implementation of the FBX broadphase lexer
|
||||
*/
|
||||
|
||||
// tab width for logging columns
|
||||
#define ASSIMP_FBX_TAB_WIDTH 4
|
||||
|
||||
#include "FBXTokenizer.h"
|
||||
#include "core/string/print_string.h"
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Token::Token(const char *p_sbegin, const char *p_send, TokenType p_type, unsigned int p_line, unsigned int p_column) :
|
||||
sbegin(p_sbegin),
|
||||
send(p_send),
|
||||
type(p_type),
|
||||
line(p_line),
|
||||
column(p_column) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
contents = std::string(sbegin, static_cast<size_t>(send - sbegin));
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Token::~Token() {
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TokenizeError(const std::string &message, unsigned int line, unsigned int column) {
|
||||
print_error("[FBX-Tokenize]" + String(message.c_str()) + " " + itos(line) + ":" + itos(column));
|
||||
}
|
||||
|
||||
// process a potential data token up to 'cur', adding it to 'output_tokens'.
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ProcessDataToken(TokenList &output_tokens, const char *&start, const char *&end,
|
||||
unsigned int line,
|
||||
unsigned int column,
|
||||
TokenType type = TokenType_DATA,
|
||||
bool must_have_token = false) {
|
||||
if (start && end) {
|
||||
// sanity check:
|
||||
// tokens should have no whitespace outside quoted text and [start,end] should
|
||||
// properly delimit the valid range.
|
||||
bool in_double_quotes = false;
|
||||
for (const char *c = start; c != end + 1; ++c) {
|
||||
if (*c == '\"') {
|
||||
in_double_quotes = !in_double_quotes;
|
||||
}
|
||||
|
||||
if (!in_double_quotes && IsSpaceOrNewLine(*c)) {
|
||||
TokenizeError("unexpected whitespace in token", line, column);
|
||||
}
|
||||
}
|
||||
|
||||
if (in_double_quotes) {
|
||||
TokenizeError("non-terminated double quotes", line, column);
|
||||
}
|
||||
|
||||
output_tokens.push_back(new_Token(start, end + 1, type, line, column));
|
||||
} else if (must_have_token) {
|
||||
TokenizeError("unexpected character, expected data token", line, column);
|
||||
}
|
||||
|
||||
start = end = nullptr;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Tokenize(TokenList &output_tokens, const char *input, size_t length, bool &corrupt) {
|
||||
// line and column numbers numbers are one-based
|
||||
unsigned int line = 1;
|
||||
unsigned int column = 1;
|
||||
|
||||
bool comment = false;
|
||||
bool in_double_quotes = false;
|
||||
bool pending_data_token = false;
|
||||
|
||||
const char *token_begin = nullptr, *token_end = nullptr;
|
||||
|
||||
// input (starting string), *cur the current string, column +=
|
||||
// modified to fix strlen() and stop buffer overflow
|
||||
for (size_t x = 0; x < length; x++) {
|
||||
const char c = input[x];
|
||||
const char *cur = &input[x];
|
||||
column += (c == '\t' ? ASSIMP_FBX_TAB_WIDTH : 1);
|
||||
|
||||
if (IsLineEnd(c)) {
|
||||
comment = false;
|
||||
|
||||
column = 0;
|
||||
++line;
|
||||
}
|
||||
|
||||
if (comment) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_double_quotes) {
|
||||
if (c == '\"') {
|
||||
in_double_quotes = false;
|
||||
token_end = cur;
|
||||
|
||||
ProcessDataToken(output_tokens, token_begin, token_end, line, column);
|
||||
pending_data_token = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case '\"':
|
||||
if (token_begin) {
|
||||
TokenizeError("unexpected double-quote", line, column);
|
||||
corrupt = true;
|
||||
return;
|
||||
}
|
||||
token_begin = cur;
|
||||
in_double_quotes = true;
|
||||
continue;
|
||||
|
||||
case ';':
|
||||
ProcessDataToken(output_tokens, token_begin, token_end, line, column);
|
||||
comment = true;
|
||||
continue;
|
||||
|
||||
case '{':
|
||||
ProcessDataToken(output_tokens, token_begin, token_end, line, column);
|
||||
output_tokens.push_back(new_Token(cur, cur + 1, TokenType_OPEN_BRACKET, line, column));
|
||||
continue;
|
||||
|
||||
case '}':
|
||||
ProcessDataToken(output_tokens, token_begin, token_end, line, column);
|
||||
output_tokens.push_back(new_Token(cur, cur + 1, TokenType_CLOSE_BRACKET, line, column));
|
||||
continue;
|
||||
|
||||
case ',':
|
||||
if (pending_data_token) {
|
||||
ProcessDataToken(output_tokens, token_begin, token_end, line, column, TokenType_DATA, true);
|
||||
}
|
||||
output_tokens.push_back(new_Token(cur, cur + 1, TokenType_COMMA, line, column));
|
||||
continue;
|
||||
|
||||
case ':':
|
||||
if (pending_data_token) {
|
||||
ProcessDataToken(output_tokens, token_begin, token_end, line, column, TokenType_KEY, true);
|
||||
} else {
|
||||
TokenizeError("unexpected colon", line, column);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsSpaceOrNewLine(c)) {
|
||||
if (token_begin) {
|
||||
// peek ahead and check if the next token is a colon in which
|
||||
// case this counts as KEY token.
|
||||
TokenType type = TokenType_DATA;
|
||||
for (const char *peek = cur; *peek && IsSpaceOrNewLine(*peek); ++peek) {
|
||||
if (*peek == ':') {
|
||||
type = TokenType_KEY;
|
||||
cur = peek;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ProcessDataToken(output_tokens, token_begin, token_end, line, column, type);
|
||||
}
|
||||
|
||||
pending_data_token = false;
|
||||
} else {
|
||||
token_end = cur;
|
||||
if (!token_begin) {
|
||||
token_begin = cur;
|
||||
}
|
||||
|
||||
pending_data_token = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace FBXDocParser
|
@ -1,203 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXTokenizer.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXTokenizer.h
|
||||
* @brief FBX lexer
|
||||
*/
|
||||
#ifndef FBX_TOKENIZER_H
|
||||
#define FBX_TOKENIZER_H
|
||||
|
||||
#include "FBXParseTools.h"
|
||||
#include "core/string/ustring.h"
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace FBXDocParser {
|
||||
/** Rough classification for text FBX tokens used for constructing the
|
||||
* basic scope hierarchy. */
|
||||
enum TokenType {
|
||||
// {
|
||||
TokenType_OPEN_BRACKET = 0,
|
||||
|
||||
// }
|
||||
TokenType_CLOSE_BRACKET,
|
||||
|
||||
// '"blablubb"', '2', '*14' - very general token class,
|
||||
// further processing happens at a later stage.
|
||||
TokenType_DATA,
|
||||
|
||||
//
|
||||
TokenType_BINARY_DATA,
|
||||
|
||||
// ,
|
||||
TokenType_COMMA,
|
||||
|
||||
// blubb:
|
||||
TokenType_KEY
|
||||
};
|
||||
|
||||
/** Represents a single token in a FBX file. Tokens are
|
||||
* classified by the #TokenType enumerated types.
|
||||
*
|
||||
* Offers iterator protocol. Tokens are immutable. */
|
||||
class Token {
|
||||
private:
|
||||
static const unsigned int BINARY_MARKER = static_cast<unsigned int>(-1);
|
||||
|
||||
public:
|
||||
/** construct a textual token */
|
||||
Token(const char *p_sbegin, const char *p_send, TokenType p_type, unsigned int p_line, unsigned int p_column);
|
||||
|
||||
/** construct a binary token */
|
||||
Token(const char *p_sbegin, const char *p_send, TokenType p_type, size_t p_offset);
|
||||
~Token();
|
||||
|
||||
public:
|
||||
std::string StringContents() const {
|
||||
return std::string(begin(), end());
|
||||
}
|
||||
|
||||
bool IsBinary() const {
|
||||
return column == BINARY_MARKER;
|
||||
}
|
||||
|
||||
const char *begin() const {
|
||||
return sbegin;
|
||||
}
|
||||
|
||||
const char *end() const {
|
||||
return send;
|
||||
}
|
||||
|
||||
TokenType Type() const {
|
||||
return type;
|
||||
}
|
||||
|
||||
size_t Offset() const {
|
||||
return offset;
|
||||
}
|
||||
|
||||
unsigned int Line() const {
|
||||
return static_cast<unsigned int>(line);
|
||||
}
|
||||
|
||||
unsigned int Column() const {
|
||||
return column;
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef DEBUG_ENABLED
|
||||
// full string copy for the sole purpose that it nicely appears
|
||||
// in msvc's debugger window.
|
||||
std::string contents;
|
||||
#endif
|
||||
|
||||
const char *sbegin = nullptr;
|
||||
const char *send = nullptr;
|
||||
const TokenType type;
|
||||
|
||||
union {
|
||||
size_t line;
|
||||
size_t offset;
|
||||
};
|
||||
const unsigned int column = 0;
|
||||
};
|
||||
|
||||
// Fixed leak by using shared_ptr for tokens
|
||||
typedef Token *TokenPtr;
|
||||
typedef std::vector<TokenPtr> TokenList;
|
||||
|
||||
#define new_Token new Token
|
||||
|
||||
/** Main FBX tokenizer function. Transform input buffer into a list of preprocessed tokens.
|
||||
*
|
||||
* Skips over comments and generates line and column numbers.
|
||||
*
|
||||
* @param output_tokens Receives a list of all tokens in the input data.
|
||||
* @param input_buffer Textual input buffer to be processed, 0-terminated.
|
||||
* @print_error if something goes wrong */
|
||||
void Tokenize(TokenList &output_tokens, const char *input, size_t length, bool &corrupt);
|
||||
|
||||
/** Tokenizer function for binary FBX files.
|
||||
*
|
||||
* Emits a token list suitable for direct parsing.
|
||||
*
|
||||
* @param output_tokens Receives a list of all tokens in the input data.
|
||||
* @param input_buffer Binary input buffer to be processed.
|
||||
* @param length Length of input buffer, in bytes. There is no 0-terminal.
|
||||
* @print_error if something goes wrong */
|
||||
void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, bool &corrupt);
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_TOKENIZER_H
|
@ -1,222 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXUtil.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXUtil.cpp
|
||||
* @brief Implementation of internal FBX utility functions
|
||||
*/
|
||||
|
||||
#include "FBXUtil.h"
|
||||
#include "FBXTokenizer.h"
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
namespace FBXDocParser {
|
||||
namespace Util {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const char *TokenTypeString(TokenType t) {
|
||||
switch (t) {
|
||||
case TokenType_OPEN_BRACKET:
|
||||
return "TOK_OPEN_BRACKET";
|
||||
|
||||
case TokenType_CLOSE_BRACKET:
|
||||
return "TOK_CLOSE_BRACKET";
|
||||
|
||||
case TokenType_DATA:
|
||||
return "TOK_DATA";
|
||||
|
||||
case TokenType_COMMA:
|
||||
return "TOK_COMMA";
|
||||
|
||||
case TokenType_KEY:
|
||||
return "TOK_KEY";
|
||||
|
||||
case TokenType_BINARY_DATA:
|
||||
return "TOK_BINARY_DATA";
|
||||
}
|
||||
|
||||
//ai_assert(false);
|
||||
return "";
|
||||
}
|
||||
|
||||
// Generated by this formula: T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
|
||||
static const uint8_t base64DecodeTable[128] = {
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255,
|
||||
255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
|
||||
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255
|
||||
};
|
||||
|
||||
uint8_t DecodeBase64(char ch) {
|
||||
const uint8_t idx = static_cast<uint8_t>(ch);
|
||||
if (idx > 127) {
|
||||
return 255;
|
||||
}
|
||||
return base64DecodeTable[idx];
|
||||
}
|
||||
|
||||
size_t ComputeDecodedSizeBase64(const char *in, size_t inLength) {
|
||||
if (inLength < 2) {
|
||||
return 0;
|
||||
}
|
||||
const size_t equals = size_t(in[inLength - 1] == '=') + size_t(in[inLength - 2] == '=');
|
||||
const size_t full_length = (inLength * 3) >> 2; // div by 4
|
||||
if (full_length < equals) {
|
||||
return 0;
|
||||
}
|
||||
return full_length - equals;
|
||||
}
|
||||
|
||||
size_t DecodeBase64(const char *in, size_t inLength, uint8_t *out, size_t maxOutLength) {
|
||||
if (maxOutLength == 0 || inLength < 2) {
|
||||
return 0;
|
||||
}
|
||||
const size_t realLength = inLength - size_t(in[inLength - 1] == '=') - size_t(in[inLength - 2] == '=');
|
||||
size_t dst_offset = 0;
|
||||
int val = 0, valb = -8;
|
||||
for (size_t src_offset = 0; src_offset < realLength; ++src_offset) {
|
||||
const uint8_t table_value = Util::DecodeBase64(in[src_offset]);
|
||||
if (table_value == 255) {
|
||||
return 0;
|
||||
}
|
||||
val = (val << 6) + table_value;
|
||||
valb += 6;
|
||||
if (valb >= 0) {
|
||||
out[dst_offset++] = static_cast<uint8_t>((val >> valb) & 0xFF);
|
||||
valb -= 8;
|
||||
val &= 0xFFF;
|
||||
}
|
||||
}
|
||||
return dst_offset;
|
||||
}
|
||||
|
||||
static const char to_base64_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
char EncodeBase64(char byte) {
|
||||
return to_base64_string[(size_t)byte];
|
||||
}
|
||||
|
||||
/** Encodes a block of 4 bytes to base64 encoding
|
||||
* @param bytes Bytes to encode.
|
||||
* @param out_string String to write encoded values to.
|
||||
* @param string_pos Position in out_string.
|
||||
*/
|
||||
void EncodeByteBlock(const char *bytes, std::string &out_string, size_t string_pos) {
|
||||
char b0 = (bytes[0] & 0xFC) >> 2;
|
||||
char b1 = (bytes[0] & 0x03) << 4 | ((bytes[1] & 0xF0) >> 4);
|
||||
char b2 = (bytes[1] & 0x0F) << 2 | ((bytes[2] & 0xC0) >> 6);
|
||||
char b3 = (bytes[2] & 0x3F);
|
||||
|
||||
out_string[string_pos + 0] = EncodeBase64(b0);
|
||||
out_string[string_pos + 1] = EncodeBase64(b1);
|
||||
out_string[string_pos + 2] = EncodeBase64(b2);
|
||||
out_string[string_pos + 3] = EncodeBase64(b3);
|
||||
}
|
||||
|
||||
std::string EncodeBase64(const char *data, size_t length) {
|
||||
// calculate extra bytes needed to get a multiple of 3
|
||||
size_t extraBytes = 3 - length % 3;
|
||||
|
||||
// number of base64 bytes
|
||||
size_t encodedBytes = 4 * (length + extraBytes) / 3;
|
||||
|
||||
std::string encoded_string(encodedBytes, '=');
|
||||
|
||||
// read blocks of 3 bytes
|
||||
for (size_t ib3 = 0; ib3 < length / 3; ib3++) {
|
||||
const size_t iByte = ib3 * 3;
|
||||
const size_t iEncodedByte = ib3 * 4;
|
||||
const char *currData = &data[iByte];
|
||||
|
||||
EncodeByteBlock(currData, encoded_string, iEncodedByte);
|
||||
}
|
||||
|
||||
// if size of data is not a multiple of 3, also encode the final bytes (and add zeros where needed)
|
||||
if (extraBytes > 0) {
|
||||
char finalBytes[4] = { 0, 0, 0, 0 };
|
||||
memcpy(&finalBytes[0], &data[length - length % 3], length % 3);
|
||||
|
||||
const size_t iEncodedByte = encodedBytes - 4;
|
||||
EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte);
|
||||
|
||||
// add '=' at the end
|
||||
for (size_t i = 0; i < 4 * extraBytes / 3; i++) {
|
||||
encoded_string[encodedBytes - i - 1] = '=';
|
||||
}
|
||||
}
|
||||
return encoded_string;
|
||||
}
|
||||
} // namespace Util
|
||||
} // namespace FBXDocParser
|
@ -1,122 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* FBXUtil.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file FBXUtil.h
|
||||
* @brief FBX utility functions for internal use
|
||||
*/
|
||||
#ifndef FBX_UTIL_H
|
||||
#define FBX_UTIL_H
|
||||
|
||||
#include "FBXTokenizer.h"
|
||||
#include <stdint.h>
|
||||
|
||||
namespace FBXDocParser {
|
||||
|
||||
namespace Util {
|
||||
|
||||
/** Get a string representation for a #TokenType. */
|
||||
const char *TokenTypeString(TokenType t);
|
||||
|
||||
/** Decode a single Base64-encoded character.
|
||||
*
|
||||
* @param ch Character to decode (from base64 to binary).
|
||||
* @return decoded byte value*/
|
||||
uint8_t DecodeBase64(char ch);
|
||||
|
||||
/** Compute decoded size of a Base64-encoded string
|
||||
*
|
||||
* @param in Characters to decode.
|
||||
* @param inLength Number of characters to decode.
|
||||
* @return size of the decoded data (number of bytes)*/
|
||||
size_t ComputeDecodedSizeBase64(const char *in, size_t inLength);
|
||||
|
||||
/** Decode a Base64-encoded string
|
||||
*
|
||||
* @param in Characters to decode.
|
||||
* @param inLength Number of characters to decode.
|
||||
* @param out Pointer where we will store the decoded data.
|
||||
* @param maxOutLength Size of output buffer.
|
||||
* @return size of the decoded data (number of bytes)*/
|
||||
size_t DecodeBase64(const char *in, size_t inLength, uint8_t *out, size_t maxOutLength);
|
||||
|
||||
char EncodeBase64(char byte);
|
||||
|
||||
/** Encode bytes in base64-encoding
|
||||
*
|
||||
* @param data Binary data to encode.
|
||||
* @param inLength Number of bytes to encode.
|
||||
* @return base64-encoded string*/
|
||||
std::string EncodeBase64(const char *data, size_t length);
|
||||
} // namespace Util
|
||||
} // namespace FBXDocParser
|
||||
|
||||
#endif // FBX_UTIL_H
|
@ -1,39 +0,0 @@
|
||||
The files in this folder were originally from ASSIMP, but have been heavily modified to fix bugs and match coding
|
||||
conventions of the Godot Engine project. We have kept a copy of the applicable licenses in the folder as required by
|
||||
the license.
|
||||
|
||||
Open Asset Import Library (assimp)
|
||||
|
||||
Copyright (c) 2006-2020, assimp team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
@ -1,58 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* register_types.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "register_types.h"
|
||||
|
||||
#include "editor/editor_node.h"
|
||||
#include "modules/fbx/editor_scene_importer_fbx.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
static void _editor_init() {
|
||||
Ref<EditorSceneFormatImporterFBX> import_fbx;
|
||||
import_fbx.instantiate();
|
||||
ResourceImporterScene::get_singleton()->add_importer(import_fbx);
|
||||
}
|
||||
#endif
|
||||
|
||||
void register_fbx_types() {
|
||||
#ifdef TOOLS_ENABLED
|
||||
ClassDB::APIType prev_api = ClassDB::get_current_api();
|
||||
ClassDB::set_current_api(ClassDB::API_EDITOR);
|
||||
|
||||
GDREGISTER_CLASS(EditorSceneFormatImporterFBX);
|
||||
|
||||
ClassDB::set_current_api(prev_api);
|
||||
|
||||
EditorNode::add_init_callback(_editor_init);
|
||||
#endif
|
||||
}
|
||||
|
||||
void unregister_fbx_types() {
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* register_types.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_REGISTER_TYPES_H
|
||||
#define FBX_REGISTER_TYPES_H
|
||||
|
||||
void register_fbx_types();
|
||||
void unregister_fbx_types();
|
||||
|
||||
#endif // FBX_REGISTER_TYPES_H
|
@ -1,151 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* import_utils.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "import_utils.h"
|
||||
|
||||
Vector3 ImportUtils::deg2rad(const Vector3 &p_rotation) {
|
||||
return p_rotation / 180.0 * Math_PI;
|
||||
}
|
||||
|
||||
Vector3 ImportUtils::rad2deg(const Vector3 &p_rotation) {
|
||||
return p_rotation / Math_PI * 180.0;
|
||||
}
|
||||
|
||||
Basis ImportUtils::EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation) {
|
||||
Basis ret;
|
||||
|
||||
// FBX is using intrinsic euler, we can convert intrinsic to extrinsic (the one used in godot
|
||||
// by simply invert its order: https://www.cs.utexas.edu/~theshark/courses/cs354/lectures/cs354-14.pdf
|
||||
switch (mode) {
|
||||
case FBXDocParser::Model::RotOrder_EulerXYZ:
|
||||
ret.set_euler(p_rotation, Basis::EULER_ORDER_XYZ);
|
||||
break;
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerXZY:
|
||||
ret.set_euler(p_rotation, Basis::EULER_ORDER_XZY);
|
||||
break;
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerYZX:
|
||||
ret.set_euler(p_rotation, Basis::EULER_ORDER_YZX);
|
||||
break;
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerYXZ:
|
||||
ret.set_euler(p_rotation, Basis::EULER_ORDER_YXZ);
|
||||
break;
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerZXY:
|
||||
ret.set_euler(p_rotation, Basis::EULER_ORDER_ZXY);
|
||||
break;
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerZYX:
|
||||
ret.set_euler(p_rotation, Basis::EULER_ORDER_ZYX);
|
||||
break;
|
||||
|
||||
case FBXDocParser::Model::RotOrder_SphericXYZ:
|
||||
// TODO do this.
|
||||
break;
|
||||
|
||||
default:
|
||||
// If you land here, Please integrate all enums.
|
||||
CRASH_NOW_MSG("This is not unreachable.");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Quaternion ImportUtils::EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation) {
|
||||
return ImportUtils::EulerToBasis(mode, p_rotation);
|
||||
}
|
||||
|
||||
Vector3 ImportUtils::BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basis &p_rotation) {
|
||||
// FBX is using intrinsic euler, we can convert intrinsic to extrinsic (the one used in godot
|
||||
// by simply invert its order: https://www.cs.utexas.edu/~theshark/courses/cs354/lectures/cs354-14.pdf
|
||||
switch (mode) {
|
||||
case FBXDocParser::Model::RotOrder_EulerXYZ:
|
||||
return p_rotation.get_euler(Basis::EULER_ORDER_XYZ);
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerXZY:
|
||||
return p_rotation.get_euler(Basis::EULER_ORDER_XZY);
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerYZX:
|
||||
return p_rotation.get_euler(Basis::EULER_ORDER_YZX);
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerYXZ:
|
||||
return p_rotation.get_euler(Basis::EULER_ORDER_YXZ);
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerZXY:
|
||||
return p_rotation.get_euler(Basis::EULER_ORDER_ZXY);
|
||||
|
||||
case FBXDocParser::Model::RotOrder_EulerZYX:
|
||||
return p_rotation.get_euler(Basis::EULER_ORDER_ZYX);
|
||||
|
||||
case FBXDocParser::Model::RotOrder_SphericXYZ:
|
||||
// TODO
|
||||
return Vector3();
|
||||
|
||||
default:
|
||||
// If you land here, Please integrate all enums.
|
||||
CRASH_NOW_MSG("This is not unreachable.");
|
||||
return Vector3();
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 ImportUtils::QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quaternion &p_rotation) {
|
||||
return BasisToEuler(mode, p_rotation);
|
||||
}
|
||||
|
||||
Transform3D get_unscaled_transform(const Transform3D &p_initial, real_t p_scale) {
|
||||
Transform3D unscaled = Transform3D(p_initial.basis, p_initial.origin * p_scale);
|
||||
ERR_FAIL_COND_V_MSG(unscaled.basis.determinant() == 0, Transform3D(), "det is zero unscaled?");
|
||||
return unscaled;
|
||||
}
|
||||
|
||||
Vector3 get_poly_normal(const std::vector<Vector3> &p_vertices) {
|
||||
ERR_FAIL_COND_V_MSG(p_vertices.size() < 3, Vector3(0, 0, 0), "At least 3 vertices are necessary");
|
||||
// Using long double to make sure that normal is computed for even really tiny objects.
|
||||
typedef long double ldouble;
|
||||
ldouble x = 0.0;
|
||||
ldouble y = 0.0;
|
||||
ldouble z = 0.0;
|
||||
for (size_t i = 0; i < p_vertices.size(); i += 1) {
|
||||
const Vector3 current = p_vertices[i];
|
||||
const Vector3 next = p_vertices[(i + 1) % p_vertices.size()];
|
||||
x += (ldouble(current.y) - ldouble(next.y)) * (ldouble(current.z) + ldouble(next.z));
|
||||
y += (ldouble(current.z) - ldouble(next.z)) * (ldouble(current.x) + ldouble(next.x));
|
||||
z += (ldouble(current.x) - ldouble(next.x)) * (ldouble(current.y) + ldouble(next.y));
|
||||
}
|
||||
const ldouble l2 = x * x + y * y + z * z;
|
||||
if (l2 == 0.0) {
|
||||
return (p_vertices[0] - p_vertices[1]).normalized().cross((p_vertices[0] - p_vertices[2]).normalized()).normalized();
|
||||
} else {
|
||||
const double l = Math::sqrt(double(l2));
|
||||
return Vector3(x / l, y / l, z / l);
|
||||
}
|
||||
}
|
@ -1,400 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* import_utils.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef IMPORT_UTILS_FBX_IMPORTER_H
|
||||
#define IMPORT_UTILS_FBX_IMPORTER_H
|
||||
|
||||
#include "core/io/image_loader.h"
|
||||
|
||||
#include "data/import_state.h"
|
||||
#include "fbx_parser/FBXDocument.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
|
||||
|
||||
/**
|
||||
* Import Utils
|
||||
* Conversion tools / glue code to convert from FBX to Godot
|
||||
*/
|
||||
class ImportUtils {
|
||||
public:
|
||||
/// Convert a vector from degrees to radians.
|
||||
static Vector3 deg2rad(const Vector3 &p_rotation);
|
||||
|
||||
/// Convert a vector from radians to degrees.
|
||||
static Vector3 rad2deg(const Vector3 &p_rotation);
|
||||
|
||||
/// Converts rotation order vector (in rad) to quaternion.
|
||||
static Basis EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation);
|
||||
|
||||
/// Converts rotation order vector (in rad) to quaternion.
|
||||
static Quaternion EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation);
|
||||
|
||||
/// Converts basis into rotation order vector (in rad).
|
||||
static Vector3 BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basis &p_rotation);
|
||||
|
||||
/// Converts quaternion into rotation order vector (in rad).
|
||||
static Vector3 QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quaternion &p_rotation);
|
||||
|
||||
static void debug_xform(String name, const Transform3D &t) {
|
||||
print_verbose(name + " " + t.origin + " rotation: " + (t.basis.get_euler() * (180 / Math_PI)));
|
||||
}
|
||||
|
||||
static String FBXNodeToName(const std::string &name) {
|
||||
// strip Model:: prefix, avoiding ambiguities (i.e. don't strip if
|
||||
// this causes ambiguities, well possible between empty identifiers,
|
||||
// such as "Model::" and ""). Make sure the behaviour is consistent
|
||||
// across multiple calls to FixNodeName().
|
||||
|
||||
// We must remove this from the name
|
||||
// Some bones have this
|
||||
// SubDeformer::
|
||||
// Meshes, Joints have this, some other IK elements too.
|
||||
// Model::
|
||||
|
||||
String node_name = String(name.c_str());
|
||||
|
||||
if (node_name.substr(0, 7) == "Model::") {
|
||||
node_name = node_name.substr(7, node_name.length() - 7);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 13) == "SubDeformer::") {
|
||||
node_name = node_name.substr(13, node_name.length() - 13);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 11) == "AnimStack::") {
|
||||
node_name = node_name.substr(11, node_name.length() - 11);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 15) == "AnimCurveNode::") {
|
||||
node_name = node_name.substr(15, node_name.length() - 15);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 11) == "AnimCurve::") {
|
||||
node_name = node_name.substr(11, node_name.length() - 11);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 10) == "Geometry::") {
|
||||
node_name = node_name.substr(10, node_name.length() - 10);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 10) == "Material::") {
|
||||
node_name = node_name.substr(10, node_name.length() - 10);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
if (node_name.substr(0, 9) == "Texture::") {
|
||||
node_name = node_name.substr(9, node_name.length() - 9);
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
return node_name.replace(":", "");
|
||||
}
|
||||
|
||||
static std::string FBXAnimMeshName(const std::string &name) {
|
||||
if (name.length()) {
|
||||
size_t indexOf = name.find_first_of("::");
|
||||
if (indexOf != std::string::npos && indexOf < name.size() - 2) {
|
||||
return name.substr(indexOf + 2);
|
||||
}
|
||||
}
|
||||
return name.length() ? name : "AnimMesh";
|
||||
}
|
||||
|
||||
static Vector3 safe_import_vector3(const Vector3 &p_vec) {
|
||||
Vector3 vector = p_vec;
|
||||
if (Math::is_zero_approx(vector.x)) {
|
||||
vector.x = 0;
|
||||
}
|
||||
|
||||
if (Math::is_zero_approx(vector.y)) {
|
||||
vector.y = 0;
|
||||
}
|
||||
|
||||
if (Math::is_zero_approx(vector.z)) {
|
||||
vector.z = 0;
|
||||
}
|
||||
return vector;
|
||||
}
|
||||
|
||||
static void debug_xform(String name, const Basis &t) {
|
||||
//print_verbose(name + " rotation: " + (t.get_euler() * (180 / Math_PI)));
|
||||
}
|
||||
|
||||
static Vector3 FixAxisConversions(Vector3 input) {
|
||||
return Vector3(input.x, input.y, input.z);
|
||||
}
|
||||
|
||||
static void AlignMeshAxes(std::vector<Vector3> &vertex_data) {
|
||||
for (size_t x = 0; x < vertex_data.size(); x++) {
|
||||
vertex_data[x] = FixAxisConversions(vertex_data[x]);
|
||||
}
|
||||
}
|
||||
|
||||
struct AssetImportFbx {
|
||||
enum ETimeMode {
|
||||
TIME_MODE_DEFAULT = 0,
|
||||
TIME_MODE_120 = 1,
|
||||
TIME_MODE_100 = 2,
|
||||
TIME_MODE_60 = 3,
|
||||
TIME_MODE_50 = 4,
|
||||
TIME_MODE_48 = 5,
|
||||
TIME_MODE_30 = 6,
|
||||
TIME_MODE_30_DROP = 7,
|
||||
TIME_MODE_NTSC_DROP_FRAME = 8,
|
||||
TIME_MODE_NTSC_FULL_FRAME = 9,
|
||||
TIME_MODE_PAL = 10,
|
||||
TIME_MODE_CINEMA = 11,
|
||||
TIME_MODE_1000 = 12,
|
||||
TIME_MODE_CINEMA_ND = 13,
|
||||
TIME_MODE_CUSTOM = 14,
|
||||
TIME_MODE_TIME_MODE_COUNT = 15
|
||||
};
|
||||
enum UpAxis {
|
||||
UP_VECTOR_AXIS_X = 1,
|
||||
UP_VECTOR_AXIS_Y = 2,
|
||||
UP_VECTOR_AXIS_Z = 3
|
||||
};
|
||||
enum FrontAxis {
|
||||
FRONT_PARITY_EVEN = 1,
|
||||
FRONT_PARITY_ODD = 2,
|
||||
};
|
||||
|
||||
enum CoordAxis {
|
||||
COORD_RIGHT = 0,
|
||||
COORD_LEFT = 1
|
||||
};
|
||||
};
|
||||
|
||||
/** Get fbx fps for time mode meta data
|
||||
*/
|
||||
static float get_fbx_fps(int32_t time_mode) {
|
||||
switch (time_mode) {
|
||||
case AssetImportFbx::TIME_MODE_DEFAULT:
|
||||
return 24;
|
||||
case AssetImportFbx::TIME_MODE_120:
|
||||
return 120;
|
||||
case AssetImportFbx::TIME_MODE_100:
|
||||
return 100;
|
||||
case AssetImportFbx::TIME_MODE_60:
|
||||
return 60;
|
||||
case AssetImportFbx::TIME_MODE_50:
|
||||
return 50;
|
||||
case AssetImportFbx::TIME_MODE_48:
|
||||
return 48;
|
||||
case AssetImportFbx::TIME_MODE_30:
|
||||
return 30;
|
||||
case AssetImportFbx::TIME_MODE_30_DROP:
|
||||
return 30;
|
||||
case AssetImportFbx::TIME_MODE_NTSC_DROP_FRAME:
|
||||
return 29.9700262f;
|
||||
case AssetImportFbx::TIME_MODE_NTSC_FULL_FRAME:
|
||||
return 29.9700262f;
|
||||
case AssetImportFbx::TIME_MODE_PAL:
|
||||
return 25;
|
||||
case AssetImportFbx::TIME_MODE_CINEMA:
|
||||
return 24;
|
||||
case AssetImportFbx::TIME_MODE_1000:
|
||||
return 1000;
|
||||
case AssetImportFbx::TIME_MODE_CINEMA_ND:
|
||||
return 23.976f;
|
||||
case AssetImportFbx::TIME_MODE_CUSTOM:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static float get_fbx_fps(const FBXDocParser::FileGlobalSettings *FBXSettings) {
|
||||
int time_mode = FBXSettings->TimeMode();
|
||||
|
||||
// get the animation FPS
|
||||
float frames_per_second = get_fbx_fps(time_mode);
|
||||
|
||||
// handle animation custom FPS time.
|
||||
if (time_mode == ImportUtils::AssetImportFbx::TIME_MODE_CUSTOM) {
|
||||
print_verbose("FBX Animation has custom FPS setting");
|
||||
frames_per_second = FBXSettings->CustomFrameRate();
|
||||
|
||||
// not our problem this is the modeller, we can print as an error so they can fix the source.
|
||||
if (frames_per_second == 0) {
|
||||
print_error("Custom animation time in file is set to 0 value, animation won't play, please edit your file to correct the FPS value");
|
||||
}
|
||||
}
|
||||
return frames_per_second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find hardcoded textures from assimp which could be in many different directories
|
||||
*/
|
||||
|
||||
/**
|
||||
* set_texture_mapping_mode
|
||||
* Helper to check the mapping mode of the texture (repeat, clamp and mirror)
|
||||
*/
|
||||
// static void set_texture_mapping_mode(aiTextureMapMode *map_mode, Ref<ImageTexture> texture) {
|
||||
// ERR_FAIL_COND(texture.is_null());
|
||||
// ERR_FAIL_COND(map_mode == nullptr);
|
||||
// aiTextureMapMode tex_mode = map_mode[0];
|
||||
|
||||
// int32_t flags = Texture::FLAGS_DEFAULT;
|
||||
// if (tex_mode == aiTextureMapMode_Wrap) {
|
||||
// //Default
|
||||
// } else if (tex_mode == aiTextureMapMode_Clamp) {
|
||||
// flags = flags & ~Texture::FLAG_REPEAT;
|
||||
// } else if (tex_mode == aiTextureMapMode_Mirror) {
|
||||
// flags = flags | Texture::FLAG_MIRRORED_REPEAT;
|
||||
// }
|
||||
// texture->set_flags(flags);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Load or load from cache image :)
|
||||
* We need to upgrade this in the later version :) should not be hard
|
||||
*/
|
||||
//static Ref<Image> load_image(ImportState &state, const aiScene *p_scene, String p_path){
|
||||
// Map<String, Ref<Image> >::Element *match = state.path_to_image_cache.find(p_path);
|
||||
|
||||
// // if our cache contains this image then don't bother
|
||||
// if (match) {
|
||||
// return match->get();
|
||||
// }
|
||||
|
||||
// Vector<String> split_path = p_path.get_basename().split("*");
|
||||
// if (split_path.size() == 2) {
|
||||
// size_t texture_idx = split_path[1].to_int();
|
||||
// ERR_FAIL_COND_V(texture_idx >= p_scene->mNumTextures, Ref<Image>());
|
||||
// aiTexture *tex = p_scene->mTextures[texture_idx];
|
||||
// String filename = AssimpUtils::get_raw_string_from_assimp(tex->mFilename);
|
||||
// filename = filename.get_file();
|
||||
// print_verbose("Open Asset Import: Loading embedded texture " + filename);
|
||||
// if (tex->mHeight == 0) {
|
||||
// if (tex->CheckFormat("png")) {
|
||||
// Ref<Image> img = Image::_png_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
|
||||
// ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
|
||||
// state.path_to_image_cache.insert(p_path, img);
|
||||
// return img;
|
||||
// } else if (tex->CheckFormat("jpg")) {
|
||||
// Ref<Image> img = Image::_jpg_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
|
||||
// ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
|
||||
// state.path_to_image_cache.insert(p_path, img);
|
||||
// return img;
|
||||
// } else if (tex->CheckFormat("dds")) {
|
||||
// ERR_FAIL_COND_V_MSG(true, Ref<Image>(), "Open Asset Import: Embedded dds not implemented");
|
||||
// }
|
||||
// } else {
|
||||
// Ref<Image> img;
|
||||
// img.instantiate();
|
||||
// PoolByteArray arr;
|
||||
// uint32_t size = tex->mWidth * tex->mHeight;
|
||||
// arr.resize(size);
|
||||
// memcpy(arr.write().ptr(), tex->pcData, size);
|
||||
// ERR_FAIL_COND_V(arr.size() % 4 != 0, Ref<Image>());
|
||||
// //ARGB8888 to RGBA8888
|
||||
// for (int32_t i = 0; i < arr.size() / 4; i++) {
|
||||
// arr.write().ptr()[(4 * i) + 3] = arr[(4 * i) + 0];
|
||||
// arr.write().ptr()[(4 * i) + 0] = arr[(4 * i) + 1];
|
||||
// arr.write().ptr()[(4 * i) + 1] = arr[(4 * i) + 2];
|
||||
// arr.write().ptr()[(4 * i) + 2] = arr[(4 * i) + 3];
|
||||
// }
|
||||
// img->create(tex->mWidth, tex->mHeight, true, Image::FORMAT_RGBA8, arr);
|
||||
// ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
|
||||
// state.path_to_image_cache.insert(p_path, img);
|
||||
// return img;
|
||||
// }
|
||||
// return Ref<Image>();
|
||||
// } else {
|
||||
// Ref<Texture> texture = ResourceLoader::load(p_path);
|
||||
// ERR_FAIL_COND_V(texture.is_null(), Ref<Image>());
|
||||
// Ref<Image> image = texture->get_image();
|
||||
// ERR_FAIL_COND_V(image.is_null(), Ref<Image>());
|
||||
// state.path_to_image_cache.insert(p_path, image);
|
||||
// return image;
|
||||
// }
|
||||
|
||||
// return Ref<Image>();
|
||||
//}
|
||||
|
||||
// /* create texture from assimp data, if found in path */
|
||||
// static bool CreateAssimpTexture(
|
||||
// AssimpImporter::ImportState &state,
|
||||
// aiString texture_path,
|
||||
// String &filename,
|
||||
// String &path,
|
||||
// AssimpImageData &image_state) {
|
||||
// filename = get_raw_string_from_assimp(texture_path);
|
||||
// path = state.path.get_base_dir().plus_file(filename.replace("\\", "/"));
|
||||
// bool found = false;
|
||||
// find_texture_path(state.path, path, found);
|
||||
// if (found) {
|
||||
// image_state.raw_image = AssimpUtils::load_image(state, state.assimp_scene, path);
|
||||
// if (image_state.raw_image.is_valid()) {
|
||||
// image_state.texture.instantiate();
|
||||
// image_state.texture->create_from_image(image_state.raw_image);
|
||||
// image_state.texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSY);
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return false;
|
||||
// }
|
||||
// /** GetAssimpTexture
|
||||
// * Designed to retrieve textures for you
|
||||
// */
|
||||
// static bool GetAssimpTexture(
|
||||
// AssimpImporter::ImportState &state,
|
||||
// aiMaterial *ai_material,
|
||||
// aiTextureType texture_type,
|
||||
// String &filename,
|
||||
// String &path,
|
||||
// AssimpImageData &image_state) {
|
||||
// aiString ai_filename = aiString();
|
||||
// if (AI_SUCCESS == ai_material->GetTexture(texture_type, 0, &ai_filename, nullptr, nullptr, nullptr, nullptr, image_state.map_mode)) {
|
||||
// return CreateAssimpTexture(state, ai_filename, filename, path, image_state);
|
||||
// }
|
||||
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
// Apply the transforms so the basis will have scale 1.
|
||||
Transform3D get_unscaled_transform(const Transform3D &p_initial, real_t p_scale);
|
||||
|
||||
/// Uses the Newell's method to compute any polygon normal.
|
||||
/// The polygon must be at least size of 3 or bigger.
|
||||
Vector3 get_poly_normal(const std::vector<Vector3> &p_vertices);
|
||||
|
||||
#endif // IMPORT_UTILS_FBX_IMPORTER_H
|
@ -1,48 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* validation_tools.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "validation_tools.h"
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
#include "core/string/print_string.h"
|
||||
#include "core/string/ustring.h"
|
||||
|
||||
ValidationTracker::Entries *ValidationTracker::entries_singleton = memnew(ValidationTracker::Entries);
|
||||
|
||||
// for printing our CSV to dump validation problems of files
|
||||
// later we can make some agnostic tooling for this but this is fine for the time being.
|
||||
void ValidationTracker::Entries::add_validation_error(String asset_path, String message) {
|
||||
print_error(message);
|
||||
// note: implementation is static
|
||||
validation_entries[asset_path].push_back(message);
|
||||
}
|
||||
|
||||
#endif // TOOLS_ENABLED
|
@ -1,92 +0,0 @@
|
||||
/*************************************************************************/
|
||||
/* validation_tools.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FBX_VALIDATION_TOOLS_H
|
||||
#define FBX_VALIDATION_TOOLS_H
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/string/print_string.h"
|
||||
#include "core/templates/local_vector.h"
|
||||
#include "core/templates/map.h"
|
||||
|
||||
class ValidationTracker {
|
||||
protected:
|
||||
struct Entries {
|
||||
Map<String, LocalVector<String>> validation_entries = Map<String, LocalVector<String>>();
|
||||
|
||||
// for printing our CSV to dump validation problems of files
|
||||
// later we can make some agnostic tooling for this but this is fine for the time being.
|
||||
void add_validation_error(String asset_path, String message);
|
||||
void print_to_csv() {
|
||||
print_verbose("Exporting assset validation log please wait");
|
||||
String massive_log_file;
|
||||
|
||||
String csv_header = "file_path, error message, extra data\n";
|
||||
massive_log_file += csv_header;
|
||||
|
||||
for (const KeyValue<String, LocalVector<String>> &element : validation_entries) {
|
||||
for (unsigned int x = 0; x < element.value.size(); x++) {
|
||||
const String &line_entry = element.key + ", " + element.value[x].c_escape() + "\n";
|
||||
massive_log_file += line_entry;
|
||||
}
|
||||
}
|
||||
|
||||
String path = "asset_validation_errors.csv";
|
||||
Error err;
|
||||
FileAccess *file = FileAccess::open(path, FileAccess::WRITE, &err);
|
||||
if (!file || err) {
|
||||
if (file) {
|
||||
memdelete(file);
|
||||
}
|
||||
print_error("ValidationTracker Error - failed to create file - path: %s\n" + path);
|
||||
return;
|
||||
}
|
||||
|
||||
file->store_string(massive_log_file);
|
||||
if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
|
||||
print_error("ValidationTracker Error - failed to write to file - path: %s\n" + path);
|
||||
}
|
||||
file->close();
|
||||
memdelete(file);
|
||||
}
|
||||
};
|
||||
// asset path, error messages
|
||||
static Entries *entries_singleton;
|
||||
|
||||
public:
|
||||
static Entries *get_singleton() {
|
||||
return entries_singleton;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
#endif // FBX_VALIDATION_TOOLS_H
|
Loading…
Reference in New Issue
Block a user