Example #1
0
/* set action color to return value of color_control proc */
static void
prepare_color_control(action_struct * cur)
{

    if(is_a_hash(cur->hash_arg)) {
        VALUE try_val = get_from_hash(cur->hash_arg, "color_control");

        if(rb_respond_to(try_val, rb_intern("call"))) {
            cur->pen.color_control_proc = try_val;
            cur->pen.color_control_arity = FIX2INT(rb_funcall(try_val, rb_intern("arity"), 0));
            cur->pen.has_color_control_proc = true;
        }
        else if(is_a_hash(try_val)) {
            VALUE try_add = get_from_hash(try_val, "add");
            VALUE try_mult = get_from_hash(try_val, "mult");

            if(is_an_array(try_add)) {

                cur->pen.color_add = convert_rb_color_to_rgba(try_add);

                cur->pen.has_color_control_transform = true;
            }
            if(is_an_array(try_mult)) {

                cur->pen.color_mult = convert_rb_color_to_rgba(try_mult);

                cur->pen.has_color_control_transform = true;
            }

        }
    }
}
Example #2
0
void
glow_fill_do_action(int x, int y, texture_info * tex, VALUE hash_arg,
                    texplay_sync sync_mode, bool primary, action_struct * payload)
{
    action_struct cur;
    rgba seed_color;
    texture_info fill_image;
    texture_info * fill_image_ptr = NULL;
    
    if(!bound_by_rect(x, y, 0, 0, tex->width, tex->height)) return;

    draw_prologue(&cur, tex, 0, 0, 1024, 1024, &hash_arg, sync_mode, primary, &payload);

    /* fill hates alpha_blend so let's turn it off */
    payload->pen.alpha_blend = false;

    if(is_a_hash(hash_arg)) {
        VALUE try_image = get_from_hash(hash_arg, "texture");
        if(is_gosu_image(try_image)) {
            get_texture_info(try_image, &fill_image);
            fill_image_ptr = &fill_image;
        }
    }

    seed_color = get_pixel_color(tex, x, y);

    /* last argument is pointer to texture fill data (if it exists) or NULL (if it doesn't) */
    glow_floodFill( x, y, &seed_color, &cur, tex, fill_image_ptr );

    draw_epilogue(&cur, tex, primary);
}
Example #3
0
static void
prepare_fill_texture(action_struct * payload)
{
    if(is_a_hash(payload->hash_arg)) {
        VALUE try_image = get_from_hash(payload->hash_arg, "texture");
        if(is_gosu_image(try_image)) {

            get_texture_info(try_image, &payload->pen.source_tex);
            payload->pen.has_source_texture = true;
        }
    }
}
Example #4
0
/** rectangle algorithm **/
void
rect_do_action(int x1, int y1, int x2, int y2, texture_info * tex, VALUE hash_arg,
               texplay_sync sync_mode, bool primary, action_struct * payload)
{
    action_struct cur;
    bool fill = false;
    int thickness = 1;

    draw_prologue(&cur, tex, x1, y1,
                  x2, y2, &hash_arg, sync_mode, primary, &payload);

    
    if(is_a_hash(hash_arg)) {

        /* make our private copy of the hash so we can mess with it */
        hash_arg = rb_obj_dup(hash_arg);

        if(RTEST(get_from_hash(hash_arg, "fill")) || RTEST(get_from_hash(hash_arg, "filled"))) {
            fill = true;

            /* since we're filling the rect, line thickness is irrelevant */
            delete_from_hash(hash_arg, "thickness");
        }
        else if(RTEST(get_from_hash(hash_arg, "thickness"))) {
            thickness = NUM2INT(get_from_hash(hash_arg, "thickness"));
            /* TO DO: find a better way of doing this */

            if(thickness > 1) {
                cur.xmin = x1 - thickness / 2;
                cur.ymin = y1 - thickness / 2;
                cur.xmax = x2 + thickness / 2 + 1;
                cur.ymax = y2 + thickness / 2 + 1;
            }
        }
    }
    if(!fill) {
        line_do_action(x1, y1, x2, y1, tex, hash_arg, no_sync, false, payload);
        line_do_action(x1, y1, x1, y2, tex, hash_arg, no_sync, false, payload);
        line_do_action(x1, y2, x2, y2, tex, hash_arg, no_sync, false, payload);
        line_do_action(x2, y1, x2, y2, tex, hash_arg, no_sync, false, payload);
    }
    else {
        if(y1 > y2) SWAP(y1, y2);

        for(int y = y1; y <= y2; y++)
            line_do_action(x1, y, x2, y, tex, hash_arg, no_sync, false, payload);
    }

    draw_epilogue(&cur, tex, primary);
}
Example #5
0
/* regular polygon algorithm */
void
ngon_do_action(int x, int y, int r, int num_sides, texture_info * tex, VALUE hash_arg,
               texplay_sync sync_mode, bool primary, action_struct * payload)
{
    action_struct cur;
    int x1, y1, x2, y2, x0, y0;
    int thickness;
    float angle = 0;

    draw_prologue(&cur, tex, x - r, y - r,
                  x + r, y + r, &hash_arg, sync_mode, primary, &payload);


    if(is_a_hash(hash_arg)) {
        if(RTEST(get_from_hash(hash_arg, "thickness"))) {
            thickness = NUM2INT(get_from_hash(hash_arg, "thickness"));

            /* TO DO: find a better way of doing this */
            cur.xmin = x - r - thickness / 2;
            cur.ymin = y - r - thickness / 2;
            cur.xmax = x + r + thickness / 2;
            cur.ymax = y + r + thickness / 2;
        }

        if(RTEST(get_from_hash(hash_arg, "start_angle"))) {
            angle = NUM2INT(get_from_hash(hash_arg, "start_angle")) / 360.0 * 2 * PI;
        }
    }
    
    /* calculate first point */
    x0 = x1 = x + r * cos(angle);
    y0 = y1 = y + r * sin(angle);

    for(int n = 0; n < num_sides; n++) {
        x2 = x + r * cos((2 * PI / num_sides) * n + angle);
        y2 = y + r * sin((2 * PI / num_sides) * n + angle);

        line_do_action(x1, y1, x2, y2, tex, hash_arg, no_sync, false, payload);

        x1 = x2; y1 = y2;
    }

    line_do_action(x0, y0, x1, y1, tex, hash_arg, no_sync, false, payload);

    draw_epilogue(&cur, tex, primary);
}
Example #6
0
static void
prepare_drawing_mode(action_struct * cur)
{
  if(is_a_hash(cur->hash_arg)) {
    /* drawing mode */
    if(has_optional_hash_arg(cur->hash_arg, "mode")) {
      cur->pen.has_drawing_mode = true;

      VALUE draw_mode = get_from_hash(cur->hash_arg, "mode");


      Check_Type(draw_mode, T_SYMBOL);

      if(draw_mode == string2sym("default")) {
        cur->pen.has_drawing_mode = false;

        return;
      }
      else if(draw_mode == string2sym("clear"))
        cur->pen.drawing_mode = clear;

      else if(draw_mode == string2sym("copy"))
        cur->pen.drawing_mode = copy;

      else if(draw_mode == string2sym("noop"))
        cur->pen.drawing_mode = noop;

      else if(draw_mode == string2sym("set"))
        cur->pen.drawing_mode = set;

      else if(draw_mode == string2sym("copy_inverted"))
        cur->pen.drawing_mode = copy_inverted;

      else if(draw_mode == string2sym("invert"))
        cur->pen.drawing_mode = invert;

      else if(draw_mode == string2sym("and_reverse"))
        cur->pen.drawing_mode = and_reverse;

      else if(draw_mode == string2sym("and"))
        cur->pen.drawing_mode = and;

      else if(draw_mode == string2sym("or"))
        cur->pen.drawing_mode = or;

      else if(draw_mode == string2sym("nand"))
        cur->pen.drawing_mode = nand;

      else if(draw_mode == string2sym("nor"))
        cur->pen.drawing_mode = nor;

      else if(draw_mode == string2sym("xor"))
        cur->pen.drawing_mode = xor;

      else if(draw_mode == string2sym("equiv"))
        cur->pen.drawing_mode = equiv;

      else if(draw_mode == string2sym("and_inverted"))
        cur->pen.drawing_mode = and_inverted;

      else if(draw_mode == string2sym("or_inverted"))
        cur->pen.drawing_mode = or_inverted;

      else if(draw_mode == string2sym("additive"))
        cur->pen.drawing_mode = additive;
      else if(draw_mode == string2sym("multiply"))
        cur->pen.drawing_mode = multiply;
      else if(draw_mode == string2sym("screen"))
        cur->pen.drawing_mode = screen;
      else if(draw_mode == string2sym("overlay"))
        cur->pen.drawing_mode = overlay;
      else if(draw_mode == string2sym("darken"))
        cur->pen.drawing_mode = darken;
      else if(draw_mode == string2sym("lighten"))
        cur->pen.drawing_mode = lighten;
      else if(draw_mode == string2sym("color_dodge"))
        cur->pen.drawing_mode = color_dodge;
      else if(draw_mode == string2sym("color_burn"))
        cur->pen.drawing_mode = color_burn;
      else if(draw_mode == string2sym("hard_light"))
        cur->pen.drawing_mode = hard_light;
      else if(draw_mode == string2sym("soft_light"))
        cur->pen.drawing_mode = soft_light;
      else if(draw_mode == string2sym("difference"))
        cur->pen.drawing_mode = difference;
      else if(draw_mode == string2sym("exclusion"))
        cur->pen.drawing_mode = exclusion;
      else
        rb_raise(rb_eArgError, "unrecognized drawing mode: %s\n.",
                 sym2string(draw_mode));
    }
  }
}
Example #7
0
/* TODO: fix this function below, it's too ugly and bulky and weird **/
static void
process_common_hash_args(action_struct * cur, VALUE * hash_arg, sync_ sync_mode, bool primary)
{

    VALUE user_defaults;
    VALUE hash_blend;


    /* if a hash doesn't exist then create one */
    if(!is_a_hash(*hash_arg))
        *hash_arg = rb_hash_new();

    /* init the action to default values */
    initialize_action_struct(cur, *hash_arg, sync_mode);

    /* get the user default options & merge with given options */
    user_defaults = get_image_local(cur->tex->image, USER_DEFAULTS);
    hash_blend = rb_funcall(user_defaults, rb_intern("merge"), 1, *hash_arg);
    rb_funcall(*hash_arg, rb_intern("merge!"), 1, hash_blend);

    if(has_optional_hash_arg(*hash_arg, "color")) {
        VALUE c = get_from_hash(*hash_arg, "color");
        cur->color = convert_rb_color_to_rgba(c);
        if(c == string2sym("random")) {
            set_hash_value(*hash_arg, "color", convert_rgba_to_rb_color(&cur->color));
        }
    }

    /* shadows */
    if(RTEST(get_from_hash(*hash_arg, "shadow"))) {
        cur->pen.color_mult.red = 0.66;
        cur->pen.color_mult.green = 0.66;
        cur->pen.color_mult.blue = 0.66;
        cur->pen.color_mult.alpha = 1;

        cur->pen.has_color_control_transform = true;
    }

    /* tolerance */
    if(RTEST(get_from_hash(*hash_arg, "tolerance"))) {
      cur->pen.tolerance = NUM2DBL(get_from_hash(*hash_arg, "tolerance"));

      /* maximum length of hypotonese extended in 4-space (color space) is sqrt(4) */
      if (cur->pen.tolerance >= 2)
        cur->pen.tolerance = 2;

      if (cur->pen.tolerance < 0)
        cur->pen.tolerance = 0;

      cur->pen.has_tolerance = true;
    }

    /* lerp */
    if(RTEST(get_from_hash(*hash_arg, "lerp"))) {
      cur->pen.lerp = NUM2DBL(get_from_hash(*hash_arg, "lerp"));

      /* bounds */
      if(cur->pen.lerp > 1.0) cur->pen.lerp = 1.0;
      if(cur->pen.lerp < 0.0) cur->pen.lerp = 0.0;
      cur->pen.has_lerp = true;
    }

    /* sync mode */
    if(has_optional_hash_arg(*hash_arg, "sync_mode")) {
        VALUE user_sync_mode = get_from_hash(*hash_arg, "sync_mode");

        Check_Type(user_sync_mode, T_SYMBOL);

        if(user_sync_mode == string2sym("lazy_sync"))
            cur->sync_mode = lazy_sync;
        else if(user_sync_mode == string2sym("eager_sync"))
            cur->sync_mode = eager_sync;
        else if(user_sync_mode == string2sym("no_sync"))
            cur->sync_mode = no_sync;
        else
            rb_raise(rb_eArgError, "unrecognized sync mode: %s\n. Allowable modes are "
                     ":lazy_sync, :eager_sync, :no_sync.",
                     sym2string(user_sync_mode));

        delete_from_hash(*hash_arg, "sync_mode");

    }

    /* prepare color selection */
    prepare_color_select(cur);

    /* process drawing mode */
    prepare_drawing_mode(cur);

    /* process the color_control block or transform (if there is one) */
    prepare_color_control(cur);

    /* process the filling texture (if there is one) */
    prepare_fill_texture(cur);

    /* does the user want to blend alpha values ? */
    prepare_alpha_blend(cur);
}
Example #8
0
void
bezier_do_action(VALUE points, texture_info * tex, VALUE hash_arg, texplay_sync sync_mode,
                 bool primary, action_struct * payload)
{
    float u = 0.0;
    action_struct cur;
    float x1, y1, x2, y2;
    int first_x, first_y;
    int format;
    int num_point_pairs;
    bool closed = false;
    VALUE offset_val;
    int draw_offset_x, draw_offset_y;

    /* defaults to 200 (1 / 0.005) samples per curve */
    float step_size = 0.005;
    
    draw_prologue(&cur, tex, XMAX_OOB, YMAX_OOB, XMIN_OOB, YMIN_OOB, &hash_arg, sync_mode, primary, &payload);

    /* calculate offset */
    offset_val = get_image_local(tex->image, DRAW_OFFSET);

    draw_offset_x = NUM2INT(get_from_array(offset_val, 0));
    draw_offset_y = NUM2INT(get_from_array(offset_val, 1));

    if(is_a_hash(hash_arg)) {

        /* if the polyline is 'closed' make the last point the first */
        if(RTEST(get_from_hash(hash_arg, "closed")) || RTEST(get_from_hash(hash_arg, "close"))) {

            /* so that our additional point is not persistent */
            points = rb_obj_dup(points);
            closed = true;
        }
        
        /* number of points to sample */
        if(RTEST(get_from_hash(hash_arg, "sample_size"))) {
            VALUE c = get_from_hash(hash_arg, "sample_size");
            Check_Type(c, T_FIXNUM);
            step_size = 1.0 / (float)FIX2INT(c);
        }
    }

    if(is_a_point(get_from_array(points, 0))) {
        format = POINT_FORMAT;

        if(closed)
            rb_ary_push(points, get_from_array(points, 0));
        
        num_point_pairs = RARRAY_LEN(points);
    }
    else {
        format = SIMPLE_FORMAT;

        /* ensure points are given in pairs */
        if(RARRAY_LEN(points) % 2)
            rb_raise(rb_eArgError, "bezier needs an even number of points. got %d\n", (int)RARRAY_LEN(points));

        if(closed) {
            rb_ary_push(points, get_from_array(points, 0));
            rb_ary_push(points, get_from_array(points, 1));
        }
        
        num_point_pairs = RARRAY_LEN(points) / 2;
    }

    if(num_point_pairs > 17)
        rb_raise(rb_eArgError, "too many points for bezier curve. 17 points is current maximum. got %d\n",
                 num_point_pairs);

    /* get the first point */
    bezier_point(points, 0, &x1, &y1, num_point_pairs, format, draw_offset_x, draw_offset_y);

    /* save it so we can link up with last point properly if the curve is 'closed' */
    first_x = x1;
    first_y = y1;

    while(u <= 1) {
        bezier_point(points, u, &x2, &y2, num_point_pairs, format, draw_offset_x, draw_offset_y);
 
        line_do_action(x1, y1, x2, y2, tex, hash_arg, no_sync, false, payload);

        /* update drawing rectangle */
        update_bounds(payload, x1, y1, x2, y2);

        x1 = x2;
        y1 = y2;

        u += step_size;
    }

    /* sometimes beziers dont close properly, so we'll ensure it's closed */
    if(closed)
        line_do_action(x2, y2, first_x, first_y, tex, hash_arg, no_sync, false, payload);

    draw_epilogue(&cur, tex, primary);
}
Example #9
0
/** midpoint circle algorithm **/
void
circle_do_action(int x1, int y1, int r, texture_info * tex, VALUE hash_arg,
                 texplay_sync sync_mode, bool primary, action_struct * payload)
{

    int x, y;
    float p;
    action_struct cur;
    bool fill = false;

    draw_prologue(&cur, tex, x1 - r, y1 - r, x1 + r, y1 + r, &hash_arg,
                  sync_mode, primary, &payload);


    if(is_a_hash(hash_arg)) {

        /* make our private copy of the hash so we can mess with it */
        hash_arg = rb_obj_dup(hash_arg);

        if(RTEST(get_from_hash(hash_arg, "fill")) || RTEST(get_from_hash(hash_arg, "filled"))) {
            fill = true;

            /* to prevent infinite recursion set line thickness to 1 :D
               NB: a filled circle uses lines and a thick line uses filled circles :D */
            delete_from_hash(hash_arg, "thickness");
        }
    }
    
    x = 0 ; y = r;
    p = 5 / 4 - r;
    if(!fill) {
        while (x <= y) {
            set_pixel_color_with_style(payload, tex, x1 + x, y1 + y);
            set_pixel_color_with_style(payload, tex, x1 + x, y1 - y);
            set_pixel_color_with_style(payload, tex, x1 - x, y1 + y);
            set_pixel_color_with_style(payload, tex, x1 - x, y1 - y);
            set_pixel_color_with_style(payload, tex, x1 + y, y1 + x);
            set_pixel_color_with_style(payload, tex, x1 + y, y1 - x);
            set_pixel_color_with_style(payload, tex, x1 - y, y1 + x);
            set_pixel_color_with_style(payload, tex, x1 - y, y1 - x);

            if (p < 0) {
                p += 2 * x + 3;
            }
            else {
                y--;
                p += 2 * (x - y) + 5;
            }
            x++;
        }
    }
    else {
        while (x <= y) {
            line_do_action(x1 - x, y1 + y, x1 + x, y1 + y, tex, hash_arg, no_sync, false, payload);
            line_do_action(x1 - x, y1 - y, x1 + x, y1 - y, tex, hash_arg, no_sync, false, payload);
            line_do_action(x1 - y, y1 + x, x1 + y, y1 + x, tex, hash_arg, no_sync, false, payload);
            line_do_action(x1 - y, y1 - x, x1 + y, y1 - x, tex, hash_arg, no_sync, false, payload);

            if (p < 0) {
                p += 2 * x + 3;
            }
            else {
                y--;
                p += 2 * (x - y) + 5;
            }
            x++;
        }
    }

    draw_epilogue(&cur, tex, primary);
}
Example #10
0
void
polyline_do_action(VALUE points, texture_info * tex, VALUE hash_arg,
                   texplay_sync sync_mode, bool primary, action_struct * payload)
{

    int x1, y1, x2, y2;
    int format;
    int num_point_pairs;
    int k;
    int draw_offset_y, draw_offset_x;
    action_struct cur;
    VALUE offset_val;
    bool closed = false;
    
    draw_prologue(&cur, tex, XMAX_OOB, YMAX_OOB, XMIN_OOB, YMIN_OOB, &hash_arg, sync_mode, primary, &payload);

    /* calculate offset */
    offset_val = get_image_local(tex->image, DRAW_OFFSET);

    draw_offset_x = NUM2INT(get_from_array(offset_val, 0));
    draw_offset_y = NUM2INT(get_from_array(offset_val, 1));

    /* if the polyline is 'closed' make the last point the first */
    if(is_a_hash(hash_arg))
        if(RTEST(get_from_hash(hash_arg, "closed")) || RTEST(get_from_hash(hash_arg, "close"))) {
            
            /* so that our additional point is not persistent */
            points = rb_obj_dup(points);
            closed = true;
        }
    /* determine format of points */
    if(is_a_point(get_from_array(points, 0))) {
        format = POINT_FORMAT;

        /* if the polyline is closed to form a polygon then make the last point and first point identical */
        if(closed)
            rb_ary_push(points, get_from_array(points, 0));

        num_point_pairs = RARRAY_LEN(points);
    }
    else {
        format = SIMPLE_FORMAT;

        /* ensure there is an 'x' for every 'y'  */
        if(RARRAY_LEN(points) % 2)
            rb_raise(rb_eArgError, "polyline needs an even number of points. got %d\n",
                     (int)RARRAY_LEN(points));

        if(closed) {
            rb_ary_push(points, get_from_array(points, 0));
            rb_ary_push(points, get_from_array(points, 1));
        }

        num_point_pairs = RARRAY_LEN(points) / 2;
    }

    /* calculate first point */
    polyline_point(points, 0, &x1, &y1, format, draw_offset_x, draw_offset_y);
    
    /* calc the points and draw the polyline */
    for(k = 1; k < num_point_pairs; k++) {

        polyline_point(points, k, &x2, &y2, format, draw_offset_x, draw_offset_y);
    
        line_do_action(x1, y1, x2, y2, tex, hash_arg, no_sync, false, payload);

        /* update drawing rectangle */
        update_bounds(payload, x1, y1, x2, y2);
        
        x1 = x2; y1 = y2;
    }
    
    draw_epilogue(&cur, tex, primary);
}