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.
- data/.gitignore +1 -0
- data/.rspec +3 -0
- data/README.md +62 -0
- data/Rakefile +33 -23
- data/VERSION +1 -1
- data/ext/audio.c +473 -0
- data/ext/color.c +4 -4
- data/ext/event.c +25 -3
- data/ext/extconf.rb +35 -22
- data/ext/font.c +287 -0
- data/ext/image.c +682 -33
- data/ext/joystick.c +9 -9
- data/ext/ray.c +166 -55
- data/ext/ray.h +120 -9
- data/ext/ray_osx.m +161 -0
- data/ext/rect.c +31 -4
- data/lib/ray/audio.rb +52 -0
- data/lib/ray/color.rb +16 -0
- data/lib/ray/dsl.rb +1 -3
- data/lib/ray/dsl/event.rb +1 -39
- data/lib/ray/dsl/event_listener.rb +38 -0
- data/lib/ray/dsl/event_runner.rb +3 -1
- data/lib/ray/dsl/event_translator.rb +74 -8
- data/lib/ray/dsl/handler.rb +3 -33
- data/lib/ray/dsl/matcher.rb +129 -23
- data/lib/ray/font.rb +108 -0
- data/lib/ray/font_set.rb +37 -0
- data/lib/ray/game.rb +171 -34
- data/lib/ray/helper.rb +43 -5
- data/lib/ray/image.rb +90 -3
- data/lib/ray/image_set.rb +35 -0
- data/lib/ray/joystick.rb +30 -0
- data/lib/ray/music_set.rb +35 -0
- data/lib/ray/ray.rb +17 -9
- data/lib/ray/rect.rb +51 -0
- data/lib/ray/resource_set.rb +92 -0
- data/lib/ray/scene.rb +220 -51
- data/lib/ray/sound_set.rb +35 -0
- data/lib/ray/sprite.rb +184 -0
- data/psp/ext.c +4 -0
- data/samples/hello_world/hello.rb +35 -0
- data/samples/hello_world/hello_dsl.rb +24 -0
- data/samples/pong/pong.rb +128 -0
- data/samples/sokoban/level_1 +7 -0
- data/samples/sokoban/sokoban.rb +370 -0
- data/spec/ray/audio_spec.rb +146 -0
- data/spec/ray/color_spec.rb +13 -0
- data/spec/ray/event_spec.rb +57 -168
- data/spec/ray/font_spec.rb +93 -0
- data/spec/ray/image_set_spec.rb +48 -0
- data/spec/ray/image_spec.rb +130 -44
- data/spec/ray/joystick_spec.rb +13 -9
- data/spec/ray/matcher_spec.rb +32 -55
- data/spec/ray/ray_spec.rb +33 -31
- data/spec/ray/rect_spec.rb +80 -0
- data/spec/ray/resource_set_spec.rb +105 -0
- data/spec/ray/sprite_spec.rb +163 -0
- data/spec/res/VeraMono.ttf +0 -0
- data/spec/res/aqua2.bmp +0 -0
- data/spec/res/pop.wav +0 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +8 -0
- data/yard_ext.rb +91 -0
- metadata +104 -38
- data/bin/ray +0 -5
- data/bin/ray_irb +0 -4
- data/ext/SDLMain.h +0 -17
- data/ext/SDLMain.m +0 -381
- data/lib/ray/config.rb +0 -84
- data/lib/ray/dsl/converter.rb +0 -65
- data/lib/ray/dsl/listener.rb +0 -30
- data/lib/ray/dsl/type.rb +0 -58
- data/spec/ray/config_spec.rb +0 -90
- data/spec/ray/conversion_spec.rb +0 -43
- data/spec/ray/type_spec.rb +0 -17
- 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] :
|
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->
|
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->
|
115
|
-
ptr->
|
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->
|
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
|
-
|
212
|
+
@overload blit(hash)
|
213
|
+
Blits the receiver on another image.
|
158
214
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
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,
|
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
|
-
|
211
|
-
|
212
|
-
|
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
|
-
|
219
|
-
|
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
|
-
|
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));
|