tiny_obj 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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