ruby2d 0.2.1 → 0.3.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.
data/ext/ruby2d/ruby2d.c CHANGED
@@ -1,104 +1,465 @@
1
- #include <ruby.h>
1
+ // ruby2d.c – Native C extension for Ruby and MRuby
2
+
3
+ // Simple 2D includes
2
4
  #include <simple2d.h>
3
5
 
6
+ // Ruby includes
7
+ #if MRUBY
8
+ #include <mruby.h>
9
+ #include <mruby/array.h>
10
+ #include <mruby/string.h>
11
+ #include <mruby/variable.h>
12
+ #include <mruby/numeric.h>
13
+ #include <mruby/data.h>
14
+ #include <mruby/irep.h>
15
+ #else
16
+ #include <ruby.h>
17
+ #endif
18
+
19
+ // Define Ruby type conversions in MRuby
20
+ #if MRUBY
21
+ // C to MRuby types
22
+ #define INT2FIX(val) (mrb_fixnum_value(val))
23
+ #define INT2NUM(val) (mrb_fixnum_value((mrb_int)(val)))
24
+ #define UINT2NUM(val) (INT2NUM((unsigned mrb_int)(val)))
25
+ #define LL2NUM(val) (INT2NUM(val))
26
+ #define ULL2NUM(val) (INT2NUM((unsigned __int64)(val)))
27
+ #define DBL2NUM(val) (mrb_float_value(mrb, (mrb_float)(val)))
28
+ // MRuby to C types
29
+ #define TO_PDT(val) ((mrb_type(val) == MRB_TT_FLOAT) ? mrb_float(val) : mrb_int(mrb, (val)))
30
+ #define FIX2INT(val) (mrb_fixnum(val))
31
+ #define NUM2INT(val) ((mrb_int)TO_PDT(val))
32
+ #define NUM2UINT(val) ((unsigned mrb_int)TO_PDT(val))
33
+ #define NUM2LONG(val) (mrb_int(mrb, (val)))
34
+ #define NUM2LL(val) ((__int64)(TO_PDT(val)))
35
+ #define NUM2ULL(val) ((unsigned __int64)(TO_PDT(val)))
36
+ #define NUM2DBL(val) (mrb_to_flo(mrb, (val)))
37
+ #define NUM2CHR(val) ((mrb_string_p(val) && (RSTRING_LEN(val)>=1)) ? RSTRING_PTR(val)[0] : (char)(NUM2INT(val) & 0xff))
38
+ // Memory management
39
+ #define ALLOC(type) ((type *)mrb_malloc(mrb, sizeof(type)))
40
+ #define ALLOC_N(type, n) ((type *)mrb_malloc(mrb, sizeof(type) * (n)))
41
+ #define ALLOCA_N(type, n) ((type *)alloca(sizeof(type) * (n)))
42
+ #define MEMCMP(p1, p2, type, n) (memcmp((p1), (p2), sizeof(type)*(n)))
43
+ #endif
44
+
45
+ // Define common types and API calls, mapping to both Ruby and MRuby APIs
46
+ #if MRUBY
47
+ // MRuby
48
+ #define R_VAL mrb_value
49
+ #define R_NIL (mrb_nil_value())
50
+ #define R_TRUE (mrb_true_value())
51
+ #define R_FALSE (mrb_false_value())
52
+ #define R_CLASS struct RClass *
53
+ #define r_iv_get(self, var) mrb_iv_get(mrb, self, mrb_intern_lit(mrb, var))
54
+ #define r_iv_set(self, var, val) mrb_iv_set(mrb, self, mrb_intern_lit(mrb, var), val)
55
+ #define r_funcall(self, method, num_args, ...) mrb_funcall(mrb, self, method, num_args, ##__VA_ARGS__)
56
+ #define r_str_new(str) mrb_str_new(mrb, str, strlen(str))
57
+ #define r_test(val) (mrb_test(val) == true)
58
+ #define r_ary_entry(ary, pos) mrb_ary_entry(ary, pos)
59
+ #define r_data_wrap_struct(name, data) mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &name##_data_type, data))
60
+ #define r_data_get_struct(self, var, mrb_type, rb_type, data) Data_Get_Struct(mrb, r_iv_get(self, var), mrb_type, data)
61
+ #define r_define_module(name) mrb_module_get(mrb, name)
62
+ #define r_define_class(module, name) mrb_class_get_under(mrb, module, name);
63
+ #define r_define_method(class, name, function, args) mrb_define_method(mrb, class, name, function, args)
64
+ #define r_args_none (MRB_ARGS_NONE())
65
+ #define r_args_req(n) MRB_ARGS_REQ(n)
66
+ #else
67
+ // Ruby
68
+ #define R_VAL VALUE
69
+ #define R_NIL Qnil
70
+ #define R_TRUE Qtrue
71
+ #define R_FALSE Qfalse
72
+ #define R_CLASS R_VAL
73
+ #define r_iv_get(self, var) rb_iv_get(self, var)
74
+ #define r_iv_set(self, var, val) rb_iv_set(self, var, val)
75
+ #define r_funcall(self, method, num_args, ...) rb_funcall(self, rb_intern(method), num_args, ##__VA_ARGS__)
76
+ #define r_str_new(str) rb_str_new2(str)
77
+ #define r_test(val) (val != Qfalse && val != Qnil)
78
+ #define r_ary_entry(ary, pos) rb_ary_entry(ary, pos)
79
+ #define r_data_wrap_struct(name, data) Data_Wrap_Struct(rb_cObject, NULL, (free_##name), data)
80
+ #define r_data_get_struct(self, var, mrb_type, rb_type, data) Data_Get_Struct(r_iv_get(self, var), rb_type, data)
81
+ #define r_define_module(name) rb_define_module(name)
82
+ #define r_define_class(module, name) rb_define_class_under(module, name, rb_cObject);
83
+ #define r_define_method(class, name, function, args) rb_define_method(class, name, function, args)
84
+ #define r_args_none 0
85
+ #define r_args_req(n) n
86
+ #endif
87
+
4
88
  // @type_id values for rendering
5
- #define TRIANGLE 1
6
- #define QUAD 2
7
- #define IMAGE 3
8
- #define TEXT 4
89
+ #define R2D_TRIANGLE 1
90
+ #define R2D_QUAD 2
91
+ #define R2D_IMAGE 3
92
+ #define R2D_SPRITE 4
93
+ #define R2D_TEXT 5
94
+
95
+ // Create the MRuby context
96
+ #if MRUBY
97
+ static mrb_state *mrb;
98
+ #endif
9
99
 
10
100
  // Ruby 2D window
11
- VALUE self;
101
+ static R_VAL ruby2d_window;
12
102
 
13
103
  // Simple 2D window
14
- S2D_Window *window;
15
-
16
- // Ruby data types
17
- static VALUE ruby2d_module;
18
- static VALUE ruby2d_window_klass;
19
- static VALUE c_data_klass;
20
-
21
- // Structures for Ruby 2D classes
22
- struct image_data {
23
- S2D_Image *img;
24
- };
25
- struct text_data {
26
- S2D_Text *txt;
27
- };
28
- struct sound_data {
29
- S2D_Sound *snd;
30
- };
104
+ static S2D_Window *window;
105
+
106
+
107
+ // Method signatures and structures for Ruby 2D classes
108
+ #if MRUBY
109
+ static void free_image(mrb_state *mrb, void *p_);
110
+ static const struct mrb_data_type image_data_type = {
111
+ "image", free_image
112
+ };
113
+ static void free_sprite(mrb_state *mrb, void *p_);
114
+ static const struct mrb_data_type sprite_data_type = {
115
+ "sprite", free_sprite
116
+ };
117
+ static void free_text(mrb_state *mrb, void *p_);
118
+ static const struct mrb_data_type text_data_type = {
119
+ "text", free_text
120
+ };
121
+ static void free_sound(mrb_state *mrb, void *p_);
122
+ static const struct mrb_data_type sound_data_type = {
123
+ "sound", free_sound
124
+ };
125
+ static void free_music(mrb_state *mrb, void *p_);
126
+ static const struct mrb_data_type music_data_type = {
127
+ "music", free_music
128
+ };
129
+ #else
130
+ static void free_image(S2D_Image *img);
131
+ static void free_sprite(S2D_Sprite *spr);
132
+ static void free_text(S2D_Text *txt);
133
+ static void free_sound(S2D_Sound *snd);
134
+ static void free_music(S2D_Music *mus);
135
+ #endif
31
136
 
32
137
 
33
138
  /*
34
- * Function pointer to close the Simple 2D window
139
+ * Function pointer to free the Simple 2D window
35
140
  */
