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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 442019e9c76f9eff6a2d3f2b60956bc720ba31cc282b7b7e00ed516ec4ca1a1b
4
- data.tar.gz: 13ada62da0a9d2083be44ae85ef206b3ccebf2bbbca694067716ff281f48ca41
3
+ metadata.gz: 5cb4b288a4c32292401439d4431e618b20db9feb501536521dfc73df992c9297
4
+ data.tar.gz: 83dc33eeb7db6cd9c80da7cbfe2bac6fcd89a714e802f50e827046a1ec74830b
5
5
  SHA512:
6
- metadata.gz: 9e7128a7034acfe42341e3ba6b29af0cc39bdac2da20ef28f826273f8423d4a998e60b1c5fc50923e788bab831a8bce4e771dd6ab71dc6c393e25e607350191b
7
- data.tar.gz: e171e4ad79b7c0bf604904d8108c8e6bf9f0cce80562a43dae8db55b3e75114cfd2e5ac75adaca6ecd76842a8d8554a1b36551e7836bc6da70889e00b0977232
6
+ metadata.gz: 9433112c3fa3db15ac7d8aa80cfda608d6959f979dc6b957e9e44a7c0c4045794ad1e94eb55b9371070907691df3c42678693d95993243b9d97ade144baf9bd2
7
+ data.tar.gz: fb56c01fbfb2ffa382b2b2ddba6d36a87e65e468787bc253ddfda15a69be6f8aa787bb14c01416dbcb5f6f342a20494a85c8811c36b1373b7ac3270e82cae498
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tiny_obj (0.1.0)
4
+ tiny_obj (0.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -1,10 +1,18 @@
1
- #include "ruby.h"
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
  }
@@ -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 */
@@ -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
- VALUE ret = rb_hash_new();
57
-
58
- tinyobj::attrib_t attrib;
59
- std::vector<tinyobj::shape_t> shapes;
60
- std::vector<tinyobj::material_t> materials;
61
- std::string warn, err;
62
- bool result = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, StringValuePtr(fn), StringValuePtr(dir));
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
- if (!err.empty())
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
- rb_hash_aset(ret, ID2SYM(rb_intern("success")), result ? Qtrue : Qfalse);
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
- if (!warn.empty())
70
- rb_hash_aset(ret, ID2SYM(rb_intern("warnings")), rb_str_new2(warn.c_str()));
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
- VALUE rb_vertices = rb_ary_new2(attrib.vertices.size()),
142
- rb_normals = rb_ary_new2(attrib.normals.size()),
143
- rb_texcoords = rb_ary_new2(attrib.texcoords.size()),
144
- rb_colors = rb_ary_new2(attrib.colors.size());
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);
@@ -1,3 +1,3 @@
1
1
  module TinyOBJ
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
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.1.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-15 00:00:00.000000000 Z
11
+ date: 2018-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler