tiny_obj 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/ext/tiny_obj/init_tinyobj.c +11 -3
- data/ext/tiny_obj/rb_tinyobj.h +16 -0
- data/ext/tiny_obj/tinyobj.cpp +376 -27
- data/lib/tiny_obj/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5cb4b288a4c32292401439d4431e618b20db9feb501536521dfc73df992c9297
|
4
|
+
data.tar.gz: 83dc33eeb7db6cd9c80da7cbfe2bac6fcd89a714e802f50e827046a1ec74830b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9433112c3fa3db15ac7d8aa80cfda608d6959f979dc6b957e9e44a7c0c4045794ad1e94eb55b9371070907691df3c42678693d95993243b9d97ade144baf9bd2
|
7
|
+
data.tar.gz: fb56c01fbfb2ffa382b2b2ddba6d36a87e65e468787bc253ddfda15a69be6f8aa787bb14c01416dbcb5f6f342a20494a85c8811c36b1373b7ac3270e82cae498
|
data/Gemfile.lock
CHANGED
data/ext/tiny_obj/init_tinyobj.c
CHANGED
@@ -1,10 +1,18 @@
|
|
1
|
-
#include "
|
1
|
+
#include "rb_tinyobj.h"
|
2
2
|
|
3
3
|
VALUE rb_mTinyOBJ;
|
4
|
-
|
5
|
-
VALUE rb_tinyobj_load(int argc, VALUE *argv, VALUE self);
|
4
|
+
VALUE rb_cOBJ;
|
6
5
|
|
7
6
|
void Init_tiny_obj(void) {
|
8
7
|
rb_mTinyOBJ = rb_define_module("TinyOBJ");
|
8
|
+
rb_cOBJ = rb_define_class_under(rb_mTinyOBJ, "OBJ", rb_cObject);
|
9
|
+
rb_define_method(rb_cOBJ, "to_hash", rb_obj_to_hash, 0);
|
10
|
+
rb_define_method(rb_cOBJ, "num_indices", rb_obj_num_indices, -1);
|
11
|
+
rb_define_method(rb_cOBJ, "num_distinct_vertices", rb_obj_num_distinct_vertices, -1);
|
12
|
+
rb_define_method(rb_cOBJ, "fill_buffers", rb_obj_fill_buffers, -1);
|
13
|
+
rb_define_method(rb_cOBJ, "vertices", rb_obj_vertices, -1);
|
14
|
+
rb_define_method(rb_cOBJ, "normals", rb_obj_normals, -1);
|
15
|
+
rb_define_method(rb_cOBJ, "texcoords", rb_obj_texcoords, -1);
|
16
|
+
rb_define_method(rb_cOBJ, "colors", rb_obj_colors, -1);
|
9
17
|
rb_define_singleton_method(rb_mTinyOBJ, "load", rb_tinyobj_load, -1);
|
10
18
|
}
|
data/ext/tiny_obj/rb_tinyobj.h
CHANGED
@@ -2,6 +2,22 @@
|
|
2
2
|
#define RB_TINYOBJ_H 1
|
3
3
|
|
4
4
|
#include "ruby.h"
|
5
|
+
|
6
|
+
#ifdef __cplusplus
|
5
7
|
#include "tiny_obj_loader.h"
|
8
|
+
extern "C" {
|
9
|
+
#endif
|
10
|
+
VALUE rb_tinyobj_load(int argc, VALUE *argv, VALUE self);
|
11
|
+
VALUE rb_obj_to_hash(VALUE self);
|
12
|
+
VALUE rb_obj_num_distinct_vertices(int argc, VALUE *argv, VALUE self);
|
13
|
+
VALUE rb_obj_num_indices(int argc, VALUE *argv, VALUE self);
|
14
|
+
VALUE rb_obj_fill_buffers(int argc, VALUE *argv, VALUE self);
|
15
|
+
VALUE rb_obj_vertices(int argc, VALUE *argv, VALUE self);
|
16
|
+
VALUE rb_obj_normals(int argc, VALUE *argv, VALUE self);
|
17
|
+
VALUE rb_obj_texcoords(int argc, VALUE *argv, VALUE self);
|
18
|
+
VALUE rb_obj_colors(int argc, VALUE *argv, VALUE self);
|
19
|
+
#ifdef __cplusplus
|
20
|
+
}
|
21
|
+
#endif
|
6
22
|
|
7
23
|
#endif /* RB_TINYOBJ_H */
|
data/ext/tiny_obj/tinyobj.cpp
CHANGED
@@ -2,9 +2,54 @@
|
|
2
2
|
#define TINYOBJLOADER_USE_DOUBLE
|
3
3
|
#include "rb_tinyobj.h"
|
4
4
|
#include <stdlib.h>
|
5
|
+
#include <unordered_map>
|
6
|
+
#include <stdint.h>
|
7
|
+
|
8
|
+
// taken from Fiddle
|
9
|
+
#if SIZEOF_VOIDP == SIZEOF_LONG
|
10
|
+
# define NUM2PTR(x) ((void*)(NUM2ULONG(x)))
|
11
|
+
#else
|
12
|
+
# define NUM2PTR(x) ((void*)(NUM2ULL(x)))
|
13
|
+
#endif
|
5
14
|
|
6
15
|
#define NIL_OR_STR(cstr) (strlen(cstr) > 0 ? Qnil : rb_str_new2(cstr))
|
7
16
|
|
17
|
+
extern VALUE rb_cOBJ;
|
18
|
+
|
19
|
+
typedef struct {
|
20
|
+
bool result;
|
21
|
+
std::string *warnings;
|
22
|
+
std::vector<tinyobj::shape_t> *shapes;
|
23
|
+
std::vector<tinyobj::material_t> *materials;
|
24
|
+
tinyobj::attrib_t *attrib;
|
25
|
+
} obj_t;
|
26
|
+
|
27
|
+
void obj_free(void* data) {
|
28
|
+
obj_t *obj = (obj_t *) data;
|
29
|
+
delete obj->warnings;
|
30
|
+
delete obj->shapes;
|
31
|
+
delete obj->materials;
|
32
|
+
delete obj->attrib;
|
33
|
+
free(data);
|
34
|
+
}
|
35
|
+
|
36
|
+
size_t obj_size(const void* data) {
|
37
|
+
return sizeof(obj_t);
|
38
|
+
}
|
39
|
+
|
40
|
+
static const rb_data_type_t obj_type = {
|
41
|
+
.wrap_struct_name = "OBJ3D",
|
42
|
+
.function = {
|
43
|
+
.dmark = NULL,
|
44
|
+
.dfree = obj_free,
|
45
|
+
.dsize = obj_size,
|
46
|
+
.reserved = { 0, 0 }
|
47
|
+
},
|
48
|
+
.parent = NULL,
|
49
|
+
.data = NULL,
|
50
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
51
|
+
};
|
52
|
+
|
8
53
|
VALUE build_rb_texopt(tinyobj::texture_option_t *opt) {
|
9
54
|
VALUE rt = rb_hash_new();
|
10
55
|
if (opt->colorspace.size() > 0)
|
@@ -45,6 +90,18 @@ VALUE build_rb_texopt(tinyobj::texture_option_t *opt) {
|
|
45
90
|
return rt;
|
46
91
|
}
|
47
92
|
|
93
|
+
inline void hash_combine(std::size_t& seed, int count, const float *vals) {
|
94
|
+
std::hash<float> hasher;
|
95
|
+
for (int i = 0; i < count; i++)
|
96
|
+
seed ^= hasher(vals[i]) + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
97
|
+
}
|
98
|
+
|
99
|
+
inline void hash_combine(std::size_t& seed, int count, const long *vals) {
|
100
|
+
std::hash<long> hasher;
|
101
|
+
for (int i = 0; i < count; i++)
|
102
|
+
seed ^= hasher(vals[i]) + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
103
|
+
}
|
104
|
+
|
48
105
|
extern "C" {
|
49
106
|
VALUE rb_tinyobj_load(int argc, VALUE *argv, VALUE self) {
|
50
107
|
VALUE fn, dir;
|
@@ -53,23 +110,327 @@ extern "C" {
|
|
53
110
|
dir = rb_funcall(rb_cFile, rb_intern("dirname"), 1, fn);
|
54
111
|
}
|
55
112
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
std::vector<tinyobj::shape_t>
|
60
|
-
std::vector<tinyobj::material_t>
|
61
|
-
|
62
|
-
|
113
|
+
obj_t *obj = (obj_t *) malloc(sizeof(obj_t));
|
114
|
+
memset(obj, 0, sizeof(obj_t));
|
115
|
+
obj->warnings = new std::string();
|
116
|
+
obj->shapes = new std::vector<tinyobj::shape_t>();
|
117
|
+
obj->materials = new std::vector<tinyobj::material_t>();
|
118
|
+
obj->attrib = new tinyobj::attrib_t();
|
119
|
+
std::string err;
|
63
120
|
|
64
|
-
|
121
|
+
obj->result = tinyobj::LoadObj(obj->attrib, obj->shapes, obj->materials, obj->warnings, &err, StringValuePtr(fn), StringValuePtr(dir));
|
122
|
+
if (!err.empty()) {
|
123
|
+
obj_free(obj);
|
65
124
|
rb_raise(rb_eRuntimeError, "error loading OBJ: %s", err.c_str());
|
125
|
+
}
|
126
|
+
|
127
|
+
return TypedData_Wrap_Struct(rb_cOBJ, &obj_type, obj);
|
128
|
+
}
|
129
|
+
|
130
|
+
static inline void *VAL2PTR(VALUE val) {
|
131
|
+
if (val == Qundef || NIL_P(val)) return NULL;
|
132
|
+
if (rb_respond_to(val, rb_intern("to_ptr"))) {
|
133
|
+
val = rb_funcall(val, rb_intern("to_ptr"), 0);
|
134
|
+
}
|
135
|
+
if (NIL_P(val)) return NULL;
|
136
|
+
return NUM2PTR(rb_funcall(val, rb_intern("to_i"), 0));
|
137
|
+
}
|
138
|
+
|
139
|
+
/* call-seq: fill_buffers(positions: nil, normals: nil, texcoords: nil, colors: nil, indices: nil,
|
140
|
+
* vertex_stride:, index_stride:, index_type:)
|
141
|
+
*
|
142
|
+
* Fills one or more buffers with data. This is much faster than doing it in
|
143
|
+
* Ruby because it avoids populating Ruby arrays with Ruby numeric types.
|
144
|
+
* Instead everything happens at a low level, giving essentially native
|
145
|
+
* performance for filling vertices, normals, texcoords, etc., which would
|
146
|
+
* otherwise be an expensive operation in Ruby.
|
147
|
+
*
|
148
|
+
* * `positions`, `normals`, `texcoords`, `colors` and `indices` are all
|
149
|
+
* pointers to the memory location into which to store the data. Any of
|
150
|
+
* these which is `nil` is simply omitted (data is not filled). If it
|
151
|
+
* `responds_to?(:to_ptr)` then that method is called first, and the data
|
152
|
+
* will be placed into whatever memory the result of the method refers to.
|
153
|
+
* If it does not, then the object itself represents the buffer. In both
|
154
|
+
* cases, the buffer must return a memory location from #to_i. Basically,
|
155
|
+
* the data buffer is meant to be an instance of Fiddle::Pointer, but can
|
156
|
+
* be any object which satisfies these constraints.
|
157
|
+
*
|
158
|
+
* Note that each object can point to different offsets into the same
|
159
|
+
* buffer. You don't need to use a separate allocation of memory for each
|
160
|
+
* argument.
|
161
|
+
*
|
162
|
+
* **IMPORTANT:** If the buffer's `to_i` method does not return an
|
163
|
+
* appropriate memory offset, the program will have undefined behavior
|
164
|
+
* and will typically result in a crash.
|
165
|
+
*
|
166
|
+
* * `vertex_stride` represents how many bytes to 'skip over' from one
|
167
|
+
* vertex position, color, normal or texcoord to the next. This can be used
|
168
|
+
* to populate a single buffer with interleaved vertex data.
|
169
|
+
*
|
170
|
+
* * `index_stride` is the same as `vertex_stride`, but for vertex indices.
|
171
|
+
* It is separated from `vertex_stride` because index data is often not
|
172
|
+
* interleaved with vertex data, and often lives in its own separate
|
173
|
+
* buffer. Nothing prevents you from interleaving it with the vertex data,
|
174
|
+
* of course, by specifying the same value as you did for `vertex_stride`.
|
175
|
+
*
|
176
|
+
* * `index_type` represents the primitive data type of a single index. It
|
177
|
+
* can be one of:
|
178
|
+
*
|
179
|
+
* * `:uint8` - each index is an 8-bit unsigned integer
|
180
|
+
* * `:uint16` - each index is a 16-bit unsigned integer
|
181
|
+
* * `:uint32` - each index is a 32-bit unsigned integer
|
182
|
+
* * `:uint64` - each index is a 64-bit unsigned integer
|
183
|
+
*
|
184
|
+
* Example:
|
185
|
+
*
|
186
|
+
* # In this example, we'll fill 2 buffers, one with vertex data and the
|
187
|
+
* # other with index data. In the vertex data we will gather positions,
|
188
|
+
* # normals and texture coordinates but we will omit vertex colors.
|
189
|
+
*
|
190
|
+
* vertex_stride = Fiddle::SIZEOF_FLOAT * (
|
191
|
+
* 3 + # 3 floats for each position (x, y, z)
|
192
|
+
* 3 + # 3 floats for each normal (x, y, z)
|
193
|
+
* 2 # 2 floats for each texture coord (u, v)
|
194
|
+
* )
|
195
|
+
* index_stride = 2 # each index will be one uint16, or two 8-bit bytes
|
196
|
+
* vertex_buffer = Fiddle::Pointer.malloc(obj.num_distinct_vertices * vertex_stride)
|
197
|
+
* index_buffer = Fiddle::Pointer.malloc(obj.num_indices * index_stride)
|
198
|
+
* obj.fill_buffers(positions: vertex_buffer,
|
199
|
+
* normals: vertex_buffer + Fiddle::SIZEOF_FLOAT * 3,
|
200
|
+
* texcoords: vertex_buffer + Fiddle::SIZEOF_FLOAT * 6,
|
201
|
+
* indices: index_buffer,
|
202
|
+
* vertex_stride: vertex_stride,
|
203
|
+
* index_stride: index_stride,
|
204
|
+
* index_type: :uint16)
|
205
|
+
*
|
206
|
+
* # vertex_buffer now contains interleaved vertex data, and
|
207
|
+
* # index_buffer now contains index data. Print the first complete
|
208
|
+
* # vertex:
|
209
|
+
* Vertex = Fiddle::Importer.struct(['float pos[3]', 'float normal[3]', 'float texcoord[2]'])
|
210
|
+
* v = Vertex.new(vertex_buffer)
|
211
|
+
* p position: v.pos, normal: v.normal, texcoord: v.texcoord
|
212
|
+
*/
|
213
|
+
VALUE rb_obj_fill_buffers(int argc, VALUE *argv, VALUE self) {
|
214
|
+
#define UINT8 0
|
215
|
+
#define UINT16 1
|
216
|
+
#define UINT32 2
|
217
|
+
#define UINT64 3
|
218
|
+
static ID kwargs_ids[9];
|
219
|
+
if (!kwargs_ids[0]) {
|
220
|
+
kwargs_ids[0] = rb_intern_const("vertex_stride");
|
221
|
+
kwargs_ids[1] = rb_intern_const("index_stride");
|
222
|
+
kwargs_ids[2] = rb_intern_const("index_type");
|
223
|
+
kwargs_ids[3] = rb_intern_const("positions");
|
224
|
+
kwargs_ids[4] = rb_intern_const("normals");
|
225
|
+
kwargs_ids[5] = rb_intern_const("texcoords");
|
226
|
+
kwargs_ids[6] = rb_intern_const("colors");
|
227
|
+
kwargs_ids[7] = rb_intern_const("indices");
|
228
|
+
kwargs_ids[8] = rb_intern_const("flip_v");
|
229
|
+
};
|
230
|
+
VALUE kwargs[9] = {Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil};
|
231
|
+
VALUE opts = Qnil;
|
232
|
+
rb_scan_args(argc, argv, "00:", &opts);
|
233
|
+
rb_get_kwargs(opts, kwargs_ids, 3, 6, kwargs);
|
234
|
+
|
235
|
+
bool flip_v = kwargs[8] == Qundef || kwargs[8] == Qfalse || kwargs[8] == Qnil ? false : true;
|
236
|
+
char *positions = (char *) VAL2PTR(kwargs[3]);
|
237
|
+
char *normals = (char *) VAL2PTR(kwargs[4]);
|
238
|
+
char *texcoords = (char *) VAL2PTR(kwargs[5]);
|
239
|
+
char *colors = (char *) VAL2PTR(kwargs[6]);
|
240
|
+
char *indices = (char *) VAL2PTR(kwargs[7]);
|
241
|
+
size_t vertex_stride = NUM2SIZET(kwargs[0]);
|
242
|
+
size_t index_stride = NUM2SIZET(kwargs[1]);
|
243
|
+
int index_type = -1;
|
244
|
+
if (SYM2ID(kwargs[2]) == rb_intern("uint8" )) index_type = UINT8;
|
245
|
+
else if (SYM2ID(kwargs[2]) == rb_intern("uint16")) index_type = UINT16;
|
246
|
+
else if (SYM2ID(kwargs[2]) == rb_intern("uint32")) index_type = UINT32;
|
247
|
+
else if (SYM2ID(kwargs[2]) == rb_intern("uint64")) index_type = UINT64;
|
248
|
+
else rb_raise(rb_eArgError, "unknown index_type");
|
249
|
+
|
250
|
+
obj_t *obj;
|
251
|
+
TypedData_Get_Struct(self, obj_t, &obj_type, obj);
|
252
|
+
std::vector<tinyobj::shape_t> &shapes = *(obj->shapes);
|
253
|
+
tinyobj::attrib_t &attrib = *(obj->attrib);
|
254
|
+
|
255
|
+
size_t vertex_offset = 0;
|
256
|
+
size_t index_offset = 0;
|
257
|
+
std::unordered_map<size_t, int64_t> vertex_map;
|
258
|
+
for (size_t s = 0; s < shapes.size(); s++) {
|
259
|
+
for (size_t i = 0; i < shapes[s].mesh.indices.size(); i++) {
|
260
|
+
size_t hash = 0;
|
261
|
+
long vertex[] = {
|
262
|
+
3 * shapes[s].mesh.indices[i].vertex_index + 0,
|
263
|
+
3 * shapes[s].mesh.indices[i].vertex_index + 1,
|
264
|
+
3 * shapes[s].mesh.indices[i].vertex_index + 2,
|
265
|
+
2 * shapes[s].mesh.indices[i].texcoord_index + 0,
|
266
|
+
2 * shapes[s].mesh.indices[i].texcoord_index + 1,
|
267
|
+
3 * shapes[s].mesh.indices[i].normal_index + 0,
|
268
|
+
3 * shapes[s].mesh.indices[i].normal_index + 1,
|
269
|
+
3 * shapes[s].mesh.indices[i].normal_index + 2,
|
270
|
+
};
|
271
|
+
hash_combine(hash, sizeof(vertex) / sizeof(long), vertex);
|
272
|
+
uint64_t index;
|
273
|
+
if (vertex_map.count(hash) == 0) {
|
274
|
+
if (positions && vertex[0] >= 0) {
|
275
|
+
*((float *)(positions + vertex_offset )) = attrib.vertices[vertex[0]];
|
276
|
+
*((float *)(positions + vertex_offset+1*sizeof(float))) = attrib.vertices[vertex[1]];
|
277
|
+
*((float *)(positions + vertex_offset+2*sizeof(float))) = attrib.vertices[vertex[2]];
|
278
|
+
}
|
279
|
+
if (colors && vertex[0] >= 0) {
|
280
|
+
*((float *)(colors + vertex_offset )) = attrib.colors[vertex[0]];
|
281
|
+
*((float *)(colors + vertex_offset+1*sizeof(float))) = attrib.colors[vertex[1]];
|
282
|
+
*((float *)(colors + vertex_offset+2*sizeof(float))) = attrib.colors[vertex[2]];
|
283
|
+
}
|
284
|
+
if (texcoords && vertex[3] >= 0) {
|
285
|
+
*((float *)(texcoords + vertex_offset )) = attrib.texcoords[vertex[3]];
|
286
|
+
if (flip_v)
|
287
|
+
*((float *)(texcoords + vertex_offset+1*sizeof(float))) = 1.0f - attrib.texcoords[vertex[4]];
|
288
|
+
else
|
289
|
+
*((float *)(texcoords + vertex_offset+1*sizeof(float))) = attrib.texcoords[vertex[4]];
|
290
|
+
}
|
291
|
+
if (normals && vertex[5] >= 0) {
|
292
|
+
*((float *)(normals + vertex_offset )) = attrib.normals[vertex[5]];
|
293
|
+
*((float *)(normals + vertex_offset+1*sizeof(float))) = attrib.normals[vertex[6]];
|
294
|
+
*((float *)(normals + vertex_offset+2*sizeof(float))) = attrib.normals[vertex[7]];
|
295
|
+
}
|
296
|
+
index = vertex_map.size();
|
297
|
+
vertex_map[hash] = index;
|
298
|
+
vertex_offset += vertex_stride;
|
299
|
+
} else {
|
300
|
+
index = vertex_map[hash];
|
301
|
+
}
|
302
|
+
// printf("%zu\n", index);
|
303
|
+
if (indices) {
|
304
|
+
switch(index_type) {
|
305
|
+
case UINT8: *((uint8_t *)(indices + index_offset)) = (uint8_t) index; break;
|
306
|
+
case UINT16: *((uint16_t *)(indices + index_offset)) = (uint16_t) index; break;
|
307
|
+
case UINT32: *((uint32_t *)(indices + index_offset)) = (uint32_t) index; break;
|
308
|
+
case UINT64: *((uint64_t *)(indices + index_offset)) = (uint64_t) index; break;
|
309
|
+
default: rb_raise(rb_eRuntimeError, "BUG: unexpected index type: %d", index_type);
|
310
|
+
}
|
311
|
+
index_offset += index_stride;
|
312
|
+
}
|
313
|
+
}
|
314
|
+
}
|
315
|
+
|
316
|
+
return self;
|
317
|
+
}
|
66
318
|
|
67
|
-
|
319
|
+
VALUE rb_obj_num_distinct_vertices(int argc, VALUE *argv, VALUE self) {
|
320
|
+
// cache = {}
|
321
|
+
// h[:shapes].each do |shape|
|
322
|
+
// shape[:mesh][:indices].each_with_index do |index, i|
|
323
|
+
// hash = [
|
324
|
+
// index[ :vertex_index] && 3.times.map { |i| 3 * index[:vertex_index] + i },
|
325
|
+
// index[ :vertex_index] && 3.times.map { |i| 3 * index[:vertex_index] + i },
|
326
|
+
// index[ :normal_index] && 3.times.map { |i| 3 * index[:normal_index] + i },
|
327
|
+
// index[:texcoord_index] && 2.times.map { |i| 2 * index[:texcoord_index] + i }
|
328
|
+
// ]
|
329
|
+
// cache[hash] = cache.size unless cache.include?(hash)
|
330
|
+
// end
|
331
|
+
// end
|
68
332
|
|
69
|
-
|
70
|
-
|
333
|
+
obj_t *obj;
|
334
|
+
TypedData_Get_Struct(self, obj_t, &obj_type, obj);
|
335
|
+
std::vector<tinyobj::shape_t> &shapes = *(obj->shapes);
|
336
|
+
|
337
|
+
size_t count = 0;
|
338
|
+
std::unordered_map<size_t, size_t> vertex_map;
|
339
|
+
for (size_t s = 0; s < shapes.size(); s++) {
|
340
|
+
for (size_t i = 0; i < shapes[s].mesh.indices.size(); i++) {
|
341
|
+
tinyobj::index_t &index = shapes[s].mesh.indices[i];
|
342
|
+
size_t hash = 0;
|
343
|
+
long vertex[] = {
|
344
|
+
3 * index.vertex_index + 0,
|
345
|
+
3 * index.vertex_index + 1,
|
346
|
+
3 * index.vertex_index + 2,
|
347
|
+
2 * index.texcoord_index + 0,
|
348
|
+
2 * index.texcoord_index + 1,
|
349
|
+
3 * index.normal_index + 0,
|
350
|
+
3 * index.normal_index + 1,
|
351
|
+
3 * index.normal_index + 2
|
352
|
+
};
|
353
|
+
hash_combine(hash, sizeof(vertex) / sizeof(long), vertex);
|
354
|
+
if (vertex_map.count(hash) == 0) {
|
355
|
+
vertex_map[hash] = hash;
|
356
|
+
count++;
|
357
|
+
}
|
358
|
+
}
|
359
|
+
}
|
360
|
+
|
361
|
+
return SIZET2NUM(count);
|
362
|
+
}
|
363
|
+
|
364
|
+
VALUE rb_obj_num_indices(int argc, VALUE *argv, VALUE self) {
|
365
|
+
// h[:shapes].reduce(0) { |a, shape| a + shape[:mesh][:indices].size }
|
366
|
+
|
367
|
+
obj_t *obj;
|
368
|
+
TypedData_Get_Struct(self, obj_t, &obj_type, obj);
|
369
|
+
std::vector<tinyobj::shape_t> &shapes = *(obj->shapes);
|
370
|
+
|
371
|
+
long count = 0;
|
372
|
+
for (size_t s = 0; s < shapes.size(); s++) {
|
373
|
+
count += shapes[s].mesh.indices.size();
|
374
|
+
}
|
375
|
+
|
376
|
+
return LONG2NUM(count);
|
377
|
+
}
|
378
|
+
|
379
|
+
VALUE rb_obj_vertices(int argc, VALUE *argv, VALUE self) {
|
380
|
+
obj_t *obj;
|
381
|
+
TypedData_Get_Struct(self, obj_t, &obj_type, obj);
|
382
|
+
tinyobj::attrib_t &attrib = *(obj->attrib);
|
383
|
+
VALUE rb_vertices = rb_ary_new2(attrib.vertices.size());
|
384
|
+
for (size_t i = 0; i < attrib.vertices.size(); i++)
|
385
|
+
rb_ary_push(rb_vertices, DBL2NUM(attrib.vertices[i]));
|
386
|
+
return rb_vertices;
|
387
|
+
}
|
388
|
+
|
389
|
+
VALUE rb_obj_normals(int argc, VALUE *argv, VALUE self) {
|
390
|
+
obj_t *obj;
|
391
|
+
TypedData_Get_Struct(self, obj_t, &obj_type, obj);
|
392
|
+
tinyobj::attrib_t &attrib = *(obj->attrib);
|
393
|
+
VALUE rb_normals = rb_ary_new2(attrib.normals.size());
|
394
|
+
for (size_t i = 0; i < attrib.normals.size(); i++)
|
395
|
+
rb_ary_push(rb_normals, DBL2NUM(attrib.normals[i]));
|
396
|
+
return rb_normals;
|
397
|
+
}
|
398
|
+
|
399
|
+
VALUE rb_obj_texcoords(int argc, VALUE *argv, VALUE self) {
|
400
|
+
obj_t *obj;
|
401
|
+
TypedData_Get_Struct(self, obj_t, &obj_type, obj);
|
402
|
+
tinyobj::attrib_t &attrib = *(obj->attrib);
|
403
|
+
VALUE rb_texcoords = rb_ary_new2(attrib.texcoords.size());
|
404
|
+
for (size_t i = 0; i < attrib.texcoords.size(); i++)
|
405
|
+
rb_ary_push(rb_texcoords, DBL2NUM(attrib.texcoords[i]));
|
406
|
+
return rb_texcoords;
|
407
|
+
}
|
408
|
+
|
409
|
+
VALUE rb_obj_colors(int argc, VALUE *argv, VALUE self) {
|
410
|
+
obj_t *obj;
|
411
|
+
TypedData_Get_Struct(self, obj_t, &obj_type, obj);
|
412
|
+
tinyobj::attrib_t &attrib = *(obj->attrib);
|
413
|
+
VALUE rb_colors = rb_ary_new2(attrib.colors.size());
|
414
|
+
for (size_t i = 0; i < attrib.colors.size(); i++)
|
415
|
+
rb_ary_push(rb_colors, DBL2NUM(attrib.colors[i]));
|
416
|
+
return rb_colors;
|
417
|
+
}
|
418
|
+
|
419
|
+
VALUE rb_obj_to_hash(VALUE self) {
|
420
|
+
obj_t *obj;
|
421
|
+
TypedData_Get_Struct(self, obj_t, &obj_type, obj);
|
422
|
+
std::string &warnings = *(obj->warnings);
|
423
|
+
std::vector<tinyobj::shape_t> &shapes = *(obj->shapes);
|
424
|
+
std::vector<tinyobj::material_t> &materials = *(obj->materials);
|
425
|
+
|
426
|
+
VALUE ret = rb_hash_new();
|
427
|
+
rb_hash_aset(ret, ID2SYM(rb_intern("success")), obj->result ? Qtrue : Qfalse);
|
428
|
+
|
429
|
+
if (warnings.size() > 0)
|
430
|
+
rb_hash_aset(ret, ID2SYM(rb_intern("warnings")), rb_str_new2(warnings.c_str()));
|
71
431
|
|
72
432
|
VALUE rb_materials = rb_ary_new2(materials.size());
|
433
|
+
rb_hash_aset(ret, ID2SYM(rb_intern("materials")), rb_materials);
|
73
434
|
for (size_t m = 0; m < materials.size(); m++) {
|
74
435
|
VALUE rb_material = rb_hash_new();
|
75
436
|
rb_ary_push(rb_materials, rb_material);
|
@@ -138,22 +499,10 @@ extern "C" {
|
|
138
499
|
rb_hash_aset(rb_material, ID2SYM(rb_intern("unknown_parameters")), rb_unknown_parameter);
|
139
500
|
}
|
140
501
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
rb_hash_aset(ret, ID2SYM(rb_intern("vertices")), rb_vertices);
|
146
|
-
rb_hash_aset(ret, ID2SYM(rb_intern("normals")), rb_normals);
|
147
|
-
rb_hash_aset(ret, ID2SYM(rb_intern("texcoords")), rb_texcoords);
|
148
|
-
rb_hash_aset(ret, ID2SYM(rb_intern("colors")), rb_colors);
|
149
|
-
for (size_t i = 0; i < attrib.vertices.size(); i++)
|
150
|
-
rb_ary_push(rb_vertices, DBL2NUM(attrib.vertices[i]));
|
151
|
-
for (size_t i = 0; i < attrib.normals.size(); i++)
|
152
|
-
rb_ary_push(rb_normals, DBL2NUM(attrib.normals[i]));
|
153
|
-
for (size_t i = 0; i < attrib.texcoords.size(); i++)
|
154
|
-
rb_ary_push(rb_texcoords, DBL2NUM(attrib.texcoords[i]));
|
155
|
-
for (size_t i = 0; i < attrib.colors.size(); i++)
|
156
|
-
rb_ary_push(rb_colors, DBL2NUM(attrib.colors[i]));
|
502
|
+
rb_hash_aset(ret, ID2SYM(rb_intern("vertices")), rb_funcall(self, rb_intern("vertices"), 0));
|
503
|
+
rb_hash_aset(ret, ID2SYM(rb_intern("normals")), rb_funcall(self, rb_intern("normals"), 0));
|
504
|
+
rb_hash_aset(ret, ID2SYM(rb_intern("texcoords")), rb_funcall(self, rb_intern("texcoords"), 0));
|
505
|
+
rb_hash_aset(ret, ID2SYM(rb_intern("colors")), rb_funcall(self, rb_intern("colors"), 0));
|
157
506
|
|
158
507
|
VALUE rb_shapes = rb_ary_new2(shapes.size());
|
159
508
|
rb_hash_aset(ret, ID2SYM(rb_intern("shapes")), rb_shapes);
|
data/lib/tiny_obj/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tiny_obj
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Colin MacKenzie IV
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-11-
|
11
|
+
date: 2018-11-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|