tiny_gltf 0.1.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +3 -0
  3. data/Gemfile.lock +3 -3
  4. data/bin/setup +2 -0
  5. data/ext/tiny_gltf/rb_tiny_gltf.h +18 -7
  6. data/ext/tiny_gltf/rb_tiny_gltf_accessor.cpp +4 -12
  7. data/ext/tiny_gltf/rb_tiny_gltf_animation.cpp +6 -5
  8. data/ext/tiny_gltf/rb_tiny_gltf_animation_channel.cpp +6 -5
  9. data/ext/tiny_gltf/rb_tiny_gltf_animation_sampler.cpp +6 -5
  10. data/ext/tiny_gltf/rb_tiny_gltf_asset.cpp +4 -3
  11. data/ext/tiny_gltf/rb_tiny_gltf_buffer.cpp +37 -8
  12. data/ext/tiny_gltf/rb_tiny_gltf_buffer_view.cpp +4 -3
  13. data/ext/tiny_gltf/rb_tiny_gltf_camera.cpp +4 -3
  14. data/ext/tiny_gltf/rb_tiny_gltf_extension_map.cpp +2 -2
  15. data/ext/tiny_gltf/rb_tiny_gltf_image.cpp +72 -12
  16. data/ext/tiny_gltf/rb_tiny_gltf_init.c +66 -1
  17. data/ext/tiny_gltf/rb_tiny_gltf_light.cpp +2 -1
  18. data/ext/tiny_gltf/rb_tiny_gltf_material.cpp +6 -5
  19. data/ext/tiny_gltf/rb_tiny_gltf_mesh.cpp +5 -17
  20. data/ext/tiny_gltf/rb_tiny_gltf_model.cpp +10 -10
  21. data/ext/tiny_gltf/rb_tiny_gltf_node.cpp +8 -7
  22. data/ext/tiny_gltf/rb_tiny_gltf_parameter_map.cpp +2 -2
  23. data/ext/tiny_gltf/rb_tiny_gltf_primitive.cpp +8 -7
  24. data/ext/tiny_gltf/rb_tiny_gltf_sampler.cpp +3 -2
  25. data/ext/tiny_gltf/rb_tiny_gltf_scene.cpp +7 -6
  26. data/ext/tiny_gltf/rb_tiny_gltf_skin.cpp +6 -5
  27. data/ext/tiny_gltf/rb_tiny_gltf_texture.cpp +7 -6
  28. data/ext/tiny_gltf/rb_tiny_gltf_types.cpp +7 -7
  29. data/ext/tiny_gltf/rb_tiny_gltf_value.cpp +5 -4
  30. data/ext/tiny_gltf/stb_image.h +1890 -869
  31. data/ext/tiny_gltf/stb_image_write.h +1241 -1451
  32. data/ext/tiny_gltf/tiny_gltf.h +3671 -1082
  33. data/lib/tiny_gltf.rb +385 -126
  34. data/lib/tiny_gltf/version.rb +1 -1
  35. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b954a969cc444a33651e63d72d15d816b3b5f109d419179dfded48934099c9d3
4
- data.tar.gz: fefc289f2b3c6caa665a267aa5c7f8a19c732c44a8321cca22dc5739b3a75d6f
3
+ metadata.gz: 5158d1be6e6b7ca81b1811dfe102928bf646465f249aa40d1d9a6c28ff8db94a
4
+ data.tar.gz: 8144cd44561010a81aeabd21ae722290882e99767d2aa6a1db7dbcac14436756
5
5
  SHA512:
