Compare commits

...

25 Commits

Author SHA1 Message Date
Kim Kulling
fa65d538dd Update HMPLoader.cpp
- Fix possible division by zero
- closes https://github.com/assimp/assimp/issues/4235
2021-12-10 14:32:44 +01:00
Kim Kulling
6bb856335f Merge pull request #4249 from assimp/kimkulling-fix_nullptr_dereferencing_issue4237
Fix nullptr dereferencing from std::shared_ptr
2021-12-10 11:02:32 +01:00
Kim Kulling
68682d75b5 Fix nullptr dereferencing from std::shared_ptr
- Finding from fuzzer
- closes https://github.com/assimp/assimp/issues/4237
2021-12-10 08:39:21 +01:00
Kim Kulling
ea2e442046 Merge pull request #4245 from assimp/kimkulling-fix-division-by-zero-issue4240
Fix division by zero in PointInTriangle2D
2021-12-07 21:37:50 +01:00
Kim Kulling
e51feac2c5 Update PolyTools.h 2021-12-07 21:19:01 +01:00
Kim Kulling
1e4861f86e Fix division by zero in PointInTriangle2D
- closes https://github.com/assimp/assimp/issues/4240
2021-12-07 20:45:21 +01:00
Kim Kulling
70f5cca9c3 Merge pull request #4219 from assimp/kimkulling-v5.1.3
Update CMakeLists.txt
2021-12-04 21:01:52 +01:00
Kim Kulling
983b20cda6 Update CMakeLists.txt
- tag v5.1.3
2021-12-04 20:26:29 +01:00
Kim Kulling
16149348ed Merge pull request #4217 from umlaeute/bugfix/x3d-extension-check
Fix file-extension check for X3D-files
2021-12-01 16:07:12 +01:00
IOhannes m zmölnig
0e2ac2a91c X3D: simplistic attempt to avoid crashes due to nullptr access
Related: https://github.com/assimp/assimp/issues/4201

while the crashes go away, i'm not sure whether this is the correct fix.
also, afaict the X3D importer produces wrong results anyhow
2021-12-01 12:21:29 +01:00
IOhannes m zmölnig
c8cdf3009e X3D: replace 'here' debugging printout by an assertion.
if mNodeElementCur is NULL, we get a crash anyhow...
2021-12-01 12:19:19 +01:00
IOhannes m zmölnig
23d7811276 X3D: consistent initialization with nullptr 2021-12-01 11:35:06 +01:00
IOhannes m zmölnig
836963428e Fix file-extension check for X3D-files
using the pre-existing and well-tested GetExtension() (which happens
to also normalize the extension), rather than attempting our own
buggy one...

Closes: https://github.com/assimp/assimp/issues/4177
2021-12-01 11:17:42 +01:00
Kim Kulling
8c9a148776 Merge pull request #4216 from inhosens/master
Interpolate euler rotations for quaternion animations
2021-12-01 00:24:15 +01:00
Kim Kulling
834ec20008 Merge branch 'master' into master 2021-11-30 23:44:42 +01:00
Kim Kulling
cc05b4c8f1 Merge pull request #4211 from ms-maxvollmer/ms-maxvollmer/crashfixes2
Added checks for out of bounds data access/writing
2021-11-30 23:44:00 +01:00
Kim Kulling
d6f3f292f2 Merge branch 'master' into ms-maxvollmer/crashfixes2 2021-11-30 23:17:59 +01:00
Inho Lee
4a37aa2ef8 Interpolate euler rotations for quaternion animations
FBX uses euler rotation but assimp library's base type is
quaternion. When assimp convert FBX some animation information
can be lost.
This patch interpolates euler-angle rotations and insert
additional keyframes for the FBX format.
2021-11-30 12:49:59 +01:00
Kim Kulling
745f5e7e65 Merge pull request #4193 from PencilAmazing/BlenderCollections
Update blender importer to work with Blender 2.8+ files
2021-11-28 23:51:06 +01:00
Pencil Amazing
095bd67e10 Fix memory leaks in CollectionObject by making ob a weak pointer and removing prev pointer.
Something was cyclic in CollectionObject and we don't traverse backwards anyways
2021-11-26 22:09:06 -04:00
Pencil Amazing
e831ecf3c2 Add a separate test case for Blender 276 and update Box.blend to be 293 2021-11-26 22:09:06 -04:00
Pencil Amazing
44fa1ec6a7 Make Blender importer aware of collections, and use them when available. Also add the default startup file for Blender 2.93 2021-11-26 22:09:06 -04:00
Max Vollmer (Microsoft Havok)
5e1188c44e Check that positions exist before accessing them 2021-11-26 13:01:38 +00:00
Max Vollmer (Microsoft Havok)
0015823bef Reject files with an invalid byteLength value 2021-11-26 13:01:15 +00:00
Max Vollmer (Microsoft Havok)
38382715f7 Ensure we don't access the vector with an out of bounds index 2021-11-26 13:01:00 +00:00
20 changed files with 291 additions and 72 deletions

