ray 0.0.0.pre2 → 0.0.1

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