ray 0.0.1 → 0.1.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (188) hide show
  1. data/.gemtest +0 -0
  2. data/.yardopts +4 -0
  3. data/README.md +17 -21
  4. data/Rakefile +18 -139
  5. data/VERSION +1 -1
  6. data/ext/audio.cpp +723 -0
  7. data/ext/{color.c → color.cpp} +25 -13
  8. data/ext/drawable.cpp +91 -0
  9. data/ext/event.cpp +460 -0
  10. data/ext/extconf.rb +5 -104
  11. data/ext/font.cpp +190 -0
  12. data/ext/image.cpp +733 -0
  13. data/ext/input.cpp +74 -0
  14. data/ext/ray.cpp +168 -0
  15. data/ext/ray.hpp +356 -0
  16. data/ext/{rect.c → rect.cpp} +51 -37
  17. data/ext/shader.cpp +169 -0
  18. data/ext/shape.cpp +409 -0
  19. data/ext/sprite.cpp +306 -0
  20. data/ext/text.cpp +181 -0
  21. data/ext/vector.cpp +215 -0
  22. data/guide.md +619 -0
  23. data/lib/ray/audio.rb +0 -41
  24. data/lib/ray/color.rb +32 -10
  25. data/lib/ray/drawable.rb +16 -0
  26. data/lib/ray/dsl/event_listener.rb +25 -2
  27. data/lib/ray/dsl/event_runner.rb +33 -5
  28. data/lib/ray/dsl/event_translator.rb +66 -30
  29. data/lib/ray/dsl/handler.rb +3 -2
  30. data/lib/ray/dsl/matcher.rb +58 -14
  31. data/lib/ray/font.rb +38 -96
  32. data/lib/ray/font_set.rb +8 -8
  33. data/lib/ray/game.rb +87 -66
  34. data/lib/ray/helper.rb +105 -10
  35. data/lib/ray/image.rb +150 -24
  36. data/lib/ray/image_set.rb +3 -1
  37. data/lib/ray/input.rb +10 -0
  38. data/lib/ray/music_set.rb +5 -3
  39. data/lib/ray/ray.rb +21 -9
  40. data/lib/ray/rect.rb +48 -7
  41. data/lib/ray/rmagick.rb +41 -0
  42. data/lib/ray/scene.rb +99 -43
  43. data/lib/ray/scene_list.rb +67 -0
  44. data/lib/ray/shape.rb +132 -0
  45. data/lib/ray/sound_set.rb +4 -2
  46. data/lib/ray/sprite.rb +49 -111
  47. data/lib/ray/text.rb +101 -0
  48. data/lib/ray/text_helper.rb +37 -0
  49. data/lib/ray/turtle.rb +215 -0
  50. data/lib/ray/vector.rb +226 -0
  51. data/samples/audio/spacial.rb +44 -0
  52. data/samples/hello_world/hello.rb +9 -13
  53. data/samples/hello_world/hello_dsl.rb +8 -12
  54. data/samples/hello_world/text.rb +15 -0
  55. data/samples/opengl/binding.rb +38 -0
  56. data/samples/opengl/image.rb +32 -0
  57. data/samples/opengl/opengl.rb +34 -0
  58. data/samples/opengl/shader.rb +42 -0
  59. data/samples/pong/pong.rb +14 -10
  60. data/samples/run_scene.rb +53 -0
  61. data/samples/shaders/scene.rb +40 -0
  62. data/samples/shaders/shaders.rb +42 -0
  63. data/samples/shaders/shape.rb +34 -0
  64. data/samples/sokoban/sokoban.rb +18 -18
  65. data/samples/test/actual_scene.rb +41 -0
  66. data/samples/test/scene_riot.rb +39 -0
  67. data/samples/test/scene_spec.rb +32 -0
  68. data/samples/test/scene_test_unit.rb +25 -0
  69. data/samples/turtle/byzantium.rb +45 -0
  70. data/samples/turtle/hilbert.rb +48 -0
  71. data/samples/turtle/koch.rb +55 -0
  72. data/samples/turtle/mandala.rb +61 -0
  73. data/samples/turtle/tree.rb +57 -0
  74. data/test/audio_test.rb +69 -0
  75. data/test/color_test.rb +77 -0
  76. data/test/drawable_test.rb +19 -0
  77. data/test/dsl_test.rb +93 -0
  78. data/test/font_test.rb +57 -0
  79. data/test/helpers.rb +94 -0
  80. data/test/image_test.rb +82 -0
  81. data/test/ray_test.rb +25 -0
  82. data/test/rect_test.rb +121 -0
  83. data/{spec → test}/res/VeraMono.ttf +0 -0
  84. data/{spec → test}/res/aqua.bmp +0 -0
  85. data/{spec → test}/res/aqua.png +0 -0
  86. data/{spec → test}/res/aqua2.bmp +0 -0
  87. data/{spec → test}/res/not_a_jpeg.jpeg +0 -0
  88. data/{spec → test}/res/pop.wav +0 -0
  89. data/test/resource_set_test.rb +99 -0
  90. data/test/run_all.rb +7 -0
  91. data/test/shape_test.rb +101 -0
  92. data/test/sprite_test.rb +89 -0
  93. data/test/text_test.rb +78 -0
  94. data/test/turtle_test.rb +176 -0
  95. data/test/vector_test.rb +111 -0
  96. data/yard_ext.rb +0 -28
  97. metadata +95 -139
  98. data/.gitignore +0 -23
  99. data/.gitmodules +0 -3
  100. data/.rspec +0 -3
  101. data/ext/audio.c +0 -473
  102. data/ext/event.c +0 -557
  103. data/ext/font.c +0 -287
  104. data/ext/image.c +0 -933
  105. data/ext/joystick.c +0 -145
  106. data/ext/ray.c +0 -489
  107. data/ext/ray.h +0 -245
  108. data/ext/ray_osx.m +0 -161
  109. data/lib/ray/joystick.rb +0 -30
  110. data/psp/SDL_psp_main.c +0 -84
  111. data/psp/bigdecimal/README +0 -60
  112. data/psp/bigdecimal/bigdecimal.c +0 -4697
  113. data/psp/bigdecimal/bigdecimal.h +0 -216
  114. data/psp/bigdecimal/lib/bigdecimal/jacobian.rb +0 -85
  115. data/psp/bigdecimal/lib/bigdecimal/ludcmp.rb +0 -84
  116. data/psp/bigdecimal/lib/bigdecimal/math.rb +0 -235
  117. data/psp/bigdecimal/lib/bigdecimal/newton.rb +0 -77
  118. data/psp/bigdecimal/lib/bigdecimal/util.rb +0 -65
  119. data/psp/digest/bubblebabble/bubblebabble.c +0 -142
  120. data/psp/digest/defs.h +0 -20
  121. data/psp/digest/digest.c +0 -643
  122. data/psp/digest/digest.h +0 -32
  123. data/psp/digest/lib/digest.rb +0 -50
  124. data/psp/digest/lib/md5.rb +0 -27
  125. data/psp/digest/lib/sha1.rb +0 -27
  126. data/psp/digest/md5/md5.c +0 -420
  127. data/psp/digest/md5/md5.h +0 -80
  128. data/psp/digest/md5/md5init.c +0 -40
  129. data/psp/digest/rmd160/rmd160.c +0 -457
  130. data/psp/digest/rmd160/rmd160.h +0 -56
  131. data/psp/digest/rmd160/rmd160init.c +0 -40
  132. data/psp/digest/sha1/sha1.c +0 -269
  133. data/psp/digest/sha1/sha1.h +0 -39
  134. data/psp/digest/sha1/sha1init.c +0 -40
  135. data/psp/digest/sha2/lib/sha2.rb +0 -73
  136. data/psp/digest/sha2/sha2.c +0 -919
  137. data/psp/digest/sha2/sha2.h +0 -109
  138. data/psp/digest/sha2/sha2init.c +0 -52
  139. data/psp/enumerator/enumerator.c +0 -298
  140. data/psp/etc/etc.c +0 -559
  141. data/psp/ext.c +0 -289
  142. data/psp/fcntl/fcntl.c +0 -187
  143. data/psp/lib/rbconfig.rb +0 -178
  144. data/psp/nkf/lib/kconv.rb +0 -367
  145. data/psp/nkf/nkf-utf8/config.h +0 -88
  146. data/psp/nkf/nkf-utf8/nkf.c +0 -6040
  147. data/psp/nkf/nkf-utf8/utf8tbl.c +0 -8500
  148. data/psp/nkf/nkf-utf8/utf8tbl.h +0 -34
  149. data/psp/nkf/nkf.c +0 -654
  150. data/psp/socket/addrinfo.h +0 -173
  151. data/psp/socket/getaddrinfo.c +0 -676
  152. data/psp/socket/getnameinfo.c +0 -270
  153. data/psp/socket/pspsocket.c +0 -71
  154. data/psp/socket/pspsocket.h +0 -28
  155. data/psp/socket/socket.c +0 -4662
  156. data/psp/socket/sockport.h +0 -76
  157. data/psp/stringio/stringio.c +0 -1306
  158. data/psp/strscan/strscan.c +0 -1320
  159. data/psp/syck/bytecode.c +0 -1166
  160. data/psp/syck/emitter.c +0 -1242
  161. data/psp/syck/gram.c +0 -1894
  162. data/psp/syck/gram.h +0 -79
  163. data/psp/syck/handler.c +0 -174
  164. data/psp/syck/implicit.c +0 -2990
  165. data/psp/syck/node.c +0 -408
  166. data/psp/syck/rubyext.c +0 -2367
  167. data/psp/syck/syck.c +0 -504
  168. data/psp/syck/syck.h +0 -456
  169. data/psp/syck/token.c +0 -2725
  170. data/psp/syck/yaml2byte.c +0 -257
  171. data/psp/syck/yamlbyte.h +0 -170
  172. data/psp/thread/thread.c +0 -1175
  173. data/psp/zlib/zlib.c +0 -3547
  174. data/script.rb +0 -10
  175. data/spec/ray/audio_spec.rb +0 -146
  176. data/spec/ray/color_spec.rb +0 -57
  177. data/spec/ray/event_spec.rb +0 -80
  178. data/spec/ray/font_spec.rb +0 -93
  179. data/spec/ray/image_set_spec.rb +0 -48
  180. data/spec/ray/image_spec.rb +0 -162
  181. data/spec/ray/joystick_spec.rb +0 -21
  182. data/spec/ray/matcher_spec.rb +0 -50
  183. data/spec/ray/ray_spec.rb +0 -88
  184. data/spec/ray/rect_spec.rb +0 -154
  185. data/spec/ray/resource_set_spec.rb +0 -105
  186. data/spec/ray/sprite_spec.rb +0 -163
  187. data/spec/spec.opts +0 -4
  188. data/spec/spec_helper.rb +0 -8
