Merge remote-tracking branch 'upstream/master' into fix_export_custom_bindpose_error
commit
4ff4938df4
|
@ -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
|
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
|
# 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
|
# 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
|
# 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)
|
: nfo(nfo)
|
||||||
, reader(reader)
|
, reader(reader)
|
||||||
, cur(reader.GetCurrentPos()) {
|
, cur(reader.GetCurrentPos()) {
|
||||||
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
~chunk_guard() {
|
~chunk_guard() {
|
||||||
|
@ -905,7 +906,7 @@ public:
|
||||||
if(nfo.size != static_cast<unsigned int>(-1)) {
|
if(nfo.size != static_cast<unsigned int>(-1)) {
|
||||||
try {
|
try {
|
||||||
reader.IncPtr( static_cast< int >( nfo.size ) - reader.GetCurrentPos() + cur );
|
reader.IncPtr( static_cast< int >( nfo.size ) - reader.GetCurrentPos() + cur );
|
||||||
} catch (const DeadlyImportError& e ) {
|
} catch (const DeadlyImportError& ) {
|
||||||
// out of limit so correct the value
|
// out of limit so correct the value
|
||||||
reader.IncPtr( reader.GetReadLimit() );
|
reader.IncPtr( reader.GetReadLimit() );
|
||||||
}
|
}
|
||||||
|
@ -913,15 +914,17 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
const COB::ChunkInfo& nfo;
|
const COB::ChunkInfo& nfo;
|
||||||
StreamReaderLE& reader;
|
StreamReaderLE& reader;
|
||||||
long cur;
|
long cur;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader)
|
void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader) {
|
||||||
{
|
if (nullptr == reader) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
std::string type;
|
std::string type;
|
||||||
type += reader -> GetI1()
|
type += reader -> GetI1()
|
||||||
|
|
|
@ -772,10 +772,14 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
|
||||||
|
|
||||||
for( size_t b = 0; b < pairCount; ++b, ++iit)
|
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);
|
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
|
// one day I gonna kill that XSI Collada exporter
|
||||||
if( weight > 0.0f)
|
if( weight > 0.0f)
|
||||||
|
|
|
@ -47,10 +47,6 @@ namespace Assimp {
|
||||||
aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh)
|
aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh)
|
||||||
{
|
{
|
||||||
aiAnimMesh *animesh = new aiAnimMesh;
|
aiAnimMesh *animesh = new aiAnimMesh;
|
||||||
animesh->mVertices = NULL;
|
|
||||||
animesh->mNormals = NULL;
|
|
||||||
animesh->mTangents = NULL;
|
|
||||||
animesh->mBitangents = NULL;
|
|
||||||
animesh->mNumVertices = mesh->mNumVertices;
|
animesh->mNumVertices = mesh->mNumVertices;
|
||||||
if (mesh->mVertices) {
|
if (mesh->mVertices) {
|
||||||
animesh->mVertices = new aiVector3D[animesh->mNumVertices];
|
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 ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||||
void ExportSceneFBXA(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 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
|
// global array of all export formats which Assimp supports in its current build
|
||||||
|
@ -179,7 +180,11 @@ Exporter::ExportFormatEntry gExporters[] =
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
|
#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
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -364,7 +364,7 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out)
|
||||||
void DeleteImporterInstanceList(std::vector< BaseImporter* >& deleteList){
|
void DeleteImporterInstanceList(std::vector< BaseImporter* >& deleteList){
|
||||||
for(size_t i= 0; i<deleteList.size();++i){
|
for(size_t i= 0; i<deleteList.size();++i){
|
||||||
delete deleteList[i];
|
delete deleteList[i];
|
||||||
deleteList[i]=NULL;
|
deleteList[i]=nullptr;
|
||||||
}//for
|
}//for
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -420,11 +420,6 @@ namespace Assimp {
|
||||||
|
|
||||||
out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight();
|
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->mPosition = aiVector3D(0.0f);
|
||||||
out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f);
|
out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f);
|
||||||
out_camera->mUp = aiVector3D(0.0f, 1.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) {
|
if ((v - all_ones).SquareLength() > zero_epsilon) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
} else if (ok) {
|
||||||
else if (ok) {
|
|
||||||
if (v.SquareLength() > zero_epsilon) {
|
if (v.SquareLength() > zero_epsilon) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1253,10 +1247,10 @@ namespace Assimp {
|
||||||
ai_assert(count_faces);
|
ai_assert(count_faces);
|
||||||
ai_assert(count_vertices);
|
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::vector<unsigned int> reverseMapping;
|
||||||
std::map<unsigned int, unsigned int> translateIndexMap;
|
std::map<unsigned int, unsigned int> translateIndexMap;
|
||||||
if (process_weights) {
|
if (process_weights || mesh.GetBlendShapes().size() > 0) {
|
||||||
reverseMapping.resize(count_vertices);
|
reverseMapping.resize(count_vertices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1413,8 +1407,10 @@ namespace Assimp {
|
||||||
unsigned int count = 0;
|
unsigned int count = 0;
|
||||||
const unsigned int* outIndices = mesh.ToOutputVertexIndex(index, count);
|
const unsigned int* outIndices = mesh.ToOutputVertexIndex(index, count);
|
||||||
for (unsigned int k = 0; k < count; k++) {
|
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;
|
animMesh->mVertices[index] += vertex;
|
||||||
if (animMesh->mNormals != nullptr) {
|
if (animMesh->mNormals != nullptr) {
|
||||||
animMesh->mNormals[index] += normal;
|
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);
|
return static_cast<unsigned int>(meshes.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1734,8 +1739,7 @@ namespace Assimp {
|
||||||
|
|
||||||
void FBXConverter::TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures,
|
void FBXConverter::TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures,
|
||||||
const std::string& propName,
|
const std::string& propName,
|
||||||
aiTextureType target, const MeshGeometry* const mesh)
|
aiTextureType target, const MeshGeometry* const mesh) {
|
||||||
{
|
|
||||||
TextureMap::const_iterator it = textures.find(propName);
|
TextureMap::const_iterator it = textures.find(propName);
|
||||||
if (it == textures.end()) {
|
if (it == textures.end()) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "FBXUtil.h"
|
#include "FBXUtil.h"
|
||||||
#include "FBXProperties.h"
|
#include "FBXProperties.h"
|
||||||
#include "FBXImporter.h"
|
#include "FBXImporter.h"
|
||||||
|
|
||||||
#include <assimp/anim.h>
|
#include <assimp/anim.h>
|
||||||
#include <assimp/material.h>
|
#include <assimp/material.h>
|
||||||
#include <assimp/light.h>
|
#include <assimp/light.h>
|
||||||
|
|
|
@ -627,7 +627,7 @@ public:
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ContentLength() const {
|
uint64_t ContentLength() const {
|
||||||
return contentLength;
|
return contentLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -963,7 +963,6 @@ void ParseVectorDataArray(std::vector<float>& out, const Element& el)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read an array of uints
|
// read an array of uints
|
||||||
void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el)
|
void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el)
|
||||||
|
@ -1280,7 +1279,6 @@ float ParseTokenAsFloat(const Token& t)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// wrapper around ParseTokenAsInt() with ParseError handling
|
// wrapper around ParseTokenAsInt() with ParseError handling
|
||||||
int ParseTokenAsInt(const Token& t)
|
int ParseTokenAsInt(const Token& t)
|
||||||
|
@ -1293,8 +1291,6 @@ int ParseTokenAsInt(const Token& t)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// wrapper around ParseTokenAsInt64() with ParseError handling
|
// wrapper around ParseTokenAsInt64() with ParseError handling
|
||||||
int64_t ParseTokenAsInt64(const Token& t)
|
int64_t ParseTokenAsInt64(const Token& t)
|
||||||
|
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2019, assimp team
|
Copyright (c) 2006-2019, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
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.
|
* 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
|
* 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
|
* *absolute*, they're <b>relative</b> to the coordinate system defined
|
||||||
* by the node which corresponds to the camera. This allows for camera
|
* by the node which corresponds to the camera. This allows for camera
|
||||||
* animations. For static cameras parameters like the 'look-at' or 'up' vectors
|
* 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"
|
#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"
|
#define AI_CONFIG_EXPORT_POINT_CLOUDS "EXPORT_POINT_CLOUDS"
|
||||||
|
|
||||||
|
|
|
@ -120,6 +120,7 @@ SET( IMPORTERS
|
||||||
unit/utB3DImportExport.cpp
|
unit/utB3DImportExport.cpp
|
||||||
unit/utMDCImportExport.cpp
|
unit/utMDCImportExport.cpp
|
||||||
unit/utAssbinImportExport.cpp
|
unit/utAssbinImportExport.cpp
|
||||||
|
unit/ImportExport/utAssjsonImportExport.cpp
|
||||||
unit/ImportExport/utCOBImportExport.cpp
|
unit/ImportExport/utCOBImportExport.cpp
|
||||||
unit/ImportExport/utOgreImportExport.cpp
|
unit/ImportExport/utOgreImportExport.cpp
|
||||||
unit/ImportExport/utQ3BSPFileImportExport.cpp
|
unit/ImportExport/utQ3BSPFileImportExport.cpp
|
||||||
|
@ -166,7 +167,7 @@ SET( POST_PROCESSES
|
||||||
|
|
||||||
SOURCE_GROUP( UnitTests\\Compiler FILES unit/CCompilerTest.c )
|
SOURCE_GROUP( UnitTests\\Compiler FILES unit/CCompilerTest.c )
|
||||||
SOURCE_GROUP( UnitTests\\Common FILES ${COMMON} )
|
SOURCE_GROUP( UnitTests\\Common FILES ${COMMON} )
|
||||||
SOURCE_GROUP( UnitTests\\Importers FILES ${IMPORTERS} )
|
SOURCE_GROUP( UnitTests\\ImportExport FILES ${IMPORTERS} )
|
||||||
SOURCE_GROUP( UnitTests\\Material FILES ${MATERIAL} )
|
SOURCE_GROUP( UnitTests\\Material FILES ${MATERIAL} )
|
||||||
SOURCE_GROUP( UnitTests\\Math FILES ${MATH} )
|
SOURCE_GROUP( UnitTests\\Math FILES ${MATH} )
|
||||||
SOURCE_GROUP( UnitTests\\PostProcess FILES ${POST_PROCESSES})
|
SOURCE_GROUP( UnitTests\\PostProcess FILES ${POST_PROCESSES})
|
||||||
|
|
Binary file not shown.
|
@ -1,6 +1,6 @@
|
||||||
ply
|
ply
|
||||||
format ascii 1.0
|
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
|
element vertex 8
|
||||||
property float x
|
property float x
|
||||||
property float y
|
property float y
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
Open Asset Import Library (assimp)
|
Open Asset Import Library (assimp)
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
Copyright (c) 2006-2016, assimp team
|
Copyright (c) 2006-2019, assimp team
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
|
@ -39,17 +39,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#ifndef AI_ABSTRACTIMPORTEXPORTBASE_H_INC
|
||||||
|
#define AI_ABSTRACTIMPORTEXPORTBASE_H_INC
|
||||||
|
|
||||||
#include "UnitTestPCH.h"
|
#include "UnitTestPCH.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/** Abstract base class to test import and export
|
||||||
|
*/
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
class AbstractImportExportBase : public ::testing::Test {
|
class AbstractImportExportBase : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
|
/// @brief The class destructor.
|
||||||
virtual ~AbstractImportExportBase();
|
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();
|
virtual bool exporterTest();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline
|
||||||
|
bool AbstractImportExportBase::importerTest() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
bool AbstractImportExportBase::exporterTest() {
|
bool AbstractImportExportBase::exporterTest() {
|
||||||
return true;
|
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
|
Copyright (c) 2006-2019, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
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
|
Copyright (c) 2006-2019, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
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
|
Copyright (c) 2006-2019, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
@ -53,8 +51,8 @@ using namespace Assimp;
|
||||||
|
|
||||||
class utAssbinImportExport : public AbstractImportExportBase {
|
class utAssbinImportExport : public AbstractImportExportBase {
|
||||||
public:
|
public:
|
||||||
virtual bool importerTest() {
|
bool importerTest() override {
|
||||||
Assimp::Importer importer;
|
Importer importer;
|
||||||
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure );
|
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure );
|
||||||
|
|
||||||
Exporter exporter;
|
Exporter exporter;
|
||||||
|
@ -66,7 +64,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F( utAssbinImportExport, exportAssbin3DFromFileTest ) {
|
TEST_F( utAssbinImportExport, exportAssbin3DFromFileTest ) {
|
||||||
Assimp::Importer importer;
|
Importer importer;
|
||||||
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure );
|
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure );
|
||||||
EXPECT_NE( nullptr, scene );
|
EXPECT_NE( nullptr, scene );
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2019, assimp team
|
Copyright (c) 2006-2019, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
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
|
Copyright (c) 2006-2019, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
@ -49,35 +47,42 @@ using namespace Assimp;
|
||||||
|
|
||||||
class FindDegeneratesProcessTest : public ::testing::Test {
|
class FindDegeneratesProcessTest : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
|
FindDegeneratesProcessTest()
|
||||||
|
: Test()
|
||||||
|
, mMesh( nullptr )
|
||||||
|
, mProcess( nullptr ) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
virtual void SetUp();
|
virtual void SetUp();
|
||||||
virtual void TearDown();
|
virtual void TearDown();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
aiMesh* mesh;
|
aiMesh* mMesh;
|
||||||
FindDegeneratesProcess* process;
|
FindDegeneratesProcess* mProcess;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
void FindDegeneratesProcessTest::SetUp() {
|
void FindDegeneratesProcessTest::SetUp() {
|
||||||
mesh = new aiMesh();
|
mMesh = new aiMesh();
|
||||||
process = new FindDegeneratesProcess();
|
mProcess = new FindDegeneratesProcess();
|
||||||
|
|
||||||
mesh->mNumFaces = 1000;
|
mMesh->mNumFaces = 1000;
|
||||||
mesh->mFaces = new aiFace[1000];
|
mMesh->mFaces = new aiFace[1000];
|
||||||
|
|
||||||
mesh->mNumVertices = 5000*2;
|
mMesh->mNumVertices = 5000*2;
|
||||||
mesh->mVertices = new aiVector3D[5000*2];
|
mMesh->mVertices = new aiVector3D[5000*2];
|
||||||
|
|
||||||
for (unsigned int i = 0; i < 5000; ++i) {
|
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;
|
aiPrimitiveType_POLYGON | aiPrimitiveType_TRIANGLE;
|
||||||
|
|
||||||
unsigned int numOut = 0, numFaces = 0;
|
unsigned int numOut = 0, numFaces = 0;
|
||||||
for (unsigned int i = 0; i < 1000; ++i) {
|
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.mNumIndices = (i % 5)+1; // between 1 and 5
|
||||||
f.mIndices = new unsigned int[f.mNumIndices];
|
f.mIndices = new unsigned int[f.mNumIndices];
|
||||||
bool had = false;
|
bool had = false;
|
||||||
|
@ -102,46 +107,46 @@ void FindDegeneratesProcessTest::SetUp() {
|
||||||
if (!had)
|
if (!had)
|
||||||
++numFaces;
|
++numFaces;
|
||||||
}
|
}
|
||||||
mesh->mNumUVComponents[0] = numOut;
|
mMesh->mNumUVComponents[0] = numOut;
|
||||||
mesh->mNumUVComponents[1] = numFaces;
|
mMesh->mNumUVComponents[1] = numFaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FindDegeneratesProcessTest::TearDown() {
|
void FindDegeneratesProcessTest::TearDown() {
|
||||||
delete mesh;
|
delete mMesh;
|
||||||
delete process;
|
delete mProcess;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FindDegeneratesProcessTest, testDegeneratesDetection) {
|
TEST_F(FindDegeneratesProcessTest, testDegeneratesDetection) {
|
||||||
process->EnableInstantRemoval(false);
|
mProcess->EnableInstantRemoval(false);
|
||||||
process->ExecuteOnMesh(mesh);
|
mProcess->ExecuteOnMesh(mMesh);
|
||||||
|
|
||||||
unsigned int out = 0;
|
unsigned int out = 0;
|
||||||
for (unsigned int i = 0; i < 1000; ++i) {
|
for (unsigned int i = 0; i < 1000; ++i) {
|
||||||
aiFace& f = mesh->mFaces[i];
|
aiFace& f = mMesh->mFaces[i];
|
||||||
out += f.mNumIndices;
|
out += f.mNumIndices;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPECT_EQ(1000U, mesh->mNumFaces);
|
EXPECT_EQ(1000U, mMesh->mNumFaces);
|
||||||
EXPECT_EQ(10000U, mesh->mNumVertices);
|
EXPECT_EQ(10000U, mMesh->mNumVertices);
|
||||||
EXPECT_EQ(out, mesh->mNumUVComponents[0]);
|
EXPECT_EQ(out, mMesh->mNumUVComponents[0]);
|
||||||
EXPECT_EQ(static_cast<unsigned int>(
|
EXPECT_EQ(static_cast<unsigned int>(
|
||||||
aiPrimitiveType_LINE | aiPrimitiveType_POINT |
|
aiPrimitiveType_LINE | aiPrimitiveType_POINT |
|
||||||
aiPrimitiveType_POLYGON | aiPrimitiveType_TRIANGLE),
|
aiPrimitiveType_POLYGON | aiPrimitiveType_TRIANGLE),
|
||||||
mesh->mPrimitiveTypes);
|
mMesh->mPrimitiveTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FindDegeneratesProcessTest, testDegeneratesRemoval) {
|
TEST_F(FindDegeneratesProcessTest, testDegeneratesRemoval) {
|
||||||
process->EnableAreaCheck(false);
|
mProcess->EnableAreaCheck(false);
|
||||||
process->EnableInstantRemoval(true);
|
mProcess->EnableInstantRemoval(true);
|
||||||
process->ExecuteOnMesh(mesh);
|
mProcess->ExecuteOnMesh(mMesh);
|
||||||
|
|
||||||
EXPECT_EQ(mesh->mNumUVComponents[1], mesh->mNumFaces);
|
EXPECT_EQ(mMesh->mNumUVComponents[1], mMesh->mNumFaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FindDegeneratesProcessTest, testDegeneratesRemovalWithAreaCheck) {
|
TEST_F(FindDegeneratesProcessTest, testDegeneratesRemovalWithAreaCheck) {
|
||||||
process->EnableAreaCheck(true);
|
mProcess->EnableAreaCheck(true);
|
||||||
process->EnableInstantRemoval(true);
|
mProcess->EnableInstantRemoval(true);
|
||||||
process->ExecuteOnMesh(mesh);
|
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
|
Copyright (c) 2006-2019, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
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 std;
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
class FindInvalidDataProcessTest : public ::testing::Test
|
class utFindInvalidDataProcess : public ::testing::Test {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
utFindInvalidDataProcess()
|
||||||
|
: Test()
|
||||||
|
, mMesh(nullptr)
|
||||||
|
, mProcess(nullptr) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
virtual void SetUp();
|
virtual void SetUp();
|
||||||
virtual void TearDown();
|
virtual void TearDown();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
aiMesh* pcMesh;
|
aiMesh* mMesh;
|
||||||
FindInvalidDataProcess* piProcess;
|
FindInvalidDataProcess* mProcess;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void FindInvalidDataProcessTest::SetUp() {
|
void utFindInvalidDataProcess::SetUp() {
|
||||||
ASSERT_TRUE( AI_MAX_NUMBER_OF_TEXTURECOORDS >= 3);
|
ASSERT_TRUE( AI_MAX_NUMBER_OF_TEXTURECOORDS >= 3);
|
||||||
|
|
||||||
piProcess = new FindInvalidDataProcess();
|
mProcess = new FindInvalidDataProcess();
|
||||||
pcMesh = new aiMesh();
|
mMesh = new aiMesh();
|
||||||
|
|
||||||
pcMesh->mNumVertices = 1000;
|
mMesh->mNumVertices = 1000;
|
||||||
pcMesh->mVertices = new aiVector3D[1000];
|
mMesh->mVertices = new aiVector3D[1000];
|
||||||
for (unsigned int i = 0; i < 1000;++i)
|
for (unsigned int i = 0; i < 1000; ++i) {
|
||||||
pcMesh->mVertices[i] = aiVector3D((float)i);
|
mMesh->mVertices[i] = aiVector3D((float)i);
|
||||||
|
}
|
||||||
|
|
||||||
pcMesh->mNormals = new aiVector3D[1000];
|
mMesh->mNormals = new aiVector3D[1000];
|
||||||
for (unsigned int i = 0; i < 1000;++i)
|
for (unsigned int i = 0; i < 1000; ++i) {
|
||||||
pcMesh->mNormals[i] = aiVector3D((float)i+1);
|
mMesh->mNormals[i] = aiVector3D((float)i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
pcMesh->mTangents = new aiVector3D[1000];
|
mMesh->mTangents = new aiVector3D[1000];
|
||||||
for (unsigned int i = 0; i < 1000;++i)
|
for (unsigned int i = 0; i < 1000; ++i) {
|
||||||
pcMesh->mTangents[i] = aiVector3D((float)i);
|
mMesh->mTangents[i] = aiVector3D((float)i);
|
||||||
|
}
|
||||||
|
|
||||||
pcMesh->mBitangents = new aiVector3D[1000];
|
mMesh->mBitangents = new aiVector3D[1000];
|
||||||
for (unsigned int i = 0; i < 1000;++i)
|
for (unsigned int i = 0; i < 1000; ++i) {
|
||||||
pcMesh->mBitangents[i] = aiVector3D((float)i);
|
mMesh->mBitangents[i] = aiVector3D((float)i);
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a)
|
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) {
|
||||||
{
|
mMesh->mTextureCoords[a] = new aiVector3D[1000];
|
||||||
pcMesh->mTextureCoords[a] = new aiVector3D[1000];
|
for (unsigned int i = 0; i < 1000; ++i) {
|
||||||
for (unsigned int i = 0; i < 1000;++i)
|
mMesh->mTextureCoords[a][i] = aiVector3D((float)i);
|
||||||
pcMesh->mTextureCoords[a][i] = aiVector3D((float)i);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void FindInvalidDataProcessTest::TearDown()
|
void utFindInvalidDataProcess::TearDown() {
|
||||||
{
|
delete mProcess;
|
||||||
delete piProcess;
|
delete mMesh;
|
||||||
delete pcMesh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
TEST_F(FindInvalidDataProcessTest, testStepNegativeResult)
|
TEST_F(utFindInvalidDataProcess, testStepNegativeResult) {
|
||||||
{
|
::memset(mMesh->mNormals, 0, mMesh->mNumVertices*sizeof(aiVector3D) );
|
||||||
::memset(pcMesh->mNormals,0,pcMesh->mNumVertices*sizeof(aiVector3D));
|
::memset(mMesh->mBitangents, 0, mMesh->mNumVertices*sizeof(aiVector3D) );
|
||||||
::memset(pcMesh->mBitangents,0,pcMesh->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 != mMesh->mVertices);
|
||||||
EXPECT_TRUE(NULL == pcMesh->mNormals);
|
EXPECT_EQ(NULL, mMesh->mNormals);
|
||||||
EXPECT_TRUE(NULL == pcMesh->mTangents);
|
EXPECT_EQ(NULL, mMesh->mTangents);
|
||||||
EXPECT_TRUE(NULL == pcMesh->mBitangents);
|
EXPECT_EQ(NULL, mMesh->mBitangents);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < 2;++i)
|
for (unsigned int i = 0; i < 2; ++i) {
|
||||||
EXPECT_TRUE(NULL != pcMesh->mTextureCoords[i]);
|
EXPECT_TRUE(NULL != mMesh->mTextureCoords[i]);
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned int i = 2; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
|
for (unsigned int i = 2; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||||
EXPECT_TRUE(NULL == pcMesh->mTextureCoords[i]);
|
EXPECT_EQ(NULL, mMesh->mTextureCoords[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
TEST_F(FindInvalidDataProcessTest, testStepPositiveResult)
|
TEST_F(utFindInvalidDataProcess, testStepPositiveResult) {
|
||||||
{
|
mProcess->ProcessMesh(mMesh);
|
||||||
piProcess->ProcessMesh(pcMesh);
|
|
||||||
|
|
||||||
EXPECT_TRUE(NULL != pcMesh->mVertices);
|
EXPECT_NE(nullptr, mMesh->mVertices);
|
||||||
|
|
||||||
EXPECT_TRUE(NULL != pcMesh->mNormals);
|
EXPECT_NE(nullptr, mMesh->mNormals);
|
||||||
EXPECT_TRUE(NULL != pcMesh->mTangents);
|
EXPECT_NE(nullptr, mMesh->mTangents);
|
||||||
EXPECT_TRUE(NULL != pcMesh->mBitangents);
|
EXPECT_NE(nullptr, mMesh->mBitangents);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
|
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||||
EXPECT_TRUE(NULL != pcMesh->mTextureCoords[i]);
|
EXPECT_NE(nullptr, mMesh->mTextureCoords[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,13 +48,21 @@ using namespace Assimp;
|
||||||
|
|
||||||
class utGenBoundingBoxesProcess : public ::testing::Test {
|
class utGenBoundingBoxesProcess : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
|
utGenBoundingBoxesProcess()
|
||||||
|
: Test()
|
||||||
|
, mProcess(nullptr)
|
||||||
|
, mMesh(nullptr)
|
||||||
|
, mScene(nullptr) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
mProcess = new GenBoundingBoxesProcess;
|
mProcess = new GenBoundingBoxesProcess;
|
||||||
mMesh = new aiMesh();
|
mMesh = new aiMesh();
|
||||||
mMesh->mNumVertices = 100;
|
mMesh->mNumVertices = 100;
|
||||||
mMesh->mVertices = new aiVector3D[100];
|
mMesh->mVertices = new aiVector3D[100];
|
||||||
for (unsigned int i = 0; i < 100; ++i) {
|
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 = new aiScene();
|
||||||
mScene->mNumMeshes = 1;
|
mScene->mNumMeshes = 1;
|
||||||
|
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2019, assimp team
|
Copyright (c) 2006-2019, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
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 std;
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
class JoinVerticesTest : public ::testing::Test {
|
class utJoinVertices : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
|
utJoinVertices()
|
||||||
|
: Test()
|
||||||
|
, piProcess(nullptr)
|
||||||
|
, pcMesh(nullptr) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
virtual void SetUp();
|
virtual void SetUp();
|
||||||
virtual void TearDown();
|
virtual void TearDown();
|
||||||
|
|
||||||
|
@ -60,8 +66,7 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void JoinVerticesTest::SetUp()
|
void utJoinVertices::SetUp() {
|
||||||
{
|
|
||||||
// construct the process
|
// construct the process
|
||||||
piProcess = new JoinVerticesProcess();
|
piProcess = new JoinVerticesProcess();
|
||||||
|
|
||||||
|
@ -71,11 +76,9 @@ void JoinVerticesTest::SetUp()
|
||||||
|
|
||||||
pcMesh->mNumVertices = 900;
|
pcMesh->mNumVertices = 900;
|
||||||
aiVector3D*& pv = pcMesh->mVertices = new aiVector3D[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;
|
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;
|
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
|
// generate faces - each vertex is referenced once
|
||||||
pcMesh->mNumFaces = 300;
|
pcMesh->mNumFaces = 300;
|
||||||
pcMesh->mFaces = new aiFace[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];
|
aiFace& face = pcMesh->mFaces[i];
|
||||||
face.mIndices = new unsigned int[ face.mNumIndices = 3 ];
|
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++;
|
face.mIndices[a] = p++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// generate extra members - set them to zero to make sure they're identical
|
// generate extra members - set them to zero to make sure they're identical
|
||||||
pcMesh->mTextureCoords[0] = new aiVector3D[900];
|
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];
|
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;
|
delete this->pcMesh;
|
||||||
|
pcMesh = nullptr;
|
||||||
delete this->piProcess;
|
delete this->piProcess;
|
||||||
|
piProcess = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
TEST_F(JoinVerticesTest, testProcess)
|
TEST_F(utJoinVertices, testProcess) {
|
||||||
{
|
|
||||||
// execute the step on the given data
|
// execute the step on the given data
|
||||||
piProcess->ProcessMesh(pcMesh,0);
|
piProcess->ProcessMesh(pcMesh,0);
|
||||||
|
|
||||||
|
@ -122,15 +124,14 @@ TEST_F(JoinVerticesTest, testProcess)
|
||||||
ASSERT_EQ(300U, pcMesh->mNumFaces);
|
ASSERT_EQ(300U, pcMesh->mNumFaces);
|
||||||
ASSERT_EQ(300U, pcMesh->mNumVertices);
|
ASSERT_EQ(300U, pcMesh->mNumVertices);
|
||||||
|
|
||||||
ASSERT_TRUE(NULL != pcMesh->mNormals);
|
ASSERT_TRUE( nullptr != pcMesh->mNormals);
|
||||||
ASSERT_TRUE(NULL != pcMesh->mTangents);
|
ASSERT_TRUE( nullptr != pcMesh->mTangents);
|
||||||
ASSERT_TRUE(NULL != pcMesh->mBitangents);
|
ASSERT_TRUE( nullptr != pcMesh->mBitangents);
|
||||||
ASSERT_TRUE(NULL != pcMesh->mTextureCoords[0]);
|
ASSERT_TRUE( nullptr != pcMesh->mTextureCoords[0]);
|
||||||
|
|
||||||
// the order doesn't care
|
// the order doesn't care
|
||||||
float fSum = 0.f;
|
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];
|
aiVector3D& v = pcMesh->mVertices[i];
|
||||||
fSum += v.x + v.y + v.z;
|
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
|
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
|
Copyright (c) 2006-2019, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
@ -50,83 +48,83 @@ using namespace Assimp;
|
||||||
|
|
||||||
class LimitBoneWeightsTest : public ::testing::Test {
|
class LimitBoneWeightsTest : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
|
LimitBoneWeightsTest()
|
||||||
|
: Test()
|
||||||
|
, mProcess(nullptr)
|
||||||
|
, mMesh(nullptr) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
virtual void SetUp();
|
virtual void SetUp();
|
||||||
virtual void TearDown();
|
virtual void TearDown();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
LimitBoneWeightsProcess* piProcess;
|
LimitBoneWeightsProcess *mProcess;
|
||||||
aiMesh* pcMesh;
|
aiMesh *mMesh;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void LimitBoneWeightsTest::SetUp()
|
void LimitBoneWeightsTest::SetUp() {
|
||||||
{
|
|
||||||
// construct the process
|
// construct the process
|
||||||
this->piProcess = new LimitBoneWeightsProcess();
|
this->mProcess = new LimitBoneWeightsProcess();
|
||||||
|
|
||||||
// now need to create a nice mesh for testing purposes
|
// now need to create a nice mesh for testing purposes
|
||||||
this->pcMesh = new aiMesh();
|
this->mMesh = new aiMesh();
|
||||||
|
|
||||||
pcMesh->mNumVertices = 500;
|
mMesh->mNumVertices = 500;
|
||||||
pcMesh->mVertices = new aiVector3D[500]; // uninit.
|
mMesh->mVertices = new aiVector3D[500]; // uninit.
|
||||||
pcMesh->mNumBones = 30;
|
mMesh->mNumBones = 30;
|
||||||
pcMesh->mBones = new aiBone*[30];
|
mMesh->mBones = new aiBone*[30];
|
||||||
unsigned int iCur = 0;
|
unsigned int iCur = 0;
|
||||||
for (unsigned int i = 0; i < 30;++i)
|
for (unsigned int i = 0; i < 30;++i) {
|
||||||
{
|
aiBone* pc = mMesh->mBones[i] = new aiBone();
|
||||||
aiBone* pc = pcMesh->mBones[i] = new aiBone();
|
|
||||||
pc->mNumWeights = 250;
|
pc->mNumWeights = 250;
|
||||||
pc->mWeights = new aiVertexWeight[pc->mNumWeights];
|
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];
|
aiVertexWeight& v = pc->mWeights[qq];
|
||||||
v.mVertexId = iCur++;
|
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
|
v.mWeight = 1.0f / 15; // each vertex should occur once in two bones
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void LimitBoneWeightsTest::TearDown()
|
void LimitBoneWeightsTest::TearDown() {
|
||||||
{
|
delete mMesh;
|
||||||
delete pcMesh;
|
delete mProcess;
|
||||||
delete piProcess;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
TEST_F(LimitBoneWeightsTest, testProcess)
|
TEST_F(LimitBoneWeightsTest, testProcess) {
|
||||||
{
|
|
||||||
// execute the step on the given data
|
// execute the step on the given data
|
||||||
piProcess->ProcessMesh(pcMesh);
|
mProcess->ProcessMesh(mMesh);
|
||||||
|
|
||||||
// check whether everything is ok ...
|
// check whether everything is ok ...
|
||||||
typedef std::vector<LimitBoneWeightsProcess::Weight> VertexWeightList;
|
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);
|
asWeights[i].reserve(4);
|
||||||
|
}
|
||||||
|
|
||||||
// sort back as per-vertex lists
|
// sort back as per-vertex lists
|
||||||
for (unsigned int i = 0; i < pcMesh->mNumBones;++i)
|
for (unsigned int i = 0; i < mMesh->mNumBones;++i) {
|
||||||
{
|
aiBone& pcBone = **(mMesh->mBones+i);
|
||||||
aiBone& pcBone = **(pcMesh->mBones+i);
|
for (unsigned int q = 0; q < pcBone.mNumWeights;++q) {
|
||||||
for (unsigned int q = 0; q < pcBone.mNumWeights;++q)
|
|
||||||
{
|
|
||||||
aiVertexWeight weight = pcBone.mWeights[q];
|
aiVertexWeight weight = pcBone.mWeights[q];
|
||||||
asWeights[weight.mVertexId].push_back(LimitBoneWeightsProcess::Weight (i,weight.mWeight));
|
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
|
// 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);
|
EXPECT_LE(asWeights[i].size(), 4U);
|
||||||
float fSum = 0.0f;
|
float fSum = 0.0f;
|
||||||
for (VertexWeightList::const_iterator
|
for (VertexWeightList::const_iterator iter = asWeights[i].begin(); iter != asWeights[i].end();++iter) {
|
||||||
iter = asWeights[i].begin();
|
|
||||||
iter != asWeights[i].end();++iter)
|
|
||||||
{
|
|
||||||
fSum += (*iter).mWeight;
|
fSum += (*iter).mWeight;
|
||||||
}
|
}
|
||||||
EXPECT_GE(fSum, 0.95F);
|
EXPECT_GE(fSum, 0.95F);
|
||||||
|
|
|
@ -51,18 +51,24 @@ using namespace Assimp;
|
||||||
|
|
||||||
class PretransformVerticesTest : public ::testing::Test {
|
class PretransformVerticesTest : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
|
PretransformVerticesTest()
|
||||||
|
: Test()
|
||||||
|
, mScene(nullptr)
|
||||||
|
, mProcess(nullptr) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
virtual void SetUp();
|
virtual void SetUp();
|
||||||
virtual void TearDown();
|
virtual void TearDown();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
aiScene *mScene;
|
||||||
aiScene* scene;
|
PretransformVertices *mProcess;
|
||||||
PretransformVertices* process;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
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];
|
father->mChildren = new aiNode*[father->mNumChildren = 5];
|
||||||
for (unsigned int i = 0; i < 5; ++i) {
|
for (unsigned int i = 0; i < 5; ++i) {
|
||||||
aiNode* nd = father->mChildren[i] = new aiNode();
|
aiNode* nd = father->mChildren[i] = new aiNode();
|
||||||
|
@ -79,26 +85,26 @@ void AddNodes(unsigned int num, aiNode* father, unsigned int depth)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (depth > 1) {
|
if (depth > 1) {
|
||||||
for (unsigned int i = 0; i < 5; ++i)
|
for (unsigned int i = 0; i < 5; ++i) {
|
||||||
AddNodes(i, father->mChildren[i],depth-1);
|
AddNodes(i, father->mChildren[i], depth - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void PretransformVerticesTest::SetUp()
|
void PretransformVerticesTest::SetUp() {
|
||||||
{
|
mScene = new aiScene();
|
||||||
scene = new aiScene();
|
|
||||||
|
|
||||||
// add 5 empty materials
|
// 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) {
|
for (unsigned int i = 0; i < 5;++i) {
|
||||||
scene->mMaterials[i] = new aiMaterial();
|
mScene->mMaterials[i] = new aiMaterial();
|
||||||
}
|
}
|
||||||
|
|
||||||
// add 25 test meshes
|
// add 25 test meshes
|
||||||
scene->mMeshes = new aiMesh*[scene->mNumMeshes = 25];
|
mScene->mMeshes = new aiMesh*[mScene->mNumMeshes = 25];
|
||||||
for ( unsigned int i = 0; i < 25; ++i) {
|
for ( unsigned int i = 0; i < 25; ++i) {
|
||||||
aiMesh* mesh = scene->mMeshes[ i ] = new aiMesh();
|
aiMesh* mesh = mScene->mMeshes[ i ] = new aiMesh();
|
||||||
|
|
||||||
mesh->mPrimitiveTypes = aiPrimitiveType_POINT;
|
mesh->mPrimitiveTypes = aiPrimitiveType_POINT;
|
||||||
mesh->mFaces = new aiFace[ mesh->mNumFaces = 10+i ];
|
mesh->mFaces = new aiFace[ mesh->mNumFaces = 10+i ];
|
||||||
|
@ -124,36 +130,33 @@ void PretransformVerticesTest::SetUp()
|
||||||
}
|
}
|
||||||
|
|
||||||
// construct some nodes (1+25)
|
// construct some nodes (1+25)
|
||||||
scene->mRootNode = new aiNode();
|
mScene->mRootNode = new aiNode();
|
||||||
scene->mRootNode->mName.Set("Root");
|
mScene->mRootNode->mName.Set("Root");
|
||||||
AddNodes(0,scene->mRootNode,2);
|
AddNodes(0, mScene->mRootNode, 2);
|
||||||
|
|
||||||
process = new PretransformVertices();
|
mProcess = new PretransformVertices();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void PretransformVerticesTest::TearDown()
|
void PretransformVerticesTest::TearDown() {
|
||||||
{
|
delete mScene;
|
||||||
delete scene;
|
delete mProcess;
|
||||||
delete process;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
TEST_F(PretransformVerticesTest, testProcessCollapseHierarchy)
|
TEST_F(PretransformVerticesTest, testProcessCollapseHierarchy) {
|
||||||
{
|
mProcess->KeepHierarchy(false);
|
||||||
process->KeepHierarchy(false);
|
mProcess->Execute(mScene);
|
||||||
process->Execute(scene);
|
|
||||||
|
|
||||||
EXPECT_EQ(5U, scene->mNumMaterials);
|
EXPECT_EQ(5U, mScene->mNumMaterials);
|
||||||
EXPECT_EQ(10U, scene->mNumMeshes); // every second mesh has normals
|
EXPECT_EQ(10U, mScene->mNumMeshes); // every second mesh has normals
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
TEST_F(PretransformVerticesTest, testProcessKeepHierarchy)
|
TEST_F(PretransformVerticesTest, testProcessKeepHierarchy) {
|
||||||
{
|
mProcess->KeepHierarchy(true);
|
||||||
process->KeepHierarchy(true);
|
mProcess->Execute(mScene);
|
||||||
process->Execute(scene);
|
|
||||||
|
|
||||||
EXPECT_EQ(5U, scene->mNumMaterials);
|
EXPECT_EQ(5U, mScene->mNumMaterials);
|
||||||
EXPECT_EQ(49U, scene->mNumMeshes); // see note on mesh 12 above
|
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 std;
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
|
class ScenePreprocessorTest : public ::testing::Test {
|
||||||
class ScenePreprocessorTest : public ::testing::Test
|
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
ScenePreprocessorTest()
|
||||||
|
: Test()
|
||||||
|
, mScenePreprocessor(nullptr)
|
||||||
|
, mScene(nullptr) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
virtual void SetUp();
|
virtual void SetUp();
|
||||||
virtual void TearDown();
|
virtual void TearDown();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void CheckIfOnly(aiMesh* p, unsigned int num, unsigned flag);
|
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); }
|
private:
|
||||||
void ProcessMesh(aiMesh* mesh) { pp->ProcessMesh(mesh); }
|
ScenePreprocessor *mScenePreprocessor;
|
||||||
|
aiScene *mScene;
|
||||||
ScenePreprocessor* pp;
|
|
||||||
aiScene* scene;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ScenePreprocessorTest::SetUp()
|
void ScenePreprocessorTest::SetUp() {
|
||||||
{
|
|
||||||
// setup a dummy scene with a single node
|
// setup a dummy scene with a single node
|
||||||
scene = new aiScene();
|
mScene = new aiScene();
|
||||||
scene->mRootNode = new aiNode();
|
mScene->mRootNode = new aiNode();
|
||||||
scene->mRootNode->mName.Set("<test>");
|
mScene->mRootNode->mName.Set("<test>");
|
||||||
|
|
||||||
// add some translation
|
// add some translation
|
||||||
scene->mRootNode->mTransformation.a4 = 1.f;
|
mScene->mRootNode->mTransformation.a4 = 1.f;
|
||||||
scene->mRootNode->mTransformation.b4 = 2.f;
|
mScene->mRootNode->mTransformation.b4 = 2.f;
|
||||||
scene->mRootNode->mTransformation.c4 = 3.f;
|
mScene->mRootNode->mTransformation.c4 = 3.f;
|
||||||
|
|
||||||
// and allocate a ScenePreprocessor to operate on the scene
|
// and allocate a ScenePreprocessor to operate on the scene
|
||||||
pp = new ScenePreprocessor(scene);
|
mScenePreprocessor = new ScenePreprocessor(mScene);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void ScenePreprocessorTest::TearDown()
|
void ScenePreprocessorTest::TearDown() {
|
||||||
{
|
delete mScenePreprocessor;
|
||||||
delete pp;
|
delete mScene;
|
||||||
delete scene;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Check whether ProcessMesh() returns flag for a mesh that consist of primitives with num indices
|
// 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
|
// Triangles only
|
||||||
for (unsigned i = 0; i < p->mNumFaces;++i) {
|
for (unsigned i = 0; i < p->mNumFaces;++i) {
|
||||||
p->mFaces[i].mNumIndices = num;
|
p->mFaces[i].mNumIndices = num;
|
||||||
}
|
}
|
||||||
pp->ProcessMesh(p);
|
mScenePreprocessor->ProcessMesh(p);
|
||||||
EXPECT_EQ(flag, p->mPrimitiveTypes);
|
EXPECT_EQ(flag, p->mPrimitiveTypes);
|
||||||
p->mPrimitiveTypes = 0;
|
p->mPrimitiveTypes = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Check whether a mesh is preprocessed correctly. Case 1: The mesh needs preprocessing
|
// Check whether a mesh is preprocessed correctly. Case 1: The mesh needs preprocessing
|
||||||
TEST_F(ScenePreprocessorTest, testMeshPreprocessingPos)
|
TEST_F(ScenePreprocessorTest, testMeshPreprocessingPos) {
|
||||||
{
|
aiMesh* p = new aiMesh;
|
||||||
aiMesh* p = new aiMesh();
|
|
||||||
p->mNumFaces = 100;
|
p->mNumFaces = 100;
|
||||||
p->mFaces = new aiFace[p->mNumFaces];
|
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
|
// Check whether a mesh is preprocessed correctly. Case 1: The mesh doesn't need preprocessing
|
||||||
TEST_F(ScenePreprocessorTest, testMeshPreprocessingNeg)
|
TEST_F(ScenePreprocessorTest, testMeshPreprocessingNeg) {
|
||||||
{
|
aiMesh* p = new aiMesh;
|
||||||
aiMesh* p = new aiMesh();
|
|
||||||
p->mPrimitiveTypes = aiPrimitiveType_TRIANGLE|aiPrimitiveType_POLYGON;
|
p->mPrimitiveTypes = aiPrimitiveType_TRIANGLE|aiPrimitiveType_POLYGON;
|
||||||
ProcessMesh(p);
|
ProcessMesh(p);
|
||||||
|
|
||||||
|
@ -160,8 +159,7 @@ TEST_F(ScenePreprocessorTest, testMeshPreprocessingNeg)
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Make a dummy animation with a single channel, '<test>'
|
// Make a dummy animation with a single channel, '<test>'
|
||||||
aiAnimation* MakeDummyAnimation()
|
aiAnimation* MakeDummyAnimation() {
|
||||||
{
|
|
||||||
aiAnimation* p = new aiAnimation();
|
aiAnimation* p = new aiAnimation();
|
||||||
p->mNumChannels = 1;
|
p->mNumChannels = 1;
|
||||||
p->mChannels = new aiNodeAnim*[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
|
// Check whether an anim is preprocessed correctly. Case 1: The anim needs preprocessing
|
||||||
TEST_F(ScenePreprocessorTest, testAnimationPreprocessingPos)
|
TEST_F(ScenePreprocessorTest, testAnimationPreprocessingPos) {
|
||||||
{
|
|
||||||
aiAnimation* p = MakeDummyAnimation();
|
aiAnimation* p = MakeDummyAnimation();
|
||||||
aiNodeAnim* anim = p->mChannels[0];
|
aiNodeAnim* anim = p->mChannels[0];
|
||||||
|
|
||||||
|
|
|
@ -52,12 +52,20 @@ using namespace Assimp;
|
||||||
|
|
||||||
class SortByPTypeProcessTest : public ::testing::Test {
|
class SortByPTypeProcessTest : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
|
SortByPTypeProcessTest()
|
||||||
|
: Test()
|
||||||
|
, mProcess1(nullptr)
|
||||||
|
, mScene(nullptr) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
virtual void SetUp();
|
virtual void SetUp();
|
||||||
virtual void TearDown();
|
virtual void TearDown();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SortByPTypeProcess* process1;
|
SortByPTypeProcess* mProcess1;
|
||||||
aiScene* scene;
|
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_POLYGON,
|
||||||
aiPrimitiveType_TRIANGLE,
|
aiPrimitiveType_TRIANGLE,
|
||||||
aiPrimitiveType_LINE,
|
aiPrimitiveType_LINE,
|
||||||
|
@ -90,19 +97,16 @@ static unsigned int result[10] =
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void SortByPTypeProcessTest::SetUp()
|
void SortByPTypeProcessTest::SetUp() {
|
||||||
{
|
mProcess1 = new SortByPTypeProcess();
|
||||||
// process0 = new DeterminePTypeHelperProcess();
|
mScene = new aiScene();
|
||||||
process1 = new SortByPTypeProcess();
|
|
||||||
scene = new aiScene();
|
|
||||||
|
|
||||||
scene->mNumMeshes = 10;
|
mScene->mNumMeshes = 10;
|
||||||
scene->mMeshes = new aiMesh*[10];
|
mScene->mMeshes = new aiMesh*[10];
|
||||||
|
|
||||||
bool five = false;
|
bool five = false;
|
||||||
for (unsigned int i = 0; i < 10; ++i)
|
for (unsigned int i = 0; i < 10; ++i) {
|
||||||
{
|
aiMesh* mesh = mScene->mMeshes[i] = new aiMesh();
|
||||||
aiMesh* mesh = scene->mMeshes[i] = new aiMesh();
|
|
||||||
mesh->mNumFaces = 1000;
|
mesh->mNumFaces = 1000;
|
||||||
aiFace* faces = mesh->mFaces = new aiFace[1000];
|
aiFace* faces = mesh->mFaces = new aiFace[1000];
|
||||||
aiVector3D* pv = mesh->mVertices = new aiVector3D[mesh->mNumFaces*5];
|
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 remaining[4] = {num[i][0],num[i][1],num[i][2],num[i][3]};
|
||||||
unsigned int n = 0;
|
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;
|
unsigned int idx = m % 4;
|
||||||
while (true)
|
while (true) {
|
||||||
{
|
if (!remaining[idx]) {
|
||||||
if (!remaining[idx])
|
if (4 == ++idx) {
|
||||||
{
|
idx = 0;
|
||||||
if (4 == ++idx)idx = 0;
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
faces->mNumIndices = idx+1;
|
faces->mNumIndices = idx+1;
|
||||||
if (4 == faces->mNumIndices)
|
if (4 == faces->mNumIndices) {
|
||||||
{
|
|
||||||
if(five)++faces->mNumIndices;
|
if(five)++faces->mNumIndices;
|
||||||
five = !five;
|
five = !five;
|
||||||
}
|
}
|
||||||
faces->mIndices = new unsigned int[faces->mNumIndices];
|
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;
|
faces->mIndices[q] = n;
|
||||||
float f = (float)remaining[idx];
|
float f = (float)remaining[idx];
|
||||||
|
|
||||||
|
@ -152,12 +153,11 @@ void SortByPTypeProcessTest::SetUp()
|
||||||
mesh->mNumVertices = n;
|
mesh->mNumVertices = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
scene->mRootNode = new aiNode();
|
mScene->mRootNode = new aiNode();
|
||||||
scene->mRootNode->mNumChildren = 5;
|
mScene->mRootNode->mNumChildren = 5;
|
||||||
scene->mRootNode->mChildren = new aiNode*[5];
|
mScene->mRootNode->mChildren = new aiNode*[5];
|
||||||
for (unsigned int i = 0; i< 5;++i )
|
for (unsigned int i = 0; i< 5;++i ) {
|
||||||
{
|
aiNode* node = mScene->mRootNode->mChildren[i] = new aiNode();
|
||||||
aiNode* node = scene->mRootNode->mChildren[i] = new aiNode();
|
|
||||||
node->mNumMeshes = 2;
|
node->mNumMeshes = 2;
|
||||||
node->mMeshes = new unsigned int[2];
|
node->mMeshes = new unsigned int[2];
|
||||||
node->mMeshes[0] = (i<<1u);
|
node->mMeshes[0] = (i<<1u);
|
||||||
|
@ -166,48 +166,28 @@ void SortByPTypeProcessTest::SetUp()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void SortByPTypeProcessTest::TearDown()
|
void SortByPTypeProcessTest::TearDown() {
|
||||||
{
|
delete mProcess1;
|
||||||
//delete process0;
|
delete mScene;
|
||||||
delete process1;
|
|
||||||
delete scene;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
//TEST_F(SortByPTypeProcessTest, DeterminePTypeStep()
|
TEST_F(SortByPTypeProcessTest, SortByPTypeStep) {
|
||||||
//{
|
ScenePreprocessor s(mScene);
|
||||||
// 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);
|
|
||||||
s.ProcessScene();
|
s.ProcessScene();
|
||||||
for (unsigned int m = 0; m< 10;++m)
|
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;
|
unsigned int idx = 0;
|
||||||
for (unsigned int m = 0,real = 0; m< 10;++m)
|
for (unsigned int m = 0,real = 0; m< 10;++m) {
|
||||||
{
|
for (unsigned int n = 0; n < 4;++n) {
|
||||||
for (unsigned int n = 0; n < 4;++n)
|
|
||||||
{
|
|
||||||
if ((idx = num[m][n]))
|
if ((idx = num[m][n]))
|
||||||
{
|
{
|
||||||
EXPECT_TRUE(real < scene->mNumMeshes);
|
EXPECT_TRUE(real < mScene->mNumMeshes);
|
||||||
|
|
||||||
aiMesh* mesh = scene->mMeshes[real];
|
aiMesh* mesh = mScene->mMeshes[real];
|
||||||
|
|
||||||
EXPECT_TRUE(NULL != mesh);
|
EXPECT_TRUE(NULL != mesh);
|
||||||
EXPECT_EQ(AI_PRIMITIVE_TYPE_FOR_N_INDICES(n+1), mesh->mPrimitiveTypes);
|
EXPECT_EQ(AI_PRIMITIVE_TYPE_FOR_N_INDICES(n+1), mesh->mPrimitiveTypes);
|
||||||
|
@ -218,8 +198,7 @@ TEST_F(SortByPTypeProcessTest, SortByPTypeStep)
|
||||||
EXPECT_TRUE(NULL != mesh->mTextureCoords[0]);
|
EXPECT_TRUE(NULL != mesh->mTextureCoords[0]);
|
||||||
|
|
||||||
EXPECT_TRUE(mesh->mNumFaces == idx);
|
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];
|
aiFace& face = mesh->mFaces[f];
|
||||||
EXPECT_TRUE(face.mNumIndices == (n+1) || (3 == n && face.mNumIndices > 3));
|
EXPECT_TRUE(face.mNumIndices == (n+1) || (3 == n && face.mNumIndices > 3));
|
||||||
}
|
}
|
||||||
|
@ -228,4 +207,3 @@ TEST_F(SortByPTypeProcessTest, SortByPTypeStep)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue