-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.cxx
156 lines (138 loc) · 4.71 KB
/
main.cxx
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
#include <cstdint>
#include <cinttypes>
#include <cstdio>
#include <array>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <Alembic/AbcGeom/All.h>
#include <Alembic/AbcCoreOgawa/All.h>
using std::uint32_t;
using std::int32_t;
using std::size_t;
using vec3f = std::array<float,3>;
struct Mesh {
std::vector<vec3f> vertexes;
std::vector<int32_t> indexes;
std::vector<int32_t> faces;
};
std::ostream& readerr(const char* filename, size_t line_number) {
return std::cerr << filename << ':' << line_number << ':';
}
bool idx_ok(int32_t idx, size_t vertex_count) {
return idx > 0 && size_t(idx) <= vertex_count;
}
bool starts_with(const char* s, const char* p) {
while (*p) {
if (*s++ != *p++) {
return false;
}
}
return true;
}
Mesh load_obj(const char* filename) {
Mesh m;
std::ifstream in(filename);
std::string line;
size_t line_number = 0;
while (std::getline(in, line)) {
++line_number;
if (line.empty()) {
continue;
}
if (starts_with(line.c_str(), "v ")) {
float x, y, z;
if(3 == std::sscanf(line.c_str(), "v %f %f %f", &x, &y, &z)) {
vec3f vertex = {x, y, z};
m.vertexes.push_back(vertex);
} else {
readerr(filename, line_number) << "not a recognized vertex format" << std::endl;
}
} else if (starts_with(line.c_str(), "f ")) {
int32_t i, j, k, l;
if (4 == std::sscanf(line.c_str(), "f %" SCNd32 " %" SCNd32 " %" SCNd32 " %" SCNd32, &i, &j, &k, &l)) {
const size_t vcount = m.vertexes.size();
if (idx_ok(i, vcount) && idx_ok(j, vcount) && idx_ok(k, vcount) && idx_ok(l, vcount)) {
m.faces.push_back(4);
m.indexes.push_back(i-1);
m.indexes.push_back(j-1);
m.indexes.push_back(k-1);
m.indexes.push_back(l-1);
} else {
readerr(filename, line_number) << "invalid index" << std::endl;
}
} else if (3 == std::sscanf(line.c_str(), "f %" SCNd32 " %" SCNd32 " %" SCNd32, &i, &j, &k)) {
const size_t vcount = m.vertexes.size();
if (idx_ok(i, vcount) && idx_ok(j, vcount) && idx_ok(k, vcount)) {
m.faces.push_back(3);
m.indexes.push_back(i-1);
m.indexes.push_back(j-1);
m.indexes.push_back(k-1);
} else {
readerr(filename, line_number) << "invalid index" << std::endl;
}
} else {
readerr(filename, line_number) << "not a valid index format" << std::endl;
}
}
}
return m;
}
namespace AA = Alembic::Abc;
namespace AAG = Alembic::AbcGeom;
struct AlembicExportParameters {
std::string application_name;
std::string scene_description;
std::string object_name;
double fps;
};
void set_property(AAG::OPolyMeshSchema& schema, const char* name, bool value) {
AA::OCompoundProperty container = schema.getUserProperties();
AA::OBoolProperty property(container, name);
property.set(value);
}
void export_to_alembic(std::ostream& out,
const AlembicExportParameters& params, const std::vector<Mesh>& meshes) {
AA::MetaData meta;
meta.set(AA::kApplicationNameKey, params.application_name);
meta.set(AA::kUserDescriptionKey, params.scene_description);
meta.set(AA::kDCCFPSKey, std::to_string(params.fps));
Alembic::AbcCoreOgawa::WriteArchive writer;
AA::OArchive archive(writer(&out, meta), AA::ErrorHandler::kThrowPolicy);
uint32_t time_sampling_idx;
{ // 'uniform' time sampling
AA::chrono_t time_per_cycle = 1.0 / params.fps;
AA::chrono_t start_time = 0.0;
time_sampling_idx = archive.addTimeSampling(AA::TimeSampling(time_per_cycle, start_time));
}
AAG::OXform xform(AAG::OObject(archive, AAG::kTop), "root_transform", time_sampling_idx);
AAG::OPolyMesh omesh(xform, params.object_name, time_sampling_idx);
AAG::OPolyMeshSchema& schema = omesh.getSchema();
{
bool is_subdivision_surface = false;
set_property(schema, "meshtype", is_subdivision_surface);
}
for (const Mesh& m : meshes) {
// Note: Alembic uses a clockwise winding order
AAG::OPolyMeshSchema::Sample sample(
AAG::V3fArraySample((const AAG::V3f*)m.vertexes.data(), m.vertexes.size()),
AAG::Int32ArraySample(m.indexes.data(), m.indexes.size()),
AAG::Int32ArraySample(m.faces.data(), m.faces.size()));
schema.set(sample);
}
}
int main(int argc, const char** argv) {
AlembicExportParameters parameters;
parameters.application_name = "AlEx";
parameters.scene_description = "An example mesh animation for Blender.";
parameters.object_name = "exobj";
parameters.fps = 24.0;
std::ofstream out("out.abc", std::ios::binary);
std::vector<Mesh> meshes;
for (int i = 1; i < argc; ++i) {
meshes.push_back(load_obj(argv[i]));
}
export_to_alembic(out, parameters, meshes);
return 0;
}