@@ -1,111 +1,12 @@
1
1
  require 'mkmf'
2
2
 
3
- def find_macosx_framework(name)
4
- paths = [
5
- "/opt/local/Library/Frameworks",
6
- "/Library/Frameworks",
7
- "/Network/Library/Frameworks",
8
- "/System/Library/Frameworks"
9
- ]
10
- paths.reverse!
3
+ $CFLAGS << " -Wextra -Wall -Wno-unused-parameter -Wno-long-long"
11
4
 
12
- paths.each do |dir|
13
- dir = File.join(dir, "#{name}.framework")
14
- next unless File.directory? dir
5
+ # Fix errors from missing.h when compiling as C++
6
+ have_func("ffs")
15
7
 
16
- return dir
17
- end
18
-
19
- nil
20
- end
21
-
22
- def have_framework(name)
23
- print "checking for framweork #{name}... "
24
- ret = find_macosx_framework(name)
25
-
26
- if ret
27
- puts "yes"
28
-
29
- $LDFLAGS << " -F#{File.dirname(ret)}"
30
- $LDFLAGS << " -framework #{name}"
31
- $CFLAGS << " -I#{File.join(ret, "Headers")}"
32
- $CFLAGS << " -DHAVE_#{name.upcase}"
33
- else
34
- puts "no"
35
- end
36
- ret
37
- end
38
-
39
- def have_sdl_ext(name, header)
40
- if res = have_framework(name)
41
- ending = header.upcase.tr('/', '_').gsub(/\.H$/, "_H")
42
- $CFLAGS << " -DHAVE_#{ending}"
43
-
44
- return res
45
- end
46
-
47
- if res = have_library(name)
48
- unless have_header(header) or have_header("SDL/#{header}")
49
- return false
50
- end
51
-
52
- return res
53
- end
54
- end
55
-
56
- $CFLAGS << " -pedantic -Wall -std=c99 -Wno-unused-parameter"
57
-
58
- unless RUBY_PLATFORM =~ /darwin/
59
- unless have_library("SDL", "SDL_Init")
60
- $stdder.puts "SDL not found"
61
- end
62
-
63
- unless (have_header("SDL/SDL.h") or have_header("SDL.h"))
64
- $stderr.puts "SDL.h not found."
65
- exit 1
66
- end
67
-
68
- unless have_library("SDLmain")
69
- $stderr.puts "SDL_main not found."
70
- exit 1
71
- end
72
-
73
- if have_library("SDL_image")
74
- have_header("SDL/SDL_image.h") or have_header("SDL_image.h")
75
- end
76
-
77
- if have_library("SDL_gfx")
78
- have_header("SDL/SDL_rotozoom.h") or have_header("SDL_rotozoom.h")
79
- end
80
-
81
- if have_library("SDL_ttf")
82
- have_header("SDL/SDL_ttf.h") or have_header("SDL_ttf.h")
83
- end
84
-
85
- if have_library("SDL_mixer")
86
- have_header("SDL/SDL_mixer.h") or have_header("SDL_mixer.h")
87
- end
88
-
89
- create_makefile("ray_ext")
90
-
91
- data = File.read("Makefile").gsub("ray_osx.o", "")
92
- open("Makefile", 'w') { |f| f.write(data) }
93
- else
94
- $CFLAGS << " #{ENV["CFLAGS"]}"
95
- $LDFLAGS << " #{ENV["LDFLAGS"]}"
96
-
97
- $CFLAGS << " -DRAY_USE_FRAMEWORK"
98
-
99
- unless have_framework("SDL") and have_framework("Cocoa") and
100
- have_framework("Foundation")
101
- $stderr.puts "missing frameworks"
102
- exit 1
103
- end
104
-
105
- have_sdl_ext("SDL_image", "SDL_image.h")
106
- have_sdl_ext("SDL_gfx", "SDL_rotozoom.h")
107
- have_sdl_ext("SDL_ttf", "SDL_ttf.h")
108
- have_sdl_ext("SDL_mixer", "SDL_mixer.h")
8
+ sfml_exts = %w(audio graphics window system)
109
9
 
