#if !defined(ASSIMP_BUILD_NO_EXPORT) && !defined(ASSIMP_BUILD_NO_PLY_EXPORTER)
#include "PlyExporter.h"
#include <memory>
#include <cmath>
#include "Exceptional.h"
#include <assimp/scene.h>
#include <assimp/version.h>
#include <assimp/IOSystem.hpp>
#include <assimp/Exporter.hpp>
#include "qnan.h"
namespace Assimp {
template <typename T> const char* type_of(T&) { return "unknown"; }
template<> const char* type_of(float&) { return "float"; }
template<> const char* type_of(double&) { return "double"; }
void ExportScenePly(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
{
PlyExporter exporter(pFile, pScene);
std::unique_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
if(outfile == NULL) {
throw DeadlyExportError("could not open output .ply file: " + std::string(pFile));
}
outfile->Write( exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()),1);
}
void ExportScenePlyBinary(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
{
PlyExporter exporter(pFile, pScene, true);
std::unique_ptr<IOStream> outfile(pIOSystem->Open(pFile, "wb"));
if (outfile == NULL) {
throw DeadlyExportError("could not open output .ply file: " + std::string(pFile));
}
outfile->Write(exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()), 1);
}
#define PLY_EXPORT_HAS_NORMALS 0x1
#define PLY_EXPORT_HAS_TANGENTS_BITANGENTS 0x2
#define PLY_EXPORT_HAS_TEXCOORDS 0x4
#define PLY_EXPORT_HAS_COLORS (PLY_EXPORT_HAS_TEXCOORDS << AI_MAX_NUMBER_OF_TEXTURECOORDS)
PlyExporter::PlyExporter(const char* _filename, const aiScene* pScene, bool binary)
: filename(_filename)
, endl("\n")
{
const std::locale& l = std::locale("C");
mOutput.imbue(l);
mOutput.precision(16);
unsigned int faces = 0u, vertices = 0u, components = 0u;
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
const aiMesh& m = *pScene->mMeshes[i];
faces += m.mNumFaces;
vertices += m.mNumVertices;
if (m.HasNormals()) {
components |= PLY_EXPORT_HAS_NORMALS;
}
if (m.HasTangentsAndBitangents()) {
components |= PLY_EXPORT_HAS_TANGENTS_BITANGENTS;
}
for (unsigned int t = 0; m.HasTextureCoords(t); ++t) {
components |= PLY_EXPORT_HAS_TEXCOORDS << t;
}
for (unsigned int t = 0; m.HasVertexColors(t); ++t) {
components |= PLY_EXPORT_HAS_COLORS << t;
}
}
mOutput << "ply" << endl;
if (binary) {
#if (defined AI_BUILD_BIG_ENDIAN)
mOutput << "format binary_big_endian 1.0" << endl;
#else
mOutput << "format binary_little_endian 1.0" << endl;
#endif
}
else {
mOutput << "format ascii 1.0" << endl;
}
mOutput << "comment Created by Open Asset Import Library - http://assimp.sf.net (v"
<< aiGetVersionMajor() << '.' << aiGetVersionMinor() << '.'
<< aiGetVersionRevision() << ")" << endl;
ai_real tmp = 0.0;
const char * typeName = type_of(tmp);
mOutput << "element vertex " << vertices << endl;
mOutput << "property " << typeName << " x" << endl;
mOutput << "property " << typeName << " y" << endl;
mOutput << "property " << typeName << " z" << endl;
if(components & PLY_EXPORT_HAS_NORMALS) {
mOutput << "property " << typeName << " nx" << endl;
mOutput << "property " << typeName << " ny" << endl;
mOutput << "property " << typeName << " nz" << endl;
}
for (unsigned int n = PLY_EXPORT_HAS_TEXCOORDS, c = 0; (components & n) && c != AI_MAX_NUMBER_OF_TEXTURECOORDS; n <<= 1, ++c) {
if (!c) {
mOutput << "property " << typeName << " s" << endl;
mOutput << "property " << typeName << " t" << endl;
}
else {
mOutput << "property " << typeName << " s" << c << endl;
mOutput << "property " << typeName << " t" << c << endl;
}
}
for (unsigned int n = PLY_EXPORT_HAS_COLORS, c = 0; (components & n) && c != AI_MAX_NUMBER_OF_COLOR_SETS; n <<= 1, ++c) {
if (!c) {
mOutput << "property " << typeName << " r" << endl;
mOutput << "property " << typeName << " g" << endl;
mOutput << "property " << typeName << " b" << endl;
mOutput << "property " << typeName << " a" << endl;
}
else {
mOutput << "property " << typeName << " r" << c << endl;
mOutput << "property " << typeName << " g" << c << endl;
mOutput << "property " << typeName << " b" << c << endl;
mOutput << "property " << typeName << " a" << c << endl;
}
}
if(components & PLY_EXPORT_HAS_TANGENTS_BITANGENTS) {
mOutput << "property " << typeName << " tx" << endl;
mOutput << "property " << typeName << " ty" << endl;
mOutput << "property " << typeName << " tz" << endl;
mOutput << "property " << typeName << " bx" << endl;
mOutput << "property " << typeName << " by" << endl;
mOutput << "property " << typeName << " bz" << endl;
}
mOutput << "element face " << faces << endl;
mOutput << "property list uchar int vertex_index" << endl;
mOutput << "end_header" << endl;
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
if (binary) {
WriteMeshVertsBinary(pScene->mMeshes[i], components);
}
else {
WriteMeshVerts(pScene->mMeshes[i], components);
}
}
for (unsigned int i = 0, ofs = 0; i < pScene->mNumMeshes; ++i) {
if (binary) {
WriteMeshIndicesBinary(pScene->mMeshes[i], ofs);
}
else {
WriteMeshIndices(pScene->mMeshes[i], ofs);
}
ofs += pScene->mMeshes[i]->mNumVertices;
}
}
PlyExporter::~PlyExporter() {
}
void PlyExporter::WriteMeshVerts(const aiMesh* m, unsigned int components)
{
static const ai_real inf = std::numeric_limits<ai_real>::infinity();
for (unsigned int i = 0; i < m->mNumVertices; ++i) {
mOutput <<
m->mVertices[i].x << " " <<
m->mVertices[i].y << " " <<
m->mVertices[i].z
;
if(components & PLY_EXPORT_HAS_NORMALS) {
if (m->HasNormals() && is_not_qnan(m->mNormals[i].x) && std::fabs(m->mNormals[i].x) != inf) {
mOutput <<
" " << m->mNormals[i].x <<
" " << m->mNormals[i].y <<
" " << m->mNormals[i].z;
}
else {
mOutput << " 0.0 0.0 0.0";
}
}
for (unsigned int n = PLY_EXPORT_HAS_TEXCOORDS, c = 0; (components & n) && c != AI_MAX_NUMBER_OF_TEXTURECOORDS; n <<= 1, ++c) {
if (m->HasTextureCoords(c)) {
mOutput <<
" " << m->mTextureCoords[c][i].x <<
" " << m->mTextureCoords[c][i].y;
}
else {
mOutput << " -1.0 -1.0";
}
}
for (unsigned int n = PLY_EXPORT_HAS_COLORS, c = 0; (components & n) && c != AI_MAX_NUMBER_OF_COLOR_SETS; n <<= 1, ++c) {
if (m->HasVertexColors(c)) {
mOutput <<
" " << m->mColors[c][i].r <<
" " << m->mColors[c][i].g <<
" " << m->mColors[c][i].b <<
" " << m->mColors[c][i].a;
}
else {
mOutput << " -1.0 -1.0 -1.0 -1.0";
}
}
if(components & PLY_EXPORT_HAS_TANGENTS_BITANGENTS) {
if (m->HasTangentsAndBitangents()) {
mOutput <<
" " << m->mTangents[i].x <<
" " << m->mTangents[i].y <<
" " << m->mTangents[i].z <<
" " << m->mBitangents[i].x <<
" " << m->mBitangents[i].y <<
" " << m->mBitangents[i].z
;
}
else {
mOutput << " 0.0 0.0 0.0 0.0 0.0 0.0";
}
}
mOutput << endl;
}
}
void PlyExporter::WriteMeshVertsBinary(const aiMesh* m, unsigned int components)
{
aiVector3D defaultNormal(0, 0, 0);
aiVector2D defaultUV(-1, -1);
aiColor4D defaultColor(-1, -1, -1, -1);
for (unsigned int i = 0; i < m->mNumVertices; ++i) {
mOutput.write(reinterpret_cast<const char*>(&m->mVertices[i].x), 12);
if (components & PLY_EXPORT_HAS_NORMALS) {
if (m->HasNormals()) {
mOutput.write(reinterpret_cast<const char*>(&m->mNormals[i].x), 12);
}
else {
mOutput.write(reinterpret_cast<const char*>(&defaultNormal.x), 12);
}
}
for (unsigned int n = PLY_EXPORT_HAS_TEXCOORDS, c = 0; (components & n) && c != AI_MAX_NUMBER_OF_TEXTURECOORDS; n <<= 1, ++c) {
if (m->HasTextureCoords(c)) {
mOutput.write(reinterpret_cast<const char*>(&m->mTextureCoords[c][i].x), 8);
}
else {
mOutput.write(reinterpret_cast<const char*>(&defaultUV.x), 8);
}
}
for (unsigned int n = PLY_EXPORT_HAS_COLORS, c = 0; (components & n) && c != AI_MAX_NUMBER_OF_COLOR_SETS; n <<= 1, ++c) {
if (m->HasVertexColors(c)) {
mOutput.write(reinterpret_cast<const char*>(&m->mColors[c][i].r), 16);
}
else {
mOutput.write(reinterpret_cast<const char*>(&defaultColor.r), 16);
}
}
if (components & PLY_EXPORT_HAS_TANGENTS_BITANGENTS) {
if (m->HasTangentsAndBitangents()) {
mOutput.write(reinterpret_cast<const char*>(&m->mTangents[i].x), 12);
mOutput.write(reinterpret_cast<const char*>(&m->mBitangents[i].x), 12);
}
else {
mOutput.write(reinterpret_cast<const char*>(&defaultNormal.x), 12);
mOutput.write(reinterpret_cast<const char*>(&defaultNormal.x), 12);
}
}
}
}
void PlyExporter::WriteMeshIndices(const aiMesh* m, unsigned int offset)
{
for (unsigned int i = 0; i < m->mNumFaces; ++i) {
const aiFace& f = m->mFaces[i];
mOutput << f.mNumIndices << " ";
for(unsigned int c = 0; c < f.mNumIndices; ++c) {
mOutput << (f.mIndices[c] + offset) << (c == f.mNumIndices-1 ? endl : " ");
}
}
}
template<typename NumIndicesType, typename IndexType>
void WriteMeshIndicesBinary_Generic(const aiMesh* m, unsigned int offset, std::ostringstream& output)
{
for (unsigned int i = 0; i < m->mNumFaces; ++i) {
const aiFace& f = m->mFaces[i];
NumIndicesType numIndices = static_cast<NumIndicesType>(f.mNumIndices);
output.write(reinterpret_cast<const char*>(&numIndices), sizeof(NumIndicesType));
for (unsigned int c = 0; c < f.mNumIndices; ++c) {
IndexType index = f.mIndices[c] + offset;
output.write(reinterpret_cast<const char*>(&index), sizeof(IndexType));
}
}
}
void PlyExporter::WriteMeshIndicesBinary(const aiMesh* m, unsigned int offset)
{
WriteMeshIndicesBinary_Generic<unsigned char, int>(m, offset, mOutput);
}
}
#endif