ruby2d 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }