source: libcaca/trunk/ruby/cucul/cucul-canvas.c @ 1948

Last change on this file since 1948 was 1948, checked in by Pascal Terjan, 13 years ago

Improve Ruby API for draw_{,thin_}polyline and fix a leak on error

  • Property svn:eol-style set to native
File size: 17.2 KB
RevLine 
[1944]1/*
2 *  libcucul Ruby bindings
3 *  Copyright (c) 2007 Pascal Terjan <pterjan@linuxfr.org>
4 *
5 *  This library is free software. It comes without any warranty, to
6 *  the extent permitted by applicable law. You can redistribute it
7 *  and/or modify it under the terms of the Do What The Fuck You Want
8 *  To Public License, Version 2, as published by Sam Hocevar. See
9 *  http://sam.zoy.org/wtfpl/COPYING for more details.
10 */
11
12#include <ruby.h>
13#include <cucul.h>
14#include <errno.h>
15
16#define _SELF  (DATA_PTR(self))
17
18#define simple_func(x)                                  \
19static VALUE x (VALUE self)                             \
20{                                                       \
21    if( cucul_##x (_SELF) <0)                           \
22        rb_raise(rb_eRuntimeError, strerror(errno));    \
23                                                        \
24    return self;                                        \
25}
26
27#define get_int(x)                                      \
28static VALUE get_##x (VALUE self)                       \
29{                                                       \
30    return INT2NUM(cucul_get_##x (_SELF));              \
31}
32
33static void canvas_free(void * p)
34{
35    cucul_free_canvas((cucul_canvas_t *)p);
36}
37
38static VALUE canvas_alloc(VALUE klass)
39{
40    cucul_canvas_t *canvas;
41    VALUE obj;
42   
43    canvas = cucul_create_canvas(0, 0);
44    obj = Data_Wrap_Struct(klass, 0, canvas_free, canvas);
45   
46    return obj;
47}
48
49static VALUE canvas_initialize(VALUE self, VALUE width, VALUE height)
50{
51    unsigned int w, h;
52
53    w = NUM2INT(width);
54    h = NUM2INT(height);
55   
56    cucul_set_canvas_size(_SELF, w, h);
57   
58    return self;
59}
60
61get_int(canvas_height)
62get_int(canvas_width)
63
64static VALUE set_canvas_width(VALUE self, VALUE width)
65{
66    cucul_set_canvas_size(_SELF, NUM2INT(width), cucul_get_canvas_height(_SELF));
67    return width;
68}
69
70static VALUE set_canvas_width2(VALUE self, VALUE width)
71{
72    set_canvas_width(self, width);
73    return self;
74}
75
76static VALUE set_canvas_height(VALUE self, VALUE height)
77{
78    cucul_set_canvas_size(_SELF, cucul_get_canvas_width(_SELF), NUM2INT(height));
79    return height;
80}
81
82static VALUE set_canvas_height2(VALUE self, VALUE height)
83{
84    set_canvas_height(self, height);
85    return self;
86}
87
88static VALUE set_canvas_size(VALUE self, VALUE height, VALUE width)
89{
90    cucul_set_canvas_size(_SELF, NUM2INT(width), NUM2INT(height));
91    return self;
92}
93
94/****/
95
96static VALUE gotoxy(VALUE self, VALUE x, VALUE y)
97{
98    if( cucul_gotoxy(_SELF, NUM2INT(x), NUM2INT(y)) <0) {
99        rb_raise(rb_eRuntimeError, strerror(errno));
100    }
101    return self;
102}
103
104get_int(cursor_x)
105get_int(cursor_y)
106
107simple_func(clear_canvas)
108
109static VALUE put_char(VALUE self, VALUE x, VALUE y, VALUE ch)
110{
111    cucul_put_char(_SELF, NUM2INT(x), NUM2INT(y), NUM2ULONG(ch));
112    return self;
113}
114
115static VALUE get_char(VALUE self, VALUE x, VALUE y)
116{
117    unsigned long int ch;
118    ch = cucul_get_char(_SELF, NUM2INT(x), NUM2INT(y));
119    return INT2NUM(ch);
120}
121
122static VALUE put_str(VALUE self, VALUE x, VALUE y, VALUE str)
123{
124    cucul_put_str(_SELF, NUM2INT(x), NUM2INT(y), StringValuePtr(str));
125    return self;
126}
127
128static VALUE get_attr(VALUE self, VALUE x, VALUE y)
129{
130    unsigned long int ch;
131    ch = cucul_get_attr(_SELF, NUM2INT(x), NUM2INT(y));
132    return INT2NUM(ch);
133}
134
135static VALUE set_attr(VALUE self, VALUE attr)
136{
137    if(cucul_set_attr(_SELF, NUM2ULONG(attr)) <0)
138        rb_raise(rb_eRuntimeError, strerror(errno));
139
140    return self;
141}
142
143static VALUE set_attr2(VALUE self, VALUE attr)
144{
145    set_attr(self, attr);
146    return self;
147}
148
149static VALUE put_attr(VALUE self, VALUE x, VALUE y, VALUE attr)
150{
151    if(cucul_put_attr(_SELF, NUM2INT(x), NUM2INT(y), NUM2ULONG(attr)) <0)
152        rb_raise(rb_eRuntimeError, strerror(errno));
153
154    return self;
155}
156
157static VALUE set_color_ansi(VALUE self, VALUE fg, VALUE bg)
158{
159    if(cucul_set_color_ansi(_SELF, NUM2INT(fg), NUM2INT(bg)) <0)
160        rb_raise(rb_eRuntimeError, strerror(errno));
161
162    return self;
163}
164
165static VALUE set_color_argb(VALUE self, VALUE fg, VALUE bg)
166{
167    if(cucul_set_color_argb(_SELF, NUM2UINT(fg), NUM2UINT(bg)) <0) {
168        rb_raise(rb_eRuntimeError, strerror(errno));
169    }
170    return self;
171}
172
173static VALUE cprintf(int argc, VALUE* argv, VALUE self)
174{
175    int x, y;
176    VALUE rx, ry, format, rest, string;
177    rb_scan_args(argc, argv, "3*", &rx, &ry, &format, &rest);
178    x = NUM2INT(rx);
179    y = NUM2INT(ry);
180    string = rb_funcall2(rb_mKernel, rb_intern("sprintf"), argc-2, argv+2);
181    cucul_put_str(_SELF, x, y, StringValuePtr(string));
182    return self;
183}
184
185
186get_int(canvas_handle_x)
187get_int(canvas_handle_y)
188
189static VALUE set_canvas_handle(VALUE self, VALUE x, VALUE y)
190{
191    cucul_set_canvas_handle(_SELF, NUM2INT(x), NUM2INT(y));
192    return self;
193}
194
195static VALUE blit(int argc, VALUE* argv, VALUE self) {
196    VALUE x, y, src, mask;
197    cucul_canvas_t *csrc, *cmask;
198
199    rb_scan_args(argc, argv, "31", &x, &y, &src, &mask);
200
201    Check_Type(x, T_FIXNUM);
202    Check_Type(y, T_FIXNUM);
203    Check_Type(src, TYPE(self));
204    Data_Get_Struct(src, cucul_canvas_t, csrc);
205    if(!NIL_P(mask))
206    {
207        Check_Type(mask, TYPE(self));
208        Data_Get_Struct(mask, cucul_canvas_t, cmask);
209    }
210    else
211        cmask = NULL;
212   
213    if(cucul_blit(_SELF, NUM2INT(x), NUM2INT(y), csrc, cmask)<0)
214        rb_raise(rb_eRuntimeError, strerror(errno));
215
216    return self;
217}
218
219static VALUE set_canvas_boundaries(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h)
220{
221    if(cucul_set_canvas_boundaries(_SELF, NUM2INT(x), NUM2INT(y), NUM2UINT(w), NUM2UINT(h))<0)
222    {
223        rb_raise(rb_eRuntimeError, strerror(errno));
224    }
225    return self;
226}
227
228/****/
229
230simple_func(invert)
231simple_func(flip)
232simple_func(flop)
233simple_func(rotate_180)
234simple_func(rotate_left)
235simple_func(rotate_right)
236simple_func(stretch_left)
237simple_func(stretch_right)
238
239/****/
240
241static VALUE draw_line(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE ch)
242{
243    cucul_draw_line(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2),NUM2ULONG(ch));
244    return self;
245}
246
[1948]247static VALUE draw_polyline(VALUE self, VALUE points, VALUE ch)
[1944]248{
249    int i, n;
250    int *ax, *ay;
[1948]251    int error = 0;
252    VALUE v, x, y;
[1944]253
[1948]254    n = RARRAY(points)->len;
[1944]255
256    ax = (int*)malloc(n*sizeof(int));
257    if(!ax)
258        rb_raise(rb_eNoMemError,"Out of memory");
259
260    ay = (int*)malloc(n*sizeof(int));
261    if(!ay)
262    {
263        free(ax);
264        rb_raise(rb_eNoMemError,"Out of memory");
265    }
266
267    for(i=0; i<n; i++)
268    {
[1948]269        v = rb_ary_entry(points, i);
270        if((TYPE(v) == T_ARRAY) && (RARRAY(v)->len == 2))
271        {
272            x = rb_ary_entry(v,0);
273            y = rb_ary_entry(v,1);
274            if(rb_obj_is_kind_of(x, rb_cInteger) &&
275               rb_obj_is_kind_of(y, rb_cInteger))
276            {
277                ax[i] = NUM2INT(x);
278                ay[i] = NUM2INT(y);
279            } else
280                error = 1;
281        }
282        else
283            error = 1;
[1944]284    }
285
[1948]286    if(error)
287    {
288        free(ax);
289        free(ay);
290        rb_raise(rb_eArgError, "Invalid list of points");
291    }
292
[1944]293    n--;
294
295    cucul_draw_polyline(_SELF, ax, ay, n, NUM2ULONG(ch));
296
297    free(ax);
298    free(ay);
299
300    return self;
301}
302
303static VALUE draw_thin_line(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2)
304{
305    cucul_draw_thin_line(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2));
306    return self;
307}
308
[1948]309static VALUE draw_thin_polyline(VALUE self, VALUE points)
[1944]310{
311    int i, n;
312    int *ax, *ay;
[1948]313    int error = 0;
314    VALUE v, x, y;
[1944]315
[1948]316    n = RARRAY(points)->len;
[1944]317
318    ax = (int*)malloc(n*sizeof(int));
319    if(!ax)
320        rb_raise(rb_eNoMemError,"Out of memory");
321
322    ay = (int*)malloc(n*sizeof(int));
323    if(!ay)
324    {
325        free(ax);
326        rb_raise(rb_eNoMemError,"Out of memory");
327    }
328
329    for(i=0; i<n; i++)
330    {
[1948]331        v = rb_ary_entry(points, i);
332        if((TYPE(v) == T_ARRAY) && (RARRAY(v)->len == 2))
333        {
334            x = rb_ary_entry(v,0);
335            y = rb_ary_entry(v,1);
336            if(rb_obj_is_kind_of(x, rb_cInteger) &&
337               rb_obj_is_kind_of(y, rb_cInteger))
338            {
339                ax[i] = NUM2INT(x);
340                ay[i] = NUM2INT(y);
341            } else
342                error = 1;
343        }
344        else
345            error = 1;
[1944]346    }
347
[1948]348    if(error)
349    {
350        free(ax);
351        free(ay);
352        rb_raise(rb_eArgError, "Invalid list of points");
353    }
354
[1944]355    n--;
356
357    cucul_draw_thin_polyline(_SELF, ax, ay, n);
358
359    free(ax);
360    free(ay);
361
362    return self;
363}
364
365static VALUE draw_circle(VALUE self, VALUE x, VALUE y, VALUE r, VALUE ch)
366{
367    cucul_draw_circle(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(r), NUM2ULONG(ch));
368    return self;
369}
370
371static VALUE draw_ellipse(VALUE self, VALUE x, VALUE y, VALUE a, VALUE b, VALUE ch)
372{
373    cucul_draw_ellipse(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(a), NUM2INT(b), NUM2ULONG(ch));
374    return self;
375}
376
377static VALUE draw_thin_ellipse(VALUE self, VALUE x, VALUE y, VALUE a, VALUE b)
378{
379    cucul_draw_thin_ellipse(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(a), NUM2INT(b));
380    return self;
381}
382
383static VALUE fill_ellipse(VALUE self, VALUE x, VALUE y, VALUE a, VALUE b, VALUE ch)
384{
385    cucul_fill_ellipse(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(a), NUM2INT(b), NUM2ULONG(ch));
386    return self;
387}
388
389static VALUE draw_box(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE ch)
390{
391    cucul_draw_box(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2), NUM2ULONG(ch));
392    return self;
393}
394
395static VALUE draw_thin_box(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2)
396{
397    cucul_draw_thin_box(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2));
398    return self;
399}
400
401static VALUE draw_cp437_box(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2)
402{
403    cucul_draw_cp437_box(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2));
404    return self;
405}
406
407static VALUE fill_box(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE ch)
408{
409    cucul_fill_box(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2), NUM2ULONG(ch));
410    return self;
411}
412
413static VALUE draw_triangle(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE x3, VALUE y3, VALUE ch)
414{
415    cucul_draw_triangle(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2),  NUM2INT(x3), NUM2INT(y3), NUM2ULONG(ch));
416    return self;
417}
418
419static VALUE draw_thin_triangle(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE x3, VALUE y3)
420{
421    cucul_draw_thin_triangle(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2),  NUM2INT(x3), NUM2INT(y3));
422    return self;
423}
424
425static VALUE fill_triangle(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE x3, VALUE y3, VALUE ch)
426{
427    cucul_fill_triangle(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2),  NUM2INT(x3), NUM2INT(y3), NUM2ULONG(ch));
428    return self;
429}
430
431/****/
432
433get_int(frame_count)
434
435static VALUE set_frame(VALUE self, VALUE id)
436{
437    if(cucul_set_frame(_SELF, NUM2INT(id))<0)
438        rb_raise(rb_eArgError, strerror(errno));
439
440    return self;
441}
442
443static VALUE set_frame2(VALUE self, VALUE id)
444{
445    set_frame(self, id);
446    return self;
447}
448
449static VALUE get_frame_name(VALUE self)
450{
451    return rb_str_new2(cucul_get_frame_name(_SELF));
452}
453
454static VALUE set_frame_name(VALUE self, VALUE name)
455{
456    if(cucul_set_frame_name(_SELF, StringValuePtr(name))<0)
457        rb_raise(rb_eRuntimeError, strerror(errno));
458
459    return self;
460}
461
462static VALUE set_frame_name2(VALUE self, VALUE name)
463{
464    set_frame_name(self, name);
465    return self;
466}
467
468static VALUE create_frame(VALUE self, VALUE id)
469{
470    if(cucul_create_frame(_SELF, NUM2INT(id))<0) {
471        rb_raise(rb_eRuntimeError, strerror(errno));
472    }
473    return self;
474}
475
476static VALUE free_frame(VALUE self, VALUE id)
477{
478    if(cucul_free_frame(_SELF, NUM2INT(id))<0) {
479        rb_raise(rb_eArgError, strerror(errno));
480    }
481    return self;
482}
483
484/****/
485
486static VALUE import_memory(VALUE self, VALUE data, VALUE format)
487{
488    long int bytes;
489    bytes = cucul_import_memory (_SELF, StringValuePtr(data), RSTRING(StringValue(data))->len, StringValuePtr(format));
490    if(bytes <= 0)
491        rb_raise(rb_eRuntimeError, strerror(errno));
492
493    return self;
494}
495
496static VALUE import_file(VALUE self, VALUE filename, VALUE format)
497{
498    long int bytes;
499    bytes = cucul_import_file (_SELF, StringValuePtr(filename), StringValuePtr(format));
500    if(bytes <= 0)
501        rb_raise(rb_eRuntimeError, strerror(errno));
502
503    return self;
504}
505
506static VALUE export_memory(VALUE self, VALUE format)
507{
508    unsigned long int bytes;
509    void *result;
510    VALUE ret;
511    result = cucul_export_memory (_SELF, StringValuePtr(format), &bytes);
512    ret = rb_str_new(result, bytes);
513    free(result);
514    return ret;
515}
516
517static VALUE export_list()
518{
519    VALUE ary, ary2;
520   
521    char const* const* list;
522   
523    list = cucul_get_export_list();
524   
525    ary = rb_ary_new();
526   
527    while (*list != NULL)
528    {
529        ary2 = rb_ary_new();
530        rb_ary_push(ary2, rb_str_new2(*list));
531        list++;
532        rb_ary_push(ary2, rb_str_new2(*list));
533        list++;
534        rb_ary_push(ary, ary2);
535    }
536
537    return ary;
538}
539
540static VALUE import_list()
541{
542    VALUE ary, ary2;
543   
544    char const* const* list;
545   
546    list = cucul_get_import_list();
547   
548    ary = rb_ary_new();
549   
550    while (*list != NULL)
551    {
552        ary2 = rb_ary_new();
553        rb_ary_push(ary2, rb_str_new2(*list));
554        list++;
555        rb_ary_push(ary2, rb_str_new2(*list));
556        list++;
557        rb_ary_push(ary, ary2);
558    }
559
560    return ary;
561}
562
563/****/
564
565void Init_cucul_canvas(VALUE mCucul)
566{
567    VALUE cCanvas = rb_define_class_under(mCucul, "Canvas", rb_cObject);
568    rb_define_alloc_func(cCanvas, canvas_alloc);
569
570    rb_define_method(cCanvas, "initialize", canvas_initialize, 2);
571    rb_define_method(cCanvas, "width", get_canvas_width, 0);
572    rb_define_method(cCanvas, "width=", set_canvas_width, 1);
573    rb_define_method(cCanvas, "set_width", set_canvas_width2, 1);
574    rb_define_method(cCanvas, "height", get_canvas_height, 0);
575    rb_define_method(cCanvas, "height=", set_canvas_height, 0);
576    rb_define_method(cCanvas, "set_height", set_canvas_height2, 0);
577    rb_define_method(cCanvas, "set_size", set_canvas_size, 2);
578       
579    rb_define_method(cCanvas, "gotoxy", gotoxy, 2);
580    rb_define_method(cCanvas, "cursor_x", get_cursor_x, 0);
581    rb_define_method(cCanvas, "cursor_y", get_cursor_y, 0);
582    rb_define_method(cCanvas, "handle_x", get_canvas_handle_x, 0);
583    rb_define_method(cCanvas, "handle_y", get_canvas_handle_y, 0);
584    rb_define_method(cCanvas, "set_handle", set_canvas_handle, 2);
585    rb_define_method(cCanvas, "blit", blit, -1);
586    rb_define_method(cCanvas, "set_boundaries", set_canvas_boundaries, 4);
587
588    rb_define_method(cCanvas, "clear", clear_canvas, 0);
589   
590    rb_define_method(cCanvas, "put_char", put_char, 3);
591    rb_define_method(cCanvas, "get_char", get_char, 2);
592    rb_define_method(cCanvas, "put_str", put_str, 3);
593    rb_define_method(cCanvas, "printf", cprintf, -1);
594
595    rb_define_method(cCanvas, "get_attr", get_attr, 3);
596    rb_define_method(cCanvas, "attr=", set_attr, 1);
597    rb_define_method(cCanvas, "set_attr", set_attr2, 1);
598    rb_define_method(cCanvas, "put_attr", put_attr, 3);
599    rb_define_method(cCanvas, "set_color_ansi", set_color_ansi, 2);
600    rb_define_method(cCanvas, "set_color_argb", set_color_argb, 2);
601
602    rb_define_method(cCanvas, "invert", invert, 0);
603    rb_define_method(cCanvas, "flip", flip, 0);
604    rb_define_method(cCanvas, "flop", flop, 0);
605    rb_define_method(cCanvas, "rotate_180", rotate_180, 0);
606    rb_define_method(cCanvas, "rotate_left", rotate_left, 0);
607    rb_define_method(cCanvas, "rotate_right", rotate_right, 0);
608    rb_define_method(cCanvas, "stretch_left", stretch_left, 0);
609    rb_define_method(cCanvas, "stretch_right", stretch_right, 0);
610
611    rb_define_method(cCanvas, "draw_line", draw_line, 5);
[1948]612    rb_define_method(cCanvas, "draw_polyline", draw_polyline, 2);
[1944]613    rb_define_method(cCanvas, "draw_thin_line", draw_thin_line, 4);
[1948]614    rb_define_method(cCanvas, "draw_thin_polyline", draw_thin_polyline, 1);
[1944]615    rb_define_method(cCanvas, "draw_circle", draw_circle, 4);
616    rb_define_method(cCanvas, "draw_ellipse", draw_ellipse, 5);
617    rb_define_method(cCanvas, "draw_thin_ellipse", draw_thin_ellipse, 4);
618    rb_define_method(cCanvas, "fill_ellipse", fill_ellipse, 5);
619    rb_define_method(cCanvas, "draw_box", draw_box, 5);
620    rb_define_method(cCanvas, "draw_thin_box", draw_thin_box, 4);
621    rb_define_method(cCanvas, "draw_cp437_box", draw_cp437_box, 4);
622    rb_define_method(cCanvas, "fill_box", fill_box, 5);
623    rb_define_method(cCanvas, "draw_triangle", draw_triangle, 7);
624    rb_define_method(cCanvas, "draw_thin_triangle", draw_thin_triangle, 6);
625    rb_define_method(cCanvas, "fill_triangle", fill_triangle, 7);
626
627    rb_define_method(cCanvas, "frame_count", get_frame_count, 0);
628    rb_define_method(cCanvas, "frame=", set_frame, 1);
629    rb_define_method(cCanvas, "set_frame", set_frame2, 1);
630    rb_define_method(cCanvas, "frame_name", get_frame_name, 0);
631    rb_define_method(cCanvas, "frame_name=", set_frame_name, 1);
632    rb_define_method(cCanvas, "set_frame_name", set_frame_name2, 1);
633    rb_define_method(cCanvas, "create_frame", create_frame, 1);
634    rb_define_method(cCanvas, "free_frame", free_frame, 1);
635
636    rb_define_method(cCanvas, "import_memory", import_memory, 2);
637    rb_define_method(cCanvas, "import_file", import_file, 2);
638    rb_define_method(cCanvas, "export_memory", export_memory, 1);
639    rb_define_singleton_method(cCanvas, "export_list", export_list, 0);
640    rb_define_singleton_method(cCanvas, "import_list", import_list, 0);
641   
642}
643
Note: See TracBrowser for help on using the repository browser.