ray 0.0.0.pre2 → 0.0.1

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.
Files changed (76) hide show
  1. data/.gitignore +1 -0
  2. data/.rspec +3 -0
  3. data/README.md +62 -0
  4. data/Rakefile +33 -23
  5. data/VERSION +1 -1
  6. data/ext/audio.c +473 -0
  7. data/ext/color.c +4 -4
  8. data/ext/event.c +25 -3
  9. data/ext/extconf.rb +35 -22
  10. data/ext/font.c +287 -0
  11. data/ext/image.c +682 -33
  12. data/ext/joystick.c +9 -9
  13. data/ext/ray.c +166 -55
  14. data/ext/ray.h +120 -9
  15. data/ext/ray_osx.m +161 -0
  16. data/ext/rect.c +31 -4
  17. data/lib/ray/audio.rb +52 -0
  18. data/lib/ray/color.rb +16 -0
  19. data/lib/ray/dsl.rb +1 -3
  20. data/lib/ray/dsl/event.rb +1 -39
  21. data/lib/ray/dsl/event_listener.rb +38 -0
  22. data/lib/ray/dsl/event_runner.rb +3 -1
  23. data/lib/ray/dsl/event_translator.rb +74 -8
  24. data/lib/ray/dsl/handler.rb +3 -33
  25. data/lib/ray/dsl/matcher.rb +129 -23
  26. data/lib/ray/font.rb +108 -0
  27. data/lib/ray/font_set.rb +37 -0
  28. data/lib/ray/game.rb +171 -34
  29. data/lib/ray/helper.rb +43 -5
  30. data/lib/ray/image.rb +90 -3
  31. data/lib/ray/image_set.rb +35 -0
  32. data/lib/ray/joystick.rb +30 -0
  33. data/lib/ray/music_set.rb +35 -0
  34. data/lib/ray/ray.rb +17 -9
  35. data/lib/ray/rect.rb +51 -0
  36. data/lib/ray/resource_set.rb +92 -0
  37. data/lib/ray/scene.rb +220 -51
  38. data/lib/ray/sound_set.rb +35 -0
  39. data/lib/ray/sprite.rb +184 -0
  40. data/psp/ext.c +4 -0
  41. data/samples/hello_world/hello.rb +35 -0
  42. data/samples/hello_world/hello_dsl.rb +24 -0
  43. data/samples/pong/pong.rb +128 -0
  44. data/samples/sokoban/level_1 +7 -0
  45. data/samples/sokoban/sokoban.rb +370 -0
  46. data/spec/ray/audio_spec.rb +146 -0
  47. data/spec/ray/color_spec.rb +13 -0
  48. data/spec/ray/event_spec.rb +57 -168
  49. data/spec/ray/font_spec.rb +93 -0
  50. data/spec/ray/image_set_spec.rb +48 -0
  51. data/spec/ray/image_spec.rb +130 -44
  52. data/spec/ray/joystick_spec.rb +13 -9
  53. data/spec/ray/matcher_spec.rb +32 -55
  54. data/spec/ray/ray_spec.rb +33 -31
  55. data/spec/ray/rect_spec.rb +80 -0
  56. data/spec/ray/resource_set_spec.rb +105 -0
  57. data/spec/ray/sprite_spec.rb +163 -0
  58. data/spec/res/VeraMono.ttf +0 -0
  59. data/spec/res/aqua2.bmp +0 -0
  60. data/spec/res/pop.wav +0 -0
  61. data/spec/spec.opts +4 -0
  62. data/spec/spec_helper.rb +8 -0
  63. data/yard_ext.rb +91 -0
  64. metadata +104 -38
  65. data/bin/ray +0 -5
  66. data/bin/ray_irb +0 -4
  67. data/ext/SDLMain.h +0 -17
  68. data/ext/SDLMain.m +0 -381
  69. data/lib/ray/config.rb +0 -84
  70. data/lib/ray/dsl/converter.rb +0 -65
  71. data/lib/ray/dsl/listener.rb +0 -30
  72. data/lib/ray/dsl/type.rb +0 -58
  73. data/spec/ray/config_spec.rb +0 -90
  74. data/spec/ray/conversion_spec.rb +0 -43
  75. data/spec/ray/type_spec.rb +0 -17
  76. data/spec_runner.rb +0 -27
data/ext/image.c CHANGED
@@ -69,6 +69,36 @@ void ray_init_image_with_filename(VALUE self, VALUE filename) {
69
69
  #endif
70
70
  }
71
71
 