10
+ if sfml_exts.all? { |ext| have_library("sfml-#{ext}") }
110
11
  create_makefile("ray_ext")
111
12
  end
@@ -0,0 +1,190 @@
1
+ #include "ray.hpp"
2
+
3
+ typedef struct {
4
+ unsigned long style;
5
+ int font_size;
6
+ } ray_font_style;
7
+
8
+ VALUE ray_cFont = Qnil;
9
+
10
+ void ray_free_font(ray_font *font) {
11
+ delete font;
12
+ }
13
+
14
+ VALUE ray_font2rb(const ray_font &font) {
15
+ ray_font *ptr = new ray_font(font);
16
+ return Data_Wrap_Struct(ray_cFont, 0, ray_free_font, ptr);
17
+ }
18
+
19
+ ray_font *ray_rb2font(VALUE object) {
20
+ if (!RAY_IS_A(object, ray_cFont)) {
21
+ rb_raise(rb_eTypeError, "Can't convert %s into Ray::Font",
22
+ RAY_OBJ_CLASSNAME(object));
23
+ }
24
+
25
+ ray_font *ptr = NULL;
26
+ Data_Get_Struct(object, ray_font, ptr);
27
+
28
+ return ptr;
29
+ }
30
+
31
+ VALUE ray_alloc_font(VALUE self) {
32
+ ray_font *ptr = new ray_font;
33
+ VALUE ret = Data_Wrap_Struct(self, 0, ray_free_font, ptr);
34
+
35
+ return ret;
36
+ }
37
+
38
+ /* @return [Ray::Font] The default font */
39
+ VALUE ray_font_default(VALUE self) {
40
+ return ray_font2rb(sf::Font::GetDefaultFont());
41
+ }
42
+
43
+ void ray_init_font_with_filename(VALUE self, VALUE filename) {
44
+ ray_font *font = NULL;
45
+ Data_Get_Struct(self, ray_font, font);
46
+
47
+ if (!font->LoadFromFile(StringValuePtr(filename))) {
48
+ rb_raise(rb_eRuntimeError, "Could not load the font");
49
+ }
50
+ }
51
+
52
+ void ray_init_font_with_io(VALUE self, VALUE io) {
53
+ ray_font *font = NULL;
54
+ Data_Get_Struct(self, ray_font, font);
55
+
56
+ VALUE string = rb_funcall2(io, RAY_METH("read"), 0, NULL);
57
+ char *content = StringValuePtr(string);
58
+
59
+ if (!font->LoadFromMemory(content, (int)RSTRING_LEN(string))) {
60
+ rb_raise(rb_eRuntimeError, "Could not load the font");
61
+ }
62
+ }
63
+
64
+ /*
65
+ Creates a new font.
66
+ @param [String, #read] arg Filename or IO object.
67
+ */
68
+ VALUE ray_init_font(VALUE self, VALUE arg) {
69
+ if (rb_respond_to(arg, RAY_METH("to_str")))
70
+ ray_init_font_with_filename(self, rb_String(arg));
71
+ else if (rb_respond_to(arg, RAY_METH("read")))
72
+ ray_init_font_with_io(self, arg);
73
+ else {
74
+ rb_raise(rb_eTypeError, "Can't convert %s into String",
75
+ RAY_OBJ_CLASSNAME(arg));
76
+ }
77
+
78
+ return Qnil;
79
+ }
80
+
81
+ ray_font_style ray_parse_font_style(VALUE opts) {
82
+ ray_font_style style;
83
+
84
+ VALUE font_size = rb_hash_aref(opts, RAY_SYM("size"));
85
+ if (!NIL_P(font_size))
86
+ style.font_size = NUM2INT(font_size);
87
+ else
88
+ rb_raise(rb_eArgError, "Character size not specified");
89
+
90
+ style.style = sf::Text::Regular;
91
+ VALUE font_style = Qnil;
92
+ if (!NIL_P(font_style = rb_hash_aref(opts, RAY_SYM("style"))))
93
+ style.style = NUM2INT(font_style);
94
+
95
+ return style;
96
+ }
97
+
98
+ /* @return [Integer] the recommended spacing between lines for this font */
99
+ VALUE ray_font_line_skip(VALUE self, VALUE size) {
100
+ ray_font *font = ray_rb2font(self);
101
+ return INT2FIX(font->GetLineSpacing(NUM2INT(size)));
102
+ }
103
+
104
+ VALUE ray_font_simple_size_of(VALUE self, VALUE str, VALUE opts) {
105
+ ray_font *font = ray_rb2font(self);
106
+ ray_font_style style = ray_parse_font_style(opts);
107
+
108
+ char *c_str = StringValuePtr(str);
109
+ sf::String string((uint32_t*)c_str);
110
+
111
+ sf::Text text(string, *font);
112
+ text.SetStyle(style.style);
113
+ text.SetCharacterSize(style.font_size);
114
+
115
+ ray_rect rect = RAY_RECT(text.GetRect());
116
+ return ray_vector2_to_rb(sf::Vector2f(rect.Width, rect.Height));
117
+ }
118
+
119
+ VALUE ray_font_simple_draw(VALUE self, VALUE str, VALUE hash) {
120
+ ray_font *font = ray_rb2font(self);
121
+ ray_font_style style = ray_parse_font_style(hash);
122
+
123
+ VALUE rb_color = rb_hash_aref(hash, RAY_SYM("color"));
124
+ ray_color c_color(255, 255, 255, 255);
125
+ if (!NIL_P(rb_color))
126
+ c_color = ray_rb2col(rb_color);
127
+
128
+ char *c_str = StringValuePtr(str);
129
+ sf::String string((uint32_t*)c_str);
130
+
131
+ sf::Text text(string, *font);
132
+ text.SetStyle(style.style);
133
+ text.SetCharacterSize(style.font_size);
134
+ text.SetColor(c_color);
135
+
136
+ ray_rect rect = RAY_RECT(text.GetRect());
137
+
138
+ ray_vector2 pos(0, 0);
139
+ VALUE rb_pos = rb_hash_aref(hash, RAY_SYM("at"));
140
+ if (NIL_P(rb_pos))
141
+ rb_pos = rb_hash_aref(hash, RAY_SYM("to"));
142
+ if (!NIL_P(rb_pos))
143
+ pos = ray_convert_to_vector2(rb_pos);
144
+
145
+ text.SetPosition(pos.x, pos.y);
146
+
147
+ VALUE on = rb_hash_aref(hash, RAY_SYM("on"));
148
+ if (NIL_P(on)) {
149
+ VALUE image_hash = rb_hash_new();
150
+ rb_hash_aset(image_hash, RAY_SYM("width"), INT2FIX(rect.Width));
151
+ rb_hash_aset(image_hash, RAY_SYM("height"), INT2FIX(rect.Height));
152
+
153
+ on = rb_funcall(ray_cImage, RAY_METH("new"), 1, image_hash);
154
+ }
155
+
156
+ ray_image *image = ray_rb2image(on);
157
+ image->draw(text);
158
+
159
+ return on;
160
+ }
161
+
162
+ /*
163
+ Doucment-class: Ray::Font
164
+
165
+ Class used to draw text.
166
+ It can render text on an image:
167
+ font.draw("Hello world!", :on => image, :at => [10, 20]) # => image
168
+ Or create a new image containing the text, to use it later (which is
169
+ potentially better than rendering the same string a great amount of
170
+ times):
171
+ font.draw("Hello world!") # => a new image
172
+ */
173
+
174
+ void Init_ray_font() {
175
+ ray_cFont = rb_define_class_under(ray_mRay, "Font", rb_cObject);
176
+ rb_define_alloc_func(ray_cFont, ray_alloc_font);
177
+ rb_define_method(ray_cFont, "initialize", ray_init_font, 1);
178
+
179
+ rb_define_singleton_method(ray_cFont, "default", ray_font_default, 0);
180
+
181
+ rb_define_method(ray_cFont, "line_skip", ray_font_line_skip, 1);
182
+ rb_define_method(ray_cFont, "simple_size_of", ray_font_simple_size_of, 2);
183
+
184
+ rb_define_method(ray_cFont, "simple_draw", ray_font_simple_draw, 2);
185
+
186
+ rb_define_const(ray_cFont, "STYLE_NORMAL", INT2FIX(sf::Text::Regular));
187
+ rb_define_const(ray_cFont, "STYLE_ITALIC", INT2FIX(sf::Text::Italic));
188
+ rb_define_const(ray_cFont, "STYLE_BOLD", INT2FIX(sf::Text::Bold));
189
+ rb_define_const(ray_cFont, "STYLE_UNDERLINE", INT2FIX(sf::Text::Underlined));
190
+ }
@@ -0,0 +1,733 @@
1
+ #include "ray.hpp"
2
+
3
+ VALUE ray_cImage = Qnil;
4
+
5
+ ray_image::ray_image(bool should_be_screen):
6
+ is_screen(should_be_screen),
7
+ pixel_modifier(NULL)
8
+ {}
9
+
10
+ ray_image::~ray_image() {
11
+ if (pixel_modifier) delete pixel_modifier;
12
+ }
13
+
14
+ bool ray_image::create_with_size(int w, int h) {
15
+ return render_image.Create(w, h);
16
+ }
17
+
18
+ bool ray_image::create_with_filename(const std::string &filename) {
19
+ sf::Image temp_image;
20
+ if (!temp_image.LoadFromFile(filename))
21
+ return false;
22
+
23
+ sf::Sprite temp_sprite(temp_image);
24
+
25
+ if (!create_with_size(temp_image.GetWidth(), temp_image.GetHeight()))
26
+ return false;
27
+
28
+ render_image.Draw(temp_sprite);
29
+ sprite.SetImage(render_image.GetImage());
30
+
31
+ update();
32
+
33
+ return true;
34
+ }
35
+
36
+ bool ray_image::create_with_io(VALUE io) {
37
+ VALUE string = rb_funcall2(io, RAY_METH("read"), 0, NULL);
38
+ char *content = StringValuePtr(string);
39
+
40
+ sf::Image temp_image;
41
+ if (!temp_image.LoadFromMemory(content, RSTRING_LEN(string)))
42
+ return false;
43
+
44
+ sf::Sprite temp_sprite(temp_image);
45
+
46
+ if (!create_with_size(temp_image.GetWidth(), temp_image.GetHeight()))
47
+ return false;
48
+
49
+ render_image.Draw(temp_sprite);
50
+ sprite.SetImage(render_image.GetImage());
51
+
52
+ update();
53
+
54
+ return true;
55
+ }
56
+
57
+ bool ray_image::create_with_image(ray_image &src) {
58
+ sf::Sprite &src_sprite = src.get_sprite();
59
+ sf::Vector2f size = src_sprite.GetSize();
60
+
61
+ if (!create_with_size(src.width(), src.height()))
62
+ return false;
63
+
64
+ draw_image(src, ray_rect(0, 0, src.width(), src.height()),
65
+ ray_vector2(0, 0),
66
+ 0.f, ray_vector2(1.f, 1.f));
67
+ update();
68
+
69
+ return true;
70
+ }
71
+
72
+ bool ray_image::save_as(const std::string &filename) const {
73
+ if (is_screen) {
74
+ sf::Image screen_copy;
75
+
76
+ if (!screen_copy.CopyScreen(ray_screen, sf::IntRect(0, 0, width(),
77
+ height()))) {
78
+ return false;
79
+ }
80
+
81
+ return screen_copy.SaveToFile(filename);
82
+ }
83
+ else {
84
+ return render_image.GetImage().SaveToFile(filename);
85
+ }
86
+ }
87
+
88
+ int ray_image::width() const { return target().GetWidth(); }
89
+ int ray_image::height() const { return target().GetHeight(); }
90
+
91
+ void ray_image::update() {
92
+ if (is_screen)
93
+ ray_screen.Display();
94
+ else
95
+ render_image.Display();
96
+ }
97
+
98
+ void ray_image::fill(sf::Color color) {
99
+ target().Clear(color);
100
+ }
101
+
102
+ void ray_image::draw(const sf::Drawable &drawable,
103
+ sf::Shader *shader) {
104
+ if (shader)
105
+ target().Draw(drawable, *shader);
106
+ else
107
+ target().Draw(drawable);
108
+ }
109
+
110
+ void ray_image::draw_image(ray_image &image,
111
+ const ray_rect &src_rect,
112
+ const ray_vector2 &dest_pos,
113
+ float angle, const ray_vector2 &zoom,
114
+ sf::Shader *shader,
115
+ const ray_color &color) {
116
+ sf::Image screen_copy;
117
+
118
+ if (image.is_screen) {
119
+ if (!screen_copy.CopyScreen(ray_screen, sf::IntRect(0, 0, image.width(),
120
+ image.height()))) {
121
+ return;
122
+ }
123
+
124
+ sprite = sf::Sprite(screen_copy);
125
+ }
126
+ else {
127
+ sprite = sf::Sprite(image.render_image.GetImage());
128
+ }
129
+
130
+ sprite.SetSubRect(RAY_INT_RECT(src_rect));
131
+
132
+ sprite.SetPosition(dest_pos);
133
+
134
+ sprite.SetScale(zoom);
135
+ sprite.SetRotation(angle);
136
+
137
+ sprite.SetColor(color);
138
+
139
+ if (!shader)
140
+ target().Draw(sprite);
141
+ else
142
+ target().Draw(sprite, *shader);
143
+ }
144
+
145
+ ray_color ray_image::at(int x, int y) const {
146
+ if (pixel_modifier)
147
+ return pixel_modifier->GetPixel(x, y);
148
+
149
+ if (is_screen) {
150
+ sf::Image img;
151
+ img.CopyScreen(ray_screen, sf::IntRect(x, y, 1, 1));
152
+ return img.GetPixel(0, 0);
153
+ }
154
+
155
+ return render_image.GetImage().GetPixel(x, y);
156
+ }
157
+
158
+ bool ray_image::set_at(int x, int y, const ray_color &color) {
159
+ if (!pixel_modifier) return false;
160
+
161
+ pixel_modifier->SetPixel(x, y, color);
162
+ return true;
163
+ }
164
+
165
+ const uint8_t *ray_image::pixels() const {
166
+ return render_image.GetImage().GetPixelsPtr();
167
+ }
168
+
169
+ ray_rect ray_image::clip() const {
170
+ sf::FloatRect rect = target().GetView().GetViewport();
171
+ return ray_rect(rect.Left * width(), rect.Top * height(),
172
+ rect.Width * width(), rect.Height * height());
173
+ }
174
+
175
+ void ray_image::set_clip(const ray_rect &other) {
176
+ sf::FloatRect rect(other.Left / (float)width(),
177
+ other.Top / (float)height(),
178
+ other.Width / (float)width(),
179
+ other.Height / (float)height());
180
+ sf::View view(target().GetDefaultView());
181
+ view.SetViewport(rect);
182
+
183
+ target().SetView(view);
184
+ }
185
+
186
+ bool ray_image::lock() {
187
+ if (pixel_modifier) return true;
188
+
189
+ if (is_screen) {
190
+ pixel_modifier = new sf::Image;
191
+
192
+ if (!pixel_modifier->CopyScreen(ray_screen,
193
+ sf::IntRect(0, 0, width(), height()))) {
194
+ delete pixel_modifier;
195
+ pixel_modifier = NULL;
196
+
197
+ return false;
198
+ }
199
+ }
200
+ else
201
+ pixel_modifier = new sf::Image(render_image.GetImage());
202
+
203
+ return true;
204
+ }
205
+
206
+ void ray_image::unlock() {
207
+ if (!pixel_modifier) return;
208
+
209
+ target().Clear(ray_color(0, 0, 0, 0));
210
+ sf::Sprite tmp_sprite(*pixel_modifier);
211
+ target().Draw(tmp_sprite);
212
+
213
+ delete pixel_modifier;
214
+ pixel_modifier = NULL;
215
+ }
216
+
217
+ void ray_image::activate() {
218
+ if (is_screen)
219
+ ray_screen.SetActive();
220
+ else
221
+ render_image.SetActive();
222
+ }
223
+
224
+ void ray_image::bind() {
225
+ render_image.GetImage().Bind();
226
+ }
227
+
228
+ bool ray_image::is_image() const {
229
+ return !is_screen;
230
+ }
231
+
232
+ const sf::Image &ray_image::image() const {
233
+ return render_image.GetImage();
234
+ }
235
+
236
+ bool ray_image::operator==(const ray_image &other) const {
237
+ return (&(target()) == &(other.target()));
238
+ }
239
+
240
+ sf::RenderTarget &ray_image::target() {
241
+ return is_screen ? (sf::RenderTarget&)ray_screen :
242
+ (sf::RenderTarget&)render_image;
243
+ }
244
+
245
+ const sf::RenderTarget &ray_image::target() const {
246
+ return is_screen ? (sf::RenderTarget&)ray_screen :
247
+ (sf::RenderTarget&)render_image;
248
+ }
249
+
250
+ ray_image *ray_rb2image(VALUE object) {
251
+ if (!RAY_IS_A(object, ray_cImage)) {
252
+ rb_raise(rb_eTypeError, "Can't convert %s into Ray::Image",
253
+ RAY_OBJ_CLASSNAME(object));
254
+ }
255
+
256
+ ray_image *ptr = NULL;
257
+ Data_Get_Struct(object, ray_image, ptr);
258
+
259
+ return ptr;
260
+ }
261
+
262
+ /*
263
+ @return [true, false] True if it is possible to draw on an image.
264
+ If this is false, many methods won't work as expected.
265
+ */
266
+ VALUE ray_image_available(VALUE self) {
267
+ return sf::RenderImage::IsAvailable() ? Qtrue : Qfalse;
268
+ }
269
+
270
+ void ray_init_image_with_hash(VALUE self, VALUE arg) {
271
+ VALUE width = rb_hash_aref(arg, RAY_SYM("width"));
272
+ if (NIL_P(width)) width = rb_hash_aref(arg, RAY_SYM("w"));
273
+
274
+ VALUE height = rb_hash_aref(arg, RAY_SYM("height"));
275
+ if (NIL_P(height)) height = rb_hash_aref(arg, RAY_SYM("h"));
276
+
277
+ ray_image *image = ray_rb2image(self);
278
+ bool res = image->create_with_size(NUM2INT(width), NUM2INT(height));
279
+
280
+ if (!res)
281
+ rb_raise(rb_eRuntimeError, "Could not create the image");
282
+ }
283
+
284
+ void ray_init_image_with_filename(VALUE self, VALUE filename) {
285
+ char *c_filename = StringValuePtr(filename);
286
+ ray_image *image = ray_rb2image(self);
287
+
288
+ if (!image->create_with_filename(c_filename))
289
+ rb_raise(rb_eRuntimeError, "Could not create the image");
290
+ }
291
+
292
+ void ray_init_image_with_io(VALUE self, VALUE io) {
293
+ ray_image *image = ray_rb2image(self);
294
+ if (!image->create_with_io(io))
295
+ rb_raise(rb_eRuntimeError, "Could not create the image");
296
+ }
297
+
298
+ /*
299
+ Creates a new image.
300
+
301
+ @overload initialize(hash)
302
+ @option hash [Integer] :width Width of the surface
303
+ @option hash [Integer] :height Height of the surface
304
+
305
+ @option hash [Integer] :w Alias for width
306
+ @option hash [Integer] :h Alias for height
307
+
308
+ @overload initialize(filename)
309
+ Loads the image from a file.
310
+ @param [String, #to_str] filename The name of the file to open
311
+
312
+ @overload initialize(io)
313
+ Loads the image friom an IO object.
314
+ @param [IO, #read] io Object the data will be loaded from.
315
+ */
316
+ VALUE ray_init_image(VALUE self, VALUE arg) {
317
+ if (RAY_IS_A(arg, rb_cHash))
318
+ ray_init_image_with_hash(self, arg);
319
+ else if (rb_respond_to(arg, RAY_METH("to_str")))
320
+ ray_init_image_with_filename(self, rb_String(arg));
321
+ else if (rb_respond_to(arg, RAY_METH("read")))
322
+ ray_init_image_with_io(self, arg);
323
+ else {
324
+ rb_raise(rb_eTypeError, "Can't convert %s into Hash",
325
+ RAY_OBJ_CLASSNAME(arg));
326
+ }
327
+
328
+ return Qnil;
329
+ }
330
+
331
+ VALUE ray_init_image_copy(VALUE self, VALUE obj) {
332
+ ray_image *img = ray_rb2image(self);
333
+ ray_image *src = ray_rb2image(obj);
334
+
335
+ if (!img->create_with_image(*src))
336
+ rb_raise(rb_eRuntimeError, "Could not create the image");
337
+
338
+ return self;
339
+ }
340
+
341
+ void ray_free_image(ray_image *ptr) {
342
+ delete ptr;
343
+ }
344
+
345
+ VALUE ray_alloc_image(VALUE self) {
346
+ ray_image *ptr = new ray_image(false);
347
+ VALUE ret = Data_Wrap_Struct(self, 0, ray_free_image, ptr);
348
+
349
+ return ret;
350
+ }
351
+
352
+ VALUE ray_create_screen() {
353
+ ray_image *ptr = new ray_image(true);
354
+ VALUE ret = Data_Wrap_Struct(ray_cImage, 0, ray_free_image, ptr);
355
+
356
+ return ret;
357
+ }
358
+
359
+ /*
360
+ @overload save_as(filename)
361
+ Saves the image in a file.
362
+ */
363
+ VALUE ray_image_save_as(VALUE self, VALUE filename) {
364
+ if (!ray_rb2image(self)->save_as(StringValuePtr(filename))) {
365
+ rb_raise(rb_eRuntimeError, "Couldn't save image to file");
366
+ }
367
+
368
+ return self;
369
+ }
370
+
371
+ /*
372
+ @overload fill(col)
373
+ Fills the image with a given color.
374
+ @param [Ray::Color] col The color used to fill the image.
375
+ */
376
+ VALUE ray_image_fill(VALUE self, VALUE col) {
377
+ rb_check_frozen(self);
378
+
379
+ ray_image *img = ray_rb2image(self);
380
+ img->fill(ray_rb2col(col));
381
+
382
+ return self;
383
+ }
384
+
385
+ /* Updates the image. */
386
+ VALUE ray_image_flip(VALUE self) {
387
+ rb_check_frozen(self);
388
+ ray_rb2image(self)->update();
389
+ return self;
390
+ }
391
+
392
+ /*
393
+ @overload blit(hash)
394
+ Blits the receiver on another image.
395
+
396
+ @option hash [Ray::Vector2, #to_vector2] :at Position where the receiver
397
+ should be drawn.
398
+ @option hash [Ray::Rect, Array] :rect Rects that will be copied.
399
+ If an array is given, it
400
+ passed to Ray::Rect.new.
401
+ If the size is (0, 0), it will
402
+ be reset to the image's size.
403
+ @option hash [Ray::Rect, Array] :from Alias for rect
404
+
405
+ @option hash [Ray::Image, required] :on The image on which the receiver should
406
+ be drawn.
407
+
408
+ @option hash [Ray::Image] :to Alias for on.
409
+
410
+ @option hash [Float] :angle Rotation in degrees.
411
+ @option hash [Ray::Vector2, Float] :zoom Zoom level. If a float is
412
+ specified, Vector2[zoom, zoom] will be used.
413
+
414
+ @option hash [Ray::Shader] :shader Shader to be used.
415
+
416
+ @option hash [Ray::Color] :color (Ray::Color.white) Color used, affecting
417
+ the whole image. Each pixel is multiplied by this color.
418
+ */
419
+ VALUE ray_image_blit(VALUE self, VALUE hash) {
420
+ ray_image *origin = ray_rb2image(self);
421
+
422
+ ray_rect from_rect;
423
+ ray_vector2 dest_pos;
424
+
425
+ VALUE pos = rb_hash_aref(hash, RAY_SYM("at"));
426
+ if (!NIL_P(pos))
427
+ dest_pos = ray_convert_to_vector2(pos);
428
+
429
+ VALUE rect = rb_hash_aref(hash, RAY_SYM("rect"));
430
+ if (NIL_P(rect)) rect = rb_hash_aref(hash, RAY_SYM("from"));
431
+
432
+ if (!NIL_P(rect))
433
+ from_rect = ray_convert_to_rect(rect);
434
+
435
+ VALUE surf = rb_hash_aref(hash, RAY_SYM("on"));
436
+ if (surf == Qnil) surf = rb_hash_aref(hash, RAY_SYM("to"));
437
+
438
+ rb_check_frozen(surf);
439
+
440
+ ray_image *target = ray_rb2image(surf);
441
+
442
+ VALUE rb_angle = Qnil, rb_zoom = Qnil;
443
+ float angle = 0.0f;
444
+ ray_vector2 zoom(1.0f, 1.0f);
445
+
446
+ if (!NIL_P(rb_angle = rb_hash_aref(hash, RAY_SYM("angle"))))
447
+ angle = (float)NUM2DBL(rb_angle);
448
+
449
+ if (!NIL_P(rb_zoom = rb_hash_aref(hash, RAY_SYM("zoom")))) {
450
+ if (RAY_IS_A(rb_zoom, rb_cFloat)) {
451
+ float zoom_val = (float)NUM2DBL(rb_zoom);
452
+ zoom = ray_vector2(zoom_val, zoom_val);
453
+ }
454
+ else
455
+ zoom = ray_convert_to_vector2(rb_zoom);
456
+ }
457
+
458
+ if (from_rect.Width == 0 && from_rect.Height == 0) {
459
+ from_rect.Width = origin->width();
460
+ from_rect.Height = origin->height();
461
+ }
462
+
463
+ VALUE rb_shader = rb_hash_aref(hash, RAY_SYM("shader"));
464
+ sf::Shader *shader = NULL;
465
+ if (!NIL_P(rb_shader))
466
+ shader = ray_rb2shader(rb_shader);
467
+
468
+ ray_color color(255, 255, 255);
469
+ VALUE rb_color = rb_hash_aref(hash, RAY_SYM("color"));
470
+ if (!NIL_P(rb_color))
471
+ color = ray_rb2col(rb_color);
472
+
473
+ target->draw_image(*origin, from_rect, dest_pos, angle, zoom,
474
+ shader, color);
475
+
476
+ return surf;
477
+ }
478
+
479
+ /* @return [Integer] Width of the surface */
480
+ VALUE ray_image_width(VALUE self) {
481
+ return INT2FIX(ray_rb2image(self)->width());
482
+ }
483
+
484
+ /* @return [Integer] Height of the surface */
485
+ VALUE ray_image_height(VALUE self) {
486
+ return INT2FIX(ray_rb2image(self)->height());
487
+ }
488
+
489
+ /*
490
+ @overload ==(obj)
491
+ @return [true, false] true if obj manipulates the same surface as the
492
+ receiver.
493
+ */
494
+ VALUE ray_image_is_equal(VALUE self, VALUE obj) {
495
+ if (!RAY_IS_A(obj, ray_cImage))
496
+ return Qfalse;
497
+
498
+ ray_image *first_img = ray_rb2image(self);
499
+ ray_image *sec_img = ray_rb2image(obj);
500
+
501
+ return (*first_img == *sec_img) ? Qtrue : Qfalse;
502
+ }
503
+
504
+
505
+ VALUE ray_image_ensure_unlock(VALUE self) {
506
+ rb_check_frozen(self);
507
+ ray_rb2image(self)->unlock();
508
+ return self;
509
+ }
510
+
511
+ /*
512
+ Locks the image (allow pixel-per-pixel modifications).
513
+ Don't forget to call unlock when you're done. You can also
514
+ pass a bock which will be called before the image gets unlocked
515
+ automatically.
516
+ */
517
+ VALUE ray_image_lock(VALUE self) {
518
+ rb_check_frozen(self);
519
+
520
+ ray_image *image = ray_rb2image(self);
521
+ if (!image->lock())
522
+ rb_raise(rb_eRuntimeError, "Couldn't lock the image");
523
+
524
+ if (rb_block_given_p())
525
+ rb_ensure(rb_yield, Qnil, ray_image_ensure_unlock, self);
526
+
527
+ return self;
528
+ }
529
+
530
+ /*
531
+ Unlocks the image. You must call this once you are done
532
+ modifying the image.
533
+ */
534
+ VALUE ray_image_unlock(VALUE self) {
535
+ return ray_image_ensure_unlock(self);
536
+ }
537
+
538
+ /*
539
+ @overload [](x, y)
540
+ @return [Ray::Color, nil] Pixel at (x, y). Nil if the point is outside the
541
+ image.
542
+ */
543
+ VALUE ray_image_at(VALUE self, VALUE rb_x, VALUE rb_y) {
544
+ ray_image *image = ray_rb2image(self);
545
+
546
+ int x = NUM2INT(rb_x);
547
+ int y = NUM2INT(rb_y);
548
+
549
+ /* (w, h) is not a valid point. Surfaces use 0-based indexing. */
550
+ if (x >= image->width() || y >= image->height())
551
+ return Qnil;
552
+
553
+ return ray_col2rb(image->at(x, y));
554
+ }
555
+
556
+ /*
557
+ @overload []=(x, y, color)
558
+ Sets the color of the point at (x, y)
559
+ @raise ArgumentError If (x, y) is outside the image.
560
+ @note Don't call this if the image isn't locked.
561
+ @example
562
+ img.lock { img[0, 0] = Ray::Color.red }
563
+ */
564
+ VALUE ray_image_set_at(VALUE self, VALUE rb_x, VALUE rb_y, VALUE rb_col) {
565
+ rb_check_frozen(self);
566
+
567
+ ray_image *image = ray_rb2image(self);
568
+
569
+ int x = NUM2INT(rb_x);
570
+ int y = NUM2INT(rb_y);
571
+
572
+ if (x >= image->width() || y >= image->height()) {
573
+ VALUE inspect = rb_inspect(self);
574
+ rb_raise(rb_eArgError, "(%d, %d) is outside %s",
575
+ x, y, StringValuePtr(inspect));
576
+ }
577
+
578
+ if (!image->set_at(x, y, ray_rb2col(rb_col)))
579
+ rb_raise(rb_eRuntimeError, "Trying to set pixel on a non locked image");
580
+
581
+ return rb_col;
582
+ }
583
+
584
+ VALUE ray_image_ensure_unclip(VALUE ary) {
585
+ ray_image *image = ray_rb2image(rb_ary_entry(ary, 0));
586
+ ray_rect rect = ray_rb2rect(rb_ary_entry(ary, 1));
587
+
588
+ image->set_clip(rect);
589
+ rb_gc_unregister_address(&ary);
590
+
591
+ return Qnil;
592
+ }
593
+
594
+ /*
595
+ @overload clip
596
+ @return [Ray::Rect] The current clipping rect
597
+
598
+ @overload clip(rect)
599
+ Changes the clipping rect (the rect which will be changed if something is
600
+ drawn on this image, the rest of the image being ignored.)
601
+
602
+ If a block is given, it is executed, and the old clipping rect is reset
603
+ afterwards.
604
+
605
+ @param [Ray::Rect, Array<Integer>] rect New clipping rect.
606
+ */
607
+ VALUE ray_image_clip(int argc, VALUE *argv, VALUE self) {
608
+ VALUE rb_rect = Qnil;
609
+ rb_scan_args(argc, argv, "01", &rb_rect);
610
+
611
+ ray_image *image = ray_rb2image(self);
612
+
613
+ ray_rect old_rect = image->clip();
614
+
615
+ if (NIL_P(rb_rect))
616
+ return ray_rect2rb(old_rect);
617
+
618
+ rb_check_frozen(self);
619
+
620
+ ray_rect rect = ray_convert_to_rect(rb_rect);
621
+ image->set_clip(rect);
622
+
623
+ if (rb_block_given_p()) {
624
+ VALUE ary = rb_ary_new();
625
+ rb_ary_push(ary, self);
626
+ rb_ary_push(ary, ray_rect2rb(old_rect));
627
+
628
+ rb_gc_register_address(&ary);
629
+
630
+ rb_ensure(rb_yield, Qnil, ray_image_ensure_unclip, ary);
631
+ }
632
+
633
+ return ray_rect2rb(rect);
634
+ }
635
+
636
+ /*
637
+ Binds the image to use it as an OpenGL texture.
638
+ */
639
+ VALUE ray_image_bind(VALUE self) {
640
+ ray_image *img = ray_rb2image(self);
641
+ if (!img->is_image())
642
+ rb_raise(rb_eRuntimeError, "Can't bind screen");
643
+
644
+ img->bind();
645
+ return self;
646
+ }
647
+
648
+ /* Activates the image to draw on it using OpenGL. */
649
+ VALUE ray_image_activate(VALUE self) {
650
+ rb_check_frozen(self);
651
+ ray_rb2image(self)->activate();
652
+
653
+ return self;
654
+ }
655
+
656
+ /*
657
+ @overload draw_shape(shape, shader = nil, color = Ray::Color.white)
658
+ Draws a shape on the image
659
+
660
+ @param [Ray::Shape] shape The shape to be drawn
661
+ @param [Ray::Shader] shader The shader to use with the shape
662
+ @param [Ray::Color] color The color used to multiply each pixel of the
663
+ shape.
664
+ */
665
+ VALUE ray_image_draw_shape(int argc, VALUE *argv, VALUE self) {
666
+ rb_check_frozen(self);
667
+
668
+ VALUE shape, shader, color;
669
+ rb_scan_args(argc, argv, "12", &shape, &shader, &color);
670
+
671
+ rb_check_frozen(self);
672
+
673
+ ray_image *image = ray_rb2image(self);
674
+
675
+ sf::Shape *c_shape = ray_rb2shape(shape);
676
+ sf::Shader *c_shader = NULL;
677
+ if (!NIL_P(shader)) c_shader = ray_rb2shader(shader);
678
+
679
+ ray_color c_color(sf::Color::White);
680
+ if (!NIL_P(color)) c_color = ray_rb2col(color);
681
+
682
+ c_shape->SetColor(c_color);
683
+
684
+ image->draw(*c_shape, c_shader);
685
+ return self;
686
+ }
687
+
688
+ /*
689
+ @overload draw_drawable(drawable)
690
+ Draws a drawable on the image
691
+ */
692
+ VALUE ray_image_draw_drawable(VALUE self, VALUE drawable) {
693
+ rb_check_frozen(self);
694
+
695
+ ray_drawable *c_drawable = ray_rb2drawable(drawable);
696
+ c_drawable->render(self);
697
+
698
+ return self;
699
+ }
700
+
701
+ void Init_ray_image() {
702
+ ray_cImage = rb_define_class_under(ray_mRay, "Image", rb_cObject);
703
+ rb_define_alloc_func(ray_cImage, ray_alloc_image);
704
+ rb_define_method(ray_cImage, "initialize", ray_init_image, 1);
705
+ rb_define_method(ray_cImage, "initialize_copy", ray_init_image_copy, 1);
706
+
707
+ rb_define_singleton_method(ray_cImage, "available?", ray_image_available, 0);
708
+
709
+ rb_define_method(ray_cImage, "save_as", ray_image_save_as, 1);
710
+
711
+ rb_define_method(ray_cImage, "fill", ray_image_fill, 1);
712
+ rb_define_method(ray_cImage, "flip", ray_image_flip, 0);
713
+
714
+ rb_define_method(ray_cImage, "blit", ray_image_blit, 1);
715
+
716
+ rb_define_method(ray_cImage, "width", ray_image_width, 0);
717
+ rb_define_method(ray_cImage, "height", ray_image_height, 0);
718
+
719
+ rb_define_method(ray_cImage, "==", ray_image_is_equal, 1);
720
+
721
+ rb_define_method(ray_cImage, "lock", ray_image_lock, 0);
722
+ rb_define_method(ray_cImage, "unlock", ray_image_unlock, 0);
723
+ rb_define_method(ray_cImage, "[]", ray_image_at, 2);
724
+ rb_define_method(ray_cImage, "[]=", ray_image_set_at, 3);
725
+
726
+ rb_define_method(ray_cImage, "clip", ray_image_clip, -1);
727
+
728
+ rb_define_method(ray_cImage, "bind", ray_image_bind, 0);
729
+ rb_define_method(ray_cImage, "activate", ray_image_activate, 0);
730
+
731
+ rb_define_method(ray_cImage, "draw_shape", ray_image_draw_shape, -1);
732
+ rb_define_method(ray_cImage, "draw_drawable", ray_image_draw_drawable, 1);
733
+ }