36
- static void close_window() {
37
- S2D_Close(window);
141
+ static void free_window() {
142
+ S2D_FreeWindow(window);
143
+ }
144
+
145
+
146
+ /*
147
+ * Ruby2D::Image#init
148
+ * Initialize image structure data
149
+ */
150
+ #if MRUBY
151
+ static R_VAL ruby2d_image_init(mrb_state* mrb, R_VAL self) {
152
+ mrb_value path;
153
+ mrb_get_args(mrb, "o", &path);
154
+ #else
155
+ static R_VAL ruby2d_image_init(R_VAL self, R_VAL path) {
156
+ #endif
157
+ sprintf(S2D_msg, "Init image: %s", RSTRING_PTR(path));
158
+ S2D_Log(S2D_msg, S2D_INFO);
159
+ S2D_Image *img = S2D_CreateImage(RSTRING_PTR(path));
160
+ r_iv_set(self, "@data", r_data_wrap_struct(image, img));
161
+ return R_NIL;
38
162
  }
39
163
 
40
164
 
41
165
  /*
42
166
  * Free image structure attached to Ruby 2D `Image` class
43
167
  */
44
- static void free_image(struct image_data *data) {
45
- S2D_FreeImage(data->img);
46
- xfree(data);
168
+ #if MRUBY
169
+ static void free_image(mrb_state *mrb, void *p_) {
170
+ S2D_Image *img = (S2D_Image *)p_;
171
+ #else
172
+ static void free_image(S2D_Image *img) {
173
+ #endif
174
+ sprintf(S2D_msg, "Free image: %i, %i", img->x, img->y);
175
+ S2D_Log(S2D_msg, S2D_INFO);
176
+ S2D_FreeImage(img);
47
177
  }
48
178
 
49
179
 
50
180
  /*
51
- * Initialize image structure data
181
+ * Ruby2D::Sprite#init
182
+ * Initialize sprite structure data
52
183
  */
53
- static VALUE init_image(char *path) {
54
- struct image_data *data = ALLOC(struct image_data);
55
- data->img = S2D_CreateImage(path);
56
- return Data_Wrap_Struct(c_data_klass, NULL, free_image, data);
184
+ #if MRUBY
185
+ static R_VAL ruby2d_sprite_init(mrb_state* mrb, R_VAL self) {
186
+ mrb_value path;
187
+ mrb_get_args(mrb, "o", &path);
188
+ #else
189
+ static R_VAL ruby2d_sprite_init(R_VAL self, R_VAL path) {
190
+ #endif
191
+ sprintf(S2D_msg, "Init sprite: %s", RSTRING_PTR(path));
192
+ S2D_Log(S2D_msg, S2D_INFO);
193
+ S2D_Sprite *spr = S2D_CreateSprite(RSTRING_PTR(path));
194
+ r_iv_set(self, "@data", r_data_wrap_struct(sprite, spr));
195
+ return R_NIL;
57
196
  }
58
197
 
59
198
 
60
199
  /*
61
- * Free text structure attached to Ruby 2D `Text` class
200
+ * Free sprite structure attached to Ruby 2D `Sprite` class
62
201
  */
63
- static void free_text(struct text_data *data) {
64
- S2D_FreeText(data->txt);
65
- xfree(data);
202
+ #if MRUBY
203
+ static void free_sprite(mrb_state *mrb, void *p_) {
204
+ S2D_Sprite *spr = (S2D_Sprite *)p_;
205
+ #else
206
+ static void free_sprite(S2D_Sprite *spr) {
207
+ #endif
208
+ sprintf(S2D_msg, "Free sprite: %i, %i", spr->x, spr->y);
209
+ S2D_Log(S2D_msg, S2D_INFO);
210
+ S2D_FreeSprite(spr);
66
211
  }
67
212
 
68
213
 
69
214
  /*
215
+ * Ruby2D::Text#init
70
216
  * Initialize text structure data
71
217
  */
72
- static VALUE init_text(char *font, char *msg, int size) {
73
- struct text_data *data = ALLOC(struct text_data);
74
- data->txt = S2D_CreateText(font, msg, size);
75
- return Data_Wrap_Struct(c_data_klass, NULL, free_text, data);
218
+ #if MRUBY
219
+ static R_VAL ruby2d_text_init(mrb_state* mrb, R_VAL self) {
220
+ #else
221
+ static R_VAL ruby2d_text_init(R_VAL self) {
222
+ #endif
223
+ sprintf(S2D_msg, "Init text: %s", RSTRING_PTR(r_iv_get(self, "@text")));
224
+ S2D_Log(S2D_msg, S2D_INFO);
225
+
226
+ S2D_Text *txt = S2D_CreateText(
227
+ RSTRING_PTR(r_iv_get(self, "@font")),
228
+ RSTRING_PTR(r_iv_get(self, "@text")),
229
+ NUM2DBL(r_iv_get(self, "@size"))
230
+ );
231
+
232
+ r_iv_set(self, "@data", r_data_wrap_struct(text, txt));
233
+ return R_NIL;
234
+ }
235
+
236
+
237
+ /*
238
+ * Ruby2D::Text#text=
239
+ */
240
+ #if MRUBY
241
+ static R_VAL ruby2d_text_equals(mrb_state* mrb, R_VAL self) {
242
+ mrb_value text;
243
+ mrb_get_args(mrb, "o", &text);
244
+ #else
245
+ static R_VAL ruby2d_text_equals(R_VAL self, R_VAL text) {
246
+ r_iv_set(self, "@text", text);
247
+ #endif
248
+
249
+ // If called before window is shown, return
250
+ if (!r_test(ruby2d_window)) return R_NIL;
251
+
252
+ S2D_Text *txt;
253
+ r_data_get_struct(self, "@data", &text_data_type, S2D_Text, txt);
254
+
255
+ S2D_SetText(txt, RSTRING_PTR(text));
256
+ return R_NIL;
257
+ }
258
+
259
+
260
+ /*
261
+ * Free text structure attached to Ruby 2D `Text` class
262
+ */
263
+ #if MRUBY
264
+ static void free_text(mrb_state *mrb, void *p_) {
265
+ S2D_Text *txt = (S2D_Text *)p_;
266
+ #else
267
+ static void free_text(S2D_Text *txt) {
268
+ #endif
269
+ sprintf(S2D_msg, "Free text: %s", txt->msg);
270
+ S2D_Log(S2D_msg, S2D_INFO);
271
+ S2D_FreeText(txt);
272
+ }
273
+
274
+
275
+ /*
276
+ * Ruby2D::Sound#init
277
+ * Initialize sound structure data
278
+ */
279
+ #if MRUBY
280
+ static R_VAL ruby2d_sound_init(mrb_state* mrb, R_VAL self) {
281
+ mrb_value path;
282
+ mrb_get_args(mrb, "o", &path);
283
+ #else
284
+ static R_VAL ruby2d_sound_init(R_VAL self, R_VAL path) {
285
+ #endif
286
+ sprintf(S2D_msg, "Init sound: %s", RSTRING_PTR(path));
287
+ S2D_Log(S2D_msg, S2D_INFO);
288
+ S2D_Sound *snd = S2D_CreateSound(RSTRING_PTR(path));
289
+ r_iv_set(self, "@data", r_data_wrap_struct(sound, snd));
290
+ return R_NIL;
291
+ }
292
+
293
+
294
+ /*
295
+ * Ruby2D::Sound#play
296
+ */
297
+ #if MRUBY
298
+ static R_VAL ruby2d_sound_play(mrb_state* mrb, R_VAL self) {
299
+ #else
300
+ static R_VAL ruby2d_sound_play(R_VAL self) {
301
+ #endif
302
+ S2D_Sound *snd;
303
+ r_data_get_struct(self, "@data", &sound_data_type, S2D_Sound, snd);
304
+ S2D_PlaySound(snd);
305
+ return R_NIL;
306
+ }
307
+
308
+
309
+ /*
310
+ * Free sound structure attached to Ruby 2D `Sound` class
311
+ */
312
+ #if MRUBY
313
+ static void free_sound(mrb_state *mrb, void *p_) {
314
+ S2D_Sound *snd = (S2D_Sound *)p_;
315
+ #else
316
+ static void free_sound(S2D_Sound *snd) {
317
+ #endif
318
+ sprintf(S2D_msg, "Free sound");
319
+ S2D_Log(S2D_msg, S2D_INFO);
320
+ S2D_FreeSound(snd);
321
+ }
322
+
323
+
324
+ /*
325
+ * Ruby2D::Music#init
326
+ * Initialize music structure data
327
+ */
328
+ #if MRUBY
329
+ static R_VAL ruby2d_music_init(mrb_state* mrb, R_VAL self) {
330
+ mrb_value path;
331
+ mrb_get_args(mrb, "o", &path);
332
+ #else
333
+ static R_VAL ruby2d_music_init(R_VAL self, R_VAL path) {
334
+ #endif
335
+ sprintf(S2D_msg, "Init music: %s", RSTRING_PTR(path));
336
+ S2D_Log(S2D_msg, S2D_INFO);
337
+ S2D_Music *mus = S2D_CreateMusic(RSTRING_PTR(path));
338
+ r_iv_set(self, "@data", r_data_wrap_struct(music, mus));
339
+ return R_NIL;
340
+ }
341
+
342
+
343
+ /*
344
+ * Ruby2D::Music#play
345
+ */
346
+ #if MRUBY
347
+ static R_VAL ruby2d_music_play(mrb_state* mrb, R_VAL self) {
348
+ #else
349
+ static R_VAL ruby2d_music_play(R_VAL self) {
350
+ #endif
351
+ S2D_Music *mus;
352
+ r_data_get_struct(self, "@data", &music_data_type, S2D_Music, mus);
353
+ S2D_PlayMusic(mus, r_test(r_iv_get(self, "@loop")));
354
+ return R_NIL;
355
+ }
356
+
357
+
358
+ /*
359
+ * Ruby2D::Music#pause
360
+ */
361
+ #if MRUBY
362
+ static R_VAL ruby2d_music_pause(mrb_state* mrb, R_VAL self) {
363
+ #else
364
+ static R_VAL ruby2d_music_pause(R_VAL self) {
365
+ #endif
366
+ S2D_PauseMusic();
367
+ return R_NIL;
368
+ }
369
+
370
+
371
+ /*
372
+ * Ruby2D::Music#resume
373
+ */
374
+ #if MRUBY
375
+ static R_VAL ruby2d_music_resume(mrb_state* mrb, R_VAL self) {
376
+ #else
377
+ static R_VAL ruby2d_music_resume(R_VAL self) {
378
+ #endif
379
+ S2D_ResumeMusic();
380
+ return R_NIL;
381
+ }
382
+
383
+
384
+ /*
385
+ * Ruby2D::Music#stop
386
+ */
387
+ #if MRUBY
388
+ static R_VAL ruby2d_music_stop(mrb_state* mrb, R_VAL self) {
389
+ #else
390
+ static R_VAL ruby2d_music_stop(R_VAL self) {
391
+ #endif
392
+ S2D_StopMusic();
393
+ return R_NIL;
394
+ }
395
+
396
+
397
+ /*
398
+ * Ruby2D::Music#fadeout
399
+ */
400
+ #if MRUBY
401
+ static R_VAL ruby2d_music_fadeout(mrb_state* mrb, R_VAL self) {
402
+ mrb_value ms;
403
+ mrb_get_args(mrb, "o", &ms);
404
+ #else
405
+ static R_VAL ruby2d_music_fadeout(R_VAL self, R_VAL ms) {
406
+ #endif
407
+ S2D_FadeOutMusic(NUM2INT(ms));
408
+ return R_NIL;
409
+ }
410
+
411
+
412
+ /*
413
+ * Free sound structure attached to Ruby 2D `Sound` class
414
+ */
415
+ #if MRUBY
416
+ static void free_music(mrb_state *mrb, void *p_) {
417
+ S2D_Music *mus = (S2D_Music *)p_;
418
+ #else
419
+ static void free_music(S2D_Music *mus) {
420
+ #endif
421
+ sprintf(S2D_msg, "Free music");
422
+ S2D_Log(S2D_msg, S2D_INFO);
423
+ S2D_FreeMusic(mus);
76
424
  }
77
425
 
78
426
 
79
427
  /*
80
428
  * Simple 2D `on_key` input callback function
81
429
  */
82
- void on_key(const char *key) {
83
- rb_funcall(self, rb_intern("key_callback"), 1, rb_str_new2(key));
430
+ static void on_key(S2D_Event e, const char *key) {
431
+ switch (e) {
432
+ case S2D_KEYDOWN:
433
+ r_funcall(ruby2d_window, "key_down_callback", 1, r_str_new(key));
434
+ break;
435
+
436
+ case S2D_KEY:
437
+ r_funcall(ruby2d_window, "key_callback", 1, r_str_new(key));
438
+ break;
439
+
440
+ case S2D_KEYUP:
441
+ r_funcall(ruby2d_window, "key_up_callback", 1, r_str_new(key));
442
+ break;
443
+ }
84
444
  }
85
445
 
86
446
 
87
447
  /*
88
- * Simple 2D `on_key_down` input callback function
448
+ * Simple 2D `on_mouse` input callback function
89
449
  */
90
- void on_key_down(const char *key) {
91
- rb_funcall(self, rb_intern("key_down_callback"), 1, rb_str_new2(key));
450
+ void on_mouse(int x, int y) {
451
+ r_funcall(ruby2d_window, "mouse_callback", 3, r_str_new("any"), INT2NUM(x), INT2NUM(y));
92
452
  }
93
453
 
94
454
 
95
455
  /*
96
456
  * Simple 2D `on_controller` input callback function
97
457
  */
98
- void on_controller(bool is_axis, int axis, int val, bool is_btn, int btn) {
99
- rb_funcall(self, rb_intern("controller_callback"), 5,
100
- is_axis ? Qtrue : Qfalse, INT2NUM(axis), INT2NUM(val),
101
- is_btn ? Qtrue : Qfalse, INT2NUM(btn)
458
+ static void on_controller(int which, bool is_axis, int axis, int val, bool is_btn, int btn, bool pressed) {
459
+ r_funcall(ruby2d_window, "controller_callback", 7,
460
+ INT2NUM(which),
461
+ is_axis ? R_TRUE : R_FALSE, INT2NUM(axis), INT2NUM(val),
462
+ is_btn ? R_TRUE : R_FALSE, INT2NUM(btn), pressed ? R_TRUE : R_FALSE
102
463
  );
103
464
  }
104
465
 
@@ -106,137 +467,171 @@ void on_controller(bool is_axis, int axis, int val, bool is_btn, int btn) {
106
467
  /*
107
468
  * Simple 2D `update` callback function
108
469
  */
109
- void update() {
470
+ static void update() {
110
471
 
111
472
  // Set the cursor
112
- rb_iv_set(self, "@mouse_x", INT2NUM(window->mouse.x));
113
- rb_iv_set(self, "@mouse_y", INT2NUM(window->mouse.y));
473
+ r_iv_set(ruby2d_window, "@mouse_x", INT2NUM(window->mouse.x));
474
+ r_iv_set(ruby2d_window, "@mouse_y", INT2NUM(window->mouse.y));
475
+
476
+ // Store frames
477
+ r_iv_set(ruby2d_window, "@frames", DBL2NUM(window->frames));
114
478
 
115
479
  // Store frame rate
116
- rb_iv_set(self, "@fps", INT2NUM(window->fps));
480
+ r_iv_set(ruby2d_window, "@fps", DBL2NUM(window->fps));
117
481
 
118
482
  // Call update proc, `window.update`
119
- rb_funcall(self, rb_intern("update_callback"), 0);
483
+ r_funcall(ruby2d_window, "update_callback", 0);
120
484
  }
121
485
 
122
486
 
123
487
  /*
124
488
  * Simple 2D `render` callback function
125
489
  */
126
- void render() {
490
+ static void render() {
491
+
492
+ // Set background color
493
+ R_VAL bc = r_iv_get(ruby2d_window, "@background");
494
+ window->background.r = NUM2DBL(r_iv_get(bc, "@r"));
495
+ window->background.g = NUM2DBL(r_iv_get(bc, "@g"));
496
+ window->background.b = NUM2DBL(r_iv_get(bc, "@b"));
497
+ window->background.a = NUM2DBL(r_iv_get(bc, "@a"));
127
498
 
128
499
  // Read window objects
129
- VALUE objects = rb_iv_get(self, "@objects");
130
- int num_objects = NUM2INT(rb_funcall(objects, rb_intern("count"), 0));
500
+ R_VAL objects = r_iv_get(ruby2d_window, "@objects");
501
+ int num_objects = NUM2INT(r_funcall(objects, "length", 0));
131
502
 
132
503
  // Switch on each object type
133
504
  for (int i = 0; i < num_objects; ++i) {
134
505
 
135
- VALUE el = rb_ary_entry(objects, i);
136
- int type_id = NUM2INT(rb_iv_get(el, "@type_id"));
506
+ R_VAL el = r_ary_entry(objects, i);
507
+ int type_id = NUM2INT(r_iv_get(el, "@type_id"));
137
508
 
138
509
  // Switch on the object's type_id
139
510
  switch(type_id) {
140
511
 
141
- case TRIANGLE: {
142
- VALUE c1 = rb_iv_get(el, "@c1");
143
- VALUE c2 = rb_iv_get(el, "@c2");
144
- VALUE c3 = rb_iv_get(el, "@c3");
512
+ case R2D_TRIANGLE: {
513
+ R_VAL c1 = r_iv_get(el, "@c1");
514
+ R_VAL c2 = r_iv_get(el, "@c2");
515
+ R_VAL c3 = r_iv_get(el, "@c3");
145
516
 
146
517
  S2D_DrawTriangle(
147
- NUM2DBL(rb_iv_get(el, "@x1")),
148
- NUM2DBL(rb_iv_get(el, "@y1")),
149
- NUM2DBL(rb_iv_get(c1, "@r")),
150
- NUM2DBL(rb_iv_get(c1, "@g")),
151
- NUM2DBL(rb_iv_get(c1, "@b")),
152
- NUM2DBL(rb_iv_get(c1, "@a")),
518
+ NUM2DBL(r_iv_get(el, "@x1")),
519
+ NUM2DBL(r_iv_get(el, "@y1")),
520
+ NUM2DBL(r_iv_get(c1, "@r")),
521
+ NUM2DBL(r_iv_get(c1, "@g")),
522
+ NUM2DBL(r_iv_get(c1, "@b")),
523
+ NUM2DBL(r_iv_get(c1, "@a")),
153
524
 
154
- NUM2DBL(rb_iv_get(el, "@x2")),
155
- NUM2DBL(rb_iv_get(el, "@y2")),
156
- NUM2DBL(rb_iv_get(c2, "@r")),
157
- NUM2DBL(rb_iv_get(c2, "@g")),
158
- NUM2DBL(rb_iv_get(c2, "@b")),
159
- NUM2DBL(rb_iv_get(c2, "@a")),
525
+ NUM2DBL(r_iv_get(el, "@x2")),
526
+ NUM2DBL(r_iv_get(el, "@y2")),
527
+ NUM2DBL(r_iv_get(c2, "@r")),
528
+ NUM2DBL(r_iv_get(c2, "@g")),
529
+ NUM2DBL(r_iv_get(c2, "@b")),
530
+ NUM2DBL(r_iv_get(c2, "@a")),
160
531
 
161
- NUM2DBL(rb_iv_get(el, "@x3")),
162
- NUM2DBL(rb_iv_get(el, "@y3")),
163
- NUM2DBL(rb_iv_get(c3, "@r")),
164
- NUM2DBL(rb_iv_get(c3, "@g")),
165
- NUM2DBL(rb_iv_get(c3, "@b")),
166
- NUM2DBL(rb_iv_get(c3, "@a"))
532
+ NUM2DBL(r_iv_get(el, "@x3")),
533
+ NUM2DBL(r_iv_get(el, "@y3")),
534
+ NUM2DBL(r_iv_get(c3, "@r")),
535
+ NUM2DBL(r_iv_get(c3, "@g")),
536
+ NUM2DBL(r_iv_get(c3, "@b")),
537
+ NUM2DBL(r_iv_get(c3, "@a"))
167
538
  );
168
539
  }
169
540
  break;
170
541
 
171
- case QUAD: {
172
- VALUE c1 = rb_iv_get(el, "@c1");
173
- VALUE c2 = rb_iv_get(el, "@c2");
174
- VALUE c3 = rb_iv_get(el, "@c3");
175
- VALUE c4 = rb_iv_get(el, "@c4");
542
+ case R2D_QUAD: {
543
+ R_VAL c1 = r_iv_get(el, "@c1");
544
+ R_VAL c2 = r_iv_get(el, "@c2");
545
+ R_VAL c3 = r_iv_get(el, "@c3");
546
+ R_VAL c4 = r_iv_get(el, "@c4");
176
547
 
177
548
  S2D_DrawQuad(
178
- NUM2DBL(rb_iv_get(el, "@x1")),
179
- NUM2DBL(rb_iv_get(el, "@y1")),
180
- NUM2DBL(rb_iv_get(c1, "@r")),
181
- NUM2DBL(rb_iv_get(c1, "@g")),
182
- NUM2DBL(rb_iv_get(c1, "@b")),
183
- NUM2DBL(rb_iv_get(c1, "@a")),
184
-
185
- NUM2DBL(rb_iv_get(el, "@x2")),
186
- NUM2DBL(rb_iv_get(el, "@y2")),
187
- NUM2DBL(rb_iv_get(c2, "@r")),
188
- NUM2DBL(rb_iv_get(c2, "@g")),
189
- NUM2DBL(rb_iv_get(c2, "@b")),
190
- NUM2DBL(rb_iv_get(c2, "@a")),
191
-
192
- NUM2DBL(rb_iv_get(el, "@x3")),
193
- NUM2DBL(rb_iv_get(el, "@y3")),
194
- NUM2DBL(rb_iv_get(c3, "@r")),
195
- NUM2DBL(rb_iv_get(c3, "@g")),
196
- NUM2DBL(rb_iv_get(c3, "@b")),
197
- NUM2DBL(rb_iv_get(c3, "@a")),
198
-
199
- NUM2DBL(rb_iv_get(el, "@x4")),
200
- NUM2DBL(rb_iv_get(el, "@y4")),
201
- NUM2DBL(rb_iv_get(c4, "@r")),
202
- NUM2DBL(rb_iv_get(c4, "@g")),
203
- NUM2DBL(rb_iv_get(c4, "@b")),
204
- NUM2DBL(rb_iv_get(c4, "@a"))
549
+ NUM2DBL(r_iv_get(el, "@x1")),
550
+ NUM2DBL(r_iv_get(el, "@y1")),
551
+ NUM2DBL(r_iv_get(c1, "@r")),
552
+ NUM2DBL(r_iv_get(c1, "@g")),
553
+ NUM2DBL(r_iv_get(c1, "@b")),
554
+ NUM2DBL(r_iv_get(c1, "@a")),
555
+
556
+ NUM2DBL(r_iv_get(el, "@x2")),
557
+ NUM2DBL(r_iv_get(el, "@y2")),
558
+ NUM2DBL(r_iv_get(c2, "@r")),
559
+ NUM2DBL(r_iv_get(c2, "@g")),
560
+ NUM2DBL(r_iv_get(c2, "@b")),
561
+ NUM2DBL(r_iv_get(c2, "@a")),
562
+
563
+ NUM2DBL(r_iv_get(el, "@x3")),
564
+ NUM2DBL(r_iv_get(el, "@y3")),
565
+ NUM2DBL(r_iv_get(c3, "@r")),
566
+ NUM2DBL(r_iv_get(c3, "@g")),
567
+ NUM2DBL(r_iv_get(c3, "@b")),
568
+ NUM2DBL(r_iv_get(c3, "@a")),
569
+
570
+ NUM2DBL(r_iv_get(el, "@x4")),
571
+ NUM2DBL(r_iv_get(el, "@y4")),
572
+ NUM2DBL(r_iv_get(c4, "@r")),
573
+ NUM2DBL(r_iv_get(c4, "@g")),
574
+ NUM2DBL(r_iv_get(c4, "@b")),
575
+ NUM2DBL(r_iv_get(c4, "@a"))
205
576
  );
206
577
  }
207
578
  break;
208
579
 
209
- case IMAGE: {
210
- if (rb_iv_get(el, "@data") == Qnil) {
211
- VALUE data = init_image(RSTRING_PTR(rb_iv_get(el, "@path")));
212
- rb_iv_set(el, "@data", data);
213
- }
580
+ case R2D_IMAGE: {
581
+ S2D_Image *img;
582
+ r_data_get_struct(el, "@data", &image_data_type, S2D_Image, img);
583
+
584
+ img->x = NUM2DBL(r_iv_get(el, "@x"));
585
+ img->y = NUM2DBL(r_iv_get(el, "@y"));
586
+
587
+ R_VAL w = r_iv_get(el, "@width");
588
+ R_VAL h = r_iv_get(el, "@height");
589
+ if (r_test(w)) img->width = NUM2INT(w);
590
+ if (r_test(h)) img->height = NUM2INT(h);
591
+
592
+ R_VAL c = r_iv_get(el, "@color");
593
+ img->color.r = NUM2DBL(r_iv_get(c, "@r"));
594
+ img->color.g = NUM2DBL(r_iv_get(c, "@g"));
595
+ img->color.b = NUM2DBL(r_iv_get(c, "@b"));
596
+ img->color.a = NUM2DBL(r_iv_get(c, "@a"));
597
+
598
+ S2D_DrawImage(img);
599
+ }
600
+ break;
601
+
602
+ case R2D_SPRITE: {
603
+ S2D_Sprite *spr;
604
+ r_data_get_struct(el, "@data", &sprite_data_type, S2D_Sprite, spr);
214
605
 
215
- struct image_data *data;
216
- Data_Get_Struct(rb_iv_get(el, "@data"), struct image_data, data);
606
+ spr->x = NUM2DBL(r_iv_get(el, "@x"));
607
+ spr->y = NUM2DBL(r_iv_get(el, "@y"));
217
608
 
218
- data->img->x = NUM2DBL(rb_iv_get(el, "@x"));
219
- data->img->y = NUM2DBL(rb_iv_get(el, "@y"));
220
- S2D_DrawImage(data->img);
609
+ S2D_ClipSprite(
610
+ spr,
611
+ NUM2INT(r_iv_get(el, "@clip_x")),
612
+ NUM2INT(r_iv_get(el, "@clip_y")),
613
+ NUM2INT(r_iv_get(el, "@clip_w")),
614
+ NUM2INT(r_iv_get(el, "@clip_h"))
615
+ );
616
+
617
+ S2D_DrawSprite(spr);
221
618
  }
222
619
  break;
223
620
 
224
- case TEXT: {
225
- if (rb_iv_get(el, "@data") == Qnil) {
226
- VALUE data = init_text(
227
- RSTRING_PTR(rb_iv_get(el, "@font")),
228
- RSTRING_PTR(rb_iv_get(el, "@text")),
229
- NUM2DBL(rb_iv_get(el, "@size"))
230
- );
231
- rb_iv_set(el, "@data", data);
232
- }
621
+ case R2D_TEXT: {
622
+ S2D_Text *txt;
623
+ r_data_get_struct(el, "@data", &text_data_type, S2D_Text, txt);
624
+
625
+ txt->x = NUM2DBL(r_iv_get(el, "@x"));
626
+ txt->y = NUM2DBL(r_iv_get(el, "@y"));
233
627
 
234
- struct text_data *data;
235
- Data_Get_Struct(rb_iv_get(el, "@data"), struct text_data, data);
628
+ R_VAL c = r_iv_get(el, "@color");
629
+ txt->color.r = NUM2DBL(r_iv_get(c, "@r"));
630
+ txt->color.g = NUM2DBL(r_iv_get(c, "@g"));
631
+ txt->color.b = NUM2DBL(r_iv_get(c, "@b"));
632
+ txt->color.a = NUM2DBL(r_iv_get(c, "@a"));
236
633
 
237
- data->txt->x = NUM2DBL(rb_iv_get(el, "@x"));
238
- data->txt->y = NUM2DBL(rb_iv_get(el, "@y"));
239
- S2D_DrawText(data->txt);
634
+ S2D_DrawText(txt);
240
635
  }
241
636
  break;
242
637
  }
@@ -247,43 +642,159 @@ void render() {
247
642
  /*
248
643
  * Ruby2D::Window#show
249
644
  */
250
- static VALUE ruby2d_show(VALUE s) {
251
- self = s;
645
+ #if MRUBY
646
+ static R_VAL ruby2d_show(mrb_state* mrb, R_VAL self) {
647
+ #else
648
+ static R_VAL ruby2d_show(R_VAL self) {
649
+ #endif
650
+ ruby2d_window = self;
252
651
 
253
- char *title = RSTRING_PTR(rb_iv_get(self, "@title"));
254
- int width = NUM2INT(rb_iv_get(self, "@width"));
255
- int height = NUM2INT(rb_iv_get(self, "@height"));
652
+ if (r_test(r_iv_get(self, "@diagnostics"))) {
653
+ S2D_Diagnostics(true);
654
+ }
655
+
656
+ // Get window attributes
657
+ char *title = RSTRING_PTR(r_iv_get(self, "@title"));
658
+ int width = NUM2INT(r_iv_get(self, "@width"));
659
+ int height = NUM2INT(r_iv_get(self, "@height"));
256
660
  int flags = 0;
257
661
 
662
+ // Get window flags
663
+ if (r_test(r_iv_get(self, "@resizable"))) {
664
+ flags = flags | S2D_RESIZABLE;
665
+ }
666
+ if (r_test(r_iv_get(self, "@borderless"))) {
667
+ flags = flags | S2D_BORDERLESS;
668
+ }
669
+ if (r_test(r_iv_get(self, "@fullscreen"))) {
670
+ flags = flags | S2D_FULLSCREEN;
671
+ }
672
+ if (r_test(r_iv_get(self, "@highdpi"))) {
673
+ flags = flags | S2D_HIGHDPI;
674
+ }
675
+
676
+ // Check viewport size and set
677
+
678
+ R_VAL vp_w = r_iv_get(self, "@viewport_width");
679
+ int viewport_width = r_test(vp_w) ? NUM2INT(vp_w) : width;
680
+
681
+ R_VAL vp_h = r_iv_get(self, "@viewport_height");
682
+ int viewport_height = r_test(vp_h) ? NUM2INT(vp_h) : height;
683
+
684
+ // Create and show window
685
+
258
686
  window = S2D_CreateWindow(
259
687
  title, width, height, update, render, flags
260
688
  );
261
689
 
262
- window->on_key = on_key;
263
- window->on_key_down = on_key_down;
264
- window->on_controller = on_controller;
690
+ window->viewport.width = viewport_width;
691
+ window->viewport.height = viewport_height;
692
+ window->on_key = on_key;
693
+ window->on_mouse = on_mouse;
694
+ window->on_controller = on_controller;
265
695
 
266
696
  S2D_Show(window);
267
697
 
268
- atexit(close_window);
269
- return Qnil;
698
+ atexit(free_window);
699
+ return R_NIL;
700
+ }
701
+
702
+
703
+ /*
704
+ * Ruby2D::Window#close
705
+ */
706
+ static R_VAL ruby2d_close() {
707
+ S2D_Close(window);
708
+ return R_NIL;
270
709
  }
271
710
 
272
711
 
712
+ #if MRUBY
713
+ /*
714
+ * MRuby entry point
715
+ */
716
+ int main(void) {
717
+ // Open the MRuby environment
718
+ mrb = mrb_open();
719
+ if (!mrb) { /* handle error */ }
720
+
721
+ // Load the Ruby 2D library
722
+ mrb_load_irep(mrb, ruby2d_lib);
723
+ #else
273
724
  /*
274
725
  * Ruby C extension init
275
726
  */
276
727
  void Init_ruby2d() {
728
+ #endif
277
729
 
278
730
  // Ruby2D
279
- ruby2d_module = rb_define_module("Ruby2D");
731
+ R_CLASS ruby2d_module = r_define_module("Ruby2D");
732
+
733
+ // Ruby2D::Image
734
+ R_CLASS ruby2d_image_class = r_define_class(ruby2d_module, "Image");
735
+
736
+ // Ruby2D::Image#init
737
+ r_define_method(ruby2d_image_class, "init", ruby2d_image_init, r_args_req(1));
738
+
739
+ // Ruby2D::Sprite
740
+ R_CLASS ruby2d_sprite_class = r_define_class(ruby2d_module, "Sprite");
741
+
742
+ // Ruby2D::Sprite#init
743
+ r_define_method(ruby2d_sprite_class, "init", ruby2d_sprite_init, r_args_req(1));
744
+
745
+ // Ruby2D::Text
746
+ R_CLASS ruby2d_text_class = r_define_class(ruby2d_module, "Text");
747
+
748
+ // Ruby2D::Text#init
749
+ r_define_method(ruby2d_text_class, "init", ruby2d_text_init, r_args_none);
750
+
751
+ // Ruby2D::Text#text=
752
+ r_define_method(ruby2d_text_class, "text=", ruby2d_text_equals, r_args_req(1));
753
+
754
+ // Ruby2D::Sound
755
+ R_CLASS ruby2d_sound_class = r_define_class(ruby2d_module, "Sound");
756
+
757
+ // Ruby2D::Sound#init
758
+ r_define_method(ruby2d_sound_class, "init", ruby2d_sound_init, r_args_req(1));
759
+
760
+ // Ruby2D::Sound#play
761
+ r_define_method(ruby2d_sound_class, "play", ruby2d_sound_play, r_args_none);
762
+
763
+ // Ruby2D::Music
764
+ R_CLASS ruby2d_music_class = r_define_class(ruby2d_module, "Music");
765
+
766
+ // Ruby2D::Music#init
767
+ r_define_method(ruby2d_music_class, "init", ruby2d_music_init, r_args_req(1));
768
+
769
+ // Ruby2D::Music#play
770
+ r_define_method(ruby2d_music_class, "play", ruby2d_music_play, r_args_none);
771
+
772
+ // Ruby2D::Music#pause
773
+ r_define_method(ruby2d_music_class, "pause", ruby2d_music_pause, r_args_none);
774
+
775
+ // Ruby2D::Music#resume
776
+ r_define_method(ruby2d_music_class, "resume", ruby2d_music_resume, r_args_none);
777
+
778
+ // Ruby2D::Music#stop
779
+ r_define_method(ruby2d_music_class, "stop", ruby2d_music_stop, r_args_none);
780
+
781
+ // Ruby2D::Music#fadeout
782
+ r_define_method(ruby2d_music_class, "fadeout", ruby2d_music_fadeout, r_args_req(1));
280
783
 
281
784
  // Ruby2D::Window
282
- ruby2d_window_klass = rb_define_class_under(ruby2d_module, "Window", rb_cObject);
785
+ R_CLASS ruby2d_window_class = r_define_class(ruby2d_module, "Window");
283
786
 
284
787
  // Ruby2D::Window#show
285
- rb_define_method(ruby2d_window_klass, "show", ruby2d_show, 0);
788
+ r_define_method(ruby2d_window_class, "show", ruby2d_show, r_args_none);
789
+
790
+ // Ruby2D::Window#close
791
+ r_define_method(ruby2d_window_class, "close", ruby2d_close, r_args_none);
792
+
793
+ #if MRUBY
794
+ // Load the Ruby 2D app
795
+ mrb_load_irep(mrb, ruby2d_app);
286
796
 
287
- // Ruby2D::CData
288
- c_data_klass = rb_define_class_under(ruby2d_module, "CData", rb_cObject);
797
+ // Close the MRuby environment
798
+ mrb_close(mrb);
799
+ #endif
289
800
  }