6
- metadata.gz: de2c43dd86086b3b5abed2be79de26b0720273ad6af6fd56752be3dd12f38a92040824a46179967c672de0e3f2461c03d8df7e9f1e2f8934ca6b009e82c0e650
7
- data.tar.gz: d023f445d65862e8b20a52b38b5597e5b2b7606974f6ccddab6f7bd105611fdd1aa538f8dd36da292106bc70e0b6c2b43c4716e478cc53e92f28595f75cc8523
6
+ metadata.gz: 48dd3bf544f2af2c009c26cbf5d28e14a89a18ab27649fd2ce83863f2a9b4758ae3a7e21f71d6289be4d06ba09eac43f1db46af47e5357ae5aa36bf47036b92e
7
+ data.tar.gz: a6eb083a256ea2fb43a8ee9c241ee2ce596b32d267907a84a533c11433a47c18812934a69bed7f603470512402c1eb7e748062b528c0c753ec581126b0ae11c1
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "test/fixtures/gltf_sample_models"]
2
+ path = test/fixtures/gltf_sample_models
3
+ url = https://github.com/KhronosGroup/glTF-Sample-Models
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tiny_gltf (0.1.0)
4
+ tiny_gltf (1.0.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -12,7 +12,7 @@ GEM
12
12
  rake-compiler (1.0.5)
13
13
  rake
14
14
  redcarpet (3.4.0)
15
- yard (0.9.16)
15
+ yard (0.9.20)
16
16
 
17
17
  PLATFORMS
18
18
  ruby
@@ -28,4 +28,4 @@ DEPENDENCIES
28
28
  yard (~> 0.9)
29
29
 
30
30
  BUNDLED WITH
31
- 2.0.0.pre.1
31
+ 2.0.2
data/bin/setup CHANGED
@@ -6,3 +6,5 @@ set -vx
6
6
  bundle install
7
7
 
8
8
  # Do any other automated setup that you need to do here
9
+ git submodule init
10
+ git submodule update
@@ -35,6 +35,8 @@ extern VALUE rb_mTinyGLTF,
35
35
  VALUE name ## _is_equal(VALUE self, VALUE other); \
36
36
  VALUE name ## _alloc(VALUE klass);
37
37
 
38
+ #define RINDEX_OR_NIL(n) (n == -1 ? Qnil : INT2NUM(n))
39
+
38
40
  GLTF_TYPE(Model);
39
41
  GLTF_TYPE(Accessor);
40
42
  GLTF_TYPE(Asset);
@@ -68,18 +70,26 @@ VALUE texture_type_to_sym(int type);
68
70
  VALUE target_to_sym(int tgt);
69
71
  VALUE shader_type_to_sym(int type);
70
72
 
71
- VALUE Accessor_byte_stride(VALUE self, VALUE buffer_view);
73
+ VALUE Buffer_to_ptr(VALUE self);
74
+ VALUE Buffer_size(VALUE self);
75
+ VALUE Buffer_to_s(VALUE self);
76
+ VALUE Buffer_uri(VALUE self);
77
+ VALUE Image_set_uri(VALUE self, VALUE uri);
78
+ VALUE Image_to_ptr(VALUE self);
79
+ VALUE Image_size(VALUE self);
80
+ VALUE Image_to_s(VALUE self);
81
+ VALUE Image_uri(VALUE self);
72
82
 
73
83
  #if __cplusplus
74
84
  /*
75
- VALUE rModel_new(const Model *);
85
+ VALUE rAccessor_new(const Accessor *, VALUE);
76
86
  */
77
- #define GLTF_RUBY_WRAP(klass) VALUE r ## klass ## _new(const klass *);
87
+ #define GLTF_RUBY_WRAP(klass) VALUE r ## klass ## _new(const klass *, VALUE);
78
88
 
79
89
  /*
80
- static inline Model *Model_unwrap(VALUE val) {
81
- Model *a = NULL;
82
- TypedData_Get_Struct(val, Model, &T_Model, a);
90
+ static inline Accessor *Accessor_unwrap(VALUE val) {
91
+ Accessor *a = NULL;
92
+ TypedData_Get_Struct(val, Accessor, &T_Accessor, a);
83
93
  if (a == NULL)
84
94
  rb_raise(rb_eArgError, "BUG: " #name " is NULL");
85
95
  return a;
@@ -101,9 +111,10 @@ VALUE Accessor_byte_stride(VALUE self, VALUE buffer_view);
101
111
  GLTF_RUBY_WRAP(ParameterMap);
102
112
  GLTF_RUBY_WRAP(Value);
103
113
 
114
+ VALUE rModel_new(const Model *);
115
+ GLTF_RUBY_UNWRAP(Model);
104
116
  GLTF_RUBY_WRAPPERS(Asset);
105
117
  GLTF_RUBY_WRAPPERS(Primitive);
106
- GLTF_RUBY_WRAPPERS(Model);
107
118
  GLTF_RUBY_WRAPPERS(Accessor);
108
119
  GLTF_RUBY_WRAPPERS(Animation);
109
120
  GLTF_RUBY_WRAPPERS(AnimationSampler);
@@ -1,17 +1,18 @@
1
1
  #include "rb_tiny_gltf.h"
2
2
 
3
- VALUE rAccessor_new(const Accessor *accessor) {
3
+ VALUE rAccessor_new(const Accessor *accessor, VALUE rmodel) {
4
4
  VALUE raccessor = rb_funcall(rb_cAccessor, rb_intern("new"), 0);
5
5
  *Accessor_unwrap(raccessor) = *accessor;
6
6
 
7
- rb_ivar_set(raccessor, rb_intern("@buffer_view_index"), INT2NUM(accessor->bufferView));
7
+ rb_ivar_set(raccessor, rb_intern("@model"), rmodel);
8
+ rb_ivar_set(raccessor, rb_intern("@buffer_view_index"), RINDEX_OR_NIL(accessor->bufferView));
8
9
  rb_ivar_set(raccessor, rb_intern("@component_type"), component_type_to_sym(accessor->componentType));
9
10
  rb_ivar_set(raccessor, rb_intern("@count"), SIZET2NUM(accessor->count));
10
11
  rb_ivar_set(raccessor, rb_intern("@name"), rb_str_new2(accessor->name.c_str()));
11
12
  rb_ivar_set(raccessor, rb_intern("@byte_offset"), SIZET2NUM(accessor->byteOffset));
12
13
  rb_ivar_set(raccessor, rb_intern("@normalized"), accessor->normalized ? Qtrue : Qfalse);
13
14
  rb_ivar_set(raccessor, rb_intern("@type"), type_to_sym(accessor->type));
14
- rb_ivar_set(raccessor, rb_intern("@extras"), rValue_new(&accessor->extras));
15
+ rb_ivar_set(raccessor, rb_intern("@extras"), rValue_new(&accessor->extras, rmodel));
15
16
  rb_ivar_set(raccessor, rb_intern("@min"), Qnil);
16
17
  rb_ivar_set(raccessor, rb_intern("@max"), Qnil);
17
18
 
@@ -31,12 +32,3 @@ VALUE rAccessor_new(const Accessor *accessor) {
31
32
 
32
33
  return raccessor;
33
34
  }
34
-
35
- /* call-seq: byte_stride(buffer_view) => Numeric
36
- *
37
- * Returns the calculated byte stride for this accessor and the given buffer
38
- * view.
39
- */
40
- VALUE Accessor_byte_stride(VALUE self, VALUE buffer_view) {
41
- return INT2NUM(Accessor_unwrap(self)->ByteStride(*BufferView_unwrap(buffer_view)));
42
- }
@@ -1,21 +1,22 @@
1
1
  #include "rb_tiny_gltf.h"
2
2
 
3
- VALUE rAnimation_new(const Animation *animation) {
3
+ VALUE rAnimation_new(const Animation *animation, VALUE rmodel) {
4
4
  VALUE ranimation = rb_funcall(rb_cAnimation, rb_intern("new"), 0);
5
5
  // *Animation_unwrap(ranimation) = *animation;
6
6
 
7
7
  VALUE rchannels = rb_ary_new();
8
8
  for (size_t i = 0; i < animation->channels.size(); i++)
9
- rb_ary_push(rchannels, rAnimationChannel_new(&animation->channels[i]));
9
+ rb_ary_push(rchannels, rAnimationChannel_new(&animation->channels[i], ranimation));
10
10
 
11
11
  VALUE rsamplers = rb_ary_new();
12
12
  for (size_t i = 0; i < animation->samplers.size(); i++)
13
- rb_ary_push(rsamplers, rAnimationSampler_new(&animation->samplers[i]));
13
+ rb_ary_push(rsamplers, rAnimationSampler_new(&animation->samplers[i], ranimation));
14
14
 
15
+ rb_ivar_set(ranimation, rb_intern("@model"), rmodel);
15
16
  rb_ivar_set(ranimation, rb_intern("@name"), rb_str_new2(animation->name.c_str()));
16
17
  rb_ivar_set(ranimation, rb_intern("@channels"), rchannels);
17
- rb_ivar_set(ranimation, rb_intern("@rsamplers"), rsamplers);
18
- rb_ivar_set(ranimation, rb_intern("@extras"), rValue_new(&animation->extras));
18
+ rb_ivar_set(ranimation, rb_intern("@samplers"), rsamplers);
19
+ rb_ivar_set(ranimation, rb_intern("@extras"), rValue_new(&animation->extras, rmodel));
19
20
 
20
21
  return ranimation;
21
22
  }
@@ -1,13 +1,14 @@
1
1
  #include "rb_tiny_gltf.h"
2
2
 
3
- VALUE rAnimationChannel_new(const AnimationChannel *animation_channel) {
3
+ VALUE rAnimationChannel_new(const AnimationChannel *animation_channel, VALUE ranimation) {
4
4
  VALUE ranimation_channel = rb_funcall(rb_cAnimationChannel, rb_intern("new"), 0);
5
5
  // *AnimationChannel_unwrap(ranimation_channel) = *animation_channel;
6
6
 
7
- rb_ivar_set(ranimation_channel, rb_intern("@sampler_index"), INT2NUM(animation_channel->sampler));
8
- rb_ivar_set(ranimation_channel, rb_intern("@target_node_index"), INT2NUM(animation_channel->target_node));
9
- rb_ivar_set(ranimation_channel, rb_intern("@target_path"), rb_intern(animation_channel->target_path.c_str()));
10
- rb_ivar_set(ranimation_channel, rb_intern("@extras"), rValue_new(&animation_channel->extras));
7
+ rb_ivar_set(ranimation_channel, rb_intern("@animation"), ranimation);
8
+ rb_ivar_set(ranimation_channel, rb_intern("@sampler_index"), RINDEX_OR_NIL(animation_channel->sampler));
9
+ rb_ivar_set(ranimation_channel, rb_intern("@target_node_index"), RINDEX_OR_NIL(animation_channel->target_node));
10
+ rb_ivar_set(ranimation_channel, rb_intern("@target_path"), ID2SYM(rb_intern(animation_channel->target_path.c_str())));
11
+ rb_ivar_set(ranimation_channel, rb_intern("@extras"), rValue_new(&animation_channel->extras, rb_funcall(ranimation, rb_intern("model"), 0)));
11
12
 
12
13
  return ranimation_channel;
13
14
  }
@@ -1,16 +1,17 @@
1
1
  #include "rb_tiny_gltf.h"
2
2
 
3
- VALUE rAnimationSampler_new(const AnimationSampler *animation_sampler) {
3
+ VALUE rAnimationSampler_new(const AnimationSampler *animation_sampler, VALUE ranimation) {
4
4
  VALUE ranimation_sampler = rb_funcall(rb_cAnimationSampler, rb_intern("new"), 0);
5
5
  // *AnimationSampler_unwrap(ranimation_sampler) = *animation_sampler;
6
6
 
7
7
  std::string interp = animation_sampler->interpolation;
8
8
  std::transform(interp.begin(), interp.end(), interp.begin(), ::tolower);
9
9
 
10
- rb_ivar_set(ranimation_sampler, rb_intern("@input"), INT2NUM(animation_sampler->input));
11
- rb_ivar_set(ranimation_sampler, rb_intern("@output"), INT2NUM(animation_sampler->output));
12
- rb_ivar_set(ranimation_sampler, rb_intern("@interpolation"), rb_intern(interp.c_str()));
13
- rb_ivar_set(ranimation_sampler, rb_intern("@extras"), rValue_new(&animation_sampler->extras));
10
+ rb_ivar_set(ranimation_sampler, rb_intern("@animation"), ranimation);
11
+ rb_ivar_set(ranimation_sampler, rb_intern("@input_index"), RINDEX_OR_NIL(animation_sampler->input));
12
+ rb_ivar_set(ranimation_sampler, rb_intern("@output_index"), RINDEX_OR_NIL(animation_sampler->output));
13
+ rb_ivar_set(ranimation_sampler, rb_intern("@interpolation"), ID2SYM(rb_intern(interp.c_str())));
14
+ rb_ivar_set(ranimation_sampler, rb_intern("@extras"), rValue_new(&animation_sampler->extras, rb_funcall(ranimation, rb_intern("model"), 0)));
14
15
 
15
16
  return ranimation_sampler;
16
17
  }
@@ -1,15 +1,16 @@
1
1
  #include "rb_tiny_gltf.h"
2
2
 
3
- VALUE rAsset_new(const Asset *asset) {
3
+ VALUE rAsset_new(const Asset *asset, VALUE rmodel) {
4
4
  VALUE rasset = rb_funcall(rb_cAsset, rb_intern("new"), 0);
5
5
  // *Asset_unwrap(rasset) = *asset;
6
6
 
7
+ rb_ivar_set(rasset, rb_intern("@model"), rmodel);
7
8
  rb_ivar_set(rasset, rb_intern("@version"), rb_str_new2(asset->version.c_str()));
8
9
  rb_ivar_set(rasset, rb_intern("@generator"), rb_str_new2(asset->generator.c_str()));
9
10
  rb_ivar_set(rasset, rb_intern("@min_version"), rb_str_new2(asset->minVersion.c_str()));
10
11
  rb_ivar_set(rasset, rb_intern("@copyright"), rb_str_new2(asset->copyright.c_str()));
11
- rb_ivar_set(rasset, rb_intern("@extensions"), rExtensionMap_new(&asset->extensions));
12
- rb_ivar_set(rasset, rb_intern("@extras"), rValue_new(&asset->extras));
12
+ rb_ivar_set(rasset, rb_intern("@extensions"), rExtensionMap_new(&asset->extensions, rmodel));
13
+ rb_ivar_set(rasset, rb_intern("@extras"), rValue_new(&asset->extras, rmodel));
13
14
 
14
15
  return rasset;
15
16
  }
@@ -1,16 +1,45 @@
1
1
  #include "rb_tiny_gltf.h"
2
2
 
3
- VALUE rBuffer_new(const Buffer *buf) {
3
+ VALUE rBuffer_new(const Buffer *buf, VALUE rmodel) {
4
4
  VALUE rbuf = rb_funcall(rb_cBuffer, rb_intern("new"), 0);
5
- // *Buffer_unwrap(rbuf) = *buf;
6
5
 
7
- rb_ivar_set(rbuf, rb_intern("@name"), rb_str_new2(buf->name.c_str()));
8
- rb_ivar_set(rbuf, rb_intern("@data"), rb_str_new((char *) buf->data.data(), buf->data.size()));
9
- rb_ivar_set(rbuf, rb_intern("@uri"), Qnil);
10
- rb_ivar_set(rbuf, rb_intern("@extras"), rValue_new(&buf->extras));
6
+ // Keep (yes duplicate but the original will be freed) the buffer data
7
+ // in memory w/o having to wrap with a ruby string, which can be expensive
8
+ // and inefficient.
9
+ Buffer *dup = Buffer_unwrap(rbuf);
10
+ dup->data = buf->data;
11
+ dup->uri = buf->uri;
11
12
 
12
- if (buf->uri.size() > 0)
13
- rb_ivar_set(rbuf, rb_intern("@uri"), rb_str_new2(buf->uri.c_str()));
13
+ rb_ivar_set(rbuf, rb_intern("@model"), rmodel);
14
+ rb_ivar_set(rbuf, rb_intern("@name"), rb_str_new2(buf->name.c_str()));
15
+ rb_ivar_set(rbuf, rb_intern("@extras"), rValue_new(&buf->extras, rmodel));
14
16
 
15
17
  return rbuf;
16
18
  }
19
+
20
+ VALUE Buffer_to_ptr(VALUE self) {
21
+ // return Fiddle::Pointer.new(addr, size)
22
+ VALUE rFiddlePointer = rb_const_get(rb_const_get(rb_cObject, rb_intern("Fiddle")),
23
+ rb_intern("Pointer"));
24
+ Buffer *buf = Buffer_unwrap(self);
25
+ return rb_funcall(rFiddlePointer, rb_intern("new"), 2,
26
+ ULL2NUM((unsigned long long) buf->data.data()),
27
+ ULL2NUM((unsigned long long) buf->data.size()));
28
+ }
29
+
30
+ VALUE Buffer_size(VALUE self) {
31
+ return ULONG2NUM(Buffer_unwrap(self)->data.size());
32
+ }
33
+
34
+ VALUE Buffer_to_s(VALUE self) {
35
+ Buffer *buf = Buffer_unwrap(self);
36
+ return rb_str_new((char *) buf->data.data(), buf->data.size());
37
+ }
38
+
39
+ VALUE Buffer_uri(VALUE self) {
40
+ Buffer *buf = Buffer_unwrap(self);
41
+ if (buf->uri.size() > 0)
42
+ return rb_str_new2(buf->uri.c_str());
43
+ else
44
+ return Qnil;
45
+ }
@@ -1,16 +1,17 @@
1
1
  #include "rb_tiny_gltf.h"
2
2
 
3
- VALUE rBufferView_new(const BufferView *view) {
3
+ VALUE rBufferView_new(const BufferView *view, VALUE rmodel) {
4
4
  VALUE rbuf = rb_funcall(rb_cBufferView, rb_intern("new"), 0);
5
5
  *BufferView_unwrap(rbuf) = *view;
6
6
 
7
+ rb_ivar_set(rbuf, rb_intern("@model"), rmodel);
7
8
  rb_ivar_set(rbuf, rb_intern("@name"), rb_str_new2(view->name.c_str()));
8
- rb_ivar_set(rbuf, rb_intern("@buffer_index"), INT2NUM(view->buffer));
9
+ rb_ivar_set(rbuf, rb_intern("@buffer_index"), RINDEX_OR_NIL(view->buffer));
9
10
  rb_ivar_set(rbuf, rb_intern("@byte_offset"), SIZET2NUM(view->byteOffset));
10
11
  rb_ivar_set(rbuf, rb_intern("@byte_length"), SIZET2NUM(view->byteLength));
11
12
  rb_ivar_set(rbuf, rb_intern("@byte_stride"), SIZET2NUM(view->byteStride));
12
13
  rb_ivar_set(rbuf, rb_intern("@target"), target_to_sym(view->target));
13
- rb_ivar_set(rbuf, rb_intern("@extras"), rValue_new(&view->extras));
14
+ rb_ivar_set(rbuf, rb_intern("@extras"), rValue_new(&view->extras, rmodel));
14
15
 
15
16
  return rbuf;
16
17
  }
@@ -1,13 +1,14 @@
1
1
  #include "rb_tiny_gltf.h"
2
2
 
3
- VALUE rCamera_new(const Camera *camera) {
3
+ VALUE rCamera_new(const Camera *camera, VALUE rmodel) {
4
4
  VALUE rcamera = rb_funcall(rb_cCamera, rb_intern("new"), 0);
5
5
  // *Camera_unwrap(rcamera) = *camera;
6
6
 
7
+ rb_ivar_set(rcamera, rb_intern("@model"), rmodel);
7
8
  rb_ivar_set(rcamera, rb_intern("@name"), rb_str_new2(camera->name.c_str()));
8
9
  rb_ivar_set(rcamera, rb_intern("@type"), rb_intern(camera->type.c_str()));
9
- rb_ivar_set(rcamera, rb_intern("@extensions"), rExtensionMap_new(&camera->extensions));
10
- rb_ivar_set(rcamera, rb_intern("@extras"), rValue_new(&camera->extras));
10
+ rb_ivar_set(rcamera, rb_intern("@extensions"), rExtensionMap_new(&camera->extensions, rmodel));
11
+ rb_ivar_set(rcamera, rb_intern("@extras"), rValue_new(&camera->extras, rmodel));
11
12
 
12
13
  if (!strcmp(camera->type.c_str(), "perspective")) {
13
14
  rb_ivar_set(rcamera, rb_intern("@aspect_ratio"), DBL2NUM(camera->perspective.aspectRatio));
@@ -1,11 +1,11 @@
1
1
  #include "rb_tiny_gltf.h"
2
2
 
3
- VALUE rExtensionMap_new(const ExtensionMap *value) {
3
+ VALUE rExtensionMap_new(const ExtensionMap *value, VALUE rmodel) {
4
4
  VALUE res = Qnil;
5
5
 
6
6
  for (ExtensionMap::const_iterator iterator = value->begin(); iterator != value->end(); iterator++) {
7
7
  if (NIL_P(res)) res = rb_hash_new();
8
- rb_hash_aset(res, rb_str_new2(iterator->first.c_str()), rValue_new(&iterator->second));
8
+ rb_hash_aset(res, rb_str_new2(iterator->first.c_str()), rValue_new(&iterator->second, rmodel));
9
9
  }
10
10
 
11
11
  return res;
@@ -1,25 +1,85 @@
1
1
  #include "rb_tiny_gltf.h"
2
2
 
3
- VALUE rImage_new(const Image *img) {
4
- VALUE rimg = rb_funcall(rb_cImage, rb_intern("new"), 0);
5
- // *Image_unwrap(rimg) = *img;
3
+ void Image_set_image_data(const Image *img, VALUE rimg) {
4
+ // Keep (yes duplicate but the original will be freed) the buffer data
5
+ // in memory w/o having to wrap with a ruby string, which can be expensive
6
+ // and inefficient.
7
+ Image *dst = Image_unwrap(rimg);
8
+ dst->image = img->image;
9
+ dst->uri = img->uri;
6
10
 
7
- rb_ivar_set(rimg, rb_intern("@name"), rb_str_new2(img->name.c_str()));
8
- rb_ivar_set(rimg, rb_intern("@data"), rb_str_new((char *) img->image.data(), img->image.size()));
9
- rb_ivar_set(rimg, rb_intern("@uri"), Qnil);
10
- rb_ivar_set(rimg, rb_intern("@mime_type"), Qnil);
11
- rb_ivar_set(rimg, rb_intern("@extras"), rValue_new(&img->extras));
12
11
  rb_ivar_set(rimg, rb_intern("@width"), INT2NUM(img->width));
13
12
  rb_ivar_set(rimg, rb_intern("@height"), INT2NUM(img->height));
14
13
  rb_ivar_set(rimg, rb_intern("@components"), INT2NUM(img->component));
15
- rb_ivar_set(rimg, rb_intern("@buffer_view_index"), INT2NUM(img->bufferView));
16
- rb_ivar_set(rimg, rb_intern("@extensions"), rExtensionMap_new(&img->extensions));
14
+ }
17
15
 
18
- if (img->uri.size() > 0)
19
- rb_ivar_set(rimg, rb_intern("@uri"), rb_str_new2(img->uri.c_str()));
16
+ VALUE rImage_new(const Image *img, VALUE rmodel) {
17
+ VALUE rimg = rb_funcall(rb_cImage, rb_intern("new"), 0);
18
+
19
+ Image_set_image_data(img, rimg);
20
+ rb_ivar_set(rimg, rb_intern("@model"), rmodel);
21
+ rb_ivar_set(rimg, rb_intern("@name"), rb_str_new2(img->name.c_str()));
22
+ rb_ivar_set(rimg, rb_intern("@mime_type"), Qnil);
23
+ rb_ivar_set(rimg, rb_intern("@extras"), rValue_new(&img->extras, rmodel));
24
+ rb_ivar_set(rimg, rb_intern("@buffer_view_index"), RINDEX_OR_NIL(img->bufferView));
25
+ rb_ivar_set(rimg, rb_intern("@extensions"), rExtensionMap_new(&img->extensions, rmodel));
20
26
 
21
27
  if (img->mimeType.size() > 0)
22
28
  rb_ivar_set(rimg, rb_intern("@mime_type"), rb_str_new2(img->mimeType.c_str()));
23
29
 
24
30
  return rimg;
25
31
  }
32
+
33
+ VALUE Image_set_uri(VALUE self, VALUE ruri) {
34
+ if (NIL_P(ruri)) return self;
35
+ const char *uri = StringValueCStr(ruri);
36
+ std::string str = uri;
37
+ if (IsDataURI(str)) {
38
+ std::vector<unsigned char> data;
39
+ std::string mime_type;
40
+ if (DecodeDataURI(&data, mime_type, str, strlen(uri), false)) {
41
+ std::string err, warn;
42
+ Image img;
43
+ rb_ivar_set(self, rb_intern("@mime_type"), rb_str_new2(mime_type.c_str()));
44
+ memset(&img, 0, sizeof(img));
45
+ if (tinygltf::LoadImageData(&img, -1, &err, &warn, 0, 0, data.data(), (int) data.size(), NULL)) {
46
+ Image_set_image_data(&img, self);
47
+ } else {
48
+ rb_raise(rb_eStandardError, "Could not parse image data: %s", err.c_str());
49
+ }
50
+ if (warn.size() > 0) {
51
+ rb_warning("%s", warn.c_str());
52
+ }
53
+ } else {
54
+ rb_raise(rb_eStandardError, "Could not decode data URI");
55
+ }
56
+ }
57
+ return self;
58
+ }
59
+
60
+ VALUE Image_to_ptr(VALUE self) {
61
+ // return Fiddle::Pointer.new(addr, size)
62
+ VALUE rFiddlePointer = rb_const_get(rb_const_get(rb_cObject, rb_intern("Fiddle")),
63
+ rb_intern("Pointer"));
64
+ Image *img = Image_unwrap(self);
65
+ return rb_funcall(rFiddlePointer, rb_intern("new"), 2,
66
+ ULL2NUM((unsigned long long) img->image.data()),
67
+ ULL2NUM((unsigned long long) img->image.size()));
68
+ }
69
+
70
+ VALUE Image_size(VALUE self) {
71
+ return ULONG2NUM(Image_unwrap(self)->image.size());
72
+ }
73
+
74
+ VALUE Image_to_s(VALUE self) {
75
+ Image *img = Image_unwrap(self);
76
+ return rb_str_new((char *) img->image.data(), img->image.size());
77
+ }
78
+
79
+ VALUE Image_uri(VALUE self) {
80
+ Image *img = Image_unwrap(self);
81
+ if (img->uri.size() > 0)
82
+ return rb_str_new2(img->uri.c_str());
83
+ else
84
+ return Qnil;
85
+ }
@@ -74,7 +74,72 @@ void Init_tiny_gltf(void) {
74
74
  DEFINE_RB_GLTF_CLASS(Scene);
75
75
  DEFINE_RB_GLTF_CLASS(Light);
76
76
 
77
- rb_define_method(rb_cAccessor, "byte_stride", Accessor_byte_stride, 1);
77
+ /*
78
+ * Document-method: to_ptr
79
+ *
80
+ * Returns a Fiddle::Pointer representing the start of the buffer data in
81
+ * memory. For performance, try to use this rather than #to_s.
82
+ */
83
+ rb_define_method(rb_cBuffer, "to_ptr", Buffer_to_ptr, 0);
84
+
85
+ /*
86
+ * Document-method: size
87
+ *
88
+ * Returns the size of the buffer data in bytes.
89
+ */
90
+ rb_define_method(rb_cBuffer, "size", Buffer_size, 0);
91
+
92
+ /*
93
+ * Document-method: to_s
94
+ *
95
+ * Returns a string containing the raw buffer data. For better performance,
96
+ * prefer #to_ptr where possible.
97
+ */
98
+ rb_define_method(rb_cBuffer, "to_s", Buffer_to_s, 0);
99
+
100
+ /*
101
+ * Document-method: uri
102
+ *
103
+ * Returns the URI from which this data was retrieved, if available. Returns
104
+ * `nil` if a URI was not used.
105
+ */
106
+ rb_define_method(rb_cBuffer, "uri", Buffer_uri, 0);
107
+
108
+ /*
109
+ * Document-method: uri=
110
+ */
111
+ rb_define_method(rb_cImage, "uri=", Image_set_uri, 1);
112
+
113
+ /*
114
+ * Document-method: to_ptr
115
+ *
116
+ * Returns a Fiddle::Pointer representing the start of the image data in
117
+ * memory. For performance, try to use this rather than #to_s.
118
+ */
119
+ rb_define_method(rb_cImage, "to_ptr", Image_to_ptr, 0);
120
+
121
+ /*
122
+ * Document-method: size
123
+ *
124
+ * Returns the size of the image data in bytes.
125
+ */
126
+ rb_define_method(rb_cImage, "size", Image_size, 0);
127
+
128
+ /*
129
+ * Document-method: to_s
130
+ *
131
+ * Returns a string containing the raw image data. For better performance,
132
+ * prefer #to_ptr where possible.
133
+ */
134
+ rb_define_method(rb_cImage, "to_s", Image_to_s, 0);
135
+
136
+ /*
137
+ * Document-method: uri
138
+ *
139
+ * Returns the URI from which this data was retrieved, if available. Returns
140
+ * `nil` if a URI was not used.
141
+ */
142
+ rb_define_method(rb_cImage, "uri", Image_uri, 0);
78
143
 
79
144
  rb_eTinyGLTFError = rb_define_class_under(rb_mTinyGLTF, "Error", rb_eStandardError);
80
145
  rb_define_singleton_method(rb_mTinyGLTF, "load", rb_tgltf_load, -1);