1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
#pragma once
#include <fstream>
#include <map>
#include <fmt/format.h>
#include "i18n.h"
#include "imodel.h"
#include "imodelsurface.h"
#include "render.h"
#include "math/Matrix4.h"
#include "os/fs.h"
#include "os/path.h"
#include "stream/ExportStream.h"
namespace model
{
class ModelExporterBase :
public IModelExporter
{
protected:
struct Surface
{
std::string materialName;
// The vertices of this surface
std::vector<MeshVertex> vertices;
// The indices connecting the vertices to triangles
IndexBuffer indices;
};
typedef std::map<std::string, Surface> Surfaces;
Surfaces _surfaces;
public:
// Adds the given Surface to the exporter's queue
void addSurface(const IModelSurface& incoming, const Matrix4& localToWorld) override
{
Surface& surface = ensureSurface(incoming.getActiveMaterial());
Matrix4 invTranspTransform = localToWorld.getFullInverse().getTransposed();
try
{
const IIndexedModelSurface& indexedSurf = dynamic_cast<const IIndexedModelSurface&>(incoming);
// Cast succeeded, load the vertices and indices directly into here
unsigned int indexStart = static_cast<unsigned int>(surface.vertices.size());
const auto& vertices = indexedSurf.getVertexArray();
const auto& indices = indexedSurf.getIndexArray();
if (indices.size() < 3)
{
// Reject this index buffer
rError() << "Rejecting model surface with less than 3 indices." << std::endl;
return;
}
// Transform vertices before inserting them
for (const auto& meshVertex : vertices)
{
// Copy-construct based on the incoming meshVertex, transform the vertex.
// Transform the normal using the inverse transpose
// We discard the tangent and bitangent vectors here, none of the exporters is using them.
surface.vertices.emplace_back(
localToWorld.transformPoint(meshVertex.vertex),
invTranspTransform.transformPoint(meshVertex.normal).getNormalised(),
meshVertex.texcoord,
meshVertex.colour);
}
surface.indices.reserve(surface.indices.size() + indices.size());
// Incoming polygons are defined in clockwise windings, so reverse the indices
// as the exporter code expects them to be counter-clockwise.
for (std::size_t i = 0; i < indices.size() - 2; i += 3)
{
surface.indices.push_back(indices[i + 2] + indexStart);
surface.indices.push_back(indices[i + 1] + indexStart);
surface.indices.push_back(indices[i + 0] + indexStart);
}
return;
}
catch (std::bad_cast&)
{
// Not an indexed surface, fall through
}
// Pull in all the triangles of that mesh
for (int i = 0; i < incoming.getNumTriangles(); ++i)
{
ModelPolygon poly = incoming.getPolygon(i);
unsigned int indexStart = static_cast<unsigned int>(surface.vertices.size());
poly.a.vertex = localToWorld.transformPoint(poly.a.vertex);
poly.b.vertex = localToWorld.transformPoint(poly.b.vertex);
poly.c.vertex = localToWorld.transformPoint(poly.c.vertex);
// Transform the normal using the inverse transpose
poly.a.normal = invTranspTransform.transformPoint(poly.a.normal).getNormalised();
poly.b.normal = invTranspTransform.transformPoint(poly.b.normal).getNormalised();
poly.c.normal = invTranspTransform.transformPoint(poly.c.normal).getNormalised();
surface.vertices.push_back(poly.a);
surface.vertices.push_back(poly.b);
surface.vertices.push_back(poly.c);
surface.indices.push_back(indexStart);
surface.indices.push_back(indexStart + 1);
surface.indices.push_back(indexStart + 2);
}
}
void addPolygons(const std::string& materialName,
const std::vector<ModelPolygon>& polys, const Matrix4& localToWorld) override
{
Surface& surface = ensureSurface(materialName);
for (const ModelPolygon& poly : polys)
{
unsigned int indexStart = static_cast<unsigned int>(surface.vertices.size());
ModelPolygon transformed(poly); // copy to transform
transformed.a.vertex = localToWorld.transformPoint(poly.a.vertex);
transformed.b.vertex = localToWorld.transformPoint(poly.b.vertex);
transformed.c.vertex = localToWorld.transformPoint(poly.c.vertex);
surface.vertices.push_back(transformed.a);
surface.vertices.push_back(transformed.b);
surface.vertices.push_back(transformed.c);
surface.indices.push_back(indexStart);
surface.indices.push_back(indexStart + 1);
surface.indices.push_back(indexStart + 2);
}
}
private:
Surface& ensureSurface(const std::string& materialName)
{
Surfaces::iterator surf = _surfaces.find(materialName);
if (surf == _surfaces.end())
{
surf = _surfaces.insert(std::make_pair(materialName, Surface())).first;
surf->second.materialName = materialName;
}
return surf->second;
}
};
}
|