View File

@@ -56,7 +56,7 @@ IF(ASSIMP_HUNTER_ENABLED)
add_definitions(-DASSIMP_USE_HUNTER)
ENDIF()
PROJECT(Assimp VERSION 5.1.0)
PROJECT(Assimp VERSION 5.1.3)
# All supported options ###############################################

View File

@@ -318,42 +318,81 @@ void BlenderImporter::ExtractScene(Scene &out, const FileDatabase &file) {
#endif
}
// ------------------------------------------------------------------------------------------------
void BlenderImporter::ParseSubCollection(const Blender::Scene &in, aiNode *root, std::shared_ptr<Collection> collection, ConversionData &conv_data) {
std::deque<Object *> root_objects;
// Count number of objects
for (std::shared_ptr<CollectionObject> cur = std::static_pointer_cast<CollectionObject>(collection->gobject.first); cur; cur = cur->next) {
if (cur->ob) {
root_objects.push_back(cur->ob);
}
}
std::deque<Collection *> root_children;
// Count number of child nodes
for (std::shared_ptr<CollectionChild> cur = std::static_pointer_cast<CollectionChild>(collection->children.first); cur; cur = cur->next) {
if (cur->collection) {
root_children.push_back(cur->collection.get());
}
}
root->mNumChildren = static_cast<unsigned int>(root_objects.size() + root_children.size());
root->mChildren = new aiNode *[root->mNumChildren]();
for (unsigned int i = 0; i < static_cast<unsigned int>(root_objects.size()); ++i) {
root->mChildren[i] = ConvertNode(in, root_objects[i], conv_data, aiMatrix4x4());
root->mChildren[i]->mParent = root;
}
// For each subcollection create a new node to represent it
unsigned int iterator = static_cast<unsigned int>(root_objects.size());
for (std::shared_ptr<CollectionChild> cur = std::static_pointer_cast<CollectionChild>(collection->children.first); cur; cur = cur->next) {
if (cur->collection) {
root->mChildren[iterator] = new aiNode(cur->collection->id.name + 2); // skip over the name prefix 'OB'
root->mChildren[iterator]->mParent = root;
ParseSubCollection(in, root->mChildren[iterator], cur->collection, conv_data);
}
iterator += 1;
}
}
// ------------------------------------------------------------------------------------------------
void BlenderImporter::ConvertBlendFile(aiScene *out, const Scene &in, const FileDatabase &file) {
ConversionData conv(file);
// FIXME it must be possible to take the hierarchy directly from
// the file. This is terrible. Here, we're first looking for
// all objects which don't have parent objects at all -
std::deque<const Object *> no_parents;
for (std::shared_ptr<Base> cur = std::static_pointer_cast<Base>(in.base.first); cur; cur = cur->next) {
if (cur->object) {
if (!cur->object->parent) {
no_parents.push_back(cur->object.get());
} else {
conv.objects.insert(cur->object.get());
}
}
}
for (std::shared_ptr<Base> cur = in.basact; cur; cur = cur->next) {
if (cur->object) {
if (cur->object->parent) {
conv.objects.insert(cur->object.get());
}
}
}
if (no_parents.empty()) {
ThrowException("Expected at least one object with no parent");
}
aiNode *root = out->mRootNode = new aiNode("<BlenderRoot>");
// Iterate over all objects directly under master_collection,
// If in.master_collection == null, then we're parsing something older.
if (in.master_collection) {
ParseSubCollection(in, root, in.master_collection, conv);
} else {
std::deque<const Object *> no_parents;
for (std::shared_ptr<Base> cur = std::static_pointer_cast<Base>(in.base.first); cur; cur = cur->next) {
if (cur->object) {
if (!cur->object->parent) {
no_parents.push_back(cur->object.get());
} else {
conv.objects.insert(cur->object.get());
}
}
}
for (std::shared_ptr<Base> cur = in.basact; cur; cur = cur->next) {
if (cur->object) {
if (cur->object->parent) {
conv.objects.insert(cur->object.get());
}
}
}
root->mNumChildren = static_cast<unsigned int>(no_parents.size());
root->mChildren = new aiNode *[root->mNumChildren]();
for (unsigned int i = 0; i < root->mNumChildren; ++i) {
root->mChildren[i] = ConvertNode(in, no_parents[i], conv, aiMatrix4x4());
root->mChildren[i]->mParent = root;
if (no_parents.empty()) {
ThrowException("Expected at least one object with no parent");
}
root->mNumChildren = static_cast<unsigned int>(no_parents.size());
root->mChildren = new aiNode *[root->mNumChildren]();
for (unsigned int i = 0; i < root->mNumChildren; ++i) {
root->mChildren[i] = ConvertNode(in, no_parents[i], conv, aiMatrix4x4());
root->mChildren[i]->mParent = root;
}
}
BuildMaterials(conv);

View File

@@ -78,6 +78,7 @@ struct ElemBase;
namespace Blender {
struct Scene;
struct Object;
struct Collection;
struct Mesh;
struct Camera;
struct Lamp;
@@ -116,6 +117,7 @@ protected:
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
void ParseBlendFile(Blender::FileDatabase &out, std::shared_ptr<IOStream> stream);
void ExtractScene(Blender::Scene &out, const Blender::FileDatabase &file);
void ParseSubCollection(const Blender::Scene &in, aiNode *root, std::shared_ptr<Blender::Collection> collection, Blender::ConversionData &conv_data);
void ConvertBlendFile(aiScene *out, const Blender::Scene &in, const Blender::FileDatabase &file);
private:

View File

@@ -94,6 +94,52 @@ void Structure ::Convert<Group>(
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure::Convert<CollectionObject>(
CollectionObject &dest,
const FileDatabase &db) const {
ReadFieldPtr<ErrorPolicy_Fail>(dest.next, "*next", db);
{
//std::shared_ptr<CollectionObject> prev;
//ReadFieldPtr<ErrorPolicy_Fail>(prev, "*prev", db);
//dest.prev = prev.get();
std::shared_ptr<Object> ob;
ReadFieldPtr<ErrorPolicy_Igno>(ob, "*ob", db);
dest.ob = ob.get();
}
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure::Convert<CollectionChild>(
CollectionChild &dest,
const FileDatabase &db) const {
ReadFieldPtr<ErrorPolicy_Fail>(dest.prev, "*prev", db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.next, "*next", db);
ReadFieldPtr<ErrorPolicy_Igno>(dest.collection, "*collection", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure::Convert<Collection>(
Collection &dest,
const FileDatabase &db) const {
ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
ReadField<ErrorPolicy_Fail>(dest.gobject, "gobject", db);
ReadField<ErrorPolicy_Fail>(dest.children, "children", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <>
void Structure ::Convert<MTex>(
@@ -660,6 +706,7 @@ void Structure ::Convert<Scene>(
ReadFieldPtr<ErrorPolicy_Warn>(dest.camera, "*camera", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.world, "*world", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.basact, "*basact", db);
ReadFieldPtr<ErrorPolicy_Warn>(dest.master_collection, "*master_collection", db);
ReadField<ErrorPolicy_Igno>(dest.base, "base", db);
db.reader->IncPtr(size);
@@ -833,6 +880,9 @@ void DNA::RegisterConverters() {
converters["Image"] = DNA::FactoryPair(&Structure::Allocate<Image>, &Structure::Convert<Image>);
converters["CustomData"] = DNA::FactoryPair(&Structure::Allocate<CustomData>, &Structure::Convert<CustomData>);
converters["CustomDataLayer"] = DNA::FactoryPair(&Structure::Allocate<CustomDataLayer>, &Structure::Convert<CustomDataLayer>);
converters["Collection"] = DNA::FactoryPair(&Structure::Allocate<Collection>, &Structure::Convert<Collection>);
converters["CollectionChild"] = DNA::FactoryPair(&Structure::Allocate<CollectionChild>, &Structure::Convert<CollectionChild>);
converters["CollectionObject"] = DNA::FactoryPair(&Structure::Allocate<CollectionObject>, &Structure::Convert<CollectionObject>);
}
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

View File

@@ -107,6 +107,7 @@ namespace Blender {
struct Object;
struct MTex;
struct Image;
struct Collection;
#include <memory>
@@ -147,6 +148,26 @@ struct Group : ElemBase {
std::shared_ptr<GroupObject> gobject;
};
// -------------------------------------------------------------------------------
struct CollectionObject : ElemBase {
//CollectionObject* prev;
std::shared_ptr<CollectionObject> next;
Object *ob;
};
// -------------------------------------------------------------------------------
struct CollectionChild : ElemBase {
std::shared_ptr<CollectionChild> next, prev;
std::shared_ptr<Collection> collection;
};
// -------------------------------------------------------------------------------
struct Collection : ElemBase {
ID id FAIL;
ListBase gobject; // CollectionObject
ListBase children; // CollectionChild
};
// -------------------------------------------------------------------------------
struct World : ElemBase {
ID id FAIL;
@@ -729,11 +750,12 @@ struct Scene : ElemBase {
std::shared_ptr<Object> camera WARN;
std::shared_ptr<World> world WARN;
std::shared_ptr<Base> basact WARN;
std::shared_ptr<Collection> master_collection WARN;
ListBase base;
Scene() :
ElemBase(), camera(), world(), basact() {
ElemBase(), camera(), world(), basact(), master_collection() {
// empty
}
};

View File

@@ -62,6 +62,12 @@ template <> void Structure :: Convert<Group> (
) const
;
template <> void Structure::Convert<Collection>(
Collection& dest,
const FileDatabase& db
) const
;
template <> void Structure :: Convert<MTex> (
MTex& dest,
const FileDatabase& db

View File

@@ -378,6 +378,11 @@ void DXFImporter::ExpandBlockReferences(DXF::Block& bl,const DXF::BlockMap& bloc
const DXF::Block& bl_src = *(*it).second;
for (std::shared_ptr<const DXF::PolyLine> pl_in : bl_src.lines) {
if (!pl_in) {
ASSIMP_LOG_ERROR("DXF: PolyLine instance is nullptr, skipping.");
continue;
}
std::shared_ptr<DXF::PolyLine> pl_out = std::shared_ptr<DXF::PolyLine>(new DXF::PolyLine(*pl_in));
if (bl_src.base.Length() || insert.scale.x!=1.f || insert.scale.y!=1.f || insert.scale.z!=1.f || insert.angle || insert.pos.Length()) {

View File

@@ -3127,7 +3127,12 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
if (chain[i] == iterEnd)
continue;
keyframeLists[i] = GetKeyframeList((*chain[i]).second, start, stop);
if (i == TransformationComp_Rotation || i == TransformationComp_PreRotation
|| i == TransformationComp_PostRotation || i == TransformationComp_GeometricRotation) {
keyframeLists[i] = GetRotationKeyframeList((*chain[i]).second, start, stop);
} else {
keyframeLists[i] = GetKeyframeList((*chain[i]).second, start, stop);
}
for (KeyFrameListList::const_iterator it = keyframeLists[i].begin(); it != keyframeLists[i].end(); ++it) {
const KeyTimeList& times = *std::get<0>(*it);
@@ -3274,6 +3279,79 @@ FBXConverter::KeyFrameListList FBXConverter::GetKeyframeList(const std::vector<c
return inputs; // pray for NRVO :-)
}
FBXConverter::KeyFrameListList FBXConverter::GetRotationKeyframeList(const std::vector<const AnimationCurveNode *> &nodes,
int64_t start, int64_t stop) {
KeyFrameListList inputs;
inputs.reserve(nodes.size() * 3);
//give some breathing room for rounding errors
const int64_t adj_start = start - 10000;
const int64_t adj_stop = stop + 10000;
for (const AnimationCurveNode *node : nodes) {
ai_assert(node);
const AnimationCurveMap &curves = node->Curves();
for (const AnimationCurveMap::value_type &kv : curves) {
unsigned int mapto;
if (kv.first == "d|X") {
mapto = 0;
} else if (kv.first == "d|Y") {
mapto = 1;
} else if (kv.first == "d|Z") {
mapto = 2;
} else {
FBXImporter::LogWarn("ignoring scale animation curve, did not recognize target component");
continue;
}
const AnimationCurve *const curve = kv.second;
ai_assert(curve->GetKeys().size() == curve->GetValues().size());
ai_assert(curve->GetKeys().size());
//get values within the start/stop time window
std::shared_ptr<KeyTimeList> Keys(new KeyTimeList());
std::shared_ptr<KeyValueList> Values(new KeyValueList());
const size_t count = curve->GetKeys().size();
int64_t tp = curve->GetKeys().at(0);
float vp = curve->GetValues().at(0);
Keys->push_back(tp);
Values->push_back(vp);
if (count > 1) {
int64_t tc = curve->GetKeys().at(1);
float vc = curve->GetValues().at(1);
for (size_t n = 1; n < count; n++) {
while (std::abs(vc - vp) >= 180.0f) {
float step = std::floor(float(tc - tp) / (vc - vp) * 179.0f);
int64_t tnew = tp + int64_t(step);
float vnew = vp + (vc - vp) * step / float(tc - tp);
if (tnew >= adj_start && tnew <= adj_stop) {
Keys->push_back(tnew);
Values->push_back(vnew);
}
tp = tnew;
vp = vnew;
}
if (tc >= adj_start && tc <= adj_stop) {
Keys->push_back(tc);
Values->push_back(vc);
}
if (n + 1 < count) {
tp = tc;
vp = vc;
tc = curve->GetKeys().at(n + 1);
vc = curve->GetValues().at(n + 1);
}
}
}
inputs.push_back(std::make_tuple(Keys, Values, mapto));
}
}
return inputs;
}
KeyTimeList FBXConverter::GetKeyTimeList(const KeyFrameListList &inputs) {
ai_assert(!inputs.empty());
@@ -3464,7 +3542,7 @@ void FBXConverter::ConvertRotationKeys(aiNodeAnim *na, const std::vector<const A
ai_assert(nodes.size());
// XXX see notes in ConvertScaleKeys()
const std::vector<KeyFrameList> &inputs = GetKeyframeList(nodes, start, stop);
const std::vector<KeyFrameList> &inputs = GetRotationKeyframeList(nodes, start, stop);
const KeyTimeList &keys = GetKeyTimeList(inputs);
na->mNumRotationKeys = static_cast<unsigned int>(keys.size());

View File

@@ -361,6 +361,7 @@ private:
// ------------------------------------------------------------------------------------------------
KeyFrameListList GetKeyframeList(const std::vector<const AnimationCurveNode*>& nodes, int64_t start, int64_t stop);
KeyFrameListList GetRotationKeyframeList(const std::vector<const AnimationCurveNode*>& nodes, int64_t start, int64_t stop);
// ------------------------------------------------------------------------------------------------
KeyTimeList GetKeyTimeList(const KeyFrameListList& inputs);

View File

@@ -473,16 +473,22 @@ void HMPImporter::ReadFirstSkin(unsigned int iNumSkins, const unsigned char *szC
// ------------------------------------------------------------------------------------------------
// Generate proepr texture coords
void HMPImporter::GenerateTextureCoords(
const unsigned int width, const unsigned int height) {
void HMPImporter::GenerateTextureCoords(const unsigned int width, const unsigned int height) {
ai_assert(nullptr != pScene->mMeshes);
ai_assert(nullptr != pScene->mMeshes[0]);
ai_assert(nullptr != pScene->mMeshes[0]->mTextureCoords[0]);
aiVector3D *uv = pScene->mMeshes[0]->mTextureCoords[0];
const float fY = (1.0f / height) + (1.0f / height) / (height - 1);
const float fX = (1.0f / width) + (1.0f / width) / (width - 1);
if (uv == nullptr) {
return;
}
if (height == 0.0f || width == 0.0) {
return;
}
const float fY = (1.0f / height) + (1.0f / height) / height;
const float fX = (1.0f / width) + (1.0f / width) / width;
for (unsigned int y = 0; y < height; ++y) {
for (unsigned int x = 0; x < width; ++x, ++uv) {

View File

@@ -235,10 +235,8 @@ void X3DImporter::ParseFile(const std::string &file, IOSystem *pIOHandler) {
bool X3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool checkSig) const {
if (checkSig) {
std::string::size_type pos = pFile.find_last_of(".x3d");
if (pos != std::string::npos) {
if (GetExtension(pFile) == "x3d")
return true;
}
}
return false;

View File

@@ -72,7 +72,7 @@ void X3DImporter::startReadGroup(XmlNode &node) {
// if "USE" defined then find already defined element.
if (!use.empty()) {
X3DNodeElementBase *ne = nullptr;
X3DNodeElementBase *ne(nullptr);
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Group, ne);
} else {
ParseHelper_Group_Begin(); // create new grouping element and go deeper if node has children.
@@ -110,7 +110,7 @@ void X3DImporter::startReadStaticGroup(XmlNode &node) {
// if "USE" defined then find already defined element.
if (!use.empty()) {
X3DNodeElementBase *ne = nullptr;
X3DNodeElementBase *ne(nullptr);
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Group, ne);
} else {
@@ -153,7 +153,7 @@ void X3DImporter::startReadSwitch(XmlNode &node) {
// if "USE" defined then find already defined element.
if (!use.empty()) {
X3DNodeElementBase *ne=nullptr;
X3DNodeElementBase *ne(nullptr);
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Group, ne);
} else {
@@ -226,8 +226,13 @@ void X3DImporter::startReadTransform(XmlNode &node) {
// if "USE" defined then find already defined element.
if (!use.empty()) {
X3DNodeElementBase *ne(nullptr);
bool newgroup = (nullptr == mNodeElementCur);
if(newgroup)
ParseHelper_Group_Begin();
ne = MACRO_USE_CHECKANDAPPLY(node, def, use, ENET_Group, ne);
if (newgroup && isNodeEmpty(node)) {
ParseHelper_Node_Exit();
}
} else {
ParseHelper_Group_Begin(); // create new grouping element and go deeper if node has children.
// at this place new group mode created and made current, so we can name it.

View File

@@ -60,14 +60,12 @@ namespace Assimp {
/// \param [in] pType - type of element to find.
/// \param [out] pNE - pointer to found node element.
inline X3DNodeElementBase *X3DImporter::MACRO_USE_CHECKANDAPPLY(XmlNode &node, std::string pDEF, std::string pUSE, X3DElemType pType, X3DNodeElementBase *pNE) {
if (nullptr == mNodeElementCur) {
printf("here\n");
}
checkNodeMustBeEmpty(node);
if (!pDEF.empty())
Assimp::Throw_DEF_And_USE(node.name());
if (!FindNodeElement(pUSE, pType, &pNE))
Assimp::Throw_USE_NotFound(node.name(), pUSE);
ai_assert(nullptr != mNodeElementCur);
mNodeElementCur->Children.push_back(pNE); /* add found object as child to current element */
return pNE;

View File

@@ -300,7 +300,7 @@ public:
inline unsigned int GetIndex() const { return index; }
operator bool() const { return vector != 0; }
operator bool() const { return vector != nullptr && index < vector->size(); }
T *operator->() { return (*vector)[index]; }

View File

@@ -600,6 +600,10 @@ inline void Buffer::Read(Value &obj, Asset &r) {
inline bool Buffer::LoadFromStream(IOStream &stream, size_t length, size_t baseOffset) {
byteLength = length ? length : stream.FileSize();
if (byteLength > stream.FileSize()) {
throw DeadlyImportError("GLTF: Invalid byteLength exceeds size of actual data.");
}
if (baseOffset) {
stream.Seek(baseOffset, aiOrigin_SET);
}

View File

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2021, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
@@ -42,6 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/** @file PolyTools.h, various utilities for our dealings with arbitrary polygons */
#pragma once
#ifndef AI_POLYTOOLS_H_INCLUDED
#define AI_POLYTOOLS_H_INCLUDED
@@ -55,8 +55,7 @@ namespace Assimp {
* The function accepts an unconstrained template parameter for use with
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
template <typename T>
inline double GetArea2D(const T& v1, const T& v2, const T& v3)
{
inline double GetArea2D(const T& v1, const T& v2, const T& v3) {
return 0.5 * (v1.x * ((double)v3.y - v2.y) + v2.x * ((double)v1.y - v3.y) + v3.x * ((double)v2.y - v1.y));
}
@@ -65,8 +64,7 @@ inline double GetArea2D(const T& v1, const T& v2, const T& v3)
* The function accepts an unconstrained template parameter for use with
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
template <typename T>
inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2)
{
inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2) {
return GetArea2D(p0,p2,p1) > 0;
}
@@ -75,20 +73,23 @@ inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2)
* The function accepts an unconstrained template parameter for use with
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
template <typename T>
inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp)
{
inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp) {
// Point in triangle test using baryzentric coordinates
const aiVector2D v0 = p1 - p0;
const aiVector2D v1 = p2 - p0;
const aiVector2D v2 = pp - p0;
double dot00 = v0 * v0;
double dot01 = v0 * v1;
double dot02 = v0 * v2;
double dot11 = v1 * v1;
double dot12 = v1 * v2;
const double invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
const double dot01 = v0 * v1;
const double dot02 = v0 * v2;
const double dot12 = v1 * v2;
const double denom = dot00 * dot11 - dot01 * dot01;
if (denom == 0.0) {
return false;
}
const double invDenom = 1.0 / denom;
dot11 = (dot11 * dot02 - dot01 * dot12) * invDenom;
dot00 = (dot00 * dot12 - dot01 * dot02) * invDenom;
@@ -133,8 +134,7 @@ inline bool IsCCW(T* in, size_t npoints) {
// in[i+2].x, in[i+2].y)) {
convex_turn = AI_MATH_PI_F - theta;
convex_sum += convex_turn;
}
else {
} else {
convex_sum -= AI_MATH_PI_F - theta;
}
}
@@ -161,15 +161,13 @@ inline bool IsCCW(T* in, size_t npoints) {
if (OnLeftSideOfLine2D(in[npoints-2],in[1],in[0])) {
convex_turn = AI_MATH_PI_F - theta;
convex_sum += convex_turn;
}
else {
} else {
convex_sum -= AI_MATH_PI_F - theta;
}
return convex_sum >= (2 * AI_MATH_PI_F);
}
// -------------------------------------------------------------------------------
/** Compute the normal of an arbitrary polygon in R3.
*
@@ -186,8 +184,7 @@ inline bool IsCCW(T* in, size_t npoints) {
* this method is much faster than the 'other' NewellNormal()
*/
template <int ofs_x, int ofs_y, int ofs_z, typename TReal>
inline void NewellNormal (aiVector3t<TReal>& out, int num, TReal* x, TReal* y, TReal* z)
{
inline void NewellNormal (aiVector3t<TReal>& out, int num, TReal* x, TReal* y, TReal* z) {
// Duplicate the first two vertices at the end
x[(num+0)*ofs_x] = x[0];
x[(num+1)*ofs_x] = x[ofs_x];
@@ -224,6 +221,6 @@ inline void NewellNormal (aiVector3t<TReal>& out, int num, TReal* x, TReal* y, T
out = aiVector3t<TReal>(sum_yz,sum_zx,sum_xy);
}
} // ! Assimp
} // ! namespace Assimp
#endif
#endif // AI_POLYTOOLS_H_INCLUDED

View File

@@ -135,7 +135,9 @@ public:
/** Extract a particular vertex from a anim mesh and interleave all components */
explicit Vertex(const aiAnimMesh* msh, unsigned int idx) {
ai_assert(idx < msh->mNumVertices);
position = msh->mVertices[idx];
if (msh->HasPositions()) {
position = msh->mVertices[idx];
}
if (msh->HasNormals()) {
normal = msh->mNormals[idx];

Binary file not shown.

Binary file not shown.

View File

@@ -114,6 +114,12 @@ TEST(utBlenderImporter, importBlenderDefault271) {
ASSERT_NE(nullptr, scene);
}
TEST(utBlenderImporter, importBlenderDefault293) {
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/BLEND/BlenderDefault_276.blend", aiProcess_ValidateDataStructure);
ASSERT_NE(nullptr, scene);
}
TEST(utBlenderImporter, importCubeHierarchy_248) {
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/BLEND/CubeHierarchy_248.blend", aiProcess_ValidateDataStructure);