72
+ void ray_init_image_with_io(VALUE self, VALUE io) {
73
+ VALUE string = rb_funcall2(io, RAY_METH("read"), 0, NULL);
74
+ char *content = StringValuePtr(string);
75
+
76
+ SDL_RWops *data = SDL_RWFromMem(content, (int)RSTRING_LEN(string));
77
+
78
+ if (!data) {
79
+ rb_raise(rb_eRuntimeError, "Could not create image data (%s)",
80
+ SDL_GetError());
81
+ }
82
+
83
+ ray_image *image = ray_rb2image(self);
84
+
85
+ #ifdef HAVE_SDL_IMAGE
86
+ image->surface = IMG_Load_RW(data, 1);
87
+
88
+ if (!image->surface) {
89
+ rb_raise(rb_eRuntimeError, "Could not create the image (%s)",
90
+ IMG_GetError());
91
+ }
92
+ #else
93
+ image->surface = SDL_LoadBMP_RW(data, 1);
94
+
95
+ if (!image->surface) {
96
+ rb_raise(rb_eRuntimeError, "Could not create the image (%s)",
97
+ SDL_GetError());
98
+ }
99
+ #endif
100
+ }
101
+
72
102
  /*
73
103
  Creates a new image.
74
104
 
@@ -80,20 +110,26 @@ void ray_init_image_with_filename(VALUE self, VALUE filename) {
80
110
  @option hash [Integer] :h Alias for height
81
111
 
82
112
  @option hash [Integer] :bits_per_pixel See Ray.create_window
83
- @option hash [Integer] :pp Alias for bits_per_pixel
113
+ @option hash [Integer] :bpp Alias for bits_per_pixel
84
114
 
85
115
  @option hash [true, false] :hw_surface See Ray.create_window
86
116
  @option hash [true, false] :sw_surface See Ray.create_window
87
117
 
88
118
  @overload initialize(filename)
89
119
  Loads the image from a file.
90
- @param [String, #to_str] filename The name of the file to open
91
- */
120
+ @param [String, #to_str] filename The name of the file to open
121
+
122
+ @overload initialize(io)
123
+ Loads the image friom an IO object.
124
+ @param [IO, #read] io Object the data will be loaded from.
125
+ */
92
126
  VALUE ray_init_image(VALUE self, VALUE arg) {
93
127
  if (RAY_IS_A(arg, rb_cHash))
94
128
  ray_init_image_with_hash(self, arg);
95
129
  else if (rb_respond_to(arg, RAY_METH("to_str")))
96
130
  ray_init_image_with_filename(self, rb_String(arg));
131
+ else if (rb_respond_to(arg, RAY_METH("read")))
132
+ ray_init_image_with_io(self, arg);
97
133
  else {
98
134
  rb_raise(rb_eTypeError, "Can't convert %s into Hash",
99
135
  RAY_OBJ_CLASSNAME(arg));
@@ -102,8 +138,21 @@ VALUE ray_init_image(VALUE self, VALUE arg) {
102
138
  return Qnil;
103
139
  }
104
140
 
141
+ VALUE ray_init_image_copy(VALUE self, VALUE obj) {
142
+ ray_image *img = ray_rb2image(self);
143
+
144
+ SDL_Surface *src = ray_rb2surface(obj);
145
+ img->surface = SDL_ConvertSurface(src, src->format, src->flags);
146
+ if (!img->surface) {
147
+ rb_raise(rb_eRuntimeError, "Could not create the image (%s)",
148
+ SDL_GetError());
149
+ }
150
+
151
+ return self;
152
+ }
153
+
105
154
  void ray_free_image(ray_image *ptr) {
106
- if (ptr->mustFree && ptr->surface) SDL_FreeSurface(ptr->surface);
155
+ if (ptr->must_free && ptr->surface) SDL_FreeSurface(ptr->surface);
107
156
  free(ptr);
108
157
  }
109
158
 
@@ -111,10 +160,18 @@ VALUE ray_create_image(SDL_Surface *surface) {
111
160
  ray_image *ptr = malloc(sizeof(ray_image));
112
161
  VALUE ret = Data_Wrap_Struct(ray_cImage, 0, ray_free_image, ptr);
113
162
 
114
- ptr->self = ret;
115
- ptr->surface = surface;
163
+ ptr->surface = surface;
164
+ ptr->must_free = 0;
165
+
166
+ return ret;
167
+ }
168
+
169
+ VALUE ray_create_gc_image(SDL_Surface *surface) {
170
+ ray_image *ptr = malloc(sizeof(ray_image));
171
+ VALUE ret = Data_Wrap_Struct(ray_cImage, 0, ray_free_image, ptr);
116
172
 
117
- ptr->mustFree = 0;
173
+ ptr->surface = surface;
174
+ ptr->must_free = 1;
118
175
 
119
176
  return ret;
120
177
  }
@@ -123,10 +180,8 @@ VALUE ray_alloc_image(VALUE self) {
123
180
  ray_image *ptr = malloc(sizeof(ray_image));
124
181
  VALUE ret = Data_Wrap_Struct(self, 0, ray_free_image, ptr);
125
182
 
126
- ptr->self = ret;
127
183
  ptr->surface = NULL;
128
-
129
- ptr->mustFree = 1;
184
+ ptr->must_free = 1;
130
185
 
131
186
  return ret;
132
187
  }
@@ -154,28 +209,32 @@ VALUE ray_image_flip(VALUE self) {
154
209
  }
155
210
 
156
211
  /*
157
- Blits the receiver on another image.
212
+ @overload blit(hash)
213
+ Blits the receiver on another image.
158
214
 
159
- @option hash [Ray::Rect, Array] :at Rects in which the image will be
160
- drawn. If an array is given, it
161
- passed to Ray::Rect.new. Only the
162
- position is read.
163
- @option hash [Ray::Rect, Array] :rect Rects that will be copied.
164
- If an array is given, it
165
- passed to Ray::Rect.new.
166
- If the size is (0, 0), it will
167
- be reset to the image's size.
168
- @option hash [Ray::Rect, Array] :from Alias for rect
169
-
170
- @option hash [Ray::Image, required] :on The image on which the receiver should
171
- be drawn.
172
-
173
- @option hash [Ray::Image, required] :to Alias for on.
215
+ @option hash [Ray::Rect, Array] :at Rects in which the image will be
216
+ drawn. If an array is given, it
217
+ passed to Ray::Rect.new. Only the
218
+ position is read.
219
+ @option hash [Ray::Rect, Array] :rect Rects that will be copied.
220
+ If an array is given, it
221
+ passed to Ray::Rect.new.
222
+ If the size is (0, 0), it will
223
+ be reset to the image's size.
224
+ @option hash [Ray::Rect, Array] :from Alias for rect
225
+
226
+ @option hash [Ray::Image, required] :on The image on which the receiver should
227
+ be drawn.
228
+
229
+ @option hash [Ray::Image, required] :to Alias for on.
230
+
231
+ @option hash [Float] :angle Rotation in degrees.
232
+ @option hash [Float] :zoom Zoom level. 1.0 for the current size.
174
233
  */
175
234
  VALUE ray_image_blit(VALUE self, VALUE hash) {
176
235
  SDL_Surface *origin = ray_rb2surface(self);
177
236
 
178
- SDL_Rect from_rect = {0, 0, origin->w, origin->h};
237
+ SDL_Rect from_rect = {0, 0, 0, 0};
179
238
  SDL_Rect to_rect = {0, 0, 0, 0};
180
239
 
181
240
  VALUE rect = rb_hash_aref(hash, RAY_SYM("at"));
@@ -202,21 +261,64 @@ VALUE ray_image_blit(VALUE self, VALUE hash) {
202
261
  RAY_OBJ_CLASSNAME(rect));
203
262
  }
204
263
 
264
+ VALUE surf = rb_hash_aref(hash, RAY_SYM("on"));
265
+ if (surf == Qnil) surf = rb_hash_aref(hash, RAY_SYM("to"));
266
+
267
+ /* avoid raising an exception, which would prevent us from freeing the surface */
268
+ SDL_Surface *target = ray_rb2surface(surf);
269
+
270
+ #ifdef HAVE_SDL_GFX
271
+ VALUE rb_angle = Qnil, rb_zoom = Qnil;
272
+ double angle = 0.0, zoom = 1.0;
273
+
274
+ if (!NIL_P(rb_angle = rb_hash_aref(hash, RAY_SYM("angle"))))
275
+ angle = NUM2DBL(rb_angle);
276
+
277
+ if (!NIL_P(rb_zoom = rb_hash_aref(hash, RAY_SYM("zoom"))))
278
+ zoom = NUM2DBL(rb_zoom);
279
+
280
+ if (!NIL_P(rb_angle) || !NIL_P(rb_zoom)) {
281
+ SDL_Surface *res = rotozoomSurface(origin, angle, zoom, 1);
282
+ if (!res) {
283
+ rb_raise(rb_eRuntimeError, "Could not create the image (%s)",
284
+ SDL_GetError());
285
+ }
286
+
287
+ if (from_rect.w == 0 && from_rect.h == 0) {
288
+ from_rect.w = res->w;
289
+ from_rect.h = res->h;
290
+ }
291
+
292
+ if (SDL_BlitSurface(res, &from_rect, target, &to_rect) == -1) {
293
+ SDL_FreeSurface(res); /* Don't leak when an error occurs */
294
+ rb_raise(rb_eRuntimeError, "Couldn't blit the image (%s)",
295
+ SDL_GetError());
296
+ }
297
+
298
+ SDL_FreeSurface(res);
299
+
300
+ return surf;
301
+ }
302
+ #endif
303
+
205
304
  if (from_rect.w == 0 && from_rect.h == 0) {
206
305
  from_rect.w = origin->w;
207
306
  from_rect.h = origin->h;
208
307
  }
209
308
 
210
- VALUE surf = rb_hash_aref(hash, RAY_SYM("on"));
211
- if (surf == Qnil) surf = rb_hash_aref(hash, RAY_SYM("to"));
212
- SDL_BlitSurface(origin, &from_rect, ray_rb2surface(surf), &to_rect);
309
+ if (SDL_BlitSurface(origin, &from_rect, target,
310
+ &to_rect) == -1) {
311
+ rb_raise(rb_eRuntimeError, "Couldn't blit the image (%s)",
312
+ SDL_GetError());
313
+ }
213
314
 
214
315
  return surf;
215
316
  }
216
317
 
217
318
  /*
218
- Sets the alpha transparency.
219
- @param [Integer, 0..255] alpha the new transparency
319
+ @overload alpha=(alpha)
320
+ Sets the alpha transparency.
321
+ @param [Integer, 0..255] alpha the new transparency
220
322
  */
221
323
  VALUE ray_image_set_alpha(VALUE self, VALUE alpha) {
222
324
  SDL_SetAlpha(ray_rb2surface(self), SDL_SRCALPHA | SDL_RLEACCEL,
@@ -245,14 +347,529 @@ VALUE ray_image_height(VALUE self) {
245
347
 
246
348
  /* @return [Integer] Bits per pixel */
247
349
  VALUE ray_image_bpp(VALUE self) {
248
- return INT2FIX(ray_rb2surface(self)->format->BitsPerPixel);
350
+ SDL_Surface *surf = ray_rb2surface(self);
351
+ if (surf->format)
352
+ return INT2FIX(ray_rb2surface(self)->format->BitsPerPixel);
353
+ return Qnil;
354
+ }
355
+
356
+ /*
357
+ @overload ==(obj)
358
+ @return [true, false] true if obj manipulates the same surface as the
359
+ receiver.
360
+ */
361
+ VALUE ray_image_is_equal(VALUE self, VALUE obj) {
362
+ if (!RAY_IS_A(obj, ray_cImage))
363
+ return Qfalse;
364
+
365
+ SDL_Surface *first_surface = ray_rb2surface(self);
366
+ SDL_Surface *sec_surface = ray_rb2surface(obj);
367
+
368
+ return (first_surface == sec_surface) ? Qtrue : Qfalse;
369
+ }
370
+
371
+ VALUE ray_image_ensure_unlock(VALUE self) {
372
+ SDL_Surface *surface = ray_rb2surface(self);
373
+ SDL_UnlockSurface(surface);
374
+
375
+ return self;
376
+ }
377
+
378
+ /*
379
+ Locks the image (allow pixel-per-pixel modifications).
380
+ Don't forget to call unlock when you're done. You can also
381
+ pass a bock which will be called before the image gets unlocked
382
+ automatically.
383
+ */
384
+ VALUE ray_image_lock(VALUE self) {
385
+ SDL_Surface *surface = ray_rb2surface(self);
386
+ SDL_LockSurface(surface);
387
+
388
+ if (rb_block_given_p())
389
+ rb_ensure(rb_yield, Qnil, ray_image_ensure_unlock, self);
390
+
391
+ return self;
392
+ }
393
+
394
+ /*
395
+ Unlocks the image. You must call this once you are done
396
+ modifying the image.
397
+ */
398
+ VALUE ray_image_unlock(VALUE self) {
399
+ return ray_image_ensure_unlock(self);
400
+ }
401
+
402
+ /*
403
+ @overload [](x, y)
404
+ @return [Ray::Color, nil] Pixel at (x, y). Nil if the point is outside the
405
+ image.
406
+ */
407
+ VALUE ray_image_at(VALUE self, VALUE rb_x, VALUE rb_y) {
408
+ SDL_Surface *surface = ray_rb2surface(self);
409
+
410
+ int x = NUM2INT(rb_x);
411
+ int y = NUM2INT(rb_y);
412
+
413
+ /* (w, h) is not a valid point. Surfaces use 0-based indexing. */
414
+ if (x >= surface->w || y >= surface->h)
415
+ return Qnil;
416
+
417
+ int bytes = surface->format->BytesPerPixel;
418
+
419
+ uint8_t *pix = (uint8_t*)surface->pixels + y * surface->pitch + x * bytes;
420
+
421
+ uint32_t res;
422
+ switch (bytes) {
423
+ case 1:
424
+ res = *pix;
425
+ break;
426
+ case 2:
427
+ res = *(uint16_t*)pix;
428
+ break;
429
+ case 3:
430
+ if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
431
+ res = pix[0] << 16 | pix[1] << 8 | pix[2];
432
+ else
433
+ res = pix[0] | pix[1] << 8 | pix[2] << 16;
434
+ break;
435
+ case 4:
436
+ res = *(uint32_t*)pix;
437
+ break;
438
+ default: /* should never happen */
439
+ res = 0;
440
+ break;
441
+ }
442
+
443
+ ray_color col;
444
+ SDL_GetRGBA(res, surface->format, &(col.r), &(col.g), &(col.b), &(col.a));
445
+
446
+ return ray_col2rb(col);
447
+ }
448
+
449
+ /*
450
+ @overload [](x, y, color)
451
+ Sets the color of the point at (x, y)
452
+ @raise ArgumentError If (x, y) is outside the image.
453
+ */
454
+ VALUE ray_image_set_at(VALUE self, VALUE rb_x, VALUE rb_y, VALUE rb_col) {
455
+ SDL_Surface *surface = ray_rb2surface(self);
456
+
457
+ int x = NUM2INT(rb_x);
458
+ int y = NUM2INT(rb_y);
459
+
460
+ if (x >= surface->w || y >= surface->h) {
461
+ VALUE inspect = rb_inspect(self);
462
+ rb_raise(rb_eArgError, "(%d, %d) is outside %s",
463
+ x, y, StringValuePtr(inspect));
464
+ }
465
+
466
+ int bytes = surface->format->BytesPerPixel;
467
+
468
+ uint8_t *pix = (uint8_t*)surface->pixels + y * surface->pitch + x * bytes;
469
+
470
+ ray_color col = ray_rb2col(rb_col);
471
+
472
+ uint32_t val = SDL_MapRGBA(surface->format, col.r, col.g, col.b, col.a);
473
+
474
+ switch (bytes) {
475
+ case 1:
476
+ *pix = val;
477
+ break;
478
+ case 2:
479
+ *(uint16_t*)pix = val;
480
+ break;
481
+ case 3:
482
+ if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
483
+ pix[0] = (val >> 16) & 0xff;
484
+ pix[1] = (val >> 8) & 0xff;
485
+ pix[2] = val & 0xff;
486
+ }
487
+ else {
488
+ pix[0] = val & 0xff;
489
+ pix[1] = (val >> 8) & 0xff;
490
+ pix[2] = (val >> 16) & 0xff;
491
+ }
492
+ break;
493
+ case 4:
494
+ *(uint32_t*)pix = val;
495
+ break;
496
+ }
497
+
498
+ return rb_col;
499
+ }
500
+
501
+ VALUE ray_image_ensure_unclip(VALUE ary) {
502
+ SDL_Surface *surface = ray_rb2surface(rb_ary_entry(ary, 0));
503
+ SDL_Rect rect = ray_rb2rect(rb_ary_entry(ary, 1));
504
+
505
+ SDL_SetClipRect(surface, &rect);
506
+
507
+ rb_gc_unregister_address(&ary);
508
+
509
+ return Qnil;
510
+ }
511
+
512
+ /*
513
+ @overload clip
514
+ @return [Ray::Rect] The current clipping rect
515
+
516
+ @overload clip(rect)
517
+ Changes the clipping rect (the rect which will be changed if something is
518
+ drawn on this image, the rest of the image being ignored.)
519
+
520
+ If a block is given, it is executed, and the old clipping rect is reset
521
+ afterwards.
522
+
523
+ @param [Ray::Rect, Array<Integer>] rect New clipping rect.
524
+ */
525
+ VALUE ray_image_clip(int argc, VALUE *argv, VALUE self) {
526
+ VALUE rb_rect = Qnil;
527
+ rb_scan_args(argc, argv, "01", &rb_rect);
528
+
529
+ SDL_Rect old_rect;
530
+ SDL_GetClipRect(ray_rb2surface(self), &old_rect);
531
+
532
+ if (NIL_P(rb_rect))
533
+ return ray_rect2rb(old_rect);
534
+
535
+ SDL_Rect rect = ray_convert_to_rect(rb_rect);
536
+ SDL_SetClipRect(ray_rb2surface(self), &rect);
537
+
538
+ if (rb_block_given_p()) {
539
+ VALUE ary = rb_ary_new();
540
+ rb_ary_push(ary, self);
541
+ rb_ary_push(ary, ray_rect2rb(old_rect));
542
+
543
+ rb_gc_register_address(&ary);
544
+
545
+ rb_ensure(rb_yield, Qnil, ray_image_ensure_unclip, ary);
546
+ }
547
+
548
+ return ray_rect2rb(rect);
549
+ }
550
+
551
+ #ifdef HAVE_SDL_GFX
552
+
553
+ /*
554
+ @overload rotozoom(angle, zoom)
555
+ Rotates and zoomes on the image.
556
+ @param [Float] angle Angle in degrees
557
+ @param [Float] zoom
558
+ @return [SDL::Image] the modified image.
559
+
560
+ @see #rotozoom!
561
+ */
562
+ VALUE ray_image_rotozoom(VALUE self, VALUE angle, VALUE zoom) {
563
+ SDL_Surface *surface = ray_rb2surface(self);
564
+ SDL_Surface *res = rotozoomSurface(surface, NUM2DBL(angle),
565
+ NUM2DBL(zoom), 1);
566
+
567
+ if (!res) {
568
+ rb_raise(rb_eRuntimeError, "Could not create the image (%s)",
569
+ SDL_GetError());
570
+ }
571
+
572
+ return ray_create_gc_image(res);
573
+ }
574
+
575
+ /*
576
+ @overload rotozoom!(angle, zoom)
577
+ Rotates and zoomes on the image, but does not create a new instance
578
+ of Ray::Image, which may be better for memory management.
579
+
580
+ Notice Ray.create_window(...).rotozoom!(...) will not modify
581
+ the image used as the screen.
582
+
583
+ @see #rotozoom
584
+ */
585
+ VALUE ray_image_rotozoom_bang(VALUE self, VALUE angle, VALUE zoom) {
586
+ ray_image *img = ray_rb2image(self);
587
+ SDL_Surface *res = rotozoomSurface(img->surface, NUM2DBL(angle),
588
+ NUM2DBL(zoom), 1);
589
+
590
+ if (!res) {
591
+ rb_raise(rb_eRuntimeError, "Could not create the image (%s)",
592
+ SDL_GetError());
593
+ }
594
+
595
+ if (img->must_free)
596
+ SDL_FreeSurface(img->surface);
597
+
598
+ img->surface = res;
599
+ img->must_free = 1;
600
+
601
+ return self;
602
+ }
603
+
604
+ /*
605
+ @overload draw_pixel(point, color)
606
+ Draws a point.
607
+
608
+ @param [Ray::Rect, Array<Integer>] point The point which should be changed.
609
+ @param [Ray::Color] color Its new color.
610
+ */
611
+ VALUE ray_image_draw_pixel(VALUE self, VALUE rb_point, VALUE rb_color) {
612
+ SDL_Surface *surface = ray_rb2surface(self);
613
+
614
+ SDL_Rect point = ray_convert_to_rect(rb_point);
615
+ ray_color color = ray_rb2col(rb_color);
616
+
617
+ pixelRGBA(surface, point.x, point.y, color.r, color.g, color.b, color.a);
618
+
619
+ return self;
620
+ }
621
+
622
+ /*
623
+ @overload draw_line(p1, p2, color)
624
+ Draws a line.
625
+
626
+ @param [Ray::Rect, Array<Integer>] p1 First point of the line.
627
+ @param [Ray::Rect, Array<Integer>] p2 Second point of the line.
628
+ @param [Ray::Color] color Color of the line.
629
+ */
630
+ VALUE ray_image_draw_line(VALUE self, VALUE p1, VALUE p2, VALUE rb_color) {
631
+ SDL_Surface *surface = ray_rb2surface(self);
632
+
633
+ SDL_Rect first_point = ray_convert_to_rect(p1);
634
+ SDL_Rect second_point = ray_convert_to_rect(p2);
635
+ ray_color color = ray_rb2col(rb_color);
636
+
637
+ aalineRGBA(surface, first_point.x, first_point.y,
638
+ second_point.x, second_point.y,
639
+ color.r, color.g, color.b, color.a);
640
+ return self;
641
+ }
642
+
643
+ /*
644
+ @overload draw_rect(rect, color)
645
+ Draws a rect.
646
+
647
+ @param [Ray::Rect, Array<Integer>] rect Rect to draw
648
+ @param [Ray::Color] color color of the rect
649
+ */
650
+ VALUE ray_image_draw_rect(VALUE self, VALUE rb_rect, VALUE rb_color) {
651
+ SDL_Surface *surface = ray_rb2surface(self);
652
+ SDL_Rect rect = ray_convert_to_rect(rb_rect);
653
+ ray_color color = ray_rb2col(rb_color);
654
+
655
+ rectangleRGBA(surface, rect.x, rect.y, rect.x + rect.w, rect.y + rect.h,
656
+ color.r, color.g, color.b, color.a);
657
+
658
+ return self;
659
+ }
660
+
661
+ /*
662
+ @overload draw_filled_rect(rect, color)
663
+ Draws a filled rect.
664
+
665
+ @param [Ray::Rect, Array<Integer>] rb_rect Rect to draw.
666
+ @param [Ray::Color] rb_color Color of the rect.
667
+ */
668
+ VALUE ray_image_draw_filled_rect(VALUE self, VALUE rb_rect, VALUE rb_color) {
669
+ SDL_Surface *surface = ray_rb2surface(self);
670
+ SDL_Rect rect = ray_convert_to_rect(rb_rect);
671
+ ray_color color = ray_rb2col(rb_color);
672
+
673
+ boxRGBA(surface, rect.x, rect.y, rect.x + rect.w, rect.y + rect.h,
674
+ color.r, color.g, color.b, color.a);
675
+
676
+ return self;
677
+ }
678
+
679
+ /*
680
+ @overload draw_circle(center, radius, color)
681
+ Draws a circle
682
+
683
+ @param [Ray::Rect, Array<Integer>] center Center of the circle.
684
+ @param [Integer] radius Radius of the circle.
685
+ @param [Ray::Color] color Color of the circle.
686
+ */
687
+ VALUE ray_image_draw_circle(VALUE self, VALUE center, VALUE radius,
688
+ VALUE rb_color) {
689
+ SDL_Surface *surface = ray_rb2surface(self);
690
+ SDL_Rect rect = ray_convert_to_rect(center);
691
+ ray_color color = ray_rb2col(rb_color);
692
+
693
+ aacircleRGBA(surface, rect.x, rect.y, NUM2INT(radius),
694
+ color.r, color.g, color.b, color.a);
695
+
696
+ return self;
697
+ }
698
+
699
+ /*
700
+ @overload draw_filled_circle(center, radius, color)
701
+ Draws a filled circle
702
+
703
+ @param [Ray::Rect, Array<Integer>] center Center of the circle.
704
+ @param [Integer] radius Radius of the circle.
705
+ @param [Ray::Color] color Color of the circle.
706
+ */
707
+ VALUE ray_image_draw_filled_circle(VALUE self, VALUE center, VALUE radius,
708
+ VALUE rb_color) {
709
+ SDL_Surface *surface = ray_rb2surface(self);
710
+ SDL_Rect rect = ray_convert_to_rect(center);
711
+ ray_color color = ray_rb2col(rb_color);
712
+
713
+ filledCircleRGBA(surface, rect.x, rect.y, NUM2INT(radius),
714
+ color.r, color.g, color.b, color.a);
715
+
716
+ return self;
717
+ }
718
+
719
+ /*
720
+ @overload draw_ellipse(rect, color)
721
+ Draws an ellipse.
722
+
723
+ @param [Ray::Rect, Array<Integer>] rect Rect in which the ellipse should be drawn.
724
+ @param [Ray::Color] color Color in which the ellipse should be drawn.
725
+ */
726
+ VALUE ray_image_draw_ellipse(VALUE self, VALUE rb_rect, VALUE rb_color) {
727
+ SDL_Surface *surface = ray_rb2surface(self);
728
+ SDL_Rect rect = ray_convert_to_rect(rb_rect);
729
+ ray_color color = ray_rb2col(rb_color);
730
+
731
+ aaellipseRGBA(surface, rect.x + rect.w / 2,
732
+ rect.y + rect.h / 2, rect.w / 2, rect.h / 2,
733
+ color.r, color.g, color.b, color.a);
734
+ return self;
735
+ }
736
+
737
+ /*
738
+ @overload draw_flled_ellipse(rect, color)
739
+ Draws a filled ellipse.
740
+
741
+ @param [Ray::Rect, Array<Integer>] rect Rect in which the ellipse should be drawn.
742
+ @param [Ray::Color] color Color in which the ellipse should be drawn.
743
+ */
744
+ VALUE ray_image_draw_filled_ellipse(VALUE self, VALUE rb_rect, VALUE rb_color) {
745
+ SDL_Surface *surface = ray_rb2surface(self);
746
+ SDL_Rect rect = ray_convert_to_rect(rb_rect);
747
+ ray_color color = ray_rb2col(rb_color);
748
+
749
+ filledEllipseRGBA(surface, rect.x + rect.w / 2,
750
+ rect.y + rect.h / 2, rect.w / 2, rect.h / 2,
751
+ color.r, color.g, color.b, color.a);
752
+ return self;
753
+ }
754
+
755
+ /*
756
+ @overload draw_triangle(p1, p2, p3, color)
757
+ Draws a triangle.
758
+ */
759
+ VALUE ray_image_draw_triangle(VALUE self, VALUE p1, VALUE p2, VALUE p3,
760
+ VALUE rb_color) {
761
+ SDL_Surface *surface = ray_rb2surface(self);
762
+
763
+ SDL_Rect first_point = ray_convert_to_rect(p1);
764
+ SDL_Rect second_point = ray_convert_to_rect(p2);
765
+ SDL_Rect third_point = ray_convert_to_rect(p3);
766
+
767
+ ray_color color = ray_rb2col(rb_color);
768
+
769
+ aatrigonRGBA(surface, first_point.x, first_point.y,
770
+ second_point.x, second_point.y,
771
+ third_point.x, third_point.y,
772
+ color.r, color.g, color.b, color.a);
773
+
774
+ return self;
249
775
  }
250
776
 
777
+ /*
778
+ @overload draw_filled_triangle(p1, p2, p3, color)
779
+ Draws a filled triangle.
780
+ */
781
+ VALUE ray_image_draw_filled_triangle(VALUE self, VALUE p1, VALUE p2, VALUE p3,
782
+ VALUE rb_color) {
783
+ SDL_Surface *surface = ray_rb2surface(self);
784
+
785
+ SDL_Rect first_point = ray_convert_to_rect(p1);
786
+ SDL_Rect second_point = ray_convert_to_rect(p2);
787
+ SDL_Rect third_point = ray_convert_to_rect(p3);
788
+
789
+ ray_color color = ray_rb2col(rb_color);
790
+
791
+ filledTrigonRGBA(surface, first_point.x, first_point.y,
792
+ second_point.x, second_point.y,
793
+ third_point.x, third_point.y,
794
+ color.r, color.g, color.b, color.a);
795
+
796
+ return self;
797
+ }
798
+
799
+ /*
800
+ @overload draw_polygon(points, color)
801
+ Draws a polygon.
802
+
803
+ @param [Array<Array<Integer>, Ray::Rect>] points Points which should be joined
804
+ to draw the polygon.
805
+ @param [Ray::Color] color The color in which the polygon should be drawn.
806
+ */
807
+ VALUE ray_image_draw_polygon(VALUE self, VALUE points, VALUE rb_color) {
808
+ SDL_Surface *surface = ray_rb2surface(self);
809
+
810
+ size_t size = RARRAY_LEN(points);
811
+ int16_t *x_array = malloc(sizeof(int16_t) * size);
812
+ int16_t *y_array = malloc(sizeof(int16_t) * size);
813
+
814
+ size_t i = 0;
815
+ for (; i < size; i++) {
816
+ SDL_Rect rect = ray_convert_to_rect(rb_ary_entry(points, i));
817
+
818
+ x_array[i] = (int16_t)rect.x;
819
+ y_array[i] = (int16_t)rect.y;
820
+ }
821
+
822
+ ray_color color = ray_rb2col(rb_color);
823
+ aapolygonRGBA(surface, x_array, y_array, (int)size,
824
+ color.r, color.g, color.b, color.a);
825
+
826
+ free(x_array);
827
+ free(y_array);
828
+
829
+ return self;
830
+ }
831
+
832
+ /*
833
+ @overload draw_filled_polygon(points, color)
834
+ Draws a filled polygon.
835
+
836
+ @param [Array<Array<Integer>, Ray::Rect>] points Points which should be joined
837
+ to draw the polygon.
838
+ @param [Ray::Color] color The color in which the polygon should be drawn.
839
+ */
840
+ VALUE ray_image_draw_filled_polygon(VALUE self, VALUE points, VALUE rb_color) {
841
+ SDL_Surface *surface = ray_rb2surface(self);
842
+
843
+ size_t size = RARRAY_LEN(points);
844
+ int16_t *x_array = malloc(sizeof(int16_t) * size);
845
+ int16_t *y_array = malloc(sizeof(int16_t) * size);
846
+
847
+ size_t i = 0;
848
+ for (; i < size; i++) {
849
+ SDL_Rect rect = ray_convert_to_rect(rb_ary_entry(points, i));
850
+
851
+ x_array[i] = (int16_t)rect.x;
852
+ y_array[i] = (int16_t)rect.y;
853
+ }
854
+
855
+ ray_color color = ray_rb2col(rb_color);
856
+ filledPolygonRGBA(surface, x_array, y_array, (int)size,
857
+ color.r, color.g, color.b, color.a);
858
+
859
+ free(x_array);
860
+ free(y_array);
861
+
862
+ return self;
863
+ }
864
+
865
+ #endif
866
+
251
867
  void Init_ray_image() {
252
868
  ray_cImage = rb_define_class_under(ray_mRay, "Image", rb_cObject);
253
869
 
254
870
  rb_define_alloc_func(ray_cImage, ray_alloc_image);
255
871
  rb_define_method(ray_cImage, "initialize", ray_init_image, 1);
872
+ rb_define_method(ray_cImage, "initialize_copy", ray_init_image_copy, 1);
256
873
 
257
874
  rb_define_method(ray_cImage, "fill", ray_image_fill, 1);
258
875
  rb_define_method(ray_cImage, "flip", ray_image_flip, 0);
@@ -267,6 +884,38 @@ void Init_ray_image() {
267
884
  rb_define_method(ray_cImage, "height", ray_image_height, 0);
268
885
  rb_define_method(ray_cImage, "bpp", ray_image_bpp, 0);
269
886
 
887
+ rb_define_method(ray_cImage, "==", ray_image_is_equal, 1);
888
+
889
+ rb_define_method(ray_cImage, "lock", ray_image_lock, 0);
890
+ rb_define_method(ray_cImage, "unlock", ray_image_unlock, 0);
891
+ rb_define_method(ray_cImage, "[]", ray_image_at, 2);
892
+ rb_define_method(ray_cImage, "[]=", ray_image_set_at, 3);
893
+
894
+ rb_define_method(ray_cImage, "clip", ray_image_clip, -1);
895
+
896
+ #ifdef HAVE_SDL_GFX
897
+ rb_define_method(ray_cImage, "rotozoom", ray_image_rotozoom, 2);
898
+ rb_define_method(ray_cImage, "rotozoom!", ray_image_rotozoom_bang, 2);
899
+
900
+ rb_define_method(ray_cImage, "draw_pixel", ray_image_draw_pixel, 2);
901
+ rb_define_method(ray_cImage, "draw_line", ray_image_draw_line, 3);
902
+ rb_define_method(ray_cImage, "draw_rect", ray_image_draw_rect, 2);
903
+ rb_define_method(ray_cImage, "draw_filled_rect", ray_image_draw_filled_rect,
904
+ 2);
905
+ rb_define_method(ray_cImage, "draw_circle", ray_image_draw_circle, 3);
906
+ rb_define_method(ray_cImage, "draw_filled_circle",
907
+ ray_image_draw_filled_circle, 3);
908
+ rb_define_method(ray_cImage, "draw_ellipse", ray_image_draw_ellipse, 2);
909
+ rb_define_method(ray_cImage, "draw_filled_ellipse",
910
+ ray_image_draw_filled_ellipse, 2);
911
+ rb_define_method(ray_cImage, "draw_triangle", ray_image_draw_triangle, 4);
912
+ rb_define_method(ray_cImage, "draw_filled_triangle",
913
+ ray_image_draw_filled_triangle, 4);
914
+ rb_define_method(ray_cImage, "draw_polygon", ray_image_draw_polygon, 2);
915
+ rb_define_method(ray_cImage, "draw_filled_polygon",
916
+ ray_image_draw_filled_polygon, 2);
917
+ #endif
918
+
270
919
  rb_define_const(ray_cImage, "FLAG_ANYFORMAT", INT2FIX(SDL_ANYFORMAT));
271
920
  rb_define_const(ray_cImage, "FLAG_ASYNCBLIT", INT2FIX(SDL_ASYNCBLIT));
272
921
  rb_define_const(ray_cImage, "FLAG_DOUBLEBUF", INT2FIX(SDL_DOUBLEBUF));