commit
9880db8d4d
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
cencoder.c - c source to a base64 encoding algorithm implementation
|
||||
|
||||
This is part of the libb64 project, and has been placed in the public domain.
|
||||
For details, see http://sourceforge.net/projects/libb64
|
||||
*/
|
||||
|
||||
#include "cencode.h" // changed from <B64/cencode.h>
|
||||
|
||||
const int CHARS_PER_LINE = 72;
|
||||
|
||||
void base64_init_encodestate(base64_encodestate* state_in)
|
||||
{
|
||||
state_in->step = step_A;
|
||||
state_in->result = 0;
|
||||
state_in->stepcount = 0;
|
||||
}
|
||||
|
||||
char base64_encode_value(char value_in)
|
||||
{
|
||||
static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
if (value_in > 63) return '=';
|
||||
return encoding[(int)value_in];
|
||||
}
|
||||
|
||||
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in)
|
||||
{
|
||||
const char* plainchar = plaintext_in;
|
||||
const char* const plaintextend = plaintext_in + length_in;
|
||||
char* codechar = code_out;
|
||||
char result;
|
||||
char fragment;
|
||||
|
||||
result = state_in->result;
|
||||
|
||||
switch (state_in->step)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
case step_A:
|
||||
if (plainchar == plaintextend)
|
||||
{
|
||||
state_in->result = result;
|
||||
state_in->step = step_A;
|
||||
return codechar - code_out;
|
||||
}
|
||||
fragment = *plainchar++;
|
||||
result = (fragment & 0x0fc) >> 2;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
result = (fragment & 0x003) << 4;
|
||||
case step_B:
|
||||
if (plainchar == plaintextend)
|
||||
{
|
||||
state_in->result = result;
|
||||
state_in->step = step_B;
|
||||
return codechar - code_out;
|
||||
}
|
||||
fragment = *plainchar++;
|
||||
result |= (fragment & 0x0f0) >> 4;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
result = (fragment & 0x00f) << 2;
|
||||
case step_C:
|
||||
if (plainchar == plaintextend)
|
||||
{
|
||||
state_in->result = result;
|
||||
state_in->step = step_C;
|
||||
return codechar - code_out;
|
||||
}
|
||||
fragment = *plainchar++;
|
||||
result |= (fragment & 0x0c0) >> 6;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
result = (fragment & 0x03f) >> 0;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
|
||||
++(state_in->stepcount);
|
||||
if (state_in->stepcount == CHARS_PER_LINE/4)
|
||||
{
|
||||
*codechar++ = '\n';
|
||||
state_in->stepcount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* control should not reach here */
|
||||
return codechar - code_out;
|
||||
}
|
||||
|
||||
int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
|
||||
{
|
||||
char* codechar = code_out;
|
||||
|
||||
switch (state_in->step)
|
||||
{
|
||||
case step_B:
|
||||
*codechar++ = base64_encode_value(state_in->result);
|
||||
*codechar++ = '=';
|
||||
*codechar++ = '=';
|
||||
break;
|
||||
case step_C:
|
||||
*codechar++ = base64_encode_value(state_in->result);
|
||||
*codechar++ = '=';
|
||||
break;
|
||||
case step_A:
|
||||
break;
|
||||
}
|
||||
*codechar++ = '\n';
|
||||
|
||||
return codechar - code_out;
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
cencode.h - c header for a base64 encoding algorithm
|
||||
|
||||
This is part of the libb64 project, and has been placed in the public domain.
|
||||
For details, see http://sourceforge.net/projects/libb64
|
||||
*/
|
||||
|
||||
#ifndef BASE64_CENCODE_H
|
||||
#define BASE64_CENCODE_H
|
||||
|
||||
typedef enum
|
||||
{
|
||||
step_A, step_B, step_C
|
||||
} base64_encodestep;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
base64_encodestep step;
|
||||
char result;
|
||||
int stepcount;
|
||||
} base64_encodestate;
|
||||
|
||||
void base64_init_encodestate(base64_encodestate* state_in);
|
||||
|
||||
char base64_encode_value(char value_in);
|
||||
|
||||
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in);
|
||||
|
||||
int base64_encode_blockend(char* code_out, base64_encodestate* state_in);
|
||||
|
||||
#endif /* BASE64_CENCODE_H */
|
|
@ -0,0 +1,818 @@
|
|||
/*
|
||||
Assimp2Json
|
||||
Copyright (c) 2011, Alexander C. Gessler
|
||||
|
||||
Licensed under a 3-clause BSD license. See the LICENSE file for more information.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||
#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
|
||||
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/Exporter.hpp>
|
||||
#include <assimp/IOStream.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/scene.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <limits>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#define CURRENT_FORMAT_VERSION 100
|
||||
|
||||
// grab scoped_ptr from assimp to avoid a dependency on boost.
|
||||
//#include <assimp/../../code/BoostWorkaround/boost/scoped_ptr.hpp>
|
||||
|
||||
#include "mesh_splitter.h"
|
||||
|
||||
extern "C" {
|
||||
#include "cencode.h"
|
||||
}
|
||||
namespace Assimp {
|
||||
|
||||
void ExportAssimp2Json(const char*, Assimp::IOSystem*, const aiScene*, const Assimp::ExportProperties*);
|
||||
|
||||
Exporter::ExportFormatEntry Assimp2Json_desc = Assimp::Exporter::ExportFormatEntry(
|
||||
"json",
|
||||
"Plain JSON representation of the Assimp scene data structure",
|
||||
"json",
|
||||
&ExportAssimp2Json,
|
||||
0u
|
||||
);
|
||||
|
||||
|
||||
// small utility class to simplify serializing the aiScene to Json
|
||||
class JSONWriter {
|
||||
public:
|
||||
enum {
|
||||
Flag_DoNotIndent = 0x1,
|
||||
Flag_WriteSpecialFloats = 0x2,
|
||||
};
|
||||
|
||||
JSONWriter(Assimp::IOStream& out, unsigned int flags = 0u)
|
||||
: out(out)
|
||||
, first()
|
||||
, flags(flags) {
|
||||
// make sure that all formatting happens using the standard, C locale and not the user's current locale
|
||||
buff.imbue(std::locale("C"));
|
||||
}
|
||||
|
||||
~JSONWriter() {
|
||||
Flush();
|
||||
}
|
||||
|
||||
void Flush() {
|
||||
const std::string s = buff.str();
|
||||
out.Write(s.c_str(), s.length(), 1);
|
||||
buff.clear();
|
||||
}
|
||||
|
||||
void PushIndent() {
|
||||
indent += '\t';
|
||||
}
|
||||
|
||||
void PopIndent() {
|
||||
indent.erase(indent.end() - 1);
|
||||
}
|
||||
|
||||
void Key(const std::string& name) {
|
||||
AddIndentation();
|
||||
Delimit();
|
||||
buff << '\"' + name + "\": ";
|
||||
}
|
||||
|
||||
template<typename Literal>
|
||||
void Element(const Literal& name) {
|
||||
AddIndentation();
|
||||
Delimit();
|
||||
|
||||
LiteralToString(buff, name) << '\n';
|
||||
}
|
||||
|
||||
template<typename Literal>
|
||||
void SimpleValue(const Literal& s) {
|
||||
LiteralToString(buff, s) << '\n';
|
||||
}
|
||||
|
||||
void SimpleValue(const void* buffer, size_t len) {
|
||||
base64_encodestate s;
|
||||
base64_init_encodestate(&s);
|
||||
|
||||
char* const out = new char[std::max(len * 2, static_cast<size_t>(16u))];
|
||||
const int n = base64_encode_block(reinterpret_cast<const char*>(buffer), static_cast<int>(len), out, &s);
|
||||
out[n + base64_encode_blockend(out + n, &s)] = '\0';
|
||||
|
||||
// base64 encoding may add newlines, but JSON strings may not contain 'real' newlines
|
||||
// (only escaped ones). Remove any newlines in out.
|
||||
for (char* cur = out; *cur; ++cur) {
|
||||
if (*cur == '\n') {
|
||||
*cur = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
buff << '\"' << out << "\"\n";
|
||||
delete[] out;
|
||||
}
|
||||
|
||||
void StartObj(bool is_element = false) {
|
||||
// if this appears as a plain array element, we need to insert a delimiter and we should also indent it
|
||||
if (is_element) {
|
||||
AddIndentation();
|
||||
if (!first) {
|
||||
buff << ',';
|
||||
}
|
||||
}
|
||||
first = true;
|
||||
buff << "{\n";
|
||||
PushIndent();
|
||||
}
|
||||
|
||||
void EndObj() {
|
||||
PopIndent();
|
||||
AddIndentation();
|
||||
first = false;
|
||||
buff << "}\n";
|
||||
}
|
||||
|
||||
void StartArray(bool is_element = false) {
|
||||
// if this appears as a plain array element, we need to insert a delimiter and we should also indent it
|
||||
if (is_element) {
|
||||
AddIndentation();
|
||||
if (!first) {
|
||||
buff << ',';
|
||||
}
|
||||
}
|
||||
first = true;
|
||||
buff << "[\n";
|
||||
PushIndent();
|
||||
}
|
||||
|
||||
void EndArray() {
|
||||
PopIndent();
|
||||
AddIndentation();
|
||||
buff << "]\n";
|
||||
first = false;
|
||||
}
|
||||
|
||||
void AddIndentation() {
|
||||
if (!(flags & Flag_DoNotIndent)) {
|
||||
buff << indent;
|
||||
}
|
||||
}
|
||||
|
||||
void Delimit() {
|
||||
if (!first) {
|
||||
buff << ',';
|
||||
}
|
||||
else {
|
||||
buff << ' ';
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename Literal>
|
||||
std::stringstream& LiteralToString(std::stringstream& stream, const Literal& s) {
|
||||
stream << s;
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::stringstream& LiteralToString(std::stringstream& stream, const aiString& s) {
|
||||
std::string t;
|
||||
|
||||
// escape backslashes and single quotes, both would render the JSON invalid if left as is
|
||||
t.reserve(s.length);
|
||||
for (size_t i = 0; i < s.length; ++i) {
|
||||
|
||||
if (s.data[i] == '\\' || s.data[i] == '\'' || s.data[i] == '\"') {
|
||||
t.push_back('\\');
|
||||
}
|
||||
|
||||
t.push_back(s.data[i]);
|
||||
}
|
||||
stream << "\"";
|
||||
stream << t;
|
||||
stream << "\"";
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::stringstream& LiteralToString(std::stringstream& stream, float f) {
|
||||
if (!std::numeric_limits<float>::is_iec559) {
|
||||
// on a non IEEE-754 platform, we make no assumptions about the representation or existence
|
||||
// of special floating-point numbers.
|
||||
stream << f;
|
||||
return stream;
|
||||
}
|
||||
|
||||
// JSON does not support writing Inf/Nan
|
||||
// [RFC 4672: "Numeric values that cannot be represented as sequences of digits
|
||||
// (such as Infinity and NaN) are not permitted."]
|
||||
// Nevertheless, many parsers will accept the special keywords Infinity, -Infinity and NaN
|
||||
if (std::numeric_limits<float>::infinity() == fabs(f)) {
|
||||
if (flags & Flag_WriteSpecialFloats) {
|
||||
stream << (f < 0 ? "\"-" : "\"") + std::string("Infinity\"");
|
||||
return stream;
|
||||
}
|
||||
// we should print this warning, but we can't - this is called from within a generic assimp exporter, we cannot use cerr
|
||||
// std::cerr << "warning: cannot represent infinite number literal, substituting 0 instead (use -i flag to enforce Infinity/NaN)" << std::endl;
|
||||
stream << "0.0";
|
||||
return stream;
|
||||
}
|
||||
// f!=f is the most reliable test for NaNs that I know of
|
||||
else if (f != f) {
|
||||
if (flags & Flag_WriteSpecialFloats) {
|
||||
stream << "\"NaN\"";
|
||||
return stream;
|
||||
}
|
||||
// we should print this warning, but we can't - this is called from within a generic assimp exporter, we cannot use cerr
|
||||
// std::cerr << "warning: cannot represent infinite number literal, substituting 0 instead (use -i flag to enforce Infinity/NaN)" << std::endl;
|
||||
stream << "0.0";
|
||||
return stream;
|
||||
}
|
||||
|
||||
stream << f;
|
||||
return stream;
|
||||
}
|
||||
|
||||
private:
|
||||
Assimp::IOStream& out;
|
||||
std::string indent, newline;
|
||||
std::stringstream buff;
|
||||
bool first;
|
||||
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
void Write(JSONWriter& out, const aiVector3D& ai, bool is_elem = true) {
|
||||
out.StartArray(is_elem);
|
||||
out.Element(ai.x);
|
||||
out.Element(ai.y);
|
||||
out.Element(ai.z);
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiQuaternion& ai, bool is_elem = true) {
|
||||
out.StartArray(is_elem);
|
||||
out.Element(ai.w);
|
||||
out.Element(ai.x);
|
||||
out.Element(ai.y);
|
||||
out.Element(ai.z);
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiColor3D& ai, bool is_elem = true) {
|
||||
out.StartArray(is_elem);
|
||||
out.Element(ai.r);
|
||||
out.Element(ai.g);
|
||||
out.Element(ai.b);
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiMatrix4x4& ai, bool is_elem = true) {
|
||||
out.StartArray(is_elem);
|
||||
for (unsigned int x = 0; x < 4; ++x) {
|
||||
for (unsigned int y = 0; y < 4; ++y) {
|
||||
out.Element(ai[x][y]);
|
||||
}
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiBone& ai, bool is_elem = true) {
|
||||
out.StartObj(is_elem);
|
||||
|
||||
out.Key("name");
|
||||
out.SimpleValue(ai.mName);
|
||||
|
||||
out.Key("offsetmatrix");
|
||||
Write(out, ai.mOffsetMatrix, false);
|
||||
|
||||
out.Key("weights");
|
||||
out.StartArray();
|
||||
for (unsigned int i = 0; i < ai.mNumWeights; ++i) {
|
||||
out.StartArray(true);
|
||||
out.Element(ai.mWeights[i].mVertexId);
|
||||
out.Element(ai.mWeights[i].mWeight);
|
||||
out.EndArray();
|
||||
}
|
||||
out.EndArray();
|
||||
out.EndObj();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiFace& ai, bool is_elem = true) {
|
||||
out.StartArray(is_elem);
|
||||
for (unsigned int i = 0; i < ai.mNumIndices; ++i) {
|
||||
out.Element(ai.mIndices[i]);
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiMesh& ai, bool is_elem = true) {
|
||||
out.StartObj(is_elem);
|
||||
|
||||
out.Key("name");
|
||||
out.SimpleValue(ai.mName);
|
||||
|
||||
out.Key("materialindex");
|
||||
out.SimpleValue(ai.mMaterialIndex);
|
||||
|
||||
out.Key("primitivetypes");
|
||||
out.SimpleValue(ai.mPrimitiveTypes);
|
||||
|
||||
out.Key("vertices");
|
||||
out.StartArray();
|
||||
for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
|
||||
out.Element(ai.mVertices[i].x);
|
||||
out.Element(ai.mVertices[i].y);
|
||||
out.Element(ai.mVertices[i].z);
|
||||
}
|
||||
out.EndArray();
|
||||
|
||||
if (ai.HasNormals()) {
|
||||
out.Key("normals");
|
||||
out.StartArray();
|
||||
for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
|
||||
out.Element(ai.mNormals[i].x);
|
||||
out.Element(ai.mNormals[i].y);
|
||||
out.Element(ai.mNormals[i].z);
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
if (ai.HasTangentsAndBitangents()) {
|
||||
out.Key("tangents");
|
||||
out.StartArray();
|
||||
for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
|
||||
out.Element(ai.mTangents[i].x);
|
||||
out.Element(ai.mTangents[i].y);
|
||||
out.Element(ai.mTangents[i].z);
|
||||
}
|
||||
out.EndArray();
|
||||
|
||||
out.Key("bitangents");
|
||||
out.StartArray();
|
||||
for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
|
||||
out.Element(ai.mBitangents[i].x);
|
||||
out.Element(ai.mBitangents[i].y);
|
||||
out.Element(ai.mBitangents[i].z);
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
if (ai.GetNumUVChannels()) {
|
||||
out.Key("numuvcomponents");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.GetNumUVChannels(); ++n) {
|
||||
out.Element(ai.mNumUVComponents[n]);
|
||||
}
|
||||
out.EndArray();
|
||||
|
||||
out.Key("texturecoords");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.GetNumUVChannels(); ++n) {
|
||||
const unsigned int numc = ai.mNumUVComponents[n] ? ai.mNumUVComponents[n] : 2;
|
||||
|
||||
out.StartArray(true);
|
||||
for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
|
||||
for (unsigned int c = 0; c < numc; ++c) {
|
||||
out.Element(ai.mTextureCoords[n][i][c]);
|
||||
}
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
if (ai.GetNumColorChannels()) {
|
||||
out.Key("colors");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.GetNumColorChannels(); ++n) {
|
||||
out.StartArray(true);
|
||||
for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
|
||||
out.Element(ai.mColors[n][i].r);
|
||||
out.Element(ai.mColors[n][i].g);
|
||||
out.Element(ai.mColors[n][i].b);
|
||||
out.Element(ai.mColors[n][i].a);
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
if (ai.mNumBones) {
|
||||
out.Key("bones");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.mNumBones; ++n) {
|
||||
Write(out, *ai.mBones[n]);
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
out.Key("faces");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.mNumFaces; ++n) {
|
||||
Write(out, ai.mFaces[n]);
|
||||
}
|
||||
out.EndArray();
|
||||
|
||||
out.EndObj();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiNode& ai, bool is_elem = true) {
|
||||
out.StartObj(is_elem);
|
||||
|
||||
out.Key("name");
|
||||
out.SimpleValue(ai.mName);
|
||||
|
||||
out.Key("transformation");
|
||||
Write(out, ai.mTransformation, false);
|
||||
|
||||
if (ai.mNumMeshes) {
|
||||
out.Key("meshes");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.mNumMeshes; ++n) {
|
||||
out.Element(ai.mMeshes[n]);
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
if (ai.mNumChildren) {
|
||||
out.Key("children");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.mNumChildren; ++n) {
|
||||
Write(out, *ai.mChildren[n]);
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
out.EndObj();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
|
||||
out.StartObj(is_elem);
|
||||
|
||||
out.Key("properties");
|
||||
out.StartArray();
|
||||
for (unsigned int i = 0; i < ai.mNumProperties; ++i) {
|
||||
const aiMaterialProperty* const prop = ai.mProperties[i];
|
||||
out.StartObj(true);
|
||||
out.Key("key");
|
||||
out.SimpleValue(prop->mKey);
|
||||
out.Key("semantic");
|
||||
out.SimpleValue(prop->mSemantic);
|
||||
out.Key("index");
|
||||
out.SimpleValue(prop->mIndex);
|
||||
|
||||
out.Key("type");
|
||||
out.SimpleValue(prop->mType);
|
||||
|
||||
out.Key("value");
|
||||
switch (prop->mType) {
|
||||
case aiPTI_Float:
|
||||
if (prop->mDataLength / sizeof(float) > 1) {
|
||||
out.StartArray();
|
||||
for (unsigned int i = 0; i < prop->mDataLength / sizeof(float); ++i) {
|
||||
out.Element(reinterpret_cast<float*>(prop->mData)[i]);
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
else {
|
||||
out.SimpleValue(*reinterpret_cast<float*>(prop->mData));
|
||||
}
|
||||
break;
|
||||
|
||||
case aiPTI_Integer:
|
||||
if (prop->mDataLength / sizeof(int) > 1) {
|
||||
out.StartArray();
|
||||
for (unsigned int i = 0; i < prop->mDataLength / sizeof(int); ++i) {
|
||||
out.Element(reinterpret_cast<int*>(prop->mData)[i]);
|
||||
}
|
||||
out.EndArray();
|
||||
} else {
|
||||
out.SimpleValue(*reinterpret_cast<int*>(prop->mData));
|
||||
}
|
||||
break;
|
||||
|
||||
case aiPTI_String:
|
||||
{
|
||||
aiString s;
|
||||
aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s);
|
||||
out.SimpleValue(s);
|
||||
}
|
||||
break;
|
||||
case aiPTI_Buffer:
|
||||
{
|
||||
// binary data is written as series of hex-encoded octets
|
||||
out.SimpleValue(prop->mData, prop->mDataLength);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
out.EndObj();
|
||||
}
|
||||
|
||||
out.EndArray();
|
||||
out.EndObj();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) {
|
||||
out.StartObj(is_elem);
|
||||
|
||||
out.Key("width");
|
||||
out.SimpleValue(ai.mWidth);
|
||||
|
||||
out.Key("height");
|
||||
out.SimpleValue(ai.mHeight);
|
||||
|
||||
out.Key("formathint");
|
||||
out.SimpleValue(aiString(ai.achFormatHint));
|
||||
|
||||
out.Key("data");
|
||||
if (!ai.mHeight) {
|
||||
out.SimpleValue(ai.pcData, ai.mWidth);
|
||||
}
|
||||
else {
|
||||
out.StartArray();
|
||||
for (unsigned int y = 0; y < ai.mHeight; ++y) {
|
||||
out.StartArray(true);
|
||||
for (unsigned int x = 0; x < ai.mWidth; ++x) {
|
||||
const aiTexel& tx = ai.pcData[y*ai.mWidth + x];
|
||||
out.StartArray(true);
|
||||
out.Element(static_cast<unsigned int>(tx.r));
|
||||
out.Element(static_cast<unsigned int>(tx.g));
|
||||
out.Element(static_cast<unsigned int>(tx.b));
|
||||
out.Element(static_cast<unsigned int>(tx.a));
|
||||
out.EndArray();
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
out.EndObj();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) {
|
||||
out.StartObj(is_elem);
|
||||
|
||||
out.Key("name");
|
||||
out.SimpleValue(ai.mName);
|
||||
|
||||
out.Key("type");
|
||||
out.SimpleValue(ai.mType);
|
||||
|
||||
if (ai.mType == aiLightSource_SPOT || ai.mType == aiLightSource_UNDEFINED) {
|
||||
out.Key("angleinnercone");
|
||||
out.SimpleValue(ai.mAngleInnerCone);
|
||||
|
||||
out.Key("angleoutercone");
|
||||
out.SimpleValue(ai.mAngleOuterCone);
|
||||
}
|
||||
|
||||
out.Key("attenuationconstant");
|
||||
out.SimpleValue(ai.mAttenuationConstant);
|
||||
|
||||
out.Key("attenuationlinear");
|
||||
out.SimpleValue(ai.mAttenuationLinear);
|
||||
|
||||
out.Key("attenuationquadratic");
|
||||
out.SimpleValue(ai.mAttenuationQuadratic);
|
||||
|
||||
out.Key("diffusecolor");
|
||||
Write(out, ai.mColorDiffuse, false);
|
||||
|
||||
out.Key("specularcolor");
|
||||
Write(out, ai.mColorSpecular, false);
|
||||
|
||||
out.Key("ambientcolor");
|
||||
Write(out, ai.mColorAmbient, false);
|
||||
|
||||
if (ai.mType != aiLightSource_POINT) {
|
||||
out.Key("direction");
|
||||
Write(out, ai.mDirection, false);
|
||||
|
||||
}
|
||||
|
||||
if (ai.mType != aiLightSource_DIRECTIONAL) {
|
||||
out.Key("position");
|
||||
Write(out, ai.mPosition, false);
|
||||
}
|
||||
|
||||
out.EndObj();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
|
||||
out.StartObj(is_elem);
|
||||
|
||||
out.Key("name");
|
||||
out.SimpleValue(ai.mNodeName);
|
||||
|
||||
out.Key("prestate");
|
||||
out.SimpleValue(ai.mPreState);
|
||||
|
||||
out.Key("poststate");
|
||||
out.SimpleValue(ai.mPostState);
|
||||
|
||||
if (ai.mNumPositionKeys) {
|
||||
out.Key("positionkeys");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.mNumPositionKeys; ++n) {
|
||||
const aiVectorKey& pos = ai.mPositionKeys[n];
|
||||
out.StartArray(true);
|
||||
out.Element(pos.mTime);
|
||||
Write(out, pos.mValue);
|
||||
out.EndArray();
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
if (ai.mNumRotationKeys) {
|
||||
out.Key("rotationkeys");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.mNumRotationKeys; ++n) {
|
||||
const aiQuatKey& rot = ai.mRotationKeys[n];
|
||||
out.StartArray(true);
|
||||
out.Element(rot.mTime);
|
||||
Write(out, rot.mValue);
|
||||
out.EndArray();
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
if (ai.mNumScalingKeys) {
|
||||
out.Key("scalingkeys");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.mNumScalingKeys; ++n) {
|
||||
const aiVectorKey& scl = ai.mScalingKeys[n];
|
||||
out.StartArray(true);
|
||||
out.Element(scl.mTime);
|
||||
Write(out, scl.mValue);
|
||||
out.EndArray();
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
out.EndObj();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiAnimation& ai, bool is_elem = true) {
|
||||
out.StartObj(is_elem);
|
||||
|
||||
out.Key("name");
|
||||
out.SimpleValue(ai.mName);
|
||||
|
||||
out.Key("tickspersecond");
|
||||
out.SimpleValue(ai.mTicksPerSecond);
|
||||
|
||||
out.Key("duration");
|
||||
out.SimpleValue(ai.mDuration);
|
||||
|
||||
out.Key("channels");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.mNumChannels; ++n) {
|
||||
Write(out, *ai.mChannels[n]);
|
||||
}
|
||||
out.EndArray();
|
||||
out.EndObj();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiCamera& ai, bool is_elem = true) {
|
||||
out.StartObj(is_elem);
|
||||
|
||||
out.Key("name");
|
||||
out.SimpleValue(ai.mName);
|
||||
|
||||
out.Key("aspect");
|
||||
out.SimpleValue(ai.mAspect);
|
||||
|
||||
out.Key("clipplanefar");
|
||||
out.SimpleValue(ai.mClipPlaneFar);
|
||||
|
||||
out.Key("clipplanenear");
|
||||
out.SimpleValue(ai.mClipPlaneNear);
|
||||
|
||||
out.Key("horizontalfov");
|
||||
out.SimpleValue(ai.mHorizontalFOV);
|
||||
|
||||
out.Key("up");
|
||||
Write(out, ai.mUp, false);
|
||||
|
||||
out.Key("lookat");
|
||||
Write(out, ai.mLookAt, false);
|
||||
|
||||
out.EndObj();
|
||||
}
|
||||
|
||||
void WriteFormatInfo(JSONWriter& out) {
|
||||
out.StartObj();
|
||||
out.Key("format");
|
||||
out.SimpleValue("\"assimp2json\"");
|
||||
out.Key("version");
|
||||
out.SimpleValue(CURRENT_FORMAT_VERSION);
|
||||
out.EndObj();
|
||||
}
|
||||
|
||||
void Write(JSONWriter& out, const aiScene& ai) {
|
||||
out.StartObj();
|
||||
|
||||
out.Key("__metadata__");
|
||||
WriteFormatInfo(out);
|
||||
|
||||
out.Key("rootnode");
|
||||
Write(out, *ai.mRootNode, false);
|
||||
|
||||
out.Key("flags");
|
||||
out.SimpleValue(ai.mFlags);
|
||||
|
||||
if (ai.HasMeshes()) {
|
||||
out.Key("meshes");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.mNumMeshes; ++n) {
|
||||
Write(out, *ai.mMeshes[n]);
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
if (ai.HasMaterials()) {
|
||||
out.Key("materials");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.mNumMaterials; ++n) {
|
||||
Write(out, *ai.mMaterials[n]);
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
if (ai.HasAnimations()) {
|
||||
out.Key("animations");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.mNumAnimations; ++n) {
|
||||
Write(out, *ai.mAnimations[n]);
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
if (ai.HasLights()) {
|
||||
out.Key("lights");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.mNumLights; ++n) {
|
||||
Write(out, *ai.mLights[n]);
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
if (ai.HasCameras()) {
|
||||
out.Key("cameras");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.mNumCameras; ++n) {
|
||||
Write(out, *ai.mCameras[n]);
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
|
||||
if (ai.HasTextures()) {
|
||||
out.Key("textures");
|
||||
out.StartArray();
|
||||
for (unsigned int n = 0; n < ai.mNumTextures; ++n) {
|
||||
Write(out, *ai.mTextures[n]);
|
||||
}
|
||||
out.EndArray();
|
||||
}
|
||||
out.EndObj();
|
||||
}
|
||||
|
||||
|
||||
void ExportAssimp2Json(const char* file, Assimp::IOSystem* io, const aiScene* scene, const Assimp::ExportProperties*) {
|
||||
std::unique_ptr<Assimp::IOStream> str(io->Open(file, "wt"));
|
||||
if (!str) {
|
||||
//throw Assimp::DeadlyExportError("could not open output file");
|
||||
}
|
||||
|
||||
// get a copy of the scene so we can modify it
|
||||
aiScene* scenecopy_tmp;
|
||||
aiCopyScene(scene, &scenecopy_tmp);
|
||||
|
||||
try {
|
||||
// split meshes so they fit into a 16 bit index buffer
|
||||
MeshSplitter splitter;
|
||||
splitter.SetLimit(1 << 16);
|
||||
splitter.Execute(scenecopy_tmp);
|
||||
|
||||
// XXX Flag_WriteSpecialFloats is turned on by default, right now we don't have a configuration interface for exporters
|
||||
JSONWriter s(*str, JSONWriter::Flag_WriteSpecialFloats);
|
||||
Write(s, *scenecopy_tmp);
|
||||
|
||||
}
|
||||
catch (...) {
|
||||
aiFreeScene(scenecopy_tmp);
|
||||
throw;
|
||||
}
|
||||
aiFreeScene(scenecopy_tmp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_ASSJSON_EXPORTER
|
||||
#endif // ASSIMP_BUILD_NO_EXPORT
|
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
Assimp2Json
|
||||
Copyright (c) 2011, Alexander C. Gessler
|
||||
|
||||
Licensed under a 3-clause BSD license. See the LICENSE file for more information.
|
||||
|
||||
*/
|
||||
|
||||
#include "mesh_splitter.h"
|
||||
|
||||
#include <assimp/scene.h>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Note: this is largely based on assimp's SplitLargeMeshes_Vertex process.
|
||||
// it is refactored and the coding style is slightly improved, though.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void MeshSplitter::Execute( aiScene* pScene) {
|
||||
std::vector<std::pair<aiMesh*, unsigned int> > source_mesh_map;
|
||||
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||
SplitMesh(a, pScene->mMeshes[a],source_mesh_map);
|
||||
}
|
||||
|
||||
const unsigned int size = static_cast<unsigned int>(source_mesh_map.size());
|
||||
if (size != pScene->mNumMeshes) {
|
||||
// it seems something has been split. rebuild the mesh list
|
||||
delete[] pScene->mMeshes;
|
||||
pScene->mNumMeshes = size;
|
||||
pScene->mMeshes = new aiMesh*[size]();
|
||||
|
||||
for (unsigned int i = 0; i < size;++i) {
|
||||
pScene->mMeshes[i] = source_mesh_map[i].first;
|
||||
}
|
||||
|
||||
// now we need to update all nodes
|
||||
UpdateNode(pScene->mRootNode,source_mesh_map);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshSplitter::UpdateNode(aiNode* pcNode, const std::vector<std::pair<aiMesh*, unsigned int> >& source_mesh_map) {
|
||||
// TODO: should better use std::(multi)set for source_mesh_map.
|
||||
|
||||
// for every index in out list build a new entry
|
||||
std::vector<unsigned int> aiEntries;
|
||||
aiEntries.reserve(pcNode->mNumMeshes + 1);
|
||||
for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) {
|
||||
for (unsigned int a = 0, end = static_cast<unsigned int>(source_mesh_map.size()); a < end;++a) {
|
||||
if (source_mesh_map[a].second == pcNode->mMeshes[i]) {
|
||||
aiEntries.push_back(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now build the new list
|
||||
delete pcNode->mMeshes;
|
||||
pcNode->mNumMeshes = static_cast<unsigned int>(aiEntries.size());
|
||||
pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
|
||||
|
||||
for (unsigned int b = 0; b < pcNode->mNumMeshes;++b) {
|
||||
pcNode->mMeshes[b] = aiEntries[b];
|
||||
}
|
||||
|
||||
// recursively update children
|
||||
for (unsigned int i = 0, end = pcNode->mNumChildren; i < end;++i) {
|
||||
UpdateNode ( pcNode->mChildren[i], source_mesh_map );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#define WAS_NOT_COPIED 0xffffffff
|
||||
|
||||
typedef std::pair <unsigned int,float> PerVertexWeight;
|
||||
typedef std::vector <PerVertexWeight> VertexWeightTable;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
VertexWeightTable* ComputeVertexBoneWeightTable(const aiMesh* pMesh) {
|
||||
if (!pMesh || !pMesh->mNumVertices || !pMesh->mNumBones) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VertexWeightTable* const avPerVertexWeights = new VertexWeightTable[pMesh->mNumVertices];
|
||||
for (unsigned int i = 0; i < pMesh->mNumBones;++i) {
|
||||
|
||||
aiBone* bone = pMesh->mBones[i];
|
||||
for (unsigned int a = 0; a < bone->mNumWeights;++a) {
|
||||
const aiVertexWeight& weight = bone->mWeights[a];
|
||||
avPerVertexWeights[weight.mVertexId].push_back( std::make_pair(i,weight.mWeight) );
|
||||
}
|
||||
}
|
||||
return avPerVertexWeights;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshSplitter :: SplitMesh(unsigned int a, aiMesh* in_mesh, std::vector<std::pair<aiMesh*, unsigned int> >& source_mesh_map) {
|
||||
// TODO: should better use std::(multi)set for source_mesh_map.
|
||||
|
||||
if (in_mesh->mNumVertices <= LIMIT) {
|
||||
source_mesh_map.push_back(std::make_pair(in_mesh,a));
|
||||
return;
|
||||
}
|
||||
|
||||
// build a per-vertex weight list if necessary
|
||||
VertexWeightTable* avPerVertexWeights = ComputeVertexBoneWeightTable(in_mesh);
|
||||
|
||||
// we need to split this mesh into sub meshes. Estimate submesh size
|
||||
const unsigned int sub_meshes = (in_mesh->mNumVertices / LIMIT) + 1;
|
||||
|
||||
// create a std::vector<unsigned int> to remember which vertices have already
|
||||
// been copied and to which position (i.e. output index)
|
||||
std::vector<unsigned int> was_copied_to;
|
||||
was_copied_to.resize(in_mesh->mNumVertices,WAS_NOT_COPIED);
|
||||
|
||||
// Try to find a good estimate for the number of output faces
|
||||
// per mesh. Add 12.5% as buffer
|
||||
unsigned int size_estimated = in_mesh->mNumFaces / sub_meshes;
|
||||
size_estimated += size_estimated / 8;
|
||||
|
||||
// now generate all submeshes
|
||||
unsigned int base = 0;
|
||||
while (true) {
|
||||
const unsigned int out_vertex_index = LIMIT;
|
||||
|
||||
aiMesh* out_mesh = new aiMesh();
|
||||
out_mesh->mNumVertices = 0;
|
||||
out_mesh->mMaterialIndex = in_mesh->mMaterialIndex;
|
||||
|
||||
// the name carries the adjacency information between the meshes
|
||||
out_mesh->mName = in_mesh->mName;
|
||||
|
||||
typedef std::vector<aiVertexWeight> BoneWeightList;
|
||||
if (in_mesh->HasBones()) {
|
||||
out_mesh->mBones = new aiBone*[in_mesh->mNumBones]();
|
||||
}
|
||||
|
||||
// clear the temporary helper array
|
||||
if (base) {
|
||||
std::fill(was_copied_to.begin(), was_copied_to.end(), WAS_NOT_COPIED);
|
||||
}
|
||||
|
||||
std::vector<aiFace> vFaces;
|
||||
|
||||
// reserve enough storage for most cases
|
||||
if (in_mesh->HasPositions()) {
|
||||
out_mesh->mVertices = new aiVector3D[out_vertex_index];
|
||||
}
|
||||
|
||||
if (in_mesh->HasNormals()) {
|
||||
out_mesh->mNormals = new aiVector3D[out_vertex_index];
|
||||
}
|
||||
|
||||
if (in_mesh->HasTangentsAndBitangents()) {
|
||||
out_mesh->mTangents = new aiVector3D[out_vertex_index];
|
||||
out_mesh->mBitangents = new aiVector3D[out_vertex_index];
|
||||
}
|
||||
|
||||
for (unsigned int c = 0; in_mesh->HasVertexColors(c);++c) {
|
||||
out_mesh->mColors[c] = new aiColor4D[out_vertex_index];
|
||||
}
|
||||
|
||||
for (unsigned int c = 0; in_mesh->HasTextureCoords(c);++c) {
|
||||
out_mesh->mNumUVComponents[c] = in_mesh->mNumUVComponents[c];
|
||||
out_mesh->mTextureCoords[c] = new aiVector3D[out_vertex_index];
|
||||
}
|
||||
vFaces.reserve(size_estimated);
|
||||
|
||||
// (we will also need to copy the array of indices)
|
||||
while (base < in_mesh->mNumFaces) {
|
||||
const unsigned int iNumIndices = in_mesh->mFaces[base].mNumIndices;
|
||||
|
||||
// doesn't catch degenerates but is quite fast
|
||||
unsigned int iNeed = 0;
|
||||
for (unsigned int v = 0; v < iNumIndices;++v) {
|
||||
unsigned int index = in_mesh->mFaces[base].mIndices[v];
|
||||
|
||||
// check whether we do already have this vertex
|
||||
if (WAS_NOT_COPIED == was_copied_to[index]) {
|
||||
iNeed++;
|
||||
}
|
||||
}
|
||||
if (out_mesh->mNumVertices + iNeed > out_vertex_index) {
|
||||
// don't use this face
|
||||
break;
|
||||
}
|
||||
|
||||
vFaces.push_back(aiFace());
|
||||
aiFace& rFace = vFaces.back();
|
||||
|
||||
// setup face type and number of indices
|
||||
rFace.mNumIndices = iNumIndices;
|
||||
rFace.mIndices = new unsigned int[iNumIndices];
|
||||
|
||||
// need to update the output primitive types
|
||||
switch (rFace.mNumIndices)
|
||||
{
|
||||
case 1:
|
||||
out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
|
||||
break;
|
||||
case 2:
|
||||
out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
|
||||
break;
|
||||
case 3:
|
||||
out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
||||
break;
|
||||
default:
|
||||
out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
|
||||
}
|
||||
|
||||
// and copy the contents of the old array, offset them by current base
|
||||
for (unsigned int v = 0; v < iNumIndices;++v) {
|
||||
const unsigned int index = in_mesh->mFaces[base].mIndices[v];
|
||||
|
||||
// check whether we do already have this vertex
|
||||
if (WAS_NOT_COPIED != was_copied_to[index]) {
|
||||
rFace.mIndices[v] = was_copied_to[index];
|
||||
continue;
|
||||
}
|
||||
|
||||
// copy positions
|
||||
out_mesh->mVertices[out_mesh->mNumVertices] = (in_mesh->mVertices[index]);
|
||||
|
||||
// copy normals
|
||||
if (in_mesh->HasNormals()) {
|
||||
out_mesh->mNormals[out_mesh->mNumVertices] = (in_mesh->mNormals[index]);
|
||||
}
|
||||
|
||||
// copy tangents/bi-tangents
|
||||
if (in_mesh->HasTangentsAndBitangents()) {
|
||||
out_mesh->mTangents[out_mesh->mNumVertices] = (in_mesh->mTangents[index]);
|
||||
out_mesh->mBitangents[out_mesh->mNumVertices] = (in_mesh->mBitangents[index]);
|
||||
}
|
||||
|
||||
// texture coordinates
|
||||
for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
|
||||
if (in_mesh->HasTextureCoords( c)) {
|
||||
out_mesh->mTextureCoords[c][out_mesh->mNumVertices] = in_mesh->mTextureCoords[c][index];
|
||||
}
|
||||
}
|
||||
// vertex colors
|
||||
for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) {
|
||||
if (in_mesh->HasVertexColors( c)) {
|
||||
out_mesh->mColors[c][out_mesh->mNumVertices] = in_mesh->mColors[c][index];
|
||||
}
|
||||
}
|
||||
// check whether we have bone weights assigned to this vertex
|
||||
rFace.mIndices[v] = out_mesh->mNumVertices;
|
||||
if (avPerVertexWeights) {
|
||||
VertexWeightTable& table = avPerVertexWeights[ out_mesh->mNumVertices ];
|
||||
for (VertexWeightTable::const_iterator iter = table.begin(), end = table.end(); iter != end;++iter) {
|
||||
// allocate the bone weight array if necessary and store it in the mBones field (HACK!)
|
||||
BoneWeightList* weight_list = reinterpret_cast<BoneWeightList*>(out_mesh->mBones[(*iter).first]);
|
||||
if (!weight_list) {
|
||||
weight_list = new BoneWeightList();
|
||||
out_mesh->mBones[(*iter).first] = reinterpret_cast<aiBone*>(weight_list);
|
||||
}
|
||||
weight_list->push_back(aiVertexWeight(out_mesh->mNumVertices,(*iter).second));
|
||||
}
|
||||
}
|
||||
|
||||
was_copied_to[index] = out_mesh->mNumVertices;
|
||||
out_mesh->mNumVertices++;
|
||||
}
|
||||
base++;
|
||||
if(out_mesh->mNumVertices == out_vertex_index) {
|
||||
// break here. The face is only added if it was complete
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check which bones we'll need to create for this submesh
|
||||
if (in_mesh->HasBones()) {
|
||||
aiBone** ppCurrent = out_mesh->mBones;
|
||||
for (unsigned int k = 0; k < in_mesh->mNumBones;++k) {
|
||||
// check whether the bone exists
|
||||
BoneWeightList* const weight_list = reinterpret_cast<BoneWeightList*>(out_mesh->mBones[k]);
|
||||
|
||||
if (weight_list) {
|
||||
const aiBone* const bone_in = in_mesh->mBones[k];
|
||||
aiBone* const bone_out = new aiBone();
|
||||
*ppCurrent++ = bone_out;
|
||||
bone_out->mName = aiString(bone_in->mName);
|
||||
bone_out->mOffsetMatrix =bone_in->mOffsetMatrix;
|
||||
bone_out->mNumWeights = (unsigned int)weight_list->size();
|
||||
bone_out->mWeights = new aiVertexWeight[bone_out->mNumWeights];
|
||||
|
||||
// copy the vertex weights
|
||||
::memcpy(bone_out->mWeights, &(*weight_list)[0],bone_out->mNumWeights * sizeof(aiVertexWeight));
|
||||
|
||||
delete weight_list;
|
||||
out_mesh->mNumBones++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy the face list to the mesh
|
||||
out_mesh->mFaces = new aiFace[vFaces.size()];
|
||||
out_mesh->mNumFaces = (unsigned int)vFaces.size();
|
||||
|
||||
for (unsigned int p = 0; p < out_mesh->mNumFaces;++p) {
|
||||
out_mesh->mFaces[p] = vFaces[p];
|
||||
}
|
||||
|
||||
// add the newly created mesh to the list
|
||||
source_mesh_map.push_back(std::make_pair(out_mesh,a));
|
||||
|
||||
if (base == in_mesh->mNumFaces) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// delete the per-vertex weight list again
|
||||
delete[] avPerVertexWeights;
|
||||
|
||||
// now delete the old mesh data
|
||||
delete in_mesh;
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
Assimp2Json
|
||||
Copyright (c) 2011, Alexander C. Gessler
|
||||
|
||||
Licensed under a 3-clause BSD license. See the LICENSE file for more information.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_MESH_SPLITTER
|
||||
#define INCLUDED_MESH_SPLITTER
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Note: this is largely based on assimp's SplitLargeMeshes_Vertex process.
|
||||
// it is refactored and the coding style is slightly improved, though.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct aiScene;
|
||||
struct aiMesh;
|
||||
struct aiNode;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Splits meshes of unique vertices into meshes with no more vertices than
|
||||
* a given, configurable threshold value.
|
||||
*/
|
||||
class MeshSplitter
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
void SetLimit(unsigned int l) {
|
||||
LIMIT = l;
|
||||
}
|
||||
|
||||
unsigned int GetLimit() const {
|
||||
return LIMIT;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* At the moment a process is not supposed to fail.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
void Execute( aiScene* pScene);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void UpdateNode(aiNode* pcNode, const std::vector<std::pair<aiMesh*, unsigned int> >& source_mesh_map);
|
||||
void SplitMesh (unsigned int index, aiMesh* mesh, std::vector<std::pair<aiMesh*, unsigned int> >& source_mesh_map);
|
||||
|
||||
public:
|
||||
|
||||
unsigned int LIMIT;
|
||||
};
|
||||
|
||||
#endif // INCLUDED_MESH_SPLITTER
|
||||
|
|
@ -810,6 +810,14 @@ ADD_ASSIMP_IMPORTER( MMD
|
|||
MMD/MMDVmdParser.h
|
||||
)
|
||||
|
||||
ADD_ASSIMP_EXPORTER( Assjson
|
||||
Assjson/cencode.c
|
||||
Assjson/cencode.h
|
||||
Assjson/json_exporter.cpp
|
||||
Assjson/mesh_splitter.cpp
|
||||
Assjson/mesh_splitter.h
|
||||
)
|
||||
|
||||
# Workaround for issue #2406 - force problematic large file to be optimized to prevent string table overflow error
|
||||
# Used -Os instead of -O2 as previous issues had mentioned, since -Os is roughly speaking -O2, excluding any
|
||||
# optimizations that take up extra space. Given that the issue is a string table overflowing, -Os seemed appropriate
|
||||
|
|
|
@ -898,6 +898,7 @@ public:
|
|||
: nfo(nfo)
|
||||
, reader(reader)
|
||||
, cur(reader.GetCurrentPos()) {
|
||||
// empty
|
||||
}
|
||||
|
||||
~chunk_guard() {
|
||||
|
@ -905,7 +906,7 @@ public:
|
|||
if(nfo.size != static_cast<unsigned int>(-1)) {
|
||||
try {
|
||||
reader.IncPtr( static_cast< int >( nfo.size ) - reader.GetCurrentPos() + cur );
|
||||
} catch (const DeadlyImportError& e ) {
|
||||
} catch (const DeadlyImportError& ) {
|
||||
// out of limit so correct the value
|
||||
reader.IncPtr( reader.GetReadLimit() );
|
||||
}
|
||||
|
@ -913,15 +914,17 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
const COB::ChunkInfo& nfo;
|
||||
StreamReaderLE& reader;
|
||||
long cur;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader)
|
||||
{
|
||||
void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader) {
|
||||
if (nullptr == reader) {
|
||||
return;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
std::string type;
|
||||
type += reader -> GetI1()
|
||||
|
|
|
@ -5,8 +5,6 @@ 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,
|
||||
|
@ -43,7 +41,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
/** @file Implementation of the Collada loader */
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER
|
||||
|
||||
#include "ColladaLoader.h"
|
||||
|
@ -67,7 +64,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <numeric>
|
||||
#include <memory>
|
||||
|
||||
using namespace Assimp;
|
||||
namespace Assimp {
|
||||
|
||||
using namespace Assimp::Formatter;
|
||||
|
||||
static const aiImporterDesc desc = {
|
||||
|
@ -112,7 +110,7 @@ ColladaLoader::~ColladaLoader() {
|
|||
// Returns whether the class can handle the format of the given file.
|
||||
bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
|
||||
// check file extension
|
||||
std::string extension = GetExtension(pFile);
|
||||
const std::string extension = GetExtension(pFile);
|
||||
|
||||
if (extension == "dae") {
|
||||
return true;
|
||||
|
@ -166,12 +164,13 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
|
|||
// parse the input file
|
||||
ColladaParser parser( pIOHandler, pFile);
|
||||
|
||||
if( !parser.mRootNode)
|
||||
if( !parser.mRootNode) {
|
||||
throw DeadlyImportError( "Collada: File came out empty. Something is wrong here.");
|
||||
}
|
||||
|
||||
// reserve some storage to avoid unnecessary reallocs
|
||||
newMats.reserve(parser.mMaterialLibrary.size()*2);
|
||||
mMeshes.reserve(parser.mMeshLibrary.size()*2);
|
||||
newMats.reserve(parser.mMaterialLibrary.size()*2u);
|
||||
mMeshes.reserve(parser.mMeshLibrary.size()*2u);
|
||||
|
||||
mCameras.reserve(parser.mCameraLibrary.size());
|
||||
mLights.reserve(parser.mLightLibrary.size());
|
||||
|
@ -191,19 +190,20 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
|
|||
0, 0, parser.mUnitSize, 0,
|
||||
0, 0, 0, 1);
|
||||
if( !ignoreUpDirection ) {
|
||||
// Convert to Y_UP, if different orientation
|
||||
if( parser.mUpDirection == ColladaParser::UP_X)
|
||||
pScene->mRootNode->mTransformation *= aiMatrix4x4(
|
||||
0, -1, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
else if( parser.mUpDirection == ColladaParser::UP_Z)
|
||||
pScene->mRootNode->mTransformation *= aiMatrix4x4(
|
||||
1, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, -1, 0, 0,
|
||||
0, 0, 0, 1);
|
||||
// Convert to Y_UP, if different orientation
|
||||
if( parser.mUpDirection == ColladaParser::UP_X) {
|
||||
pScene->mRootNode->mTransformation *= aiMatrix4x4(
|
||||
0, -1, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
} else if( parser.mUpDirection == ColladaParser::UP_Z) {
|
||||
pScene->mRootNode->mTransformation *= aiMatrix4x4(
|
||||
1, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, -1, 0, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Store scene metadata
|
||||
|
@ -211,8 +211,7 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
|
|||
const size_t numMeta(parser.mAssetMetaData.size());
|
||||
pScene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(numMeta));
|
||||
size_t i = 0;
|
||||
for (auto it = parser.mAssetMetaData.cbegin(); it != parser.mAssetMetaData.cend(); ++it, ++i)
|
||||
{
|
||||
for (auto it = parser.mAssetMetaData.cbegin(); it != parser.mAssetMetaData.cend(); ++it, ++i) {
|
||||
pScene->mMetaData->Set(static_cast<unsigned int>(i), (*it).first, (*it).second);
|
||||
}
|
||||
}
|
||||
|
@ -232,9 +231,8 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
|
|||
// store all animations
|
||||
StoreAnimations( pScene, parser);
|
||||
|
||||
|
||||
// If no meshes have been loaded, it's probably just an animated skeleton.
|
||||
if (!pScene->mNumMeshes) {
|
||||
if ( 0u == pScene->mNumMeshes) {
|
||||
|
||||
if (!noSkeletonMesh) {
|
||||
SkeletonMeshBuilder hero(pScene);
|
||||
|
@ -302,13 +300,12 @@ void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Co
|
|||
// FIX for http://sourceforge.net/tracker/?func=detail&aid=3054873&group_id=226462&atid=1067632
|
||||
// need to check for both name and ID to catch all. To avoid breaking valid files,
|
||||
// the workaround is only enabled when the first attempt to resolve the node has failed.
|
||||
if (!nd) {
|
||||
if (nullptr == nd) {
|
||||
nd = FindNode(pParser.mRootNode, nodeInst.mNode);
|
||||
}
|
||||
if (!nd)
|
||||
if (nullptr == nd) {
|
||||
ASSIMP_LOG_ERROR_F("Collada: Unable to resolve reference to instanced node ", nodeInst.mNode);
|
||||
|
||||
else {
|
||||
} else {
|
||||
// attach this node to the list of children
|
||||
resolved.push_back(nd);
|
||||
}
|
||||
|
@ -318,7 +315,7 @@ void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Co
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Resolve UV channels
|
||||
void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler,
|
||||
const Collada::SemanticMappingTable& table) {
|
||||
const Collada::SemanticMappingTable& table) {
|
||||
std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel);
|
||||
if (it != table.mMap.end()) {
|
||||
if (it->second.mType != Collada::IT_Texcoord) {
|
||||
|
@ -431,8 +428,7 @@ void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Col
|
|||
out->mAspect = std::tan(AI_DEG_TO_RAD(srcCamera->mHorFov)) /
|
||||
std::tan(AI_DEG_TO_RAD(srcCamera->mVerFov));
|
||||
}
|
||||
}
|
||||
else if (srcCamera->mAspect != 10e10f && srcCamera->mVerFov != 10e10f) {
|
||||
} else if (srcCamera->mAspect != 10e10f && srcCamera->mVerFov != 10e10f) {
|
||||
out->mHorizontalFOV = 2.0f * AI_RAD_TO_DEG(std::atan(srcCamera->mAspect *
|
||||
std::tan(AI_DEG_TO_RAD(srcCamera->mVerFov) * 0.5f)));
|
||||
}
|
||||
|
@ -470,7 +466,7 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
|
|||
}
|
||||
}
|
||||
|
||||
if( !srcMesh) {
|
||||
if( nullptr == srcMesh) {
|
||||
ASSIMP_LOG_WARN_F( "Collada: Unable to find geometry for ID \"", mid.mMeshOrController, "\". Skipping." );
|
||||
continue;
|
||||
}
|
||||
|
@ -770,12 +766,13 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
|
|||
IndexPairVector::const_iterator iit = weightStartPerVertex[orgIndex];
|
||||
size_t pairCount = pSrcController->mWeightCounts[orgIndex];
|
||||
|
||||
for( size_t b = 0; b < pairCount; ++b, ++iit)
|
||||
{
|
||||
size_t jointIndex = iit->first;
|
||||
size_t vertexIndex = iit->second;
|
||||
|
||||
ai_real weight = ReadFloat( weightsAcc, weights, vertexIndex, 0);
|
||||
for( size_t b = 0; b < pairCount; ++b, ++iit) {
|
||||
const size_t jointIndex = iit->first;
|
||||
const size_t vertexIndex = iit->second;
|
||||
ai_real weight = 1.0f;
|
||||
if (!weights.mValues.empty()) {
|
||||
weight = ReadFloat(weightsAcc, weights, vertexIndex, 0);
|
||||
}
|
||||
|
||||
// one day I gonna kill that XSI Collada exporter
|
||||
if( weight > 0.0f)
|
||||
|
@ -790,19 +787,21 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
|
|||
|
||||
// count the number of bones which influence vertices of the current submesh
|
||||
size_t numRemainingBones = 0;
|
||||
for( std::vector<std::vector<aiVertexWeight> >::const_iterator it = dstBones.begin(); it != dstBones.end(); ++it)
|
||||
if( it->size() > 0)
|
||||
numRemainingBones++;
|
||||
for( std::vector<std::vector<aiVertexWeight> >::const_iterator it = dstBones.begin(); it != dstBones.end(); ++it) {
|
||||
if( it->size() > 0) {
|
||||
++numRemainingBones;
|
||||
}
|
||||
}
|
||||
|
||||
// create bone array and copy bone weights one by one
|
||||
dstMesh->mNumBones = static_cast<unsigned int>(numRemainingBones);
|
||||
dstMesh->mBones = new aiBone*[numRemainingBones];
|
||||
size_t boneCount = 0;
|
||||
for( size_t a = 0; a < numBones; ++a)
|
||||
{
|
||||
for( size_t a = 0; a < numBones; ++a) {
|
||||
// omit bones without weights
|
||||
if( dstBones[a].size() == 0)
|
||||
if( dstBones[a].empty() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// create bone with its weights
|
||||
aiBone* bone = new aiBone;
|
||||
|
@ -848,14 +847,16 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
|
|||
// and replace the bone's name by the node's name so that the user can use the standard
|
||||
// find-by-name method to associate nodes with bones.
|
||||
const Collada::Node* bnode = FindNode( pParser.mRootNode, bone->mName.data);
|
||||
if( !bnode)
|
||||
if( !bnode) {
|
||||
bnode = FindNodeBySID( pParser.mRootNode, bone->mName.data);
|
||||
}
|
||||
|
||||
// assign the name that we would have assigned for the source node
|
||||
if( bnode)
|
||||
if( bnode) {
|
||||
bone->mName.Set( FindNameForNode( bnode));
|
||||
else
|
||||
} else {
|
||||
ASSIMP_LOG_WARN_F( "ColladaLoader::CreateMesh(): could not find corresponding node for joint \"", bone->mName.data, "\"." );
|
||||
}
|
||||
|
||||
// and insert bone
|
||||
dstMesh->mBones[boneCount++] = bone;
|
||||
|
@ -867,89 +868,80 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Stores all meshes in the given scene
|
||||
void ColladaLoader::StoreSceneMeshes( aiScene* pScene)
|
||||
{
|
||||
void ColladaLoader::StoreSceneMeshes( aiScene* pScene) {
|
||||
pScene->mNumMeshes = static_cast<unsigned int>(mMeshes.size());
|
||||
if( mMeshes.size() > 0)
|
||||
{
|
||||
pScene->mMeshes = new aiMesh*[mMeshes.size()];
|
||||
std::copy( mMeshes.begin(), mMeshes.end(), pScene->mMeshes);
|
||||
mMeshes.clear();
|
||||
if( mMeshes.empty() ) {
|
||||
return;
|
||||
}
|
||||
pScene->mMeshes = new aiMesh*[mMeshes.size()];
|
||||
std::copy( mMeshes.begin(), mMeshes.end(), pScene->mMeshes);
|
||||
mMeshes.clear();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Stores all cameras in the given scene
|
||||
void ColladaLoader::StoreSceneCameras( aiScene* pScene)
|
||||
{
|
||||
void ColladaLoader::StoreSceneCameras( aiScene* pScene) {
|
||||
pScene->mNumCameras = static_cast<unsigned int>(mCameras.size());
|
||||
if( mCameras.size() > 0)
|
||||
{
|
||||
pScene->mCameras = new aiCamera*[mCameras.size()];
|
||||
std::copy( mCameras.begin(), mCameras.end(), pScene->mCameras);
|
||||
mCameras.clear();
|
||||
if( mCameras.empty() ) {
|
||||
return;
|
||||
}
|
||||
pScene->mCameras = new aiCamera*[mCameras.size()];
|
||||
std::copy( mCameras.begin(), mCameras.end(), pScene->mCameras);
|
||||
mCameras.clear();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Stores all lights in the given scene
|
||||
void ColladaLoader::StoreSceneLights( aiScene* pScene)
|
||||
{
|
||||
void ColladaLoader::StoreSceneLights( aiScene* pScene) {
|
||||
pScene->mNumLights = static_cast<unsigned int>(mLights.size());
|
||||
if( mLights.size() > 0)
|
||||
{
|
||||
pScene->mLights = new aiLight*[mLights.size()];
|
||||
std::copy( mLights.begin(), mLights.end(), pScene->mLights);
|
||||
mLights.clear();
|
||||
if( mLights.empty() ) {
|
||||
return;
|
||||
}
|
||||
pScene->mLights = new aiLight*[mLights.size()];
|
||||
std::copy( mLights.begin(), mLights.end(), pScene->mLights);
|
||||
mLights.clear();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Stores all textures in the given scene
|
||||
void ColladaLoader::StoreSceneTextures( aiScene* pScene)
|
||||
{
|
||||
void ColladaLoader::StoreSceneTextures( aiScene* pScene) {
|
||||
pScene->mNumTextures = static_cast<unsigned int>(mTextures.size());
|
||||
if( mTextures.size() > 0)
|
||||
{
|
||||
pScene->mTextures = new aiTexture*[mTextures.size()];
|
||||
std::copy( mTextures.begin(), mTextures.end(), pScene->mTextures);
|
||||
mTextures.clear();
|
||||
if( mTextures.empty() ) {
|
||||
return;
|
||||
}
|
||||
pScene->mTextures = new aiTexture*[mTextures.size()];
|
||||
std::copy( mTextures.begin(), mTextures.end(), pScene->mTextures);
|
||||
mTextures.clear();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Stores all materials in the given scene
|
||||
void ColladaLoader::StoreSceneMaterials( aiScene* pScene)
|
||||
{
|
||||
void ColladaLoader::StoreSceneMaterials( aiScene* pScene) {
|
||||
pScene->mNumMaterials = static_cast<unsigned int>(newMats.size());
|
||||
|
||||
if (newMats.size() > 0) {
|
||||
pScene->mMaterials = new aiMaterial*[newMats.size()];
|
||||
for (unsigned int i = 0; i < newMats.size();++i)
|
||||
pScene->mMaterials[i] = newMats[i].second;
|
||||
|
||||
newMats.clear();
|
||||
if (newMats.empty() ) {
|
||||
return;
|
||||
}
|
||||
pScene->mMaterials = new aiMaterial*[newMats.size()];
|
||||
for (unsigned int i = 0; i < newMats.size();++i) {
|
||||
pScene->mMaterials[i] = newMats[i].second;
|
||||
}
|
||||
newMats.clear();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Stores all animations
|
||||
void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pParser)
|
||||
{
|
||||
void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pParser) {
|
||||
// recursively collect all animations from the collada scene
|
||||
StoreAnimations( pScene, pParser, &pParser.mAnims, "");
|
||||
|
||||
// catch special case: many animations with the same length, each affecting only a single node.
|
||||
// we need to unite all those single-node-anims to a proper combined animation
|
||||
for( size_t a = 0; a < mAnims.size(); ++a)
|
||||
{
|
||||
for( size_t a = 0; a < mAnims.size(); ++a) {
|
||||
aiAnimation* templateAnim = mAnims[a];
|
||||
if( templateAnim->mNumChannels == 1)
|
||||
{
|
||||
if( templateAnim->mNumChannels == 1) {
|
||||
// search for other single-channel-anims with the same duration
|
||||
std::vector<size_t> collectedAnimIndices;
|
||||
for( size_t b = a+1; b < mAnims.size(); ++b)
|
||||
{
|
||||
for( size_t b = a+1; b < mAnims.size(); ++b) {
|
||||
aiAnimation* other = mAnims[b];
|
||||
if( other->mNumChannels == 1 && other->mDuration == templateAnim->mDuration &&
|
||||
other->mTicksPerSecond == templateAnim->mTicksPerSecond )
|
||||
|
@ -1880,19 +1872,23 @@ const Collada::Node* ColladaLoader::FindNode( const Collada::Node* pNode, const
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Finds a node in the collada scene by the given SID
|
||||
const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const
|
||||
{
|
||||
if( pNode->mSID == pSID)
|
||||
return pNode;
|
||||
const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const {
|
||||
if (nullptr == pNode) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for( size_t a = 0; a < pNode->mChildren.size(); ++a)
|
||||
{
|
||||
const Collada::Node* node = FindNodeBySID( pNode->mChildren[a], pSID);
|
||||
if( node)
|
||||
return node;
|
||||
}
|
||||
if (pNode->mSID == pSID) {
|
||||
return pNode;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
for( size_t a = 0; a < pNode->mChildren.size(); ++a) {
|
||||
const Collada::Node* node = FindNodeBySID( pNode->mChildren[a], pSID);
|
||||
if (node) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -1926,4 +1922,6 @@ std::string ColladaLoader::FindNameForNode( const Collada::Node* pNode)
|
|||
}
|
||||
}
|
||||
|
||||
} // Namespace Assimp
|
||||
|
||||
#endif // !! ASSIMP_BUILD_NO_DAE_IMPORTER
|
||||
|
|
|
@ -47,10 +47,6 @@ namespace Assimp {
|
|||
aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh)
|
||||
{
|
||||
aiAnimMesh *animesh = new aiAnimMesh;
|
||||
animesh->mVertices = NULL;
|
||||
animesh->mNormals = NULL;
|
||||
animesh->mTangents = NULL;
|
||||
animesh->mBitangents = NULL;
|
||||
animesh->mNumVertices = mesh->mNumVertices;
|
||||
if (mesh->mVertices) {
|
||||
animesh->mVertices = new aiVector3D[animesh->mNumVertices];
|
||||
|
|
|
@ -102,6 +102,7 @@ void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperti
|
|||
void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* );
|
||||
void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// global array of all export formats which Assimp supports in its current build
|
||||
|
@ -179,7 +180,11 @@ Exporter::ExportFormatEntry gExporters[] =
|
|||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
|
||||
Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 )
|
||||
Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 ),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_Assjson_EXPORTER
|
||||
Exporter::ExportFormatEntry("json", "Plain JSON representation of the Assimp scene data structure", "json", &ExportAssimp2Json, 0)
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -364,7 +364,7 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out)
|
|||
void DeleteImporterInstanceList(std::vector< BaseImporter* >& deleteList){
|
||||
for(size_t i= 0; i<deleteList.size();++i){
|
||||
delete deleteList[i];
|
||||
deleteList[i]=NULL;
|
||||
deleteList[i]=nullptr;
|
||||
}//for
|
||||
}
|
||||
|
||||
|
|
|
@ -420,11 +420,6 @@ namespace Assimp {
|
|||
|
||||
out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight();
|
||||
|
||||
//cameras are defined along positive x direction
|
||||
/*out_camera->mPosition = cam.Position();
|
||||
out_camera->mLookAt = (cam.InterestPosition() - out_camera->mPosition).Normalize();
|
||||
out_camera->mUp = cam.UpVector();*/
|
||||
|
||||
out_camera->mPosition = aiVector3D(0.0f);
|
||||
out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f);
|
||||
out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f);
|
||||
|
@ -667,8 +662,7 @@ namespace Assimp {
|
|||
if ((v - all_ones).SquareLength() > zero_epsilon) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (ok) {
|
||||
} else if (ok) {
|
||||
if (v.SquareLength() > zero_epsilon) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1253,10 +1247,10 @@ namespace Assimp {
|
|||
ai_assert(count_faces);
|
||||
ai_assert(count_vertices);
|
||||
|
||||
// mapping from output indices to DOM indexing, needed to resolve weights
|
||||
// mapping from output indices to DOM indexing, needed to resolve weights or blendshapes
|
||||
std::vector<unsigned int> reverseMapping;
|
||||
std::map<unsigned int, unsigned int> translateIndexMap;
|
||||
if (process_weights) {
|
||||
if (process_weights || mesh.GetBlendShapes().size() > 0) {
|
||||
reverseMapping.resize(count_vertices);
|
||||
}
|
||||
|
||||
|
@ -1413,8 +1407,10 @@ namespace Assimp {
|
|||
unsigned int count = 0;
|
||||
const unsigned int* outIndices = mesh.ToOutputVertexIndex(index, count);
|
||||
for (unsigned int k = 0; k < count; k++) {
|
||||
unsigned int index = translateIndexMap[outIndices[k]];
|
||||
|
||||
unsigned int outIndex = outIndices[k];
|
||||
if (translateIndexMap.find(outIndex) == translateIndexMap.end())
|
||||
continue;
|
||||
unsigned int index = translateIndexMap[outIndex];
|
||||
animMesh->mVertices[index] += vertex;
|
||||
if (animMesh->mNormals != nullptr) {
|
||||
animMesh->mNormals[index] += normal;
|
||||
|
@ -1428,6 +1424,15 @@ namespace Assimp {
|
|||
}
|
||||
}
|
||||
|
||||
const size_t numAnimMeshes = animMeshes.size();
|
||||
if (numAnimMeshes > 0) {
|
||||
out_mesh->mNumAnimMeshes = static_cast<unsigned int>(numAnimMeshes);
|
||||
out_mesh->mAnimMeshes = new aiAnimMesh*[numAnimMeshes];
|
||||
for (size_t i = 0; i < numAnimMeshes; i++) {
|
||||
out_mesh->mAnimMeshes[i] = animMeshes.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<unsigned int>(meshes.size() - 1);
|
||||
}
|
||||
|
||||
|
@ -1733,9 +1738,8 @@ namespace Assimp {
|
|||
}
|
||||
|
||||
void FBXConverter::TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures,
|
||||
const std::string& propName,
|
||||
aiTextureType target, const MeshGeometry* const mesh)
|
||||
{
|
||||
const std::string& propName,
|
||||
aiTextureType target, const MeshGeometry* const mesh) {
|
||||
TextureMap::const_iterator it = textures.find(propName);
|
||||
if (it == textures.end()) {
|
||||
return;
|
||||
|
|
|
@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "FBXUtil.h"
|
||||
#include "FBXProperties.h"
|
||||
#include "FBXImporter.h"
|
||||
|
||||
#include <assimp/anim.h>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/light.h>
|
||||
|
|
|
@ -627,7 +627,7 @@ public:
|
|||
return content;
|
||||
}
|
||||
|
||||
uint32_t ContentLength() const {
|
||||
uint64_t ContentLength() const {
|
||||
return contentLength;
|
||||
}
|
||||
|
||||
|
|
|
@ -1617,6 +1617,17 @@ void FBXExporter::WriteObjects ()
|
|||
// at the same time we can build a list of all the skeleton nodes,
|
||||
// which will be used later to mark them as type "limbNode".
|
||||
std::unordered_set<const aiNode*> limbnodes;
|
||||
|
||||
//actual bone nodes in fbx, without parenting-up
|
||||
std::unordered_set<std::string> setAllBoneNamesInScene;
|
||||
for(unsigned int m = 0; m < mScene->mNumMeshes; ++ m)
|
||||
{
|
||||
aiMesh* pMesh = mScene->mMeshes[m];
|
||||
for(unsigned int b = 0; b < pMesh->mNumBones; ++ b)
|
||||
setAllBoneNamesInScene.insert(pMesh->mBones[b]->mName.data);
|
||||
}
|
||||
aiMatrix4x4 mxTransIdentity;
|
||||
|
||||
// and a map of nodes by bone name, as finding them is annoying.
|
||||
std::map<std::string,aiNode*> node_by_bone;
|
||||
for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
|
||||
|
@ -1660,6 +1671,11 @@ void FBXExporter::WriteObjects ()
|
|||
if (node_name.find(MAGIC_NODE_TAG) != std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
//not a bone in scene && no effect in transform
|
||||
if(setAllBoneNamesInScene.find(node_name)==setAllBoneNamesInScene.end()
|
||||
&& parent->mTransformation == mxTransIdentity) {
|
||||
continue;
|
||||
}
|
||||
// otherwise check if this is the root of the skeleton
|
||||
bool end = false;
|
||||
// is the mesh part of this node?
|
||||
|
@ -1824,7 +1840,10 @@ void FBXExporter::WriteObjects ()
|
|||
|
||||
// this should be the same as the bone's mOffsetMatrix.
|
||||
// if it's not the same, the skeleton isn't in the bind pose.
|
||||
const float epsilon = 1e-4f; // some error is to be expected
|
||||
float epsilon = 1e-4f; // some error is to be expected
|
||||
float epsilon_custom = mProperties->GetPropertyFloat("BINDPOSE_EPSILON", -1);
|
||||
if(epsilon_custom > 0)
|
||||
epsilon = epsilon_custom;
|
||||
bool bone_xform_okay = true;
|
||||
if (b && ! tr.Equal(b->mOffsetMatrix, epsilon)) {
|
||||
not_in_bind_pose.insert(b);
|
||||
|
|
|
@ -963,7 +963,6 @@ void ParseVectorDataArray(std::vector<float>& out, const Element& el)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read an array of uints
|
||||
void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el)
|
||||
|
@ -1280,7 +1279,6 @@ float ParseTokenAsFloat(const Token& t)
|
|||
return i;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// wrapper around ParseTokenAsInt() with ParseError handling
|
||||
int ParseTokenAsInt(const Token& t)
|
||||
|
@ -1293,8 +1291,6 @@ int ParseTokenAsInt(const Token& t)
|
|||
return i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// wrapper around ParseTokenAsInt64() with ParseError handling
|
||||
int64_t ParseTokenAsInt64(const Token& t)
|
||||
|
|
|
@ -118,7 +118,7 @@ void ObjFileParser::parseFile( IOStreamBuffer<char> &streamBuffer ) {
|
|||
size_t lastFilePos( 0 );
|
||||
|
||||
std::vector<char> buffer;
|
||||
while ( streamBuffer.getNextDataLine( buffer, '\0' ) ) {
|
||||
while ( streamBuffer.getNextDataLine( buffer, '\\' ) ) {
|
||||
m_DataIt = buffer.begin();
|
||||
m_DataItEnd = buffer.end();
|
||||
|
||||
|
|
|
@ -127,7 +127,8 @@ inline void CompressVertex(const aiVector3D& v, uint32_t& out)
|
|||
n.X = (int32_t)v.x;
|
||||
n.Y = (int32_t)v.y;
|
||||
n.Z = (int32_t)v.z;
|
||||
out = t;
|
||||
::memcpy( &out, &t, sizeof(int32_t));
|
||||
//out = t;
|
||||
}
|
||||
|
||||
// UNREAL vertex decompression
|
||||
|
|
|
@ -5,8 +5,6 @@ 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,
|
||||
|
@ -60,7 +58,7 @@ extern "C" {
|
|||
*
|
||||
* Cameras have a representation in the node graph and can be animated.
|
||||
* An important aspect is that the camera itself is also part of the
|
||||
* scenegraph. This means, any values such as the look-at vector are not
|
||||
* scene-graph. This means, any values such as the look-at vector are not
|
||||
* *absolute*, they're <b>relative</b> to the coordinate system defined
|
||||
* by the node which corresponds to the camera. This allows for camera
|
||||
* animations. For static cameras parameters like the 'look-at' or 'up' vectors
|
||||
|
|
|
@ -981,8 +981,12 @@ enum aiComponent
|
|||
|
||||
#define AI_CONFIG_EXPORT_XFILE_64BIT "EXPORT_XFILE_64BIT"
|
||||
|
||||
/**
|
||||
*
|
||||
/** @brief Specifies whether the assimp export shall be able to export point clouds
|
||||
*
|
||||
* When this flag is not defined the render data has to contain valid faces.
|
||||
* Point clouds are only a collection of vertices which have nor spatial organization
|
||||
* by a face and the validation process will remove them. Enabling this feature will
|
||||
* switch off the flag and enable the functionality to export pure point clouds.
|
||||
*/
|
||||
#define AI_CONFIG_EXPORT_POINT_CLOUDS "EXPORT_POINT_CLOUDS"
|
||||
|
||||
|
|
|
@ -120,6 +120,7 @@ SET( IMPORTERS
|
|||
unit/utB3DImportExport.cpp
|
||||
unit/utMDCImportExport.cpp
|
||||
unit/utAssbinImportExport.cpp
|
||||
unit/ImportExport/utAssjsonImportExport.cpp
|
||||
unit/ImportExport/utCOBImportExport.cpp
|
||||
unit/ImportExport/utOgreImportExport.cpp
|
||||
unit/ImportExport/utQ3BSPFileImportExport.cpp
|
||||
|
@ -165,11 +166,11 @@ SET( POST_PROCESSES
|
|||
)
|
||||
|
||||
SOURCE_GROUP( UnitTests\\Compiler FILES unit/CCompilerTest.c )
|
||||
SOURCE_GROUP( UnitTests\\Common FILES ${COMMON} )
|
||||
SOURCE_GROUP( UnitTests\\Importers FILES ${IMPORTERS} )
|
||||
SOURCE_GROUP( UnitTests\\Material FILES ${MATERIAL} )
|
||||
SOURCE_GROUP( UnitTests\\Math FILES ${MATH} )
|
||||
SOURCE_GROUP( UnitTests\\PostProcess FILES ${POST_PROCESSES})
|
||||
SOURCE_GROUP( UnitTests\\Common FILES ${COMMON} )
|
||||
SOURCE_GROUP( UnitTests\\ImportExport FILES ${IMPORTERS} )
|
||||
SOURCE_GROUP( UnitTests\\Material FILES ${MATERIAL} )
|
||||
SOURCE_GROUP( UnitTests\\Math FILES ${MATH} )
|
||||
SOURCE_GROUP( UnitTests\\PostProcess FILES ${POST_PROCESSES})
|
||||
|
||||
add_executable( unit
|
||||
../contrib/gtest/src/gtest-all.cc
|
||||
|
|
Binary file not shown.
|
@ -1,6 +1,6 @@
|
|||
ply
|
||||
format ascii 1.0
|
||||
comment Created by Open Asset Import Library - http://assimp.sf.net (v4.1.649942190)
|
||||
comment Created by Open Asset Import Library - http://assimp.sf.net (v4.1.993695325)
|
||||
element vertex 8
|
||||
property float x
|
||||
property float y
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2016, assimp team
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
@ -39,17 +39,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
---------------------------------------------------------------------------
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef AI_ABSTRACTIMPORTEXPORTBASE_H_INC
|
||||
#define AI_ABSTRACTIMPORTEXPORTBASE_H_INC
|
||||
|
||||
#include "UnitTestPCH.h"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Abstract base class to test import and export
|
||||
*/
|
||||
// ---------------------------------------------------------------------------
|
||||
class AbstractImportExportBase : public ::testing::Test {
|
||||
public:
|
||||
/// @brief The class destructor.
|
||||
virtual ~AbstractImportExportBase();
|
||||
virtual bool importerTest() = 0;
|
||||
|
||||
/// @brief The importer-test, will return true for successful import.
|
||||
/// @return true for success, false for failure.
|
||||
virtual bool importerTest();
|
||||
|
||||
/// @brief The exporter-test, will return true for successful import.
|
||||
/// @return true for success, false for failure.
|
||||
virtual bool exporterTest();
|
||||
};
|
||||
|
||||
inline
|
||||
bool AbstractImportExportBase::importerTest() {
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool AbstractImportExportBase::exporterTest() {
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // AI_ABSTRACTIMPORTEXPORTBASE_H_INC
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
#include "UnitTestPCH.h"
|
||||
#include "AbstractImportExportBase.h"
|
||||
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/Exporter.hpp>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/scene.h>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||
|
||||
class utAssjsonImportExport : public AbstractImportExportBase {
|
||||
public:
|
||||
bool exporterTest() override {
|
||||
Importer importer;
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure);
|
||||
|
||||
Exporter exporter;
|
||||
aiReturn res = exporter.Export(scene, "json", "./spider_test.json");
|
||||
return aiReturn_SUCCESS == res;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(utAssjsonImportExport, exportTest) {
|
||||
EXPECT_TRUE(exporterTest());
|
||||
}
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_EXPORT
|
|
@ -5,8 +5,6 @@ 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,
|
||||
|
|
|
@ -5,8 +5,6 @@ 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,
|
||||
|
|
|
@ -5,8 +5,6 @@ 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,
|
||||
|
@ -53,8 +51,8 @@ using namespace Assimp;
|
|||
|
||||
class utAssbinImportExport : public AbstractImportExportBase {
|
||||
public:
|
||||
virtual bool importerTest() {
|
||||
Assimp::Importer importer;
|
||||
bool importerTest() override {
|
||||
Importer importer;
|
||||
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure );
|
||||
|
||||
Exporter exporter;
|
||||
|
@ -66,7 +64,7 @@ public:
|
|||
};
|
||||
|
||||
TEST_F( utAssbinImportExport, exportAssbin3DFromFileTest ) {
|
||||
Assimp::Importer importer;
|
||||
Importer importer;
|
||||
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure );
|
||||
EXPECT_NE( nullptr, scene );
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@ 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,
|
||||
|
|
|
@ -5,8 +5,6 @@ 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,
|
||||
|
@ -73,11 +71,6 @@ TEST_F(BlenderWorkTest,work_279) {
|
|||
ASSERT_TRUE(pTest->HasMaterials());
|
||||
ASSERT_TRUE(pTest->HasMeshes());
|
||||
ASSERT_TRUE(pTest->mMeshes[0]->mNumVertices > 0);
|
||||
ASSERT_EQ(44, pTest->mMeshes[0]->mNumFaces);
|
||||
EXPECT_EQ(1, pTest->mNumMaterials);
|
||||
ASSERT_EQ(44u, pTest->mMeshes[0]->mNumFaces);
|
||||
EXPECT_EQ(1u, pTest->mNumMaterials);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -70,10 +70,10 @@ TEST_F( utFBXImporterExporter, importBareBoxWithoutColorsAndTextureCoords ) {
|
|||
Assimp::Importer importer;
|
||||
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/FBX/box.fbx", aiProcess_ValidateDataStructure );
|
||||
EXPECT_NE( nullptr, scene );
|
||||
EXPECT_EQ(scene->mNumMeshes, 1);
|
||||
EXPECT_EQ(scene->mNumMeshes, 1u);
|
||||
aiMesh* mesh = scene->mMeshes[0];
|
||||
EXPECT_EQ(mesh->mNumFaces, 12);
|
||||
EXPECT_EQ(mesh->mNumVertices, 36);
|
||||
EXPECT_EQ(mesh->mNumFaces, 12u);
|
||||
EXPECT_EQ(mesh->mNumVertices, 36u);
|
||||
}
|
||||
|
||||
TEST_F(utFBXImporterExporter, importCubesWithNoNames) {
|
||||
|
@ -85,13 +85,13 @@ TEST_F(utFBXImporterExporter, importCubesWithNoNames) {
|
|||
const auto root = scene->mRootNode;
|
||||
ASSERT_STREQ(root->mName.C_Str(), "RootNode");
|
||||
ASSERT_TRUE(root->mChildren);
|
||||
ASSERT_EQ(root->mNumChildren, 2);
|
||||
ASSERT_EQ(root->mNumChildren, 2u);
|
||||
|
||||
const auto child0 = root->mChildren[0];
|
||||
ASSERT_TRUE(child0);
|
||||
ASSERT_STREQ(child0->mName.C_Str(), "RootNode001");
|
||||
ASSERT_TRUE(child0->mChildren);
|
||||
ASSERT_EQ(child0->mNumChildren, 1);
|
||||
ASSERT_EQ(child0->mNumChildren, 1u);
|
||||
|
||||
const auto child00 = child0->mChildren[0];
|
||||
ASSERT_TRUE(child00);
|
||||
|
@ -101,7 +101,7 @@ TEST_F(utFBXImporterExporter, importCubesWithNoNames) {
|
|||
ASSERT_TRUE(child1);
|
||||
ASSERT_STREQ(child1->mName.C_Str(), "RootNode002");
|
||||
ASSERT_TRUE(child1->mChildren);
|
||||
ASSERT_EQ(child1->mNumChildren, 1);
|
||||
ASSERT_EQ(child1->mNumChildren, 1u);
|
||||
|
||||
const auto child10 = child1->mChildren[0];
|
||||
ASSERT_TRUE(child10);
|
||||
|
@ -117,13 +117,13 @@ TEST_F(utFBXImporterExporter, importCubesWithUnicodeDuplicatedNames) {
|
|||
const auto root = scene->mRootNode;
|
||||
ASSERT_STREQ(root->mName.C_Str(), "RootNode");
|
||||
ASSERT_TRUE(root->mChildren);
|
||||
ASSERT_EQ(root->mNumChildren, 2);
|
||||
ASSERT_EQ(root->mNumChildren, 2u);
|
||||
|
||||
const auto child0 = root->mChildren[0];
|
||||
ASSERT_TRUE(child0);
|
||||
ASSERT_STREQ(child0->mName.C_Str(), "Cube2");
|
||||
ASSERT_TRUE(child0->mChildren);
|
||||
ASSERT_EQ(child0->mNumChildren, 1);
|
||||
ASSERT_EQ(child0->mNumChildren, 1u);
|
||||
|
||||
const auto child00 = child0->mChildren[0];
|
||||
ASSERT_TRUE(child00);
|
||||
|
@ -133,7 +133,7 @@ TEST_F(utFBXImporterExporter, importCubesWithUnicodeDuplicatedNames) {
|
|||
ASSERT_TRUE(child1);
|
||||
ASSERT_STREQ(child1->mName.C_Str(), "Cube3");
|
||||
ASSERT_TRUE(child1->mChildren);
|
||||
ASSERT_EQ(child1->mNumChildren, 1);
|
||||
ASSERT_EQ(child1->mNumChildren, 1u);
|
||||
|
||||
const auto child10 = child1->mChildren[0];
|
||||
ASSERT_TRUE(child10);
|
||||
|
@ -149,13 +149,13 @@ TEST_F(utFBXImporterExporter, importCubesComplexTransform) {
|
|||
const auto root = scene->mRootNode;
|
||||
ASSERT_STREQ(root->mName.C_Str(), "RootNode");
|
||||
ASSERT_TRUE(root->mChildren);
|
||||
ASSERT_EQ(root->mNumChildren, 2);
|
||||
ASSERT_EQ(root->mNumChildren, 2u);
|
||||
|
||||
const auto child0 = root->mChildren[0];
|
||||
ASSERT_TRUE(child0);
|
||||
ASSERT_STREQ(child0->mName.C_Str(), "Cube2");
|
||||
ASSERT_TRUE(child0->mChildren);
|
||||
ASSERT_EQ(child0->mNumChildren, 1);
|
||||
ASSERT_EQ(child0->mNumChildren, 1u);
|
||||
|
||||
const auto child00 = child0->mChildren[0];
|
||||
ASSERT_TRUE(child00);
|
||||
|
@ -177,35 +177,36 @@ TEST_F(utFBXImporterExporter, importCubesComplexTransform) {
|
|||
"Cube1001_$AssimpFbx$_ScalingPivotInverse",
|
||||
"Cube1001"
|
||||
};
|
||||
for (size_t i = 0; i < chain_length; ++i)
|
||||
{
|
||||
for (size_t i = 0; i < chain_length; ++i) {
|
||||
ASSERT_TRUE(parent->mChildren);
|
||||
ASSERT_EQ(parent->mNumChildren, 1);
|
||||
ASSERT_EQ(parent->mNumChildren, 1u);
|
||||
auto node = parent->mChildren[0];
|
||||
ASSERT_TRUE(node);
|
||||
ASSERT_STREQ(node->mName.C_Str(), chainStr[i]);
|
||||
parent = node;
|
||||
}
|
||||
ASSERT_EQ(0, parent->mNumChildren) << "Leaf node";
|
||||
ASSERT_EQ(0u, parent->mNumChildren) << "Leaf node";
|
||||
}
|
||||
|
||||
TEST_F( utFBXImporterExporter, importPhongMaterial ) {
|
||||
Assimp::Importer importer;
|
||||
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/FBX/phong_cube.fbx", aiProcess_ValidateDataStructure );
|
||||
EXPECT_NE( nullptr, scene );
|
||||
EXPECT_EQ( (unsigned int)1, scene->mNumMaterials );
|
||||
EXPECT_EQ( 1u, scene->mNumMaterials );
|
||||
const aiMaterial *mat = scene->mMaterials[0];
|
||||
EXPECT_NE( nullptr, mat );
|
||||
float f; aiColor3D c;
|
||||
float f;
|
||||
aiColor3D c;
|
||||
|
||||
// phong_cube.fbx has all properties defined
|
||||
EXPECT_EQ( mat->Get(AI_MATKEY_COLOR_DIFFUSE, c), aiReturn_SUCCESS );
|
||||
EXPECT_EQ( c, aiColor3D(0.5, 0.25, 0.25) );
|
||||
EXPECT_EQ( mat->Get(AI_MATKEY_COLOR_SPECULAR, c), aiReturn_SUCCESS );
|
||||
EXPECT_EQ( c, aiColor3D(0.25, 0.25, 0.5) );
|
||||
EXPECT_EQ( mat->Get(AI_MATKEY_SHININESS_STRENGTH, f), aiReturn_SUCCESS );
|
||||
EXPECT_EQ( f, 0.5 );
|
||||
EXPECT_EQ( f, 0.5f );
|
||||
EXPECT_EQ( mat->Get(AI_MATKEY_SHININESS, f), aiReturn_SUCCESS );
|
||||
EXPECT_EQ( f, 10.0 );
|
||||
EXPECT_EQ( f, 10.0f );
|
||||
EXPECT_EQ( mat->Get(AI_MATKEY_COLOR_AMBIENT, c), aiReturn_SUCCESS );
|
||||
EXPECT_EQ( c, aiColor3D(0.125, 0.25, 0.25) );
|
||||
EXPECT_EQ( mat->Get(AI_MATKEY_COLOR_EMISSIVE, c), aiReturn_SUCCESS );
|
||||
|
@ -213,7 +214,7 @@ TEST_F( utFBXImporterExporter, importPhongMaterial ) {
|
|||
EXPECT_EQ( mat->Get(AI_MATKEY_COLOR_TRANSPARENT, c), aiReturn_SUCCESS );
|
||||
EXPECT_EQ( c, aiColor3D(0.75, 0.5, 0.25) );
|
||||
EXPECT_EQ( mat->Get(AI_MATKEY_OPACITY, f), aiReturn_SUCCESS );
|
||||
EXPECT_EQ( f, 0.5 );
|
||||
EXPECT_EQ( f, 0.5f );
|
||||
}
|
||||
|
||||
TEST_F(utFBXImporterExporter, importUnitScaleFactor) {
|
||||
|
@ -234,7 +235,7 @@ TEST_F(utFBXImporterExporter, importEmbeddedAsciiTest) {
|
|||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/embedded_ascii/box.FBX", aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
|
||||
EXPECT_EQ(1, scene->mNumMaterials);
|
||||
EXPECT_EQ(1u, scene->mNumMaterials);
|
||||
aiMaterial *mat = scene->mMaterials[0];
|
||||
ASSERT_NE(nullptr, mat);
|
||||
|
||||
|
@ -243,7 +244,7 @@ TEST_F(utFBXImporterExporter, importEmbeddedAsciiTest) {
|
|||
EXPECT_EQ(aiReturn_SUCCESS, mat->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, nullptr, nullptr, modes));
|
||||
ASSERT_STREQ(path.C_Str(), "..\\..\\..\\Desktop\\uv_test.png");
|
||||
|
||||
ASSERT_EQ(1, scene->mNumTextures);
|
||||
ASSERT_EQ(1u, scene->mNumTextures);
|
||||
ASSERT_TRUE(scene->mTextures[0]->pcData);
|
||||
ASSERT_EQ(439176u, scene->mTextures[0]->mWidth) << "FBX ASCII base64 compression splits data by 512Kb, it should be two parts for this texture";
|
||||
}
|
||||
|
@ -254,7 +255,7 @@ TEST_F(utFBXImporterExporter, importEmbeddedFragmentedAsciiTest) {
|
|||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/embedded_ascii/box_embedded_texture_fragmented.fbx", aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
|
||||
EXPECT_EQ(1, scene->mNumMaterials);
|
||||
EXPECT_EQ(1u, scene->mNumMaterials);
|
||||
aiMaterial *mat = scene->mMaterials[0];
|
||||
ASSERT_NE(nullptr, mat);
|
||||
|
||||
|
@ -263,7 +264,7 @@ TEST_F(utFBXImporterExporter, importEmbeddedFragmentedAsciiTest) {
|
|||
ASSERT_EQ(aiReturn_SUCCESS, mat->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, nullptr, nullptr, modes));
|
||||
ASSERT_STREQ(path.C_Str(), "paper.png");
|
||||
|
||||
ASSERT_EQ(1, scene->mNumTextures);
|
||||
ASSERT_EQ(1u, scene->mNumTextures);
|
||||
ASSERT_TRUE(scene->mTextures[0]->pcData);
|
||||
ASSERT_EQ(968029u, scene->mTextures[0]->mWidth) << "FBX ASCII base64 compression splits data by 512Kb, it should be two parts for this texture";
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@ 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,
|
||||
|
@ -49,35 +47,42 @@ using namespace Assimp;
|
|||
|
||||
class FindDegeneratesProcessTest : public ::testing::Test {
|
||||
public:
|
||||
FindDegeneratesProcessTest()
|
||||
: Test()
|
||||
, mMesh( nullptr )
|
||||
, mProcess( nullptr ) {
|
||||
// empty
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
protected:
|
||||
aiMesh* mesh;
|
||||
FindDegeneratesProcess* process;
|
||||
aiMesh* mMesh;
|
||||
FindDegeneratesProcess* mProcess;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void FindDegeneratesProcessTest::SetUp() {
|
||||
mesh = new aiMesh();
|
||||
process = new FindDegeneratesProcess();
|
||||
mMesh = new aiMesh();
|
||||
mProcess = new FindDegeneratesProcess();
|
||||
|
||||
mesh->mNumFaces = 1000;
|
||||
mesh->mFaces = new aiFace[1000];
|
||||
mMesh->mNumFaces = 1000;
|
||||
mMesh->mFaces = new aiFace[1000];
|
||||
|
||||
mesh->mNumVertices = 5000*2;
|
||||
mesh->mVertices = new aiVector3D[5000*2];
|
||||
mMesh->mNumVertices = 5000*2;
|
||||
mMesh->mVertices = new aiVector3D[5000*2];
|
||||
|
||||
for (unsigned int i = 0; i < 5000; ++i) {
|
||||
mesh->mVertices[i] = mesh->mVertices[i+5000] = aiVector3D((float)i);
|
||||
mMesh->mVertices[i] = mMesh->mVertices[i+5000] = aiVector3D((float)i);
|
||||
}
|
||||
|
||||
mesh->mPrimitiveTypes = aiPrimitiveType_LINE | aiPrimitiveType_POINT |
|
||||
mMesh->mPrimitiveTypes = aiPrimitiveType_LINE | aiPrimitiveType_POINT |
|
||||
aiPrimitiveType_POLYGON | aiPrimitiveType_TRIANGLE;
|
||||
|
||||
unsigned int numOut = 0, numFaces = 0;
|
||||
for (unsigned int i = 0; i < 1000; ++i) {
|
||||
aiFace& f = mesh->mFaces[i];
|
||||
aiFace& f = mMesh->mFaces[i];
|
||||
f.mNumIndices = (i % 5)+1; // between 1 and 5
|
||||
f.mIndices = new unsigned int[f.mNumIndices];
|
||||
bool had = false;
|
||||
|
@ -102,46 +107,46 @@ void FindDegeneratesProcessTest::SetUp() {
|
|||
if (!had)
|
||||
++numFaces;
|
||||
}
|
||||
mesh->mNumUVComponents[0] = numOut;
|
||||
mesh->mNumUVComponents[1] = numFaces;
|
||||
mMesh->mNumUVComponents[0] = numOut;
|
||||
mMesh->mNumUVComponents[1] = numFaces;
|
||||
}
|
||||
|
||||
void FindDegeneratesProcessTest::TearDown() {
|
||||
delete mesh;
|
||||
delete process;
|
||||
delete mMesh;
|
||||
delete mProcess;
|
||||
}
|
||||
|
||||
TEST_F(FindDegeneratesProcessTest, testDegeneratesDetection) {
|
||||
process->EnableInstantRemoval(false);
|
||||
process->ExecuteOnMesh(mesh);
|
||||
mProcess->EnableInstantRemoval(false);
|
||||
mProcess->ExecuteOnMesh(mMesh);
|
||||
|
||||
unsigned int out = 0;
|
||||
for (unsigned int i = 0; i < 1000; ++i) {
|
||||
aiFace& f = mesh->mFaces[i];
|
||||
aiFace& f = mMesh->mFaces[i];
|
||||
out += f.mNumIndices;
|
||||
}
|
||||
|
||||
EXPECT_EQ(1000U, mesh->mNumFaces);
|
||||
EXPECT_EQ(10000U, mesh->mNumVertices);
|
||||
EXPECT_EQ(out, mesh->mNumUVComponents[0]);
|
||||
EXPECT_EQ(1000U, mMesh->mNumFaces);
|
||||
EXPECT_EQ(10000U, mMesh->mNumVertices);
|
||||
EXPECT_EQ(out, mMesh->mNumUVComponents[0]);
|
||||
EXPECT_EQ(static_cast<unsigned int>(
|
||||
aiPrimitiveType_LINE | aiPrimitiveType_POINT |
|
||||
aiPrimitiveType_POLYGON | aiPrimitiveType_TRIANGLE),
|
||||
mesh->mPrimitiveTypes);
|
||||
mMesh->mPrimitiveTypes);
|
||||
}
|
||||
|
||||
TEST_F(FindDegeneratesProcessTest, testDegeneratesRemoval) {
|
||||
process->EnableAreaCheck(false);
|
||||
process->EnableInstantRemoval(true);
|
||||
process->ExecuteOnMesh(mesh);
|
||||
mProcess->EnableAreaCheck(false);
|
||||
mProcess->EnableInstantRemoval(true);
|
||||
mProcess->ExecuteOnMesh(mMesh);
|
||||
|
||||
EXPECT_EQ(mesh->mNumUVComponents[1], mesh->mNumFaces);
|
||||
EXPECT_EQ(mMesh->mNumUVComponents[1], mMesh->mNumFaces);
|
||||
}
|
||||
|
||||
TEST_F(FindDegeneratesProcessTest, testDegeneratesRemovalWithAreaCheck) {
|
||||
process->EnableAreaCheck(true);
|
||||
process->EnableInstantRemoval(true);
|
||||
process->ExecuteOnMesh(mesh);
|
||||
mProcess->EnableAreaCheck(true);
|
||||
mProcess->EnableInstantRemoval(true);
|
||||
mProcess->ExecuteOnMesh(mMesh);
|
||||
|
||||
EXPECT_EQ(mesh->mNumUVComponents[1]-100, mesh->mNumFaces);
|
||||
EXPECT_EQ(mMesh->mNumUVComponents[1]-100, mMesh->mNumFaces);
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@ 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,
|
||||
|
@ -48,89 +46,100 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
using namespace std;
|
||||
using namespace Assimp;
|
||||
|
||||
class FindInvalidDataProcessTest : public ::testing::Test
|
||||
{
|
||||
class utFindInvalidDataProcess : public ::testing::Test {
|
||||
public:
|
||||
utFindInvalidDataProcess()
|
||||
: Test()
|
||||
, mMesh(nullptr)
|
||||
, mProcess(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
protected:
|
||||
aiMesh* pcMesh;
|
||||
FindInvalidDataProcess* piProcess;
|
||||
aiMesh* mMesh;
|
||||
FindInvalidDataProcess* mProcess;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void FindInvalidDataProcessTest::SetUp() {
|
||||
void utFindInvalidDataProcess::SetUp() {
|
||||
ASSERT_TRUE( AI_MAX_NUMBER_OF_TEXTURECOORDS >= 3);
|
||||
|
||||
piProcess = new FindInvalidDataProcess();
|
||||
pcMesh = new aiMesh();
|
||||
mProcess = new FindInvalidDataProcess();
|
||||
mMesh = new aiMesh();
|
||||
|
||||
pcMesh->mNumVertices = 1000;
|
||||
pcMesh->mVertices = new aiVector3D[1000];
|
||||
for (unsigned int i = 0; i < 1000;++i)
|
||||
pcMesh->mVertices[i] = aiVector3D((float)i);
|
||||
mMesh->mNumVertices = 1000;
|
||||
mMesh->mVertices = new aiVector3D[1000];
|
||||
for (unsigned int i = 0; i < 1000; ++i) {
|
||||
mMesh->mVertices[i] = aiVector3D((float)i);
|
||||
}
|
||||
|
||||
pcMesh->mNormals = new aiVector3D[1000];
|
||||
for (unsigned int i = 0; i < 1000;++i)
|
||||
pcMesh->mNormals[i] = aiVector3D((float)i+1);
|
||||
mMesh->mNormals = new aiVector3D[1000];
|
||||
for (unsigned int i = 0; i < 1000; ++i) {
|
||||
mMesh->mNormals[i] = aiVector3D((float)i + 1);
|
||||
}
|
||||
|
||||
pcMesh->mTangents = new aiVector3D[1000];
|
||||
for (unsigned int i = 0; i < 1000;++i)
|
||||
pcMesh->mTangents[i] = aiVector3D((float)i);
|
||||
mMesh->mTangents = new aiVector3D[1000];
|
||||
for (unsigned int i = 0; i < 1000; ++i) {
|
||||
mMesh->mTangents[i] = aiVector3D((float)i);
|
||||
}
|
||||
|
||||
pcMesh->mBitangents = new aiVector3D[1000];
|
||||
for (unsigned int i = 0; i < 1000;++i)
|
||||
pcMesh->mBitangents[i] = aiVector3D((float)i);
|
||||
mMesh->mBitangents = new aiVector3D[1000];
|
||||
for (unsigned int i = 0; i < 1000; ++i) {
|
||||
mMesh->mBitangents[i] = aiVector3D((float)i);
|
||||
}
|
||||
|
||||
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a)
|
||||
{
|
||||
pcMesh->mTextureCoords[a] = new aiVector3D[1000];
|
||||
for (unsigned int i = 0; i < 1000;++i)
|
||||
pcMesh->mTextureCoords[a][i] = aiVector3D((float)i);
|
||||
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) {
|
||||
mMesh->mTextureCoords[a] = new aiVector3D[1000];
|
||||
for (unsigned int i = 0; i < 1000; ++i) {
|
||||
mMesh->mTextureCoords[a][i] = aiVector3D((float)i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void FindInvalidDataProcessTest::TearDown()
|
||||
{
|
||||
delete piProcess;
|
||||
delete pcMesh;
|
||||
void utFindInvalidDataProcess::TearDown() {
|
||||
delete mProcess;
|
||||
delete mMesh;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
TEST_F(FindInvalidDataProcessTest, testStepNegativeResult)
|
||||
{
|
||||
::memset(pcMesh->mNormals,0,pcMesh->mNumVertices*sizeof(aiVector3D));
|
||||
::memset(pcMesh->mBitangents,0,pcMesh->mNumVertices*sizeof(aiVector3D));
|
||||
TEST_F(utFindInvalidDataProcess, testStepNegativeResult) {
|
||||
::memset(mMesh->mNormals, 0, mMesh->mNumVertices*sizeof(aiVector3D) );
|
||||
::memset(mMesh->mBitangents, 0, mMesh->mNumVertices*sizeof(aiVector3D) );
|
||||
|
||||
pcMesh->mTextureCoords[2][455] = aiVector3D( std::numeric_limits<float>::quiet_NaN() );
|
||||
mMesh->mTextureCoords[2][455] = aiVector3D( std::numeric_limits<float>::quiet_NaN() );
|
||||
|
||||
piProcess->ProcessMesh(pcMesh);
|
||||
mProcess->ProcessMesh(mMesh);
|
||||
|
||||
EXPECT_TRUE(NULL != pcMesh->mVertices);
|
||||
EXPECT_TRUE(NULL == pcMesh->mNormals);
|
||||
EXPECT_TRUE(NULL == pcMesh->mTangents);
|
||||
EXPECT_TRUE(NULL == pcMesh->mBitangents);
|
||||
EXPECT_TRUE(NULL != mMesh->mVertices);
|
||||
EXPECT_EQ(NULL, mMesh->mNormals);
|
||||
EXPECT_EQ(NULL, mMesh->mTangents);
|
||||
EXPECT_EQ(NULL, mMesh->mBitangents);
|
||||
|
||||
for (unsigned int i = 0; i < 2;++i)
|
||||
EXPECT_TRUE(NULL != pcMesh->mTextureCoords[i]);
|
||||
for (unsigned int i = 0; i < 2; ++i) {
|
||||
EXPECT_TRUE(NULL != mMesh->mTextureCoords[i]);
|
||||
}
|
||||
|
||||
for (unsigned int i = 2; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
|
||||
EXPECT_TRUE(NULL == pcMesh->mTextureCoords[i]);
|
||||
for (unsigned int i = 2; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||
EXPECT_EQ(NULL, mMesh->mTextureCoords[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
TEST_F(FindInvalidDataProcessTest, testStepPositiveResult)
|
||||
{
|
||||
piProcess->ProcessMesh(pcMesh);
|
||||
TEST_F(utFindInvalidDataProcess, testStepPositiveResult) {
|
||||
mProcess->ProcessMesh(mMesh);
|
||||
|
||||
EXPECT_TRUE(NULL != pcMesh->mVertices);
|
||||
EXPECT_NE(nullptr, mMesh->mVertices);
|
||||
|
||||
EXPECT_TRUE(NULL != pcMesh->mNormals);
|
||||
EXPECT_TRUE(NULL != pcMesh->mTangents);
|
||||
EXPECT_TRUE(NULL != pcMesh->mBitangents);
|
||||
EXPECT_NE(nullptr, mMesh->mNormals);
|
||||
EXPECT_NE(nullptr, mMesh->mTangents);
|
||||
EXPECT_NE(nullptr, mMesh->mBitangents);
|
||||
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
|
||||
EXPECT_TRUE(NULL != pcMesh->mTextureCoords[i]);
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||
EXPECT_NE(nullptr, mMesh->mTextureCoords[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,13 +48,21 @@ using namespace Assimp;
|
|||
|
||||
class utGenBoundingBoxesProcess : public ::testing::Test {
|
||||
public:
|
||||
utGenBoundingBoxesProcess()
|
||||
: Test()
|
||||
, mProcess(nullptr)
|
||||
, mMesh(nullptr)
|
||||
, mScene(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
mProcess = new GenBoundingBoxesProcess;
|
||||
mMesh = new aiMesh();
|
||||
mMesh->mNumVertices = 100;
|
||||
mMesh->mVertices = new aiVector3D[100];
|
||||
for (unsigned int i = 0; i < 100; ++i) {
|
||||
mMesh->mVertices[i] = aiVector3D(i, i, i);
|
||||
mMesh->mVertices[i] = aiVector3D((ai_real)i, (ai_real)i, (ai_real)i);
|
||||
}
|
||||
mScene = new aiScene();
|
||||
mScene->mNumMeshes = 1;
|
||||
|
|
|
@ -74,7 +74,7 @@ TEST_F( utIssues, OpacityBugWhenExporting_727 ) {
|
|||
if ( newScene->mNumMaterials > 0 ) {
|
||||
std::cout << "Desc = " << desc->description << "\n";
|
||||
EXPECT_EQ( AI_SUCCESS, newScene->mMaterials[ 0 ]->Get( AI_MATKEY_OPACITY, newOpacity ) );
|
||||
EXPECT_EQ( opacity, newOpacity );
|
||||
EXPECT_FLOAT_EQ( opacity, newOpacity );
|
||||
}
|
||||
delete scene;
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@ 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,
|
||||
|
@ -49,8 +47,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
using namespace std;
|
||||
using namespace Assimp;
|
||||
|
||||
class JoinVerticesTest : public ::testing::Test {
|
||||
class utJoinVertices : public ::testing::Test {
|
||||
public:
|
||||
utJoinVertices()
|
||||
: Test()
|
||||
, piProcess(nullptr)
|
||||
, pcMesh(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
|
@ -60,8 +66,7 @@ protected:
|
|||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void JoinVerticesTest::SetUp()
|
||||
{
|
||||
void utJoinVertices::SetUp() {
|
||||
// construct the process
|
||||
piProcess = new JoinVerticesProcess();
|
||||
|
||||
|
@ -71,11 +76,9 @@ void JoinVerticesTest::SetUp()
|
|||
|
||||
pcMesh->mNumVertices = 900;
|
||||
aiVector3D*& pv = pcMesh->mVertices = new aiVector3D[900];
|
||||
for (unsigned int i = 0; i < 3;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < 3;++i) {
|
||||
const unsigned int base = i*300;
|
||||
for (unsigned int a = 0; a < 300;++a)
|
||||
{
|
||||
for (unsigned int a = 0; a < 300;++a) {
|
||||
pv[base+a].x = pv[base+a].y = pv[base+a].z = (float)a;
|
||||
}
|
||||
}
|
||||
|
@ -83,38 +86,37 @@ void JoinVerticesTest::SetUp()
|
|||
// generate faces - each vertex is referenced once
|
||||
pcMesh->mNumFaces = 300;
|
||||
pcMesh->mFaces = new aiFace[300];
|
||||
for (unsigned int i = 0,p = 0; i < 300;++i)
|
||||
{
|
||||
for (unsigned int i = 0,p = 0; i < 300;++i) {
|
||||
aiFace& face = pcMesh->mFaces[i];
|
||||
face.mIndices = new unsigned int[ face.mNumIndices = 3 ];
|
||||
for (unsigned int a = 0; a < 3;++a)
|
||||
for (unsigned int a = 0; a < 3; ++a) {
|
||||
face.mIndices[a] = p++;
|
||||
}
|
||||
}
|
||||
|
||||
// generate extra members - set them to zero to make sure they're identical
|
||||
pcMesh->mTextureCoords[0] = new aiVector3D[900];
|
||||
for (unsigned int i = 0; i < 900;++i)pcMesh->mTextureCoords[0][i] = aiVector3D( 0.f );
|
||||
|
||||
pcMesh->mNormals = new aiVector3D[900];
|
||||
for (unsigned int i = 0; i < 900;++i)pcMesh->mNormals[i] = aiVector3D( 0.f );
|
||||
|
||||
pcMesh->mTangents = new aiVector3D[900];
|
||||
for (unsigned int i = 0; i < 900;++i)pcMesh->mTangents[i] = aiVector3D( 0.f );
|
||||
|
||||
pcMesh->mBitangents = new aiVector3D[900];
|
||||
for (unsigned int i = 0; i < 900;++i)pcMesh->mBitangents[i] = aiVector3D( 0.f );
|
||||
pcMesh->mNormals = new aiVector3D[900];
|
||||
pcMesh->mTangents = new aiVector3D[900];
|
||||
for (unsigned int i = 0; i < 900; ++i) {
|
||||
pcMesh->mTextureCoords[0][i] = aiVector3D(0.f);
|
||||
pcMesh->mNormals[i] = aiVector3D(0.f);
|
||||
pcMesh->mTangents[i] = aiVector3D(0.f);
|
||||
pcMesh->mBitangents[i] = aiVector3D(0.f);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void JoinVerticesTest::TearDown()
|
||||
{
|
||||
void utJoinVertices::TearDown() {
|
||||
delete this->pcMesh;
|
||||
pcMesh = nullptr;
|
||||
delete this->piProcess;
|
||||
piProcess = nullptr;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
TEST_F(JoinVerticesTest, testProcess)
|
||||
{
|
||||
TEST_F(utJoinVertices, testProcess) {
|
||||
// execute the step on the given data
|
||||
piProcess->ProcessMesh(pcMesh,0);
|
||||
|
||||
|
@ -122,15 +124,14 @@ TEST_F(JoinVerticesTest, testProcess)
|
|||
ASSERT_EQ(300U, pcMesh->mNumFaces);
|
||||
ASSERT_EQ(300U, pcMesh->mNumVertices);
|
||||
|
||||
ASSERT_TRUE(NULL != pcMesh->mNormals);
|
||||
ASSERT_TRUE(NULL != pcMesh->mTangents);
|
||||
ASSERT_TRUE(NULL != pcMesh->mBitangents);
|
||||
ASSERT_TRUE(NULL != pcMesh->mTextureCoords[0]);
|
||||
ASSERT_TRUE( nullptr != pcMesh->mNormals);
|
||||
ASSERT_TRUE( nullptr != pcMesh->mTangents);
|
||||
ASSERT_TRUE( nullptr != pcMesh->mBitangents);
|
||||
ASSERT_TRUE( nullptr != pcMesh->mTextureCoords[0]);
|
||||
|
||||
// the order doesn't care
|
||||
float fSum = 0.f;
|
||||
for (unsigned int i = 0; i < 300;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < 300; ++i) {
|
||||
aiVector3D& v = pcMesh->mVertices[i];
|
||||
fSum += v.x + v.y + v.z;
|
||||
|
||||
|
@ -141,4 +142,3 @@ TEST_F(JoinVerticesTest, testProcess)
|
|||
}
|
||||
EXPECT_EQ(150.f*299.f*3.f, fSum); // gaussian sum equation
|
||||
}
|
||||
|
||||
|
|
|
@ -5,8 +5,6 @@ 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,
|
||||
|
@ -50,83 +48,83 @@ using namespace Assimp;
|
|||
|
||||
class LimitBoneWeightsTest : public ::testing::Test {
|
||||
public:
|
||||
LimitBoneWeightsTest()
|
||||
: Test()
|
||||
, mProcess(nullptr)
|
||||
, mMesh(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
protected:
|
||||
LimitBoneWeightsProcess* piProcess;
|
||||
aiMesh* pcMesh;
|
||||
LimitBoneWeightsProcess *mProcess;
|
||||
aiMesh *mMesh;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LimitBoneWeightsTest::SetUp()
|
||||
{
|
||||
void LimitBoneWeightsTest::SetUp() {
|
||||
// construct the process
|
||||
this->piProcess = new LimitBoneWeightsProcess();
|
||||
this->mProcess = new LimitBoneWeightsProcess();
|
||||
|
||||
// now need to create a nice mesh for testing purposes
|
||||
this->pcMesh = new aiMesh();
|
||||
this->mMesh = new aiMesh();
|
||||
|
||||
pcMesh->mNumVertices = 500;
|
||||
pcMesh->mVertices = new aiVector3D[500]; // uninit.
|
||||
pcMesh->mNumBones = 30;
|
||||
pcMesh->mBones = new aiBone*[30];
|
||||
mMesh->mNumVertices = 500;
|
||||
mMesh->mVertices = new aiVector3D[500]; // uninit.
|
||||
mMesh->mNumBones = 30;
|
||||
mMesh->mBones = new aiBone*[30];
|
||||
unsigned int iCur = 0;
|
||||
for (unsigned int i = 0; i < 30;++i)
|
||||
{
|
||||
aiBone* pc = pcMesh->mBones[i] = new aiBone();
|
||||
for (unsigned int i = 0; i < 30;++i) {
|
||||
aiBone* pc = mMesh->mBones[i] = new aiBone();
|
||||
pc->mNumWeights = 250;
|
||||
pc->mWeights = new aiVertexWeight[pc->mNumWeights];
|
||||
for (unsigned int qq = 0; qq < pc->mNumWeights;++qq)
|
||||
{
|
||||
for (unsigned int qq = 0; qq < pc->mNumWeights;++qq) {
|
||||
aiVertexWeight& v = pc->mWeights[qq];
|
||||
v.mVertexId = iCur++;
|
||||
if (500 == iCur)iCur = 0;
|
||||
if (500 == iCur) {
|
||||
iCur = 0;
|
||||
}
|
||||
v.mWeight = 1.0f / 15; // each vertex should occur once in two bones
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LimitBoneWeightsTest::TearDown()
|
||||
{
|
||||
delete pcMesh;
|
||||
delete piProcess;
|
||||
void LimitBoneWeightsTest::TearDown() {
|
||||
delete mMesh;
|
||||
delete mProcess;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
TEST_F(LimitBoneWeightsTest, testProcess)
|
||||
{
|
||||
TEST_F(LimitBoneWeightsTest, testProcess) {
|
||||
// execute the step on the given data
|
||||
piProcess->ProcessMesh(pcMesh);
|
||||
mProcess->ProcessMesh(mMesh);
|
||||
|
||||
// check whether everything is ok ...
|
||||
typedef std::vector<LimitBoneWeightsProcess::Weight> VertexWeightList;
|
||||
VertexWeightList* asWeights = new VertexWeightList[pcMesh->mNumVertices];
|
||||
VertexWeightList* asWeights = new VertexWeightList[mMesh->mNumVertices];
|
||||
|
||||
for (unsigned int i = 0; i < pcMesh->mNumVertices;++i)
|
||||
for (unsigned int i = 0; i < mMesh->mNumVertices; ++i) {
|
||||
asWeights[i].reserve(4);
|
||||
}
|
||||
|
||||
// sort back as per-vertex lists
|
||||
for (unsigned int i = 0; i < pcMesh->mNumBones;++i)
|
||||
{
|
||||
aiBone& pcBone = **(pcMesh->mBones+i);
|
||||
for (unsigned int q = 0; q < pcBone.mNumWeights;++q)
|
||||
{
|
||||
for (unsigned int i = 0; i < mMesh->mNumBones;++i) {
|
||||
aiBone& pcBone = **(mMesh->mBones+i);
|
||||
for (unsigned int q = 0; q < pcBone.mNumWeights;++q) {
|
||||
aiVertexWeight weight = pcBone.mWeights[q];
|
||||
asWeights[weight.mVertexId].push_back(LimitBoneWeightsProcess::Weight (i,weight.mWeight));
|
||||
}
|
||||
}
|
||||
|
||||
// now validate the size of the lists and check whether all weights sum to 1.0f
|
||||
for (unsigned int i = 0; i < pcMesh->mNumVertices;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < mMesh->mNumVertices;++i) {
|
||||
EXPECT_LE(asWeights[i].size(), 4U);
|
||||
float fSum = 0.0f;
|
||||
for (VertexWeightList::const_iterator
|
||||
iter = asWeights[i].begin();
|
||||
iter != asWeights[i].end();++iter)
|
||||
{
|
||||
for (VertexWeightList::const_iterator iter = asWeights[i].begin(); iter != asWeights[i].end();++iter) {
|
||||
fSum += (*iter).mWeight;
|
||||
}
|
||||
EXPECT_GE(fSum, 0.95F);
|
||||
|
|
|
@ -448,3 +448,37 @@ TEST_F(utObjImportExport, import_without_linend) {
|
|||
const aiScene *scene = myImporter.ReadFile(ASSIMP_TEST_MODELS_DIR "/OBJ/box_without_lineending.obj", 0);
|
||||
ASSERT_NE(nullptr, scene);
|
||||
}
|
||||
|
||||
TEST_F(utObjImportExport, import_with_line_continuations) {
|
||||
static const char *ObjModel =
|
||||
"v -0.5 -0.5 0.5\n"
|
||||
"v -0.5 \\\n"
|
||||
" -0.5 -0.5\n"
|
||||
"v -0.5 \\\n"
|
||||
" 0.5 \\\n"
|
||||
" -0.5\n"
|
||||
"f 1 2 3\n";
|
||||
|
||||
Assimp::Importer myImporter;
|
||||
const aiScene *scene = myImporter.ReadFileFromMemory(ObjModel, strlen(ObjModel), 0);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
|
||||
EXPECT_EQ(scene->mNumMeshes, 1U);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 3U);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 1U);
|
||||
|
||||
auto vertices = scene->mMeshes[0]->mVertices;
|
||||
const float threshold = 0.0001f;
|
||||
|
||||
EXPECT_NEAR(vertices[0].x, -0.5f, threshold);
|
||||
EXPECT_NEAR(vertices[0].y, -0.5f, threshold);
|
||||
EXPECT_NEAR(vertices[0].z, 0.5f, threshold);
|
||||
|
||||
EXPECT_NEAR(vertices[1].x, -0.5f, threshold);
|
||||
EXPECT_NEAR(vertices[1].y, -0.5f, threshold);
|
||||
EXPECT_NEAR(vertices[1].z, -0.5f, threshold);
|
||||
|
||||
EXPECT_NEAR(vertices[2].x, -0.5f, threshold);
|
||||
EXPECT_NEAR(vertices[2].y, 0.5f, threshold);
|
||||
EXPECT_NEAR(vertices[2].z, -0.5f, threshold);
|
||||
}
|
||||
|
|
|
@ -51,18 +51,24 @@ using namespace Assimp;
|
|||
|
||||
class PretransformVerticesTest : public ::testing::Test {
|
||||
public:
|
||||
PretransformVerticesTest()
|
||||
: Test()
|
||||
, mScene(nullptr)
|
||||
, mProcess(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
protected:
|
||||
|
||||
aiScene* scene;
|
||||
PretransformVertices* process;
|
||||
aiScene *mScene;
|
||||
PretransformVertices *mProcess;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void AddNodes(unsigned int num, aiNode* father, unsigned int depth)
|
||||
{
|
||||
void AddNodes(unsigned int num, aiNode* father, unsigned int depth) {
|
||||
father->mChildren = new aiNode*[father->mNumChildren = 5];
|
||||
for (unsigned int i = 0; i < 5; ++i) {
|
||||
aiNode* nd = father->mChildren[i] = new aiNode();
|
||||
|
@ -79,26 +85,26 @@ void AddNodes(unsigned int num, aiNode* father, unsigned int depth)
|
|||
}
|
||||
|
||||
if (depth > 1) {
|
||||
for (unsigned int i = 0; i < 5; ++i)
|
||||
AddNodes(i, father->mChildren[i],depth-1);
|
||||
for (unsigned int i = 0; i < 5; ++i) {
|
||||
AddNodes(i, father->mChildren[i], depth - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void PretransformVerticesTest::SetUp()
|
||||
{
|
||||
scene = new aiScene();
|
||||
void PretransformVerticesTest::SetUp() {
|
||||
mScene = new aiScene();
|
||||
|
||||
// add 5 empty materials
|
||||
scene->mMaterials = new aiMaterial*[scene->mNumMaterials = 5];
|
||||
mScene->mMaterials = new aiMaterial*[mScene->mNumMaterials = 5];
|
||||
for (unsigned int i = 0; i < 5;++i) {
|
||||
scene->mMaterials[i] = new aiMaterial();
|
||||
mScene->mMaterials[i] = new aiMaterial();
|
||||
}
|
||||
|
||||
// add 25 test meshes
|
||||
scene->mMeshes = new aiMesh*[scene->mNumMeshes = 25];
|
||||
for ( unsigned int i = 0; i < 25; ++i) {
|
||||
aiMesh* mesh = scene->mMeshes[ i ] = new aiMesh();
|
||||
mScene->mMeshes = new aiMesh*[mScene->mNumMeshes = 25];
|
||||
for ( unsigned int i = 0; i < 25; ++i) {
|
||||
aiMesh* mesh = mScene->mMeshes[ i ] = new aiMesh();
|
||||
|
||||
mesh->mPrimitiveTypes = aiPrimitiveType_POINT;
|
||||
mesh->mFaces = new aiFace[ mesh->mNumFaces = 10+i ];
|
||||
|
@ -124,36 +130,33 @@ void PretransformVerticesTest::SetUp()
|
|||
}
|
||||
|
||||
// construct some nodes (1+25)
|
||||
scene->mRootNode = new aiNode();
|
||||
scene->mRootNode->mName.Set("Root");
|
||||
AddNodes(0,scene->mRootNode,2);
|
||||
mScene->mRootNode = new aiNode();
|
||||
mScene->mRootNode->mName.Set("Root");
|
||||
AddNodes(0, mScene->mRootNode, 2);
|
||||
|
||||
process = new PretransformVertices();
|
||||
mProcess = new PretransformVertices();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void PretransformVerticesTest::TearDown()
|
||||
{
|
||||
delete scene;
|
||||
delete process;
|
||||
void PretransformVerticesTest::TearDown() {
|
||||
delete mScene;
|
||||
delete mProcess;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
TEST_F(PretransformVerticesTest, testProcessCollapseHierarchy)
|
||||
{
|
||||
process->KeepHierarchy(false);
|
||||
process->Execute(scene);
|
||||
TEST_F(PretransformVerticesTest, testProcessCollapseHierarchy) {
|
||||
mProcess->KeepHierarchy(false);
|
||||
mProcess->Execute(mScene);
|
||||
|
||||
EXPECT_EQ(5U, scene->mNumMaterials);
|
||||
EXPECT_EQ(10U, scene->mNumMeshes); // every second mesh has normals
|
||||
EXPECT_EQ(5U, mScene->mNumMaterials);
|
||||
EXPECT_EQ(10U, mScene->mNumMeshes); // every second mesh has normals
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
TEST_F(PretransformVerticesTest, testProcessKeepHierarchy)
|
||||
{
|
||||
process->KeepHierarchy(true);
|
||||
process->Execute(scene);
|
||||
TEST_F(PretransformVerticesTest, testProcessKeepHierarchy) {
|
||||
mProcess->KeepHierarchy(true);
|
||||
mProcess->Execute(mScene);
|
||||
|
||||
EXPECT_EQ(5U, scene->mNumMaterials);
|
||||
EXPECT_EQ(49U, scene->mNumMeshes); // see note on mesh 12 above
|
||||
EXPECT_EQ(5U, mScene->mNumMaterials);
|
||||
EXPECT_EQ(49U, mScene->mNumMeshes); // see note on mesh 12 above
|
||||
}
|
||||
|
|
|
@ -50,67 +50,67 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
using namespace std;
|
||||
using namespace Assimp;
|
||||
|
||||
|
||||
class ScenePreprocessorTest : public ::testing::Test
|
||||
{
|
||||
class ScenePreprocessorTest : public ::testing::Test {
|
||||
public:
|
||||
ScenePreprocessorTest()
|
||||
: Test()
|
||||
, mScenePreprocessor(nullptr)
|
||||
, mScene(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
protected:
|
||||
|
||||
void CheckIfOnly(aiMesh* p, unsigned int num, unsigned flag);
|
||||
void ProcessAnimation(aiAnimation* anim) { mScenePreprocessor->ProcessAnimation(anim); }
|
||||
void ProcessMesh(aiMesh* mesh) { mScenePreprocessor->ProcessMesh(mesh); }
|
||||
|
||||
void ProcessAnimation(aiAnimation* anim) { pp->ProcessAnimation(anim); }
|
||||
void ProcessMesh(aiMesh* mesh) { pp->ProcessMesh(mesh); }
|
||||
|
||||
ScenePreprocessor* pp;
|
||||
aiScene* scene;
|
||||
private:
|
||||
ScenePreprocessor *mScenePreprocessor;
|
||||
aiScene *mScene;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ScenePreprocessorTest::SetUp()
|
||||
{
|
||||
void ScenePreprocessorTest::SetUp() {
|
||||
// setup a dummy scene with a single node
|
||||
scene = new aiScene();
|
||||
scene->mRootNode = new aiNode();
|
||||
scene->mRootNode->mName.Set("<test>");
|
||||
mScene = new aiScene();
|
||||
mScene->mRootNode = new aiNode();
|
||||
mScene->mRootNode->mName.Set("<test>");
|
||||
|
||||
// add some translation
|
||||
scene->mRootNode->mTransformation.a4 = 1.f;
|
||||
scene->mRootNode->mTransformation.b4 = 2.f;
|
||||
scene->mRootNode->mTransformation.c4 = 3.f;
|
||||
mScene->mRootNode->mTransformation.a4 = 1.f;
|
||||
mScene->mRootNode->mTransformation.b4 = 2.f;
|
||||
mScene->mRootNode->mTransformation.c4 = 3.f;
|
||||
|
||||
// and allocate a ScenePreprocessor to operate on the scene
|
||||
pp = new ScenePreprocessor(scene);
|
||||
mScenePreprocessor = new ScenePreprocessor(mScene);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ScenePreprocessorTest::TearDown()
|
||||
{
|
||||
delete pp;
|
||||
delete scene;
|
||||
void ScenePreprocessorTest::TearDown() {
|
||||
delete mScenePreprocessor;
|
||||
delete mScene;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Check whether ProcessMesh() returns flag for a mesh that consist of primitives with num indices
|
||||
void ScenePreprocessorTest::CheckIfOnly(aiMesh* p, unsigned int num, unsigned int flag)
|
||||
{
|
||||
void ScenePreprocessorTest::CheckIfOnly(aiMesh* p, unsigned int num, unsigned int flag) {
|
||||
// Triangles only
|
||||
for (unsigned i = 0; i < p->mNumFaces;++i) {
|
||||
p->mFaces[i].mNumIndices = num;
|
||||
}
|
||||
pp->ProcessMesh(p);
|
||||
mScenePreprocessor->ProcessMesh(p);
|
||||
EXPECT_EQ(flag, p->mPrimitiveTypes);
|
||||
p->mPrimitiveTypes = 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Check whether a mesh is preprocessed correctly. Case 1: The mesh needs preprocessing
|
||||
TEST_F(ScenePreprocessorTest, testMeshPreprocessingPos)
|
||||
{
|
||||
aiMesh* p = new aiMesh();
|
||||
TEST_F(ScenePreprocessorTest, testMeshPreprocessingPos) {
|
||||
aiMesh* p = new aiMesh;
|
||||
p->mNumFaces = 100;
|
||||
p->mFaces = new aiFace[p->mNumFaces];
|
||||
|
||||
|
@ -145,9 +145,8 @@ TEST_F(ScenePreprocessorTest, testMeshPreprocessingPos)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Check whether a mesh is preprocessed correctly. Case 1: The mesh doesn't need preprocessing
|
||||
TEST_F(ScenePreprocessorTest, testMeshPreprocessingNeg)
|
||||
{
|
||||
aiMesh* p = new aiMesh();
|
||||
TEST_F(ScenePreprocessorTest, testMeshPreprocessingNeg) {
|
||||
aiMesh* p = new aiMesh;
|
||||
p->mPrimitiveTypes = aiPrimitiveType_TRIANGLE|aiPrimitiveType_POLYGON;
|
||||
ProcessMesh(p);
|
||||
|
||||
|
@ -160,8 +159,7 @@ TEST_F(ScenePreprocessorTest, testMeshPreprocessingNeg)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Make a dummy animation with a single channel, '<test>'
|
||||
aiAnimation* MakeDummyAnimation()
|
||||
{
|
||||
aiAnimation* MakeDummyAnimation() {
|
||||
aiAnimation* p = new aiAnimation();
|
||||
p->mNumChannels = 1;
|
||||
p->mChannels = new aiNodeAnim*[1];
|
||||
|
@ -172,8 +170,7 @@ aiAnimation* MakeDummyAnimation()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Check whether an anim is preprocessed correctly. Case 1: The anim needs preprocessing
|
||||
TEST_F(ScenePreprocessorTest, testAnimationPreprocessingPos)
|
||||
{
|
||||
TEST_F(ScenePreprocessorTest, testAnimationPreprocessingPos) {
|
||||
aiAnimation* p = MakeDummyAnimation();
|
||||
aiNodeAnim* anim = p->mChannels[0];
|
||||
|
||||
|
|
|
@ -52,12 +52,20 @@ using namespace Assimp;
|
|||
|
||||
class SortByPTypeProcessTest : public ::testing::Test {
|
||||
public:
|
||||
SortByPTypeProcessTest()
|
||||
: Test()
|
||||
, mProcess1(nullptr)
|
||||
, mScene(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
protected:
|
||||
SortByPTypeProcess* process1;
|
||||
aiScene* scene;
|
||||
SortByPTypeProcess* mProcess1;
|
||||
aiScene* mScene;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -75,8 +83,7 @@ static unsigned int num[10][4] = {
|
|||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static unsigned int result[10] =
|
||||
{
|
||||
static unsigned int result[10] = {
|
||||
aiPrimitiveType_POLYGON,
|
||||
aiPrimitiveType_TRIANGLE,
|
||||
aiPrimitiveType_LINE,
|
||||
|
@ -90,19 +97,16 @@ static unsigned int result[10] =
|
|||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SortByPTypeProcessTest::SetUp()
|
||||
{
|
||||
// process0 = new DeterminePTypeHelperProcess();
|
||||
process1 = new SortByPTypeProcess();
|
||||
scene = new aiScene();
|
||||
void SortByPTypeProcessTest::SetUp() {
|
||||
mProcess1 = new SortByPTypeProcess();
|
||||
mScene = new aiScene();
|
||||
|
||||
scene->mNumMeshes = 10;
|
||||
scene->mMeshes = new aiMesh*[10];
|
||||
mScene->mNumMeshes = 10;
|
||||
mScene->mMeshes = new aiMesh*[10];
|
||||
|
||||
bool five = false;
|
||||
for (unsigned int i = 0; i < 10; ++i)
|
||||
{
|
||||
aiMesh* mesh = scene->mMeshes[i] = new aiMesh();
|
||||
for (unsigned int i = 0; i < 10; ++i) {
|
||||
aiMesh* mesh = mScene->mMeshes[i] = new aiMesh();
|
||||
mesh->mNumFaces = 1000;
|
||||
aiFace* faces = mesh->mFaces = new aiFace[1000];
|
||||
aiVector3D* pv = mesh->mVertices = new aiVector3D[mesh->mNumFaces*5];
|
||||
|
@ -115,27 +119,24 @@ void SortByPTypeProcessTest::SetUp()
|
|||
|
||||
unsigned int remaining[4] = {num[i][0],num[i][1],num[i][2],num[i][3]};
|
||||
unsigned int n = 0;
|
||||
for (unsigned int m = 0; m < 1000; ++m)
|
||||
{
|
||||
for (unsigned int m = 0; m < 1000; ++m) {
|
||||
unsigned int idx = m % 4;
|
||||
while (true)
|
||||
{
|
||||
if (!remaining[idx])
|
||||
{
|
||||
if (4 == ++idx)idx = 0;
|
||||
while (true) {
|
||||
if (!remaining[idx]) {
|
||||
if (4 == ++idx) {
|
||||
idx = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
faces->mNumIndices = idx+1;
|
||||
if (4 == faces->mNumIndices)
|
||||
{
|
||||
if (4 == faces->mNumIndices) {
|
||||
if(five)++faces->mNumIndices;
|
||||
five = !five;
|
||||
}
|
||||
faces->mIndices = new unsigned int[faces->mNumIndices];
|
||||
for (unsigned int q = 0; q <faces->mNumIndices;++q,++n)
|
||||
{
|
||||
for (unsigned int q = 0; q <faces->mNumIndices;++q,++n) {
|
||||
faces->mIndices[q] = n;
|
||||
float f = (float)remaining[idx];
|
||||
|
||||
|
@ -152,12 +153,11 @@ void SortByPTypeProcessTest::SetUp()
|
|||
mesh->mNumVertices = n;
|
||||
}
|
||||
|
||||
scene->mRootNode = new aiNode();
|
||||
scene->mRootNode->mNumChildren = 5;
|
||||
scene->mRootNode->mChildren = new aiNode*[5];
|
||||
for (unsigned int i = 0; i< 5;++i )
|
||||
{
|
||||
aiNode* node = scene->mRootNode->mChildren[i] = new aiNode();
|
||||
mScene->mRootNode = new aiNode();
|
||||
mScene->mRootNode->mNumChildren = 5;
|
||||
mScene->mRootNode->mChildren = new aiNode*[5];
|
||||
for (unsigned int i = 0; i< 5;++i ) {
|
||||
aiNode* node = mScene->mRootNode->mChildren[i] = new aiNode();
|
||||
node->mNumMeshes = 2;
|
||||
node->mMeshes = new unsigned int[2];
|
||||
node->mMeshes[0] = (i<<1u);
|
||||
|
@ -166,48 +166,27 @@ void SortByPTypeProcessTest::SetUp()
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SortByPTypeProcessTest::TearDown()
|
||||
{
|
||||
//delete process0;
|
||||
delete process1;
|
||||
delete scene;
|
||||
void SortByPTypeProcessTest::TearDown() {
|
||||
delete mProcess1;
|
||||
delete mScene;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
//TEST_F(SortByPTypeProcessTest, DeterminePTypeStep()
|
||||
//{
|
||||
// process0->Execute(scene);
|
||||
//
|
||||
// for (unsigned int i = 0; i < 10; ++i)
|
||||
// {
|
||||
// aiMesh* mesh = scene->mMeshes[i];
|
||||
// EXPECT_TRUE(mesh->mPrimitiveTypes == result[i]);
|
||||
// }
|
||||
//}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
TEST_F(SortByPTypeProcessTest, SortByPTypeStep)
|
||||
{
|
||||
// process0->Execute(scene);
|
||||
|
||||
// and another small test for ScenePreprocessor
|
||||
ScenePreprocessor s(scene);
|
||||
TEST_F(SortByPTypeProcessTest, SortByPTypeStep) {
|
||||
ScenePreprocessor s(mScene);
|
||||
s.ProcessScene();
|
||||
for (unsigned int m = 0; m< 10;++m)
|
||||
EXPECT_EQ(result[m], scene->mMeshes[m]->mPrimitiveTypes);
|
||||
EXPECT_EQ(result[m], mScene->mMeshes[m]->mPrimitiveTypes);
|
||||
|
||||
process1->Execute(scene);
|
||||
mProcess1->Execute(mScene);
|
||||
|
||||
unsigned int idx = 0;
|
||||
for (unsigned int m = 0,real = 0; m< 10;++m)
|
||||
{
|
||||
for (unsigned int n = 0; n < 4;++n)
|
||||
{
|
||||
if ((idx = num[m][n]))
|
||||
{
|
||||
EXPECT_TRUE(real < scene->mNumMeshes);
|
||||
for (unsigned int m = 0,real = 0; m< 10;++m) {
|
||||
for (unsigned int n = 0; n < 4;++n) {
|
||||
if ((idx = num[m][n])) {
|
||||
EXPECT_TRUE(real < mScene->mNumMeshes);
|
||||
|
||||
aiMesh* mesh = scene->mMeshes[real];
|
||||
aiMesh* mesh = mScene->mMeshes[real];
|
||||
|
||||
EXPECT_TRUE(NULL != mesh);
|
||||
EXPECT_EQ(AI_PRIMITIVE_TYPE_FOR_N_INDICES(n+1), mesh->mPrimitiveTypes);
|
||||
|
@ -218,8 +197,7 @@ TEST_F(SortByPTypeProcessTest, SortByPTypeStep)
|
|||
EXPECT_TRUE(NULL != mesh->mTextureCoords[0]);
|
||||
|
||||
EXPECT_TRUE(mesh->mNumFaces == idx);
|
||||
for (unsigned int f = 0; f < mesh->mNumFaces;++f)
|
||||
{
|
||||
for (unsigned int f = 0; f < mesh->mNumFaces;++f) {
|
||||
aiFace& face = mesh->mFaces[f];
|
||||
EXPECT_TRUE(face.mNumIndices == (n+1) || (3 == n && face.mNumIndices > 3));
|
||||
}
|
||||
|
@ -228,4 +206,3 @@ TEST_F(SortByPTypeProcessTest, SortByPTypeStep)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,8 +5,6 @@ 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,
|
||||
|
@ -55,17 +53,23 @@ class utglTF2ImportExport : public AbstractImportExportBase {
|
|||
public:
|
||||
virtual bool importerTest() {
|
||||
Assimp::Importer importer;
|
||||
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", aiProcess_ValidateDataStructure);
|
||||
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf",
|
||||
aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE( scene, nullptr );
|
||||
if ( !scene ) return false;
|
||||
if (!scene) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EXPECT_TRUE( scene->HasMaterials() );
|
||||
if ( !scene->HasMaterials() ) return false;
|
||||
if (!scene->HasMaterials()) {
|
||||
return false;
|
||||
}
|
||||
const aiMaterial *material = scene->mMaterials[0];
|
||||
|
||||
aiString path;
|
||||
aiTextureMapMode modes[2];
|
||||
EXPECT_EQ( aiReturn_SUCCESS, material->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, nullptr, nullptr, modes) );
|
||||
EXPECT_EQ( aiReturn_SUCCESS, material->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr,
|
||||
nullptr, nullptr, modes) );
|
||||
EXPECT_STREQ( path.C_Str(), "CesiumLogoFlat.png" );
|
||||
EXPECT_EQ( modes[0], aiTextureMapMode_Mirror );
|
||||
EXPECT_EQ( modes[1], aiTextureMapMode_Clamp );
|
||||
|
@ -75,7 +79,8 @@ public:
|
|||
|
||||
virtual bool binaryImporterTest() {
|
||||
Assimp::Importer importer;
|
||||
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/2CylinderEngine-glTF-Binary/2CylinderEngine.glb", aiProcess_ValidateDataStructure);
|
||||
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/2CylinderEngine-glTF-Binary/2CylinderEngine.glb",
|
||||
aiProcess_ValidateDataStructure);
|
||||
return nullptr != scene;
|
||||
}
|
||||
|
||||
|
@ -83,7 +88,8 @@ public:
|
|||
virtual bool exporterTest() {
|
||||
Assimp::Importer importer;
|
||||
Assimp::Exporter exporter;
|
||||
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", aiProcess_ValidateDataStructure );
|
||||
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf",
|
||||
aiProcess_ValidateDataStructure );
|
||||
EXPECT_NE( nullptr, scene );
|
||||
EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "gltf2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured_out.gltf" ) );
|
||||
|
||||
|
@ -105,7 +111,8 @@ TEST_F( utglTF2ImportExport, importBinaryglTF2FromFileTest ) {
|
|||
TEST_F(utglTF2ImportExport, importglTF2AndExportToOBJ) {
|
||||
Assimp::Importer importer;
|
||||
Assimp::Exporter exporter;
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", aiProcess_ValidateDataStructure);
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf",
|
||||
aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "obj", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured_out.obj"));
|
||||
}
|
||||
|
@ -113,7 +120,8 @@ TEST_F(utglTF2ImportExport, importglTF2AndExportToOBJ) {
|
|||
TEST_F(utglTF2ImportExport, importglTF2EmbeddedAndExportToOBJ) {
|
||||
Assimp::Importer importer;
|
||||
Assimp::Exporter exporter;
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-Embedded/BoxTextured.gltf", aiProcess_ValidateDataStructure);
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-Embedded/BoxTextured.gltf",
|
||||
aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "obj", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-Embedded/BoxTextured_out.obj"));
|
||||
}
|
||||
|
@ -124,10 +132,9 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModePointsWithoutIndices) {
|
|||
//Points without indices
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_00.gltf", aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 1024);
|
||||
for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i)
|
||||
{
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 1);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 1024u);
|
||||
for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) {
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 1u);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i);
|
||||
}
|
||||
}
|
||||
|
@ -137,12 +144,11 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLinesWithoutIndices) {
|
|||
//Lines without indices
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_01.gltf", aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 8);
|
||||
for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i)
|
||||
{
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i*2);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], i*2 + 1);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 8u);
|
||||
for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) {
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2u);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i*2u);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], i*2u + 1u);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,15 +157,14 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLinesLoopWithoutIndices) {
|
|||
//Lines loop without indices
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_02.gltf", aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u);
|
||||
|
||||
std::array<int, 5> l1 = {{ 0, 1, 2, 3, 0 }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2);
|
||||
for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i)
|
||||
{
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2);
|
||||
std::array<unsigned int, 5> l1 = {{ 0u, 1u, 2u, 3u, 0u }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u);
|
||||
for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) {
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2u);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], l1[i]);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], l1[i + 1]);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], l1[i + 1u]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,14 +173,13 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLinesStripWithoutIndices) {
|
|||
//Lines strip without indices
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_03.gltf", aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 5);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 5u);
|
||||
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2);
|
||||
for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i)
|
||||
{
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u);
|
||||
for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) {
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2u);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], i + 1);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], i + 1u);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,19 +188,17 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesStripWithoutIndices
|
|||
//Triangles strip without indices
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_04.gltf", aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4);
|
||||
std::array<int, 3> f1 = {{ 0, 1, 2 }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u);
|
||||
std::array<unsigned int, 3> f1 = {{ 0u, 1u, 2u }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u);
|
||||
for (unsigned int i = 0; i < 3; ++i) {
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]);
|
||||
}
|
||||
|
||||
std::array<int, 3> f2 = {{ 2, 1, 3 }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
std::array<unsigned int, 3> f2 = {{ 2u, 1u, 3u }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u);
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]);
|
||||
}
|
||||
}
|
||||
|
@ -206,19 +208,17 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesFanWithoutIndices)
|
|||
//Triangles fan without indices
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_05.gltf", aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4);
|
||||
std::array<int, 3> f1 = {{ 0, 1, 2 }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u);
|
||||
std::array<unsigned int, 3> f1 = {{ 0u, 1u, 2u }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u);
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]);
|
||||
}
|
||||
|
||||
std::array<int, 3> f2 = {{ 0, 2, 3 }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
std::array<unsigned int, 3> f2 = {{ 0u, 2u, 3u }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u);
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]);
|
||||
}
|
||||
}
|
||||
|
@ -228,19 +228,17 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesWithoutIndices) {
|
|||
//Triangles without indices
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_06.gltf", aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 6);
|
||||
std::array<int, 3> f1 = {{ 0, 1, 2 }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 6u);
|
||||
std::array<unsigned int, 3> f1 = {{ 0u, 1u, 2u }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u);
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]);
|
||||
}
|
||||
|
||||
std::array<int, 3> f2 = {{ 3, 4, 5 }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
std::array<unsigned int, 3> f2 = {{ 3u, 4u, 5u }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u);
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]);
|
||||
}
|
||||
}
|
||||
|
@ -250,10 +248,9 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModePoints) {
|
|||
//Line loop
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_07.gltf", aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 1024);
|
||||
for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i)
|
||||
{
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 1);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 1024u);
|
||||
for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) {
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 1u);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i);
|
||||
}
|
||||
}
|
||||
|
@ -263,9 +260,9 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLines) {
|
|||
//Lines
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_08.gltf", aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4);
|
||||
std::array<int, 5> l1 = {{ 0, 3, 2, 1, 0 }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u);
|
||||
std::array<unsigned int, 5> l1 = {{ 0u, 3u, 2u, 1u, 0u }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u);
|
||||
for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i)
|
||||
{
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], l1[i]);
|
||||
|
@ -278,9 +275,9 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLineLoop) {
|
|||
//Line loop
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_09.gltf", aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4);
|
||||
std::array<int, 5> l1 = {{ 0, 3, 2, 1, 0 }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u);
|
||||
std::array<unsigned int, 5> l1 = {{ 0, 3u, 2u, 1u, 0u }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u);
|
||||
for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i)
|
||||
{
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], l1[i]);
|
||||
|
@ -293,11 +290,10 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLineStrip) {
|
|||
//Lines Strip
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_10.gltf", aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4);
|
||||
std::array<int, 5> l1 = {{ 0, 3, 2, 1, 0 }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2);
|
||||
for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i)
|
||||
{
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u);
|
||||
std::array<unsigned int, 5> l1 = {{ 0u, 3u, 2u, 1u, 0u }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u);
|
||||
for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) {
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], l1[i]);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], l1[i + 1]);
|
||||
}
|
||||
|
@ -308,19 +304,17 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesStrip) {
|
|||
//Triangles strip
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_11.gltf", aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4);
|
||||
std::array<int, 3> f1 = {{ 0, 3, 1 }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u);
|
||||
std::array<unsigned int, 3> f1 = {{ 0u, 3u, 1u }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u);
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]);
|
||||
}
|
||||
|
||||
std::array<int, 3> f2 = {{ 1, 3, 2 }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
std::array<unsigned int, 3> f2 = {{ 1u, 3u, 2u }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u);
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]);
|
||||
}
|
||||
}
|
||||
|
@ -330,19 +324,17 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesFan) {
|
|||
//Triangles fan
|
||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_12.gltf", aiProcess_ValidateDataStructure);
|
||||
EXPECT_NE(nullptr, scene);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2);
|
||||
std::array<int, 3> f1 = {{ 0, 3, 2 }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u);
|
||||
EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u);
|
||||
std::array<unsigned int, 3> f1 = {{ 0u, 3u, 2u }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u );
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]);
|
||||
}
|
||||
|
||||
std::array<int, 3> f2 = {{ 0, 2, 1 }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
std::array<unsigned int, 3> f2 = {{ 0u, 2u, 1u }};
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u );
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]);
|
||||
}
|
||||
}
|
||||
|
@ -378,7 +370,8 @@ TEST_F(utglTF2ImportExport, importglTF2FromMemory) {
|
|||
|
||||
TEST_F( utglTF2ImportExport, bug_import_simple_skin ) {
|
||||
Assimp::Importer importer;
|
||||
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/simple_skin/simple_skin.gltf", aiProcess_ValidateDataStructure );
|
||||
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/simple_skin/simple_skin.gltf",
|
||||
aiProcess_ValidateDataStructure );
|
||||
EXPECT_NE( nullptr, scene );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue