teek-sdl2 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/ext/teek_sdl2/extconf.rb +112 -0
- data/ext/teek_sdl2/sdl2bridge.c +142 -0
- data/ext/teek_sdl2/sdl2image.c +83 -0
- data/ext/teek_sdl2/sdl2pixels.c +166 -0
- data/ext/teek_sdl2/sdl2surface.c +534 -0
- data/ext/teek_sdl2/sdl2text.c +234 -0
- data/ext/teek_sdl2/teek_sdl2.c +65 -0
- data/ext/teek_sdl2/teek_sdl2.h +63 -0
- data/lib/teek/sdl2/font.rb +94 -0
- data/lib/teek/sdl2/renderer.rb +227 -0
- data/lib/teek/sdl2/texture.rb +91 -0
- data/lib/teek/sdl2/version.rb +7 -0
- data/lib/teek/sdl2/viewport.rb +230 -0
- data/lib/teek/sdl2.rb +69 -0
- data/teek-sdl2.gemspec +28 -0
- data/test/test_callback_teardown.rb +35 -0
- data/test/test_helper.rb +19 -0
- data/test/test_image.rb +87 -0
- data/test/test_input.rb +185 -0
- data/test/test_renderer.rb +138 -0
- data/test/test_sdl2.rb +24 -0
- data/test/test_viewport.rb +89 -0
- metadata +120 -0
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
#include "teek_sdl2.h"
|
|
2
|
+
|
|
3
|
+
/* ---------------------------------------------------------
|
|
4
|
+
* Layer 1: Pure SDL2 surface management
|
|
5
|
+
*
|
|
6
|
+
* No Tk knowledge. Manages SDL2 windows, renderers, and
|
|
7
|
+
* textures. Can be tested standalone.
|
|
8
|
+
* --------------------------------------------------------- */
|
|
9
|
+
|
|
10
|
+
static VALUE cRenderer;
|
|
11
|
+
static VALUE cTexture;
|
|
12
|
+
static VALUE eSDL2Error;
|
|
13
|
+
|
|
14
|
+
/* Track whether SDL2 has been initialized */
|
|
15
|
+
static int sdl2_initialized = 0;
|
|
16
|
+
|
|
17
|
+
/* ---------------------------------------------------------
|
|
18
|
+
* SDL2 lazy initialization
|
|
19
|
+
* --------------------------------------------------------- */
|
|
20
|
+
|
|
21
|
+
void
|
|
22
|
+
ensure_sdl2_init(void)
|
|
23
|
+
{
|
|
24
|
+
if (sdl2_initialized) return;
|
|
25
|
+
|
|
26
|
+
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
|
27
|
+
rb_raise(rb_eRuntimeError, "SDL_Init failed: %s", SDL_GetError());
|
|
28
|
+
}
|
|
29
|
+
sdl2_initialized = 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* ---------------------------------------------------------
|
|
33
|
+
* Renderer (wraps SDL_Window + SDL_Renderer)
|
|
34
|
+
* --------------------------------------------------------- */
|
|
35
|
+
|
|
36
|
+
static void
|
|
37
|
+
renderer_mark(void *ptr)
|
|
38
|
+
{
|
|
39
|
+
(void)ptr;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static void
|
|
43
|
+
renderer_free(void *ptr)
|
|
44
|
+
{
|
|
45
|
+
struct sdl2_renderer *r = ptr;
|
|
46
|
+
if (!r->destroyed) {
|
|
47
|
+
if (r->renderer) {
|
|
48
|
+
SDL_DestroyRenderer(r->renderer);
|
|
49
|
+
r->renderer = NULL;
|
|
50
|
+
}
|
|
51
|
+
if (r->window && r->owned_window) {
|
|
52
|
+
SDL_DestroyWindow(r->window);
|
|
53
|
+
r->window = NULL;
|
|
54
|
+
}
|
|
55
|
+
r->destroyed = 1;
|
|
56
|
+
}
|
|
57
|
+
xfree(r);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static size_t
|
|
61
|
+
renderer_memsize(const void *ptr)
|
|
62
|
+
{
|
|
63
|
+
return sizeof(struct sdl2_renderer);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const rb_data_type_t renderer_type = {
|
|
67
|
+
.wrap_struct_name = "TeekSDL2::Renderer",
|
|
68
|
+
.function = {
|
|
69
|
+
.dmark = renderer_mark,
|
|
70
|
+
.dfree = renderer_free,
|
|
71
|
+
.dsize = renderer_memsize,
|
|
72
|
+
},
|
|
73
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
static VALUE
|
|
77
|
+
renderer_alloc(VALUE klass)
|
|
78
|
+
{
|
|
79
|
+
struct sdl2_renderer *r;
|
|
80
|
+
VALUE obj = TypedData_Make_Struct(klass, struct sdl2_renderer, &renderer_type, r);
|
|
81
|
+
r->window = NULL;
|
|
82
|
+
r->renderer = NULL;
|
|
83
|
+
r->owned_window = 0;
|
|
84
|
+
r->destroyed = 0;
|
|
85
|
+
return obj;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
struct sdl2_renderer *
|
|
89
|
+
get_renderer(VALUE self)
|
|
90
|
+
{
|
|
91
|
+
struct sdl2_renderer *r;
|
|
92
|
+
TypedData_Get_Struct(self, struct sdl2_renderer, &renderer_type, r);
|
|
93
|
+
if (r->destroyed || r->renderer == NULL) {
|
|
94
|
+
rb_raise(eSDL2Error, "renderer has been destroyed");
|
|
95
|
+
}
|
|
96
|
+
return r;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/*
|
|
100
|
+
* Teek::SDL2::Renderer#clear(r=0, g=0, b=0, a=255)
|
|
101
|
+
*/
|
|
102
|
+
static VALUE
|
|
103
|
+
renderer_clear(int argc, VALUE *argv, VALUE self)
|
|
104
|
+
{
|
|
105
|
+
struct sdl2_renderer *ren = get_renderer(self);
|
|
106
|
+
Uint8 r = 0, g = 0, b = 0, a = 255;
|
|
107
|
+
|
|
108
|
+
if (argc > 0) r = (Uint8)NUM2INT(argv[0]);
|
|
109
|
+
if (argc > 1) g = (Uint8)NUM2INT(argv[1]);
|
|
110
|
+
if (argc > 2) b = (Uint8)NUM2INT(argv[2]);
|
|
111
|
+
if (argc > 3) a = (Uint8)NUM2INT(argv[3]);
|
|
112
|
+
|
|
113
|
+
SDL_SetRenderDrawColor(ren->renderer, r, g, b, a);
|
|
114
|
+
SDL_RenderClear(ren->renderer);
|
|
115
|
+
return self;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/*
|
|
119
|
+
* Teek::SDL2::Renderer#present
|
|
120
|
+
*/
|
|
121
|
+
static VALUE
|
|
122
|
+
renderer_present(VALUE self)
|
|
123
|
+
{
|
|
124
|
+
struct sdl2_renderer *ren = get_renderer(self);
|
|
125
|
+
SDL_RenderPresent(ren->renderer);
|
|
126
|
+
return self;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/*
|
|
130
|
+
* Teek::SDL2::Renderer#fill_rect(x, y, w, h, r, g, b, a=255)
|
|
131
|
+
*/
|
|
132
|
+
static VALUE
|
|
133
|
+
renderer_fill_rect(int argc, VALUE *argv, VALUE self)
|
|
134
|
+
{
|
|
135
|
+
struct sdl2_renderer *ren = get_renderer(self);
|
|
136
|
+
SDL_Rect rect;
|
|
137
|
+
Uint8 r, g, b, a = 255;
|
|
138
|
+
|
|
139
|
+
rb_check_arity(argc, 7, 8);
|
|
140
|
+
rect.x = NUM2INT(argv[0]);
|
|
141
|
+
rect.y = NUM2INT(argv[1]);
|
|
142
|
+
rect.w = NUM2INT(argv[2]);
|
|
143
|
+
rect.h = NUM2INT(argv[3]);
|
|
144
|
+
r = (Uint8)NUM2INT(argv[4]);
|
|
145
|
+
g = (Uint8)NUM2INT(argv[5]);
|
|
146
|
+
b = (Uint8)NUM2INT(argv[6]);
|
|
147
|
+
if (argc > 7) a = (Uint8)NUM2INT(argv[7]);
|
|
148
|
+
|
|
149
|
+
SDL_SetRenderDrawColor(ren->renderer, r, g, b, a);
|
|
150
|
+
SDL_RenderFillRect(ren->renderer, &rect);
|
|
151
|
+
return self;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/*
|
|
155
|
+
* Teek::SDL2::Renderer#draw_rect(x, y, w, h, r, g, b, a=255)
|
|
156
|
+
*/
|
|
157
|
+
static VALUE
|
|
158
|
+
renderer_draw_rect(int argc, VALUE *argv, VALUE self)
|
|
159
|
+
{
|
|
160
|
+
struct sdl2_renderer *ren = get_renderer(self);
|
|
161
|
+
SDL_Rect rect;
|
|
162
|
+
Uint8 r, g, b, a = 255;
|
|
163
|
+
|
|
164
|
+
rb_check_arity(argc, 7, 8);
|
|
165
|
+
rect.x = NUM2INT(argv[0]);
|
|
166
|
+
rect.y = NUM2INT(argv[1]);
|
|
167
|
+
rect.w = NUM2INT(argv[2]);
|
|
168
|
+
rect.h = NUM2INT(argv[3]);
|
|
169
|
+
r = (Uint8)NUM2INT(argv[4]);
|
|
170
|
+
g = (Uint8)NUM2INT(argv[5]);
|
|
171
|
+
b = (Uint8)NUM2INT(argv[6]);
|
|
172
|
+
if (argc > 7) a = (Uint8)NUM2INT(argv[7]);
|
|
173
|
+
|
|
174
|
+
SDL_SetRenderDrawColor(ren->renderer, r, g, b, a);
|
|
175
|
+
SDL_RenderDrawRect(ren->renderer, &rect);
|
|
176
|
+
return self;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/*
|
|
180
|
+
* Teek::SDL2::Renderer#draw_line(x1, y1, x2, y2, r, g, b, a=255)
|
|
181
|
+
*/
|
|
182
|
+
static VALUE
|
|
183
|
+
renderer_draw_line(int argc, VALUE *argv, VALUE self)
|
|
184
|
+
{
|
|
185
|
+
struct sdl2_renderer *ren = get_renderer(self);
|
|
186
|
+
Uint8 r, g, b, a = 255;
|
|
187
|
+
|
|
188
|
+
rb_check_arity(argc, 7, 8);
|
|
189
|
+
r = (Uint8)NUM2INT(argv[4]);
|
|
190
|
+
g = (Uint8)NUM2INT(argv[5]);
|
|
191
|
+
b = (Uint8)NUM2INT(argv[6]);
|
|
192
|
+
if (argc > 7) a = (Uint8)NUM2INT(argv[7]);
|
|
193
|
+
|
|
194
|
+
SDL_SetRenderDrawColor(ren->renderer, r, g, b, a);
|
|
195
|
+
SDL_RenderDrawLine(ren->renderer,
|
|
196
|
+
NUM2INT(argv[0]), NUM2INT(argv[1]),
|
|
197
|
+
NUM2INT(argv[2]), NUM2INT(argv[3]));
|
|
198
|
+
return self;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/*
|
|
202
|
+
* Teek::SDL2::Renderer#output_size -> [w, h]
|
|
203
|
+
*/
|
|
204
|
+
static VALUE
|
|
205
|
+
renderer_output_size(VALUE self)
|
|
206
|
+
{
|
|
207
|
+
struct sdl2_renderer *ren = get_renderer(self);
|
|
208
|
+
int w, h;
|
|
209
|
+
|
|
210
|
+
if (SDL_GetRendererOutputSize(ren->renderer, &w, &h) != 0) {
|
|
211
|
+
rb_raise(eSDL2Error, "SDL_GetRendererOutputSize: %s", SDL_GetError());
|
|
212
|
+
}
|
|
213
|
+
return rb_ary_new_from_args(2, INT2NUM(w), INT2NUM(h));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/*
|
|
217
|
+
* Teek::SDL2::Renderer#read_pixels -> String (RGBA bytes)
|
|
218
|
+
*
|
|
219
|
+
* Reads the current renderer contents as raw RGBA pixel data.
|
|
220
|
+
* Returns a binary String of width*height*4 bytes.
|
|
221
|
+
* Call after rendering but before present for consistent results.
|
|
222
|
+
*/
|
|
223
|
+
static VALUE
|
|
224
|
+
renderer_read_pixels(VALUE self)
|
|
225
|
+
{
|
|
226
|
+
struct sdl2_renderer *ren = get_renderer(self);
|
|
227
|
+
int w, h;
|
|
228
|
+
|
|
229
|
+
if (SDL_GetRendererOutputSize(ren->renderer, &w, &h) != 0) {
|
|
230
|
+
rb_raise(eSDL2Error, "SDL_GetRendererOutputSize: %s", SDL_GetError());
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
long size = (long)w * h * 4;
|
|
234
|
+
VALUE buf = rb_str_buf_new(size);
|
|
235
|
+
rb_str_set_len(buf, size);
|
|
236
|
+
|
|
237
|
+
if (SDL_RenderReadPixels(ren->renderer, NULL, SDL_PIXELFORMAT_RGBA8888,
|
|
238
|
+
RSTRING_PTR(buf), w * 4) != 0) {
|
|
239
|
+
rb_raise(eSDL2Error, "SDL_RenderReadPixels: %s", SDL_GetError());
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return buf;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/*
|
|
246
|
+
* Teek::SDL2::Renderer#destroy
|
|
247
|
+
*/
|
|
248
|
+
static VALUE
|
|
249
|
+
renderer_destroy(VALUE self)
|
|
250
|
+
{
|
|
251
|
+
struct sdl2_renderer *r;
|
|
252
|
+
TypedData_Get_Struct(self, struct sdl2_renderer, &renderer_type, r);
|
|
253
|
+
if (!r->destroyed) {
|
|
254
|
+
if (r->renderer) {
|
|
255
|
+
SDL_DestroyRenderer(r->renderer);
|
|
256
|
+
r->renderer = NULL;
|
|
257
|
+
}
|
|
258
|
+
if (r->window && r->owned_window) {
|
|
259
|
+
SDL_DestroyWindow(r->window);
|
|
260
|
+
r->window = NULL;
|
|
261
|
+
}
|
|
262
|
+
r->destroyed = 1;
|
|
263
|
+
}
|
|
264
|
+
return Qnil;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/*
|
|
268
|
+
* Teek::SDL2::Renderer#destroyed? -> true/false
|
|
269
|
+
*/
|
|
270
|
+
static VALUE
|
|
271
|
+
renderer_destroyed_p(VALUE self)
|
|
272
|
+
{
|
|
273
|
+
struct sdl2_renderer *r;
|
|
274
|
+
TypedData_Get_Struct(self, struct sdl2_renderer, &renderer_type, r);
|
|
275
|
+
return r->destroyed ? Qtrue : Qfalse;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/* ---------------------------------------------------------
|
|
279
|
+
* Texture (wraps SDL_Texture)
|
|
280
|
+
*
|
|
281
|
+
* struct sdl2_texture is defined in teek_sdl2.h so sdl2text.c
|
|
282
|
+
* can create Texture objects from TTF-rendered surfaces.
|
|
283
|
+
* --------------------------------------------------------- */
|
|
284
|
+
|
|
285
|
+
static void
|
|
286
|
+
texture_mark(void *ptr)
|
|
287
|
+
{
|
|
288
|
+
struct sdl2_texture *t = ptr;
|
|
289
|
+
rb_gc_mark(t->renderer_obj);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
static void
|
|
293
|
+
texture_free(void *ptr)
|
|
294
|
+
{
|
|
295
|
+
struct sdl2_texture *t = ptr;
|
|
296
|
+
if (!t->destroyed && t->texture) {
|
|
297
|
+
SDL_DestroyTexture(t->texture);
|
|
298
|
+
t->texture = NULL;
|
|
299
|
+
t->destroyed = 1;
|
|
300
|
+
}
|
|
301
|
+
xfree(t);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
static size_t
|
|
305
|
+
texture_memsize(const void *ptr)
|
|
306
|
+
{
|
|
307
|
+
return sizeof(struct sdl2_texture);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const rb_data_type_t texture_type = {
|
|
311
|
+
.wrap_struct_name = "TeekSDL2::Texture",
|
|
312
|
+
.function = {
|
|
313
|
+
.dmark = texture_mark,
|
|
314
|
+
.dfree = texture_free,
|
|
315
|
+
.dsize = texture_memsize,
|
|
316
|
+
},
|
|
317
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
static VALUE
|
|
321
|
+
texture_alloc(VALUE klass)
|
|
322
|
+
{
|
|
323
|
+
struct sdl2_texture *t;
|
|
324
|
+
VALUE obj = TypedData_Make_Struct(klass, struct sdl2_texture, &texture_type, t);
|
|
325
|
+
t->texture = NULL;
|
|
326
|
+
t->w = 0;
|
|
327
|
+
t->h = 0;
|
|
328
|
+
t->destroyed = 0;
|
|
329
|
+
t->renderer_obj = Qnil;
|
|
330
|
+
return obj;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
static struct sdl2_texture *
|
|
334
|
+
get_texture(VALUE self)
|
|
335
|
+
{
|
|
336
|
+
struct sdl2_texture *t;
|
|
337
|
+
TypedData_Get_Struct(self, struct sdl2_texture, &texture_type, t);
|
|
338
|
+
if (t->destroyed || t->texture == NULL) {
|
|
339
|
+
rb_raise(eSDL2Error, "texture has been destroyed");
|
|
340
|
+
}
|
|
341
|
+
return t;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/*
|
|
345
|
+
* Teek::SDL2::Renderer#create_texture(w, h, access=:streaming)
|
|
346
|
+
*
|
|
347
|
+
* Creates an ARGB8888 texture. Access modes:
|
|
348
|
+
* :static - rarely updated
|
|
349
|
+
* :streaming - frequently updated (lock/unlock)
|
|
350
|
+
* :target - can be used as render target
|
|
351
|
+
*/
|
|
352
|
+
static VALUE
|
|
353
|
+
renderer_create_texture(int argc, VALUE *argv, VALUE self)
|
|
354
|
+
{
|
|
355
|
+
struct sdl2_renderer *ren = get_renderer(self);
|
|
356
|
+
int w, h;
|
|
357
|
+
int access = SDL_TEXTUREACCESS_STREAMING;
|
|
358
|
+
|
|
359
|
+
rb_check_arity(argc, 2, 3);
|
|
360
|
+
w = NUM2INT(argv[0]);
|
|
361
|
+
h = NUM2INT(argv[1]);
|
|
362
|
+
|
|
363
|
+
if (argc > 2 && !NIL_P(argv[2])) {
|
|
364
|
+
ID sym = SYM2ID(argv[2]);
|
|
365
|
+
if (sym == rb_intern("static"))
|
|
366
|
+
access = SDL_TEXTUREACCESS_STATIC;
|
|
367
|
+
else if (sym == rb_intern("streaming"))
|
|
368
|
+
access = SDL_TEXTUREACCESS_STREAMING;
|
|
369
|
+
else if (sym == rb_intern("target"))
|
|
370
|
+
access = SDL_TEXTUREACCESS_TARGET;
|
|
371
|
+
else
|
|
372
|
+
rb_raise(rb_eArgError, "unknown access mode (use :static, :streaming, or :target)");
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
SDL_Texture *tex = SDL_CreateTexture(ren->renderer,
|
|
376
|
+
SDL_PIXELFORMAT_ARGB8888,
|
|
377
|
+
access, w, h);
|
|
378
|
+
if (!tex) {
|
|
379
|
+
rb_raise(eSDL2Error, "SDL_CreateTexture: %s", SDL_GetError());
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
VALUE obj = texture_alloc(cTexture);
|
|
383
|
+
struct sdl2_texture *t;
|
|
384
|
+
TypedData_Get_Struct(obj, struct sdl2_texture, &texture_type, t);
|
|
385
|
+
t->texture = tex;
|
|
386
|
+
t->w = w;
|
|
387
|
+
t->h = h;
|
|
388
|
+
t->renderer_obj = self;
|
|
389
|
+
return obj;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/*
|
|
393
|
+
* Teek::SDL2::Texture#update(pixels)
|
|
394
|
+
*
|
|
395
|
+
* Updates the entire texture with pixel data.
|
|
396
|
+
* pixels must be a String of w*h*4 bytes (ARGB8888).
|
|
397
|
+
*/
|
|
398
|
+
static VALUE
|
|
399
|
+
texture_update(VALUE self, VALUE pixels)
|
|
400
|
+
{
|
|
401
|
+
struct sdl2_texture *t = get_texture(self);
|
|
402
|
+
Check_Type(pixels, T_STRING);
|
|
403
|
+
|
|
404
|
+
long expected = (long)t->w * t->h * 4;
|
|
405
|
+
if (RSTRING_LEN(pixels) != expected) {
|
|
406
|
+
rb_raise(rb_eArgError, "pixel data must be %ld bytes (got %ld)",
|
|
407
|
+
expected, RSTRING_LEN(pixels));
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
int pitch = t->w * 4;
|
|
411
|
+
if (SDL_UpdateTexture(t->texture, NULL, RSTRING_PTR(pixels), pitch) != 0) {
|
|
412
|
+
rb_raise(eSDL2Error, "SDL_UpdateTexture: %s", SDL_GetError());
|
|
413
|
+
}
|
|
414
|
+
return self;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/*
|
|
418
|
+
* Teek::SDL2::Renderer#copy(texture, src_rect=nil, dst_rect=nil)
|
|
419
|
+
*
|
|
420
|
+
* Copies texture to the renderer. Rects are [x, y, w, h] arrays or nil for full area.
|
|
421
|
+
*/
|
|
422
|
+
static VALUE
|
|
423
|
+
renderer_copy(int argc, VALUE *argv, VALUE self)
|
|
424
|
+
{
|
|
425
|
+
struct sdl2_renderer *ren = get_renderer(self);
|
|
426
|
+
VALUE tex_obj, src_rect_obj, dst_rect_obj;
|
|
427
|
+
SDL_Rect src, dst, *srcp = NULL, *dstp = NULL;
|
|
428
|
+
|
|
429
|
+
rb_scan_args(argc, argv, "12", &tex_obj, &src_rect_obj, &dst_rect_obj);
|
|
430
|
+
|
|
431
|
+
struct sdl2_texture *t = get_texture(tex_obj);
|
|
432
|
+
|
|
433
|
+
if (!NIL_P(src_rect_obj)) {
|
|
434
|
+
Check_Type(src_rect_obj, T_ARRAY);
|
|
435
|
+
src.x = NUM2INT(rb_ary_entry(src_rect_obj, 0));
|
|
436
|
+
src.y = NUM2INT(rb_ary_entry(src_rect_obj, 1));
|
|
437
|
+
src.w = NUM2INT(rb_ary_entry(src_rect_obj, 2));
|
|
438
|
+
src.h = NUM2INT(rb_ary_entry(src_rect_obj, 3));
|
|
439
|
+
srcp = &src;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if (!NIL_P(dst_rect_obj)) {
|
|
443
|
+
Check_Type(dst_rect_obj, T_ARRAY);
|
|
444
|
+
dst.x = NUM2INT(rb_ary_entry(dst_rect_obj, 0));
|
|
445
|
+
dst.y = NUM2INT(rb_ary_entry(dst_rect_obj, 1));
|
|
446
|
+
dst.w = NUM2INT(rb_ary_entry(dst_rect_obj, 2));
|
|
447
|
+
dst.h = NUM2INT(rb_ary_entry(dst_rect_obj, 3));
|
|
448
|
+
dstp = &dst;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (SDL_RenderCopy(ren->renderer, t->texture, srcp, dstp) != 0) {
|
|
452
|
+
rb_raise(eSDL2Error, "SDL_RenderCopy: %s", SDL_GetError());
|
|
453
|
+
}
|
|
454
|
+
return self;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/*
|
|
458
|
+
* Teek::SDL2::Texture#width -> Integer
|
|
459
|
+
*/
|
|
460
|
+
static VALUE
|
|
461
|
+
texture_width(VALUE self)
|
|
462
|
+
{
|
|
463
|
+
return INT2NUM(get_texture(self)->w);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/*
|
|
467
|
+
* Teek::SDL2::Texture#height -> Integer
|
|
468
|
+
*/
|
|
469
|
+
static VALUE
|
|
470
|
+
texture_height(VALUE self)
|
|
471
|
+
{
|
|
472
|
+
return INT2NUM(get_texture(self)->h);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/*
|
|
476
|
+
* Teek::SDL2::Texture#destroy
|
|
477
|
+
*/
|
|
478
|
+
static VALUE
|
|
479
|
+
texture_destroy(VALUE self)
|
|
480
|
+
{
|
|
481
|
+
struct sdl2_texture *t;
|
|
482
|
+
TypedData_Get_Struct(self, struct sdl2_texture, &texture_type, t);
|
|
483
|
+
if (!t->destroyed && t->texture) {
|
|
484
|
+
SDL_DestroyTexture(t->texture);
|
|
485
|
+
t->texture = NULL;
|
|
486
|
+
t->destroyed = 1;
|
|
487
|
+
}
|
|
488
|
+
return Qnil;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/*
|
|
492
|
+
* Teek::SDL2::Texture#destroyed? -> true/false
|
|
493
|
+
*/
|
|
494
|
+
static VALUE
|
|
495
|
+
texture_destroyed_p(VALUE self)
|
|
496
|
+
{
|
|
497
|
+
struct sdl2_texture *t;
|
|
498
|
+
TypedData_Get_Struct(self, struct sdl2_texture, &texture_type, t);
|
|
499
|
+
return t->destroyed ? Qtrue : Qfalse;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/* ---------------------------------------------------------
|
|
503
|
+
* Init
|
|
504
|
+
* --------------------------------------------------------- */
|
|
505
|
+
|
|
506
|
+
void
|
|
507
|
+
Init_sdl2surface(VALUE mTeekSDL2)
|
|
508
|
+
{
|
|
509
|
+
eSDL2Error = rb_define_class_under(mTeekSDL2, "Error", rb_eRuntimeError);
|
|
510
|
+
|
|
511
|
+
/* Renderer */
|
|
512
|
+
cRenderer = rb_define_class_under(mTeekSDL2, "Renderer", rb_cObject);
|
|
513
|
+
rb_define_alloc_func(cRenderer, renderer_alloc);
|
|
514
|
+
rb_define_method(cRenderer, "clear", renderer_clear, -1);
|
|
515
|
+
rb_define_method(cRenderer, "present", renderer_present, 0);
|
|
516
|
+
rb_define_method(cRenderer, "fill_rect", renderer_fill_rect, -1);
|
|
517
|
+
rb_define_method(cRenderer, "draw_rect", renderer_draw_rect, -1);
|
|
518
|
+
rb_define_method(cRenderer, "draw_line", renderer_draw_line, -1);
|
|
519
|
+
rb_define_method(cRenderer, "output_size", renderer_output_size, 0);
|
|
520
|
+
rb_define_method(cRenderer, "read_pixels", renderer_read_pixels, 0);
|
|
521
|
+
rb_define_method(cRenderer, "create_texture", renderer_create_texture, -1);
|
|
522
|
+
rb_define_method(cRenderer, "copy", renderer_copy, -1);
|
|
523
|
+
rb_define_method(cRenderer, "destroy", renderer_destroy, 0);
|
|
524
|
+
rb_define_method(cRenderer, "destroyed?", renderer_destroyed_p, 0);
|
|
525
|
+
|
|
526
|
+
/* Texture */
|
|
527
|
+
cTexture = rb_define_class_under(mTeekSDL2, "Texture", rb_cObject);
|
|
528
|
+
rb_define_alloc_func(cTexture, texture_alloc);
|
|
529
|
+
rb_define_method(cTexture, "update", texture_update, 1);
|
|
530
|
+
rb_define_method(cTexture, "width", texture_width, 0);
|
|
531
|
+
rb_define_method(cTexture, "height", texture_height, 0);
|
|
532
|
+
rb_define_method(cTexture, "destroy", texture_destroy, 0);
|
|
533
|
+
rb_define_method(cTexture, "destroyed?", texture_destroyed_p, 0);
|
|
534
|
+
}
|