"Fossies" - the Fresh Open Source Software Archive

Member "libcaca-0.99.beta20/ruby/caca-canvas.c" (19 Oct 2021, 22984 Bytes) of package /linux/privat/libcaca-0.99.beta20.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2  *  libcaca Ruby bindings
    3  *  Copyright © 2007—2014 Pascal Terjan <pterjan@linuxfr.org>
    4  *              2021 Sam Hocevar <sam@hocevar.net>
    5  *              All Rights Reserved
    6  *
    7  *  This library is free software. It comes without any warranty, to
    8  *  the extent permitted by applicable law. You can redistribute it
    9  *  and/or modify it under the terms of the Do What the Fuck You Want
   10  *  to Public License, Version 2, as published by Sam Hocevar. See
   11  *  http://www.wtfpl.net/ for more details.
   12  */
   13 
   14 #include <ruby.h>
   15 #include <caca.h>
   16 #include <errno.h>
   17 #include "caca-dither.h"
   18 #include "caca-font.h"
   19 #include "common.h"
   20 
   21 VALUE cCanvas;
   22 
   23 #define simple_func(x)                                  \
   24 static VALUE x (VALUE self)                             \
   25 {                                                       \
   26     if( caca_##x (_SELF) <0)                            \
   27         rb_raise(rb_eRuntimeError, "%s", strerror(errno));    \
   28                                                         \
   29     return self;                                        \
   30 }
   31 
   32 #define get_int(x)                                      \
   33 static VALUE get_##x (VALUE self)                       \
   34 {                                                       \
   35     return INT2NUM(caca_get_##x (_SELF));               \
   36 }
   37 
   38 static void canvas_free(void * p)
   39 {
   40     caca_free_canvas((caca_canvas_t *)p);
   41 }
   42 
   43 static VALUE canvas_alloc(VALUE klass)
   44 {
   45     VALUE obj;
   46     obj = Data_Wrap_Struct(klass, NULL, canvas_free, NULL);
   47     return obj;
   48 }
   49 
   50 VALUE canvas_create(caca_canvas_t *canvas)
   51 {
   52     return Data_Wrap_Struct(cCanvas, NULL, NULL, canvas);
   53 }
   54 
   55 static VALUE canvas_initialize(VALUE self, VALUE width, VALUE height)
   56 {
   57     caca_canvas_t *canvas;
   58 
   59     canvas = caca_create_canvas(NUM2INT(width), NUM2INT(height));
   60 
   61     if(canvas == NULL)
   62     {
   63         rb_raise(rb_eRuntimeError, "%s", strerror(errno));
   64     }
   65 
   66     _SELF = canvas;
   67 
   68     return self;
   69 }
   70 
   71 get_int(canvas_height)
   72 get_int(canvas_width)
   73 
   74 static VALUE set_canvas_width(VALUE self, VALUE width)
   75 {
   76     caca_set_canvas_size(_SELF, NUM2INT(width), caca_get_canvas_height(_SELF));
   77     return width;
   78 }
   79 
   80 static VALUE set_canvas_width2(VALUE self, VALUE width)
   81 {
   82     set_canvas_width(self, width);
   83     return self;
   84 }
   85 
   86 static VALUE set_canvas_height(VALUE self, VALUE height)
   87 {
   88     caca_set_canvas_size(_SELF, caca_get_canvas_width(_SELF), NUM2INT(height));
   89     return height;
   90 }
   91 
   92 static VALUE set_canvas_height2(VALUE self, VALUE height)
   93 {
   94     set_canvas_height(self, height);
   95     return self;
   96 }
   97 
   98 static VALUE set_canvas_size(VALUE self, VALUE height, VALUE width)
   99 {
  100     caca_set_canvas_size(_SELF, NUM2INT(width), NUM2INT(height));
  101     return self;
  102 }
  103 
  104 /****/
  105 
  106 static VALUE gotoxy(VALUE self, VALUE x, VALUE y)
  107 {
  108     if( caca_gotoxy(_SELF, NUM2INT(x), NUM2INT(y)) <0) {
  109         rb_raise(rb_eRuntimeError, "%s", strerror(errno));
  110     }
  111     return self;
  112 }
  113 
  114 static VALUE wherex(VALUE self)
  115 {
  116     return INT2NUM(caca_wherex(_SELF));
  117 }
  118 
  119 static VALUE wherey(VALUE self)
  120 {
  121     return INT2NUM(caca_wherey(_SELF));
  122 }
  123 
  124 simple_func(clear_canvas)
  125 
  126 static VALUE put_char(VALUE self, VALUE x, VALUE y, VALUE ch)
  127 {
  128     caca_put_char(_SELF, NUM2INT(x), NUM2INT(y), NUM2ULONG(ch));
  129     return self;
  130 }
  131 
  132 static VALUE get_char(VALUE self, VALUE x, VALUE y)
  133 {
  134     unsigned long int ch;
  135     ch = caca_get_char(_SELF, NUM2INT(x), NUM2INT(y));
  136     return INT2NUM(ch);
  137 }
  138 
  139 static VALUE put_str(VALUE self, VALUE x, VALUE y, VALUE str)
  140 {
  141     caca_put_str(_SELF, NUM2INT(x), NUM2INT(y), StringValuePtr(str));
  142     return self;
  143 }
  144 
  145 static VALUE get_attr(VALUE self, VALUE x, VALUE y)
  146 {
  147     unsigned long int ch;
  148     ch = caca_get_attr(_SELF, NUM2INT(x), NUM2INT(y));
  149     return INT2NUM(ch);
  150 }
  151 
  152 static VALUE set_attr(VALUE self, VALUE attr)
  153 {
  154     if(caca_set_attr(_SELF, NUM2ULONG(attr)) <0)
  155         rb_raise(rb_eRuntimeError, "%s", strerror(errno));
  156 
  157     return self;
  158 }
  159 
  160 static VALUE set_attr2(VALUE self, VALUE attr)
  161 {
  162     set_attr(self, attr);
  163     return self;
  164 }
  165 
  166 static VALUE put_attr(VALUE self, VALUE x, VALUE y, VALUE attr)
  167 {
  168     if(caca_put_attr(_SELF, NUM2INT(x), NUM2INT(y), NUM2ULONG(attr)) <0)
  169         rb_raise(rb_eRuntimeError, "%s", strerror(errno));
  170 
  171     return self;
  172 }
  173 
  174 static VALUE set_color_ansi(VALUE self, VALUE fg, VALUE bg)
  175 {
  176     if(caca_set_color_ansi(_SELF, NUM2INT(fg), NUM2INT(bg)) <0)
  177         rb_raise(rb_eRuntimeError, "%s", strerror(errno));
  178 
  179     return self;
  180 }
  181 
  182 static VALUE set_color_argb(VALUE self, VALUE fg, VALUE bg)
  183 {
  184     if(caca_set_color_argb(_SELF, NUM2UINT(fg), NUM2UINT(bg)) <0) {
  185         rb_raise(rb_eRuntimeError, "%s", strerror(errno));
  186     }
  187     return self;
  188 }
  189 
  190 static VALUE cprintf(int argc, VALUE* argv, VALUE self)
  191 {
  192     int x, y;
  193     VALUE rx, ry, format, rest, string;
  194     rb_scan_args(argc, argv, "3*", &rx, &ry, &format, &rest);
  195     x = NUM2INT(rx);
  196     y = NUM2INT(ry);
  197     string = rb_funcall2(rb_mKernel, rb_intern("sprintf"), argc-2, argv+2);
  198     caca_put_str(_SELF, x, y, StringValuePtr(string));
  199     return self;
  200 }
  201 
  202 
  203 get_int(canvas_handle_x)
  204 get_int(canvas_handle_y)
  205 
  206 static VALUE set_canvas_handle(VALUE self, VALUE x, VALUE y)
  207 {
  208     caca_set_canvas_handle(_SELF, NUM2INT(x), NUM2INT(y));
  209     return self;
  210 }
  211 
  212 static VALUE blit(int argc, VALUE* argv, VALUE self) {
  213     VALUE x, y, src, mask;
  214     caca_canvas_t *csrc, *cmask;
  215 
  216     rb_scan_args(argc, argv, "31", &x, &y, &src, &mask);
  217 
  218     Check_Type(x, T_FIXNUM);
  219     Check_Type(y, T_FIXNUM);
  220 
  221     if(CLASS_OF(src) != cCanvas)
  222     {
  223         rb_raise(rb_eArgError, "src is not a Caca::Canvas");
  224     }
  225     Data_Get_Struct(src, caca_canvas_t, csrc);
  226 
  227     if(!NIL_P(mask))
  228     {
  229         if(CLASS_OF(mask) != cCanvas)
  230         {
  231             rb_raise(rb_eArgError, "mask is not a Caca::Canvas");
  232         }
  233         Data_Get_Struct(mask, caca_canvas_t, cmask);
  234     }
  235     else
  236         cmask = NULL;
  237 
  238     if(caca_blit(_SELF, NUM2INT(x), NUM2INT(y), csrc, cmask)<0)
  239         rb_raise(rb_eRuntimeError, "%s", strerror(errno));
  240 
  241     return self;
  242 }
  243 
  244 static VALUE set_canvas_boundaries(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h)
  245 {
  246     if(caca_set_canvas_boundaries(_SELF, NUM2INT(x), NUM2INT(y), NUM2UINT(w), NUM2UINT(h))<0)
  247     {
  248         rb_raise(rb_eRuntimeError, "%s", strerror(errno));
  249     }
  250     return self;
  251 }
  252 
  253 /****/
  254 
  255 simple_func(invert)
  256 simple_func(flip)
  257 simple_func(flop)
  258 simple_func(rotate_180)
  259 simple_func(rotate_left)
  260 simple_func(rotate_right)
  261 simple_func(stretch_left)
  262 simple_func(stretch_right)
  263 
  264 /****/
  265 
  266 static VALUE draw_line(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE ch)
  267 {
  268     caca_draw_line(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2),NUM2ULONG(ch));
  269     return self;
  270 }
  271 
  272 static VALUE draw_polyline(VALUE self, VALUE points, VALUE ch)
  273 {
  274     int i, n;
  275     int *ax, *ay;
  276     int error = 0;
  277     VALUE v, x, y;
  278 
  279     n = RARRAY_LEN(points);
  280 
  281     ax = (int*)malloc(n*sizeof(int));
  282     if(!ax)
  283         rb_raise(rb_eNoMemError,"Out of memory");
  284 
  285     ay = (int*)malloc(n*sizeof(int));
  286     if(!ay)
  287     {
  288         free(ax);
  289         rb_raise(rb_eNoMemError,"Out of memory");
  290     }
  291 
  292     for(i=0; i<n; i++)
  293     {
  294         v = rb_ary_entry(points, i);
  295         if((TYPE(v) == T_ARRAY) && (RARRAY_LEN(v) == 2))
  296         {
  297             x = rb_ary_entry(v,0);
  298             y = rb_ary_entry(v,1);
  299             if(rb_obj_is_kind_of(x, rb_cInteger) &&
  300                rb_obj_is_kind_of(y, rb_cInteger))
  301             {
  302                 ax[i] = NUM2INT(x);
  303                 ay[i] = NUM2INT(y);
  304             } else
  305                 error = 1;
  306         }
  307         else
  308             error = 1;
  309     }
  310 
  311     if(error)
  312     {
  313         free(ax);
  314         free(ay);
  315         rb_raise(rb_eArgError, "Invalid list of points");
  316     }
  317 
  318     n--;
  319 
  320     caca_draw_polyline(_SELF, ax, ay, n, NUM2ULONG(ch));
  321 
  322     free(ax);
  323     free(ay);
  324 
  325     return self;
  326 }
  327 
  328 static VALUE draw_thin_line(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2)
  329 {
  330     caca_draw_thin_line(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2));
  331     return self;
  332 }
  333 
  334 static VALUE draw_thin_polyline(VALUE self, VALUE points)
  335 {
  336     int i, n;
  337     int *ax, *ay;
  338     int error = 0;
  339     VALUE v, x, y;
  340 
  341     n = RARRAY_LEN(points);
  342 
  343     ax = (int*)malloc(n*sizeof(int));
  344     if(!ax)
  345         rb_raise(rb_eNoMemError,"Out of memory");
  346 
  347     ay = (int*)malloc(n*sizeof(int));
  348     if(!ay)
  349     {
  350         free(ax);
  351         rb_raise(rb_eNoMemError,"Out of memory");
  352     }
  353 
  354     for(i=0; i<n; i++)
  355     {
  356         v = rb_ary_entry(points, i);
  357         if((TYPE(v) == T_ARRAY) && (RARRAY_LEN(v) == 2))
  358         {
  359             x = rb_ary_entry(v,0);
  360             y = rb_ary_entry(v,1);
  361             if(rb_obj_is_kind_of(x, rb_cInteger) &&
  362                rb_obj_is_kind_of(y, rb_cInteger))
  363             {
  364                 ax[i] = NUM2INT(x);
  365                 ay[i] = NUM2INT(y);
  366             } else
  367                 error = 1;
  368         }
  369         else
  370             error = 1;
  371     }
  372 
  373     if(error)
  374     {
  375         free(ax);
  376         free(ay);
  377         rb_raise(rb_eArgError, "Invalid list of points");
  378     }
  379 
  380     n--;
  381 
  382     caca_draw_thin_polyline(_SELF, ax, ay, n);
  383 
  384     free(ax);
  385     free(ay);
  386 
  387     return self;
  388 }
  389 
  390 static VALUE draw_circle(VALUE self, VALUE x, VALUE y, VALUE r, VALUE ch)
  391 {
  392     caca_draw_circle(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(r), NUM2ULONG(ch));
  393     return self;
  394 }
  395 
  396 static VALUE draw_ellipse(VALUE self, VALUE x, VALUE y, VALUE a, VALUE b, VALUE ch)
  397 {
  398     caca_draw_ellipse(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(a), NUM2INT(b), NUM2ULONG(ch));
  399     return self;
  400 }
  401 
  402 static VALUE draw_thin_ellipse(VALUE self, VALUE x, VALUE y, VALUE a, VALUE b)
  403 {
  404     caca_draw_thin_ellipse(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(a), NUM2INT(b));
  405     return self;
  406 }
  407 
  408 static VALUE fill_ellipse(VALUE self, VALUE x, VALUE y, VALUE a, VALUE b, VALUE ch)
  409 {
  410     caca_fill_ellipse(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(a), NUM2INT(b), NUM2ULONG(ch));
  411     return self;
  412 }
  413 
  414 static VALUE draw_box(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h, VALUE ch)
  415 {
  416     caca_draw_box(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h), NUM2ULONG(ch));
  417     return self;
  418 }
  419 
  420 static VALUE draw_thin_box(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h)
  421 {
  422     caca_draw_thin_box(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h));
  423     return self;
  424 }
  425 
  426 static VALUE draw_cp437_box(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h)
  427 {
  428     caca_draw_cp437_box(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h));
  429     return self;
  430 }
  431 
  432 static VALUE fill_box(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h, VALUE ch)
  433 {
  434     caca_fill_box(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h), NUM2ULONG(ch));
  435     return self;
  436 }
  437 
  438 static VALUE draw_triangle(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE x3, VALUE y3, VALUE ch)
  439 {
  440     caca_draw_triangle(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2),  NUM2INT(x3), NUM2INT(y3), NUM2ULONG(ch));
  441     return self;
  442 }
  443 
  444 static VALUE draw_thin_triangle(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE x3, VALUE y3)
  445 {
  446     caca_draw_thin_triangle(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2),  NUM2INT(x3), NUM2INT(y3));
  447     return self;
  448 }
  449 
  450 static VALUE fill_triangle(VALUE self, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE x3, VALUE y3, VALUE ch)
  451 {
  452     caca_fill_triangle(_SELF, NUM2INT(x1), NUM2INT(y1), NUM2INT(x2), NUM2INT(y2),  NUM2INT(x3), NUM2INT(y3), NUM2ULONG(ch));
  453     return self;
  454 }
  455 
  456 static VALUE fill_triangle_textured(VALUE self, VALUE coords, VALUE texture, VALUE uv)
  457 {
  458     caca_canvas_t *ctexture;
  459     int i, l;
  460     int ccoords[6];
  461     float cuv[6];
  462     VALUE v;
  463 
  464     l = RARRAY_LEN(coords);
  465     if(l != 6 && l != 3)
  466     {
  467         rb_raise(rb_eArgError, "invalid coords list");
  468     }
  469     for(i=0; i<l; i++)
  470     {
  471         v = rb_ary_entry(coords, i);
  472         if(l==6)
  473             ccoords[i] = NUM2INT(v);
  474         else
  475         {
  476             if((TYPE(v) != T_ARRAY) || (RARRAY_LEN(v) != 2))
  477                 rb_raise(rb_eArgError, "invalid coords list");
  478             ccoords[2*i] = NUM2INT(rb_ary_entry(v, 0));
  479             ccoords[2*i+1] = NUM2INT(rb_ary_entry(v, 1));
  480         }
  481     }
  482 
  483     l = RARRAY_LEN(uv);
  484     if(l != 6 && l != 3)
  485     {
  486         rb_raise(rb_eArgError, "invalid uv list");
  487     }
  488     for(i=0; i<l; i++)
  489     {
  490         v = rb_ary_entry(uv, i);
  491         if(l==6)
  492             cuv[i] = NUM2DBL(v);
  493         else
  494         {
  495             if((TYPE(v) != T_ARRAY) || (RARRAY_LEN(v) != 2))
  496                 rb_raise(rb_eArgError, "invalid uv list");
  497             cuv[2*i] = NUM2DBL(rb_ary_entry(v, 0));
  498             cuv[2*i+1] = NUM2DBL(rb_ary_entry(v, 1));
  499         }
  500     }
  501 
  502     if(CLASS_OF(texture) != cCanvas)
  503     {
  504         rb_raise(rb_eArgError, "texture is not a Caca::Canvas");
  505     }
  506     Data_Get_Struct(texture, caca_canvas_t, ctexture);
  507 
  508     caca_fill_triangle_textured(_SELF, ccoords, ctexture, cuv);
  509     return self;
  510 }
  511 
  512 static VALUE dither_bitmap(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h, VALUE d, VALUE pixels)
  513 {
  514     if(CLASS_OF(d) != cDither)
  515         rb_raise(rb_eArgError, "d is not a Caca::Dither");
  516     Check_Type(pixels, T_STRING);
  517 
  518     caca_dither_bitmap(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h), DATA_PTR(d), StringValuePtr(pixels));
  519     return self;
  520 }
  521 
  522 /****/
  523 
  524 get_int(frame_count)
  525 
  526 static VALUE set_frame(VALUE self, VALUE id)
  527 {
  528     if(caca_set_frame(_SELF, NUM2INT(id))<0)
  529         rb_raise(rb_eArgError, "%s", strerror(errno));
  530 
  531     return self;
  532 }
  533 
  534 static VALUE set_frame2(VALUE self, VALUE id)
  535 {
  536     set_frame(self, id);
  537     return self;
  538 }
  539 
  540 static VALUE get_frame_name(VALUE self)
  541 {
  542     return rb_str_new2(caca_get_frame_name(_SELF));
  543 }
  544 
  545 static VALUE set_frame_name(VALUE self, VALUE name)
  546 {
  547     if(caca_set_frame_name(_SELF, StringValuePtr(name))<0)
  548         rb_raise(rb_eRuntimeError, "%s", strerror(errno));
  549 
  550     return self;
  551 }
  552 
  553 static VALUE set_frame_name2(VALUE self, VALUE name)
  554 {
  555     set_frame_name(self, name);
  556     return self;
  557 }
  558 
  559 static VALUE create_frame(VALUE self, VALUE id)
  560 {
  561     if(caca_create_frame(_SELF, NUM2INT(id))<0) {
  562         rb_raise(rb_eRuntimeError, "%s", strerror(errno));
  563     }
  564     return self;
  565 }
  566 
  567 static VALUE free_frame(VALUE self, VALUE id)
  568 {
  569     if(caca_free_frame(_SELF, NUM2INT(id))<0) {
  570         rb_raise(rb_eArgError, "%s", strerror(errno));
  571     }
  572     return self;
  573 }
  574 
  575 /****/
  576 
  577 static VALUE render_canvas(VALUE self, VALUE font, VALUE width, VALUE height, VALUE pitch)
  578 {
  579     void *buf;
  580     caca_font_t *f;
  581     VALUE b;
  582 
  583     if(CLASS_OF(font) != cFont)
  584     {
  585         rb_raise(rb_eArgError, "First argument is not a Caca::Font");
  586     }
  587 
  588     buf = _caca_alloc2d(width, height, 4);
  589     if(buf == NULL)
  590     {
  591         rb_raise(rb_eNoMemError, "Out of memory");
  592     }
  593 
  594     f = DATA_PTR(font);
  595     caca_render_canvas(_SELF, f, buf, NUM2UINT(width), NUM2UINT(height), NUM2UINT(pitch));
  596 
  597     b = rb_str_new(buf, width*height*4);
  598     free(buf);
  599     return b;
  600 }
  601 
  602 static VALUE import_from_memory(VALUE self, VALUE data, VALUE format)
  603 {
  604     long int bytes;
  605     bytes = caca_import_canvas_from_memory (_SELF, StringValuePtr(data), RSTRING_LEN(StringValue(data)), StringValuePtr(format));
  606     if(bytes <= 0)
  607         rb_raise(rb_eRuntimeError, "%s", strerror(errno));
  608 
  609     return self;
  610 }
  611 
  612 static VALUE import_area_from_memory(VALUE self, VALUE x, VALUE y, VALUE data, VALUE format)
  613 {
  614     long int bytes;
  615     bytes = caca_import_area_from_memory (_SELF, NUM2INT(x), NUM2INT(y), StringValuePtr(data), RSTRING_LEN(StringValue(data)), StringValuePtr(format));
  616     if(bytes <= 0)
  617         rb_raise(rb_eRuntimeError, "%s", strerror(errno));
  618 
  619     return self;
  620 }
  621 
  622 static VALUE import_from_file(VALUE self, VALUE filename, VALUE format)
  623 {
  624     long int bytes;
  625     bytes = caca_import_canvas_from_file (_SELF, StringValuePtr(filename), StringValuePtr(format));
  626     if(bytes <= 0)
  627         rb_raise(rb_eRuntimeError, "%s", strerror(errno));
  628 
  629     return self;
  630 }
  631 
  632 static VALUE import_area_from_file(VALUE self, VALUE x, VALUE y, VALUE filename, VALUE format)
  633 {
  634     long int bytes;
  635     bytes = caca_import_area_from_file (_SELF, NUM2INT(x), NUM2INT(y), StringValuePtr(filename), StringValuePtr(format));
  636     if(bytes <= 0)
  637         rb_raise(rb_eRuntimeError, "%s", strerror(errno));
  638 
  639     return self;
  640 }
  641 
  642 static VALUE export_area_to_memory(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h, VALUE format)
  643 {
  644     size_t bytes;
  645     void *result;
  646     VALUE ret;
  647     result = caca_export_area_to_memory (_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h), StringValuePtr(format), &bytes);
  648     ret = rb_str_new(result, bytes);
  649     free(result);
  650     return ret;
  651 }
  652 
  653 static VALUE export_to_memory(VALUE self, VALUE format)
  654 {
  655     size_t bytes;
  656     void *result;
  657     VALUE ret;
  658     result = caca_export_canvas_to_memory (_SELF, StringValuePtr(format), &bytes);
  659     ret = rb_str_new(result, bytes);
  660     free(result);
  661     return ret;
  662 }
  663 
  664 get_singleton_double_list(export)
  665 get_singleton_double_list(import)
  666 
  667 /****/
  668 
  669 simple_func(disable_dirty_rect)
  670 simple_func(enable_dirty_rect)
  671 get_int(dirty_rect_count)
  672 
  673 static VALUE dirty_rect(VALUE self, VALUE n)
  674 {
  675     int x, y, width, height;
  676     VALUE ary;
  677     ary = rb_ary_new();
  678     caca_get_dirty_rect(_SELF, NUM2INT(n), &x, &y, &width, &height);
  679     rb_ary_push(ary, INT2NUM(x));
  680     rb_ary_push(ary, INT2NUM(y));
  681     rb_ary_push(ary, INT2NUM(width));
  682     rb_ary_push(ary, INT2NUM(height));
  683     return ary;
  684 }
  685 
  686 static VALUE dirty_rects(VALUE self)
  687 {
  688     int n = caca_get_dirty_rect_count(_SELF), i;
  689     VALUE ary;
  690     ary = rb_ary_new();
  691     for(i=0; i<n; i++)
  692     {
  693         rb_ary_push(ary, dirty_rect(self, INT2NUM(i)));
  694     }
  695     return ary;
  696 }
  697 
  698 /*FIXME Handle an array for the rect */
  699 static VALUE add_dirty_rect(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h)
  700 {
  701     caca_add_dirty_rect(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h));
  702     return self;
  703 }
  704 
  705 static VALUE remove_dirty_rect(VALUE self, VALUE x, VALUE y, VALUE w, VALUE h)
  706 {
  707     caca_remove_dirty_rect(_SELF, NUM2INT(x), NUM2INT(y), NUM2INT(w), NUM2INT(h));
  708     return self;
  709 }
  710 
  711 simple_func(clear_dirty_rect_list)
  712 
  713 /****/
  714 
  715 void Init_caca_canvas(VALUE mCaca)
  716 {
  717     cCanvas = rb_define_class_under(mCaca, "Canvas", rb_cObject);
  718     rb_define_alloc_func(cCanvas, canvas_alloc);
  719 
  720     rb_define_method(cCanvas, "initialize", canvas_initialize, 2);
  721     rb_define_method(cCanvas, "width", get_canvas_width, 0);
  722     rb_define_method(cCanvas, "width=", set_canvas_width, 1);
  723     rb_define_method(cCanvas, "set_width", set_canvas_width2, 1);
  724     rb_define_method(cCanvas, "height", get_canvas_height, 0);
  725     rb_define_method(cCanvas, "height=", set_canvas_height, 1);
  726     rb_define_method(cCanvas, "set_height", set_canvas_height2, 1);
  727     rb_define_method(cCanvas, "set_size", set_canvas_size, 2);
  728 
  729     rb_define_method(cCanvas, "gotoxy", gotoxy, 2);
  730     rb_define_method(cCanvas, "wherex", wherex, 0);
  731     rb_define_method(cCanvas, "wherey", wherey, 0);
  732     rb_define_method(cCanvas, "handle_x", get_canvas_handle_x, 0);
  733     rb_define_method(cCanvas, "handle_y", get_canvas_handle_y, 0);
  734     rb_define_method(cCanvas, "set_handle", set_canvas_handle, 2);
  735     rb_define_method(cCanvas, "blit", blit, -1);
  736     rb_define_method(cCanvas, "set_boundaries", set_canvas_boundaries, 4);
  737 
  738     rb_define_method(cCanvas, "clear", clear_canvas, 0);
  739 
  740     rb_define_method(cCanvas, "put_char", put_char, 3);
  741     rb_define_method(cCanvas, "get_char", get_char, 2);
  742     rb_define_method(cCanvas, "put_str", put_str, 3);
  743     rb_define_method(cCanvas, "printf", cprintf, -1);
  744 
  745     rb_define_method(cCanvas, "get_attr", get_attr, 3);
  746     rb_define_method(cCanvas, "attr=", set_attr, 1);
  747     rb_define_method(cCanvas, "set_attr", set_attr2, 1);
  748     rb_define_method(cCanvas, "put_attr", put_attr, 3);
  749     rb_define_method(cCanvas, "set_color_ansi", set_color_ansi, 2);
  750     rb_define_method(cCanvas, "set_color_argb", set_color_argb, 2);
  751 
  752     rb_define_method(cCanvas, "invert", invert, 0);
  753     rb_define_method(cCanvas, "flip", flip, 0);
  754     rb_define_method(cCanvas, "flop", flop, 0);
  755     rb_define_method(cCanvas, "rotate_180", rotate_180, 0);
  756     rb_define_method(cCanvas, "rotate_left", rotate_left, 0);
  757     rb_define_method(cCanvas, "rotate_right", rotate_right, 0);
  758     rb_define_method(cCanvas, "stretch_left", stretch_left, 0);
  759     rb_define_method(cCanvas, "stretch_right", stretch_right, 0);
  760 
  761     rb_define_method(cCanvas, "draw_line", draw_line, 5);
  762     rb_define_method(cCanvas, "draw_polyline", draw_polyline, 2);
  763     rb_define_method(cCanvas, "draw_thin_line", draw_thin_line, 4);
  764     rb_define_method(cCanvas, "draw_thin_polyline", draw_thin_polyline, 1);
  765     rb_define_method(cCanvas, "draw_circle", draw_circle, 4);
  766     rb_define_method(cCanvas, "draw_ellipse", draw_ellipse, 5);
  767     rb_define_method(cCanvas, "draw_thin_ellipse", draw_thin_ellipse, 4);
  768     rb_define_method(cCanvas, "fill_ellipse", fill_ellipse, 5);
  769     rb_define_method(cCanvas, "draw_box", draw_box, 5);
  770     rb_define_method(cCanvas, "draw_thin_box", draw_thin_box, 4);
  771     rb_define_method(cCanvas, "draw_cp437_box", draw_cp437_box, 4);
  772     rb_define_method(cCanvas, "fill_box", fill_box, 5);
  773     rb_define_method(cCanvas, "draw_triangle", draw_triangle, 7);
  774     rb_define_method(cCanvas, "draw_thin_triangle", draw_thin_triangle, 6);
  775     rb_define_method(cCanvas, "fill_triangle", fill_triangle, 7);
  776     rb_define_method(cCanvas, "fill_triangle_textured", fill_triangle_textured, 4);
  777     rb_define_method(cCanvas, "dither_bitmap", dither_bitmap, 6);
  778 
  779     rb_define_method(cCanvas, "frame_count", get_frame_count, 0);
  780     rb_define_method(cCanvas, "frame=", set_frame, 1);
  781     rb_define_method(cCanvas, "set_frame", set_frame2, 1);
  782     rb_define_method(cCanvas, "frame_name", get_frame_name, 0);
  783     rb_define_method(cCanvas, "frame_name=", set_frame_name, 1);
  784     rb_define_method(cCanvas, "set_frame_name", set_frame_name2, 1);
  785     rb_define_method(cCanvas, "create_frame", create_frame, 1);
  786     rb_define_method(cCanvas, "free_frame", free_frame, 1);
  787 
  788     rb_define_method(cCanvas, "render", render_canvas, 4);
  789     rb_define_method(cCanvas, "import_from_memory", import_from_memory, 2);
  790     rb_define_method(cCanvas, "import_area_from_memory", import_area_from_memory, 4);
  791     rb_define_method(cCanvas, "import_from_file", import_from_file, 2);
  792     rb_define_method(cCanvas, "import_area_from_file", import_area_from_file, 4);
  793     rb_define_method(cCanvas, "export_to_memory", export_to_memory, 1);
  794     rb_define_method(cCanvas, "export_area_to_memory", export_area_to_memory, 5);
  795     rb_define_singleton_method(cCanvas, "export_list", export_list, 0);
  796     rb_define_singleton_method(cCanvas, "import_list", import_list, 0);
  797 
  798     rb_define_method(cCanvas, "disable_dirty_rect", disable_dirty_rect, 0);
  799     rb_define_method(cCanvas, "enable_dirty_rect", enable_dirty_rect, 0);
  800     rb_define_method(cCanvas, "dirty_rect_count", get_dirty_rect_count, 0);
  801     rb_define_method(cCanvas, "dirty_rect", dirty_rect, 1);
  802     rb_define_method(cCanvas, "dirty_rects", dirty_rects, 0);
  803     rb_define_method(cCanvas, "add_dirty_rect", add_dirty_rect, 4);
  804     rb_define_method(cCanvas, "remove_dirty_rect", remove_dirty_rect, 4);
  805     rb_define_method(cCanvas, "clear_dirty_rect_list", clear_dirty_rect_list, 0);
  806 
  807